summaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libgo
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libgo')
-rw-r--r--libgo/LICENSE27
-rw-r--r--libgo/MERGE4
-rw-r--r--libgo/Makefile.am2803
-rw-r--r--libgo/Makefile.in4789
-rw-r--r--libgo/PATENTS22
-rw-r--r--libgo/README45
-rw-r--r--libgo/README.gcc7
-rw-r--r--libgo/aclocal.m4981
-rw-r--r--libgo/config.h.in133
-rw-r--r--libgo/config/README2
-rw-r--r--libgo/config/go.m492
-rw-r--r--libgo/config/libtool.m47516
-rw-r--r--libgo/config/ltmain.sh8636
-rw-r--r--libgo/config/ltoptions.m4369
-rw-r--r--libgo/config/ltsugar.m4123
-rw-r--r--libgo/config/ltversion.m423
-rw-r--r--libgo/config/lt~obsolete.m498
-rw-r--r--libgo/configure17026
-rw-r--r--libgo/configure.ac476
-rw-r--r--libgo/go/archive/tar/common.go75
-rw-r--r--libgo/go/archive/tar/reader.go226
-rw-r--r--libgo/go/archive/tar/reader_test.go274
-rw-r--r--libgo/go/archive/tar/testdata/gnu.tarbin0 -> 3072 bytes
-rw-r--r--libgo/go/archive/tar/testdata/small.txt1
-rw-r--r--libgo/go/archive/tar/testdata/small2.txt1
-rw-r--r--libgo/go/archive/tar/testdata/star.tarbin0 -> 3072 bytes
-rw-r--r--libgo/go/archive/tar/testdata/v7.tarbin0 -> 3584 bytes
-rw-r--r--libgo/go/archive/tar/testdata/writer-big.tarbin0 -> 4096 bytes
-rw-r--r--libgo/go/archive/tar/testdata/writer.tarbin0 -> 3072 bytes
-rw-r--r--libgo/go/archive/tar/writer.go205
-rw-r--r--libgo/go/archive/tar/writer_test.go154
-rw-r--r--libgo/go/archive/zip/reader.go278
-rw-r--r--libgo/go/archive/zip/reader_test.go180
-rw-r--r--libgo/go/archive/zip/struct.go33
-rw-r--r--libgo/go/archive/zip/testdata/gophercolor16x16.pngbin0 -> 785 bytes
-rw-r--r--libgo/go/archive/zip/testdata/r.zipbin0 -> 440 bytes
-rw-r--r--libgo/go/archive/zip/testdata/readme.notzipbin0 -> 1905 bytes
-rw-r--r--libgo/go/archive/zip/testdata/readme.zipbin0 -> 1885 bytes
-rw-r--r--libgo/go/archive/zip/testdata/test.zipbin0 -> 1170 bytes
-rw-r--r--libgo/go/asn1/asn1.go785
-rw-r--r--libgo/go/asn1/asn1_test.go634
-rw-r--r--libgo/go/asn1/common.go149
-rw-r--r--libgo/go/asn1/marshal.go482
-rw-r--r--libgo/go/asn1/marshal_test.go100
-rw-r--r--libgo/go/big/arith.go259
-rw-r--r--libgo/go/big/arith_decl.go18
-rw-r--r--libgo/go/big/arith_test.go342
-rw-r--r--libgo/go/big/calibrate_test.go92
-rw-r--r--libgo/go/big/hilbert_test.go173
-rw-r--r--libgo/go/big/int.go741
-rw-r--r--libgo/go/big/int_test.go1055
-rw-r--r--libgo/go/big/nat.go1067
-rw-r--r--libgo/go/big/nat_test.go358
-rw-r--r--libgo/go/big/rat.go326
-rw-r--r--libgo/go/big/rat_test.go282
-rw-r--r--libgo/go/bufio/bufio.go526
-rw-r--r--libgo/go/bufio/bufio_test.go572
-rw-r--r--libgo/go/bytes/buffer.go315
-rw-r--r--libgo/go/bytes/buffer_test.go349
-rw-r--r--libgo/go/bytes/bytes.go602
-rw-r--r--libgo/go/bytes/bytes_decl.go8
-rw-r--r--libgo/go/bytes/bytes_test.go844
-rw-r--r--libgo/go/bytes/export_test.go8
-rw-r--r--libgo/go/bytes/indexbyte.c28
-rw-r--r--libgo/go/cmath/abs.go12
-rw-r--r--libgo/go/cmath/asin.go170
-rw-r--r--libgo/go/cmath/cmath_test.go853
-rw-r--r--libgo/go/cmath/conj.go8
-rw-r--r--libgo/go/cmath/exp.go55
-rw-r--r--libgo/go/cmath/isinf.go21
-rw-r--r--libgo/go/cmath/isnan.go25
-rw-r--r--libgo/go/cmath/log.go64
-rw-r--r--libgo/go/cmath/phase.go11
-rw-r--r--libgo/go/cmath/polar.go12
-rw-r--r--libgo/go/cmath/pow.go60
-rw-r--r--libgo/go/cmath/rect.go13
-rw-r--r--libgo/go/cmath/sin.go132
-rw-r--r--libgo/go/cmath/sqrt.go103
-rw-r--r--libgo/go/cmath/tan.go184
-rw-r--r--libgo/go/compress/flate/deflate.go521
-rw-r--r--libgo/go/compress/flate/deflate_test.go389
-rw-r--r--libgo/go/compress/flate/flate_test.go139
-rw-r--r--libgo/go/compress/flate/huffman_bit_writer.go506
-rw-r--r--libgo/go/compress/flate/huffman_code.go373
-rw-r--r--libgo/go/compress/flate/inflate.go620
-rw-r--r--libgo/go/compress/flate/reverse_bits.go48
-rw-r--r--libgo/go/compress/flate/token.go103
-rw-r--r--libgo/go/compress/flate/util.go72
-rw-r--r--libgo/go/compress/gzip/gunzip.go230
-rw-r--r--libgo/go/compress/gzip/gunzip_test.go305
-rw-r--r--libgo/go/compress/gzip/gzip.go187
-rw-r--r--libgo/go/compress/gzip/gzip_test.go84
-rw-r--r--libgo/go/compress/zlib/reader.go112
-rw-r--r--libgo/go/compress/zlib/reader_test.go95
-rw-r--r--libgo/go/compress/zlib/testdata/e.txt1
-rw-r--r--libgo/go/compress/zlib/testdata/pi.txt1
-rw-r--r--libgo/go/compress/zlib/writer.go106
-rw-r--r--libgo/go/compress/zlib/writer_test.go106
-rw-r--r--libgo/go/container/heap/heap.go102
-rw-r--r--libgo/go/container/heap/heap_test.go166
-rwxr-xr-xlibgo/go/container/list/list.go211
-rwxr-xr-xlibgo/go/container/list/list_test.go209
-rw-r--r--libgo/go/container/ring/ring.go153
-rw-r--r--libgo/go/container/ring/ring_test.go240
-rw-r--r--libgo/go/container/vector/defs.go51
-rw-r--r--libgo/go/container/vector/intvector.go208
-rw-r--r--libgo/go/container/vector/intvector_test.go344
-rw-r--r--libgo/go/container/vector/nogen_test.go76
-rw-r--r--libgo/go/container/vector/numbers_test.go122
-rw-r--r--libgo/go/container/vector/stringvector.go208
-rw-r--r--libgo/go/container/vector/stringvector_test.go344
-rw-r--r--libgo/go/container/vector/vector.go208
-rw-r--r--libgo/go/container/vector/vector_test.go344
-rw-r--r--libgo/go/crypto/aes/aes_test.go350
-rw-r--r--libgo/go/crypto/aes/block.go176
-rw-r--r--libgo/go/crypto/aes/cipher.go71
-rw-r--r--libgo/go/crypto/aes/const.go362
-rw-r--r--libgo/go/crypto/block/cbc.go71
-rw-r--r--libgo/go/crypto/block/cfb.go96
-rw-r--r--libgo/go/crypto/block/cfb_aes_test.go311
-rw-r--r--libgo/go/crypto/block/cipher.go57
-rw-r--r--libgo/go/crypto/block/cmac.go105
-rw-r--r--libgo/go/crypto/block/cmac_aes_test.go130
-rw-r--r--libgo/go/crypto/block/ctr.go67
-rw-r--r--libgo/go/crypto/block/eax.go253
-rw-r--r--libgo/go/crypto/block/eax_aes_test.go140
-rw-r--r--libgo/go/crypto/block/ecb.go270
-rw-r--r--libgo/go/crypto/block/ecb_aes_test.go127
-rw-r--r--libgo/go/crypto/block/ecb_test.go181
-rw-r--r--libgo/go/crypto/block/ofb.go60
-rw-r--r--libgo/go/crypto/block/ofb_aes_test.go108
-rw-r--r--libgo/go/crypto/block/xor.go124
-rw-r--r--libgo/go/crypto/block/xor_test.go168
-rw-r--r--libgo/go/crypto/blowfish/block.go101
-rw-r--r--libgo/go/crypto/blowfish/blowfish_test.go192
-rw-r--r--libgo/go/crypto/blowfish/cipher.go79
-rw-r--r--libgo/go/crypto/blowfish/const.go199
-rw-r--r--libgo/go/crypto/cast5/cast5.go536
-rw-r--r--libgo/go/crypto/cast5/cast5_test.go104
-rw-r--r--libgo/go/crypto/cipher/cbc.go78
-rw-r--r--libgo/go/crypto/cipher/cbc_aes_test.go89
-rw-r--r--libgo/go/crypto/cipher/cfb.go64
-rw-r--r--libgo/go/crypto/cipher/cfb_test.go35
-rw-r--r--libgo/go/crypto/cipher/cipher.go63
-rw-r--r--libgo/go/crypto/cipher/common_test.go28
-rw-r--r--libgo/go/crypto/cipher/ctr.go51
-rw-r--r--libgo/go/crypto/cipher/ctr_aes_test.go101
-rw-r--r--libgo/go/crypto/cipher/io.go57
-rw-r--r--libgo/go/crypto/cipher/ocfb.go112
-rw-r--r--libgo/go/crypto/cipher/ocfb_test.go39
-rw-r--r--libgo/go/crypto/cipher/ofb.go44
-rw-r--r--libgo/go/crypto/cipher/ofb_test.go101
-rw-r--r--libgo/go/crypto/elliptic/elliptic.go376
-rw-r--r--libgo/go/crypto/elliptic/elliptic_test.go331
-rw-r--r--libgo/go/crypto/hmac/hmac.go100
-rw-r--r--libgo/go/crypto/hmac/hmac_test.go205
-rw-r--r--libgo/go/crypto/md4/md4.go112
-rw-r--r--libgo/go/crypto/md4/md4_test.go71
-rw-r--r--libgo/go/crypto/md4/md4block.go89
-rw-r--r--libgo/go/crypto/md5/md5.go112
-rw-r--r--libgo/go/crypto/md5/md5_test.go71
-rw-r--r--libgo/go/crypto/md5/md5block.go172
-rw-r--r--libgo/go/crypto/ocsp/ocsp.go203
-rw-r--r--libgo/go/crypto/ocsp/ocsp_test.go97
-rw-r--r--libgo/go/crypto/openpgp/armor/armor.go220
-rw-r--r--libgo/go/crypto/openpgp/armor/armor_test.go97
-rw-r--r--libgo/go/crypto/openpgp/armor/encode.go162
-rw-r--r--libgo/go/crypto/openpgp/error/error.go46
-rw-r--r--libgo/go/crypto/openpgp/s2k/s2k.go146
-rw-r--r--libgo/go/crypto/openpgp/s2k/s2k_test.go94
-rw-r--r--libgo/go/crypto/rand/rand.go21
-rw-r--r--libgo/go/crypto/rand/rand_test.go27
-rw-r--r--libgo/go/crypto/rand/rand_unix.go125
-rw-r--r--libgo/go/crypto/rand/rand_windows.go43
-rw-r--r--libgo/go/crypto/rc4/rc4.go66
-rw-r--r--libgo/go/crypto/rc4/rc4_test.go59
-rw-r--r--libgo/go/crypto/ripemd160/ripemd160.go113
-rw-r--r--libgo/go/crypto/ripemd160/ripemd160_test.go64
-rw-r--r--libgo/go/crypto/ripemd160/ripemd160block.go161
-rw-r--r--libgo/go/crypto/rsa/pkcs1v15.go273
-rw-r--r--libgo/go/crypto/rsa/pkcs1v15_test.go220
-rw-r--r--libgo/go/crypto/rsa/rsa.go445
-rw-r--r--libgo/go/crypto/rsa/rsa_test.go250
-rw-r--r--libgo/go/crypto/sha1/sha1.go114
-rw-r--r--libgo/go/crypto/sha1/sha1_test.go73
-rw-r--r--libgo/go/crypto/sha1/sha1block.go81
-rw-r--r--libgo/go/crypto/sha256/sha256.go159
-rw-r--r--libgo/go/crypto/sha256/sha256_test.go125
-rw-r--r--libgo/go/crypto/sha256/sha256block.go129
-rw-r--r--libgo/go/crypto/sha512/sha512.go163
-rw-r--r--libgo/go/crypto/sha512/sha512_test.go125
-rw-r--r--libgo/go/crypto/sha512/sha512block.go144
-rw-r--r--libgo/go/crypto/subtle/constant_time.go57
-rw-r--r--libgo/go/crypto/subtle/constant_time_test.go105
-rw-r--r--libgo/go/crypto/tls/alert.go73
-rw-r--r--libgo/go/crypto/tls/ca_set.go89
-rw-r--r--libgo/go/crypto/tls/cipher_suites.go102
-rw-r--r--libgo/go/crypto/tls/common.go258
-rw-r--r--libgo/go/crypto/tls/conn.go801
-rw-r--r--libgo/go/crypto/tls/conn_test.go52
-rw-r--r--libgo/go/crypto/tls/generate_cert.go70
-rw-r--r--libgo/go/crypto/tls/handshake_client.go300
-rw-r--r--libgo/go/crypto/tls/handshake_client_test.go211
-rw-r--r--libgo/go/crypto/tls/handshake_messages.go904
-rw-r--r--libgo/go/crypto/tls/handshake_messages_test.go202
-rw-r--r--libgo/go/crypto/tls/handshake_server.go285
-rw-r--r--libgo/go/crypto/tls/handshake_server_test.go516
-rw-r--r--libgo/go/crypto/tls/key_agreement.go246
-rw-r--r--libgo/go/crypto/tls/prf.go153
-rw-r--r--libgo/go/crypto/tls/prf_test.go104
-rw-r--r--libgo/go/crypto/tls/tls.go167
-rw-r--r--libgo/go/crypto/twofish/twofish.go358
-rw-r--r--libgo/go/crypto/twofish/twofish_test.go129
-rw-r--r--libgo/go/crypto/x509/x509.go854
-rw-r--r--libgo/go/crypto/x509/x509_test.go198
-rw-r--r--libgo/go/crypto/xtea/block.go66
-rw-r--r--libgo/go/crypto/xtea/cipher.go92
-rw-r--r--libgo/go/crypto/xtea/xtea_test.go246
-rw-r--r--libgo/go/debug/dwarf/buf.go154
-rw-r--r--libgo/go/debug/dwarf/const.go433
-rw-r--r--libgo/go/debug/dwarf/entry.go343
-rw-r--r--libgo/go/debug/dwarf/open.go80
-rw-r--r--libgo/go/debug/dwarf/testdata/typedef.c79
-rwxr-xr-xlibgo/go/debug/dwarf/testdata/typedef.elfbin0 -> 10837 bytes
-rw-r--r--libgo/go/debug/dwarf/testdata/typedef.machobin0 -> 5256 bytes
-rw-r--r--libgo/go/debug/dwarf/type.go583
-rw-r--r--libgo/go/debug/dwarf/type_test.go112
-rw-r--r--libgo/go/debug/dwarf/unit.go62
-rw-r--r--libgo/go/debug/elf/elf.go1506
-rw-r--r--libgo/go/debug/elf/elf_test.go49
-rw-r--r--libgo/go/debug/elf/file.go605
-rw-r--r--libgo/go/debug/elf/file_test.go180
-rwxr-xr-xlibgo/go/debug/elf/testdata/gcc-386-freebsd-execbin0 -> 5742 bytes
-rwxr-xr-xlibgo/go/debug/elf/testdata/gcc-amd64-linux-execbin0 -> 8844 bytes
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obin0 -> 3088 bytes
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obin0 -> 2936 bytes
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.obin0 -> 1884 bytes
-rw-r--r--libgo/go/debug/gosym/pclinetest.h7
-rw-r--r--libgo/go/debug/gosym/pclinetest.s89
-rw-r--r--libgo/go/debug/gosym/pclntab.go82
-rw-r--r--libgo/go/debug/gosym/pclntab_test.go207
-rw-r--r--libgo/go/debug/gosym/symtab.go548
-rw-r--r--libgo/go/debug/macho/file.go517
-rw-r--r--libgo/go/debug/macho/file_test.go167
-rw-r--r--libgo/go/debug/macho/macho.go305
-rwxr-xr-xlibgo/go/debug/macho/testdata/gcc-386-darwin-execbin0 -> 12588 bytes
-rwxr-xr-xlibgo/go/debug/macho/testdata/gcc-amd64-darwin-execbin0 -> 8512 bytes
-rw-r--r--libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec-debugbin0 -> 4540 bytes
-rw-r--r--libgo/go/debug/macho/testdata/hello.c8
-rw-r--r--libgo/go/debug/pe/file.go309
-rw-r--r--libgo/go/debug/pe/file_test.go99
-rw-r--r--libgo/go/debug/pe/pe.go51
-rw-r--r--libgo/go/debug/pe/testdata/gcc-386-mingw-execbin0 -> 29941 bytes
-rw-r--r--libgo/go/debug/pe/testdata/gcc-386-mingw-objbin0 -> 2372 bytes
-rw-r--r--libgo/go/debug/pe/testdata/hello.c8
-rw-r--r--libgo/go/debug/proc/proc.go222
-rw-r--r--libgo/go/debug/proc/proc_darwin.go17
-rw-r--r--libgo/go/debug/proc/proc_freebsd.go17
-rw-r--r--libgo/go/debug/proc/proc_linux.go1316
-rw-r--r--libgo/go/debug/proc/proc_rtems.go17
-rw-r--r--libgo/go/debug/proc/proc_solaris.go17
-rw-r--r--libgo/go/debug/proc/proc_windows.go17
-rw-r--r--libgo/go/debug/proc/ptrace-nptl.txt132
-rw-r--r--libgo/go/debug/proc/regs_darwin_386.go5
-rw-r--r--libgo/go/debug/proc/regs_darwin_amd64.go5
-rw-r--r--libgo/go/debug/proc/regs_freebsd_386.go5
-rw-r--r--libgo/go/debug/proc/regs_freebsd_amd64.go5
-rw-r--r--libgo/go/debug/proc/regs_linux_386.go143
-rw-r--r--libgo/go/debug/proc/regs_linux_amd64.go191
-rw-r--r--libgo/go/debug/proc/regs_linux_arm.go39
-rw-r--r--libgo/go/debug/proc/regs_windows_386.go5
-rw-r--r--libgo/go/debug/proc/regs_windows_amd64.go5
-rw-r--r--libgo/go/ebnf/ebnf.go248
-rw-r--r--libgo/go/ebnf/ebnf_test.go77
-rw-r--r--libgo/go/ebnf/parser.go208
-rw-r--r--libgo/go/encoding/ascii85/ascii85.go300
-rw-r--r--libgo/go/encoding/ascii85/ascii85_test.go188
-rw-r--r--libgo/go/encoding/base32/base32.go368
-rw-r--r--libgo/go/encoding/base32/base32_test.go194
-rw-r--r--libgo/go/encoding/base64/base64.go329
-rw-r--r--libgo/go/encoding/base64/base64_test.go196
-rw-r--r--libgo/go/encoding/binary/binary.go409
-rw-r--r--libgo/go/encoding/binary/binary_test.go162
-rw-r--r--libgo/go/encoding/git85/git.go277
-rw-r--r--libgo/go/encoding/git85/git_test.go194
-rw-r--r--libgo/go/encoding/hex/hex.go101
-rw-r--r--libgo/go/encoding/hex/hex_test.go149
-rw-r--r--libgo/go/encoding/line/line.go95
-rw-r--r--libgo/go/encoding/line/line_test.go89
-rw-r--r--libgo/go/encoding/pem/pem.go257
-rw-r--r--libgo/go/encoding/pem/pem_test.go390
-rw-r--r--libgo/go/exec/exec.go183
-rw-r--r--libgo/go/exec/exec_test.go120
-rw-r--r--libgo/go/exec/lp_unix.go45
-rw-r--r--libgo/go/exec/lp_windows.go66
-rw-r--r--libgo/go/exp/README3
-rw-r--r--libgo/go/exp/datafmt/datafmt.go731
-rw-r--r--libgo/go/exp/datafmt/datafmt_test.go351
-rw-r--r--libgo/go/exp/datafmt/parser.go386
-rw-r--r--libgo/go/exp/draw/draw.go363
-rw-r--r--libgo/go/exp/draw/draw_test.go228
-rw-r--r--libgo/go/exp/draw/event.go56
-rw-r--r--libgo/go/exp/draw/x11/auth.go93
-rw-r--r--libgo/go/exp/draw/x11/conn.go622
-rw-r--r--libgo/go/exp/eval/abort.go85
-rw-r--r--libgo/go/exp/eval/bridge.go169
-rw-r--r--libgo/go/exp/eval/compiler.go92
-rw-r--r--libgo/go/exp/eval/eval_test.go259
-rw-r--r--libgo/go/exp/eval/expr.go2015
-rw-r--r--libgo/go/exp/eval/expr1.go1874
-rw-r--r--libgo/go/exp/eval/expr_test.go355
-rw-r--r--libgo/go/exp/eval/func.go70
-rw-r--r--libgo/go/exp/eval/scope.go207
-rw-r--r--libgo/go/exp/eval/stmt.go1302
-rw-r--r--libgo/go/exp/eval/stmt_test.go343
-rw-r--r--libgo/go/exp/eval/type.go1252
-rw-r--r--libgo/go/exp/eval/typec.go409
-rw-r--r--libgo/go/exp/eval/value.go586
-rw-r--r--libgo/go/exp/eval/world.go188
-rw-r--r--libgo/go/exp/ogle/abort.go35
-rw-r--r--libgo/go/exp/ogle/arch.go125
-rw-r--r--libgo/go/exp/ogle/cmd.go373
-rw-r--r--libgo/go/exp/ogle/event.go280
-rw-r--r--libgo/go/exp/ogle/frame.go212
-rw-r--r--libgo/go/exp/ogle/goroutine.go117
-rw-r--r--libgo/go/exp/ogle/main.go9
-rw-r--r--libgo/go/exp/ogle/process.go521
-rw-r--r--libgo/go/exp/ogle/rruntime.go271
-rw-r--r--libgo/go/exp/ogle/rtype.go288
-rw-r--r--libgo/go/exp/ogle/rvalue.go515
-rw-r--r--libgo/go/exp/ogle/vars.go272
-rw-r--r--libgo/go/expvar/expvar.go299
-rw-r--r--libgo/go/expvar/expvar_test.go154
-rw-r--r--libgo/go/flag/export_test.go32
-rw-r--r--libgo/go/flag/flag.go480
-rw-r--r--libgo/go/flag/flag_test.go194
-rw-r--r--libgo/go/fmt/doc.go164
-rw-r--r--libgo/go/fmt/fmt_test.go650
-rw-r--r--libgo/go/fmt/format.go398
-rw-r--r--libgo/go/fmt/print.go921
-rw-r--r--libgo/go/fmt/scan.go985
-rw-r--r--libgo/go/fmt/scan_test.go659
-rw-r--r--libgo/go/fmt/stringer_test.go61
-rw-r--r--libgo/go/go/ast/ast.go959
-rw-r--r--libgo/go/go/ast/filter.go429
-rw-r--r--libgo/go/go/ast/print.go217
-rw-r--r--libgo/go/go/ast/scope.go242
-rw-r--r--libgo/go/go/ast/walk.go396
-rw-r--r--libgo/go/go/doc/comment.go357
-rw-r--r--libgo/go/go/doc/doc.go650
-rw-r--r--libgo/go/go/parser/interface.go208
-rw-r--r--libgo/go/go/parser/parser.go1885
-rw-r--r--libgo/go/go/parser/parser_test.go112
-rw-r--r--libgo/go/go/printer/nodes.go1493
-rw-r--r--libgo/go/go/printer/printer.go1140
-rw-r--r--libgo/go/go/printer/printer_test.go138
-rw-r--r--libgo/go/go/printer/testdata/comments.golden483
-rw-r--r--libgo/go/go/printer/testdata/comments.input483
-rw-r--r--libgo/go/go/printer/testdata/comments.x57
-rw-r--r--libgo/go/go/printer/testdata/declarations.golden715
-rw-r--r--libgo/go/go/printer/testdata/declarations.input703
-rw-r--r--libgo/go/go/printer/testdata/empty.golden5
-rw-r--r--libgo/go/go/printer/testdata/empty.input5
-rw-r--r--libgo/go/go/printer/testdata/expressions.golden554
-rw-r--r--libgo/go/go/printer/testdata/expressions.input548
-rw-r--r--libgo/go/go/printer/testdata/expressions.raw554
-rw-r--r--libgo/go/go/printer/testdata/linebreaks.golden223
-rw-r--r--libgo/go/go/printer/testdata/linebreaks.input223
-rw-r--r--libgo/go/go/printer/testdata/statements.golden417
-rw-r--r--libgo/go/go/printer/testdata/statements.input338
-rw-r--r--libgo/go/go/scanner/errors.go186
-rw-r--r--libgo/go/go/scanner/scanner.go714
-rw-r--r--libgo/go/go/scanner/scanner_test.go672
-rw-r--r--libgo/go/go/token/position.go409
-rw-r--r--libgo/go/go/token/position_test.go158
-rw-r--r--libgo/go/go/token/token.go320
-rw-r--r--libgo/go/go/typechecker/scope.go119
-rw-r--r--libgo/go/go/typechecker/testdata/test0.go94
-rw-r--r--libgo/go/go/typechecker/testdata/test1.go13
-rw-r--r--libgo/go/go/typechecker/testdata/test3.go38
-rw-r--r--libgo/go/go/typechecker/testdata/test4.go11
-rw-r--r--libgo/go/go/typechecker/typechecker.go484
-rw-r--r--libgo/go/go/typechecker/typechecker_test.go168
-rw-r--r--libgo/go/go/typechecker/universe.go38
-rw-r--r--libgo/go/gob/codec_test.go1355
-rw-r--r--libgo/go/gob/decode.go1020
-rw-r--r--libgo/go/gob/decoder.go164
-rw-r--r--libgo/go/gob/doc.go307
-rw-r--r--libgo/go/gob/encode.go573
-rw-r--r--libgo/go/gob/encoder.go207
-rw-r--r--libgo/go/gob/encoder_test.go385
-rw-r--r--libgo/go/gob/error.go41
-rw-r--r--libgo/go/gob/type.go539
-rw-r--r--libgo/go/gob/type_test.go153
-rw-r--r--libgo/go/hash/adler32/adler32.go88
-rw-r--r--libgo/go/hash/adler32/adler32_test.go63
-rw-r--r--libgo/go/hash/crc32/crc32.go111
-rw-r--r--libgo/go/hash/crc32/crc32_test.go76
-rw-r--r--libgo/go/hash/crc64/crc64.go96
-rw-r--r--libgo/go/hash/crc64/crc64_test.go78
-rw-r--r--libgo/go/hash/hash.go36
-rw-r--r--libgo/go/html/doc.go106
-rw-r--r--libgo/go/html/entity.go2250
-rw-r--r--libgo/go/html/entity_test.go26
-rw-r--r--libgo/go/html/escape.go224
-rw-r--r--libgo/go/html/parse.go666
-rw-r--r--libgo/go/html/parse_test.go158
-rw-r--r--libgo/go/html/testdata/webkit/README28
-rw-r--r--libgo/go/html/testdata/webkit/comments01.dat126
-rw-r--r--libgo/go/html/testdata/webkit/doctype01.dat335
-rw-r--r--libgo/go/html/testdata/webkit/dom2string.js135
-rw-r--r--libgo/go/html/testdata/webkit/entities01.dat612
-rw-r--r--libgo/go/html/testdata/webkit/entities02.dat129
-rw-r--r--libgo/go/html/testdata/webkit/scriptdata01.dat308
-rw-r--r--libgo/go/html/testdata/webkit/tests1.dat1949
-rw-r--r--libgo/go/html/testdata/webkit/tests10.dat430
-rw-r--r--libgo/go/html/testdata/webkit/tests11.dat482
-rw-r--r--libgo/go/html/testdata/webkit/tests12.dat62
-rw-r--r--libgo/go/html/testdata/webkit/tests13.dat9
-rw-r--r--libgo/go/html/testdata/webkit/tests14.dat74
-rw-r--r--libgo/go/html/testdata/webkit/tests15.dat208
-rw-r--r--libgo/go/html/testdata/webkit/tests16.dat2277
-rw-r--r--libgo/go/html/testdata/webkit/tests2.dat738
-rw-r--r--libgo/go/html/testdata/webkit/tests3.dat293
-rw-r--r--libgo/go/html/testdata/webkit/tests4.dat59
-rw-r--r--libgo/go/html/testdata/webkit/tests5.dat191
-rw-r--r--libgo/go/html/testdata/webkit/tests6.dat653
-rw-r--r--libgo/go/html/testdata/webkit/tests7.dat390
-rw-r--r--libgo/go/html/testdata/webkit/tests8.dat148
-rw-r--r--libgo/go/html/testdata/webkit/tests9.dat430
-rw-r--r--libgo/go/html/testdata/webkit/webkit01.dat211
-rw-r--r--libgo/go/html/token.go398
-rw-r--r--libgo/go/html/token_test.go231
-rw-r--r--libgo/go/http/chunked.go56
-rw-r--r--libgo/go/http/client.go236
-rw-r--r--libgo/go/http/client_test.go40
-rw-r--r--libgo/go/http/dump.go76
-rw-r--r--libgo/go/http/fs.go265
-rw-r--r--libgo/go/http/fs_test.go172
-rw-r--r--libgo/go/http/lex.go144
-rw-r--r--libgo/go/http/lex_test.go70
-rw-r--r--libgo/go/http/persist.go303
-rw-r--r--libgo/go/http/pprof/pprof.go92
-rw-r--r--libgo/go/http/readrequest_test.go132
-rw-r--r--libgo/go/http/request.go693
-rw-r--r--libgo/go/http/request_test.go155
-rw-r--r--libgo/go/http/requestwrite_test.go139
-rw-r--r--libgo/go/http/response.go251
-rw-r--r--libgo/go/http/response_test.go203
-rw-r--r--libgo/go/http/responsewrite_test.go85
-rw-r--r--libgo/go/http/serve_test.go220
-rw-r--r--libgo/go/http/server.go766
-rw-r--r--libgo/go/http/status.go106
-rw-r--r--libgo/go/http/testdata/file1
-rw-r--r--libgo/go/http/transfer.go441
-rw-r--r--libgo/go/http/url.go595
-rw-r--r--libgo/go/http/url_test.go675
-rw-r--r--libgo/go/image/color.go251
-rw-r--r--libgo/go/image/format.go86
-rw-r--r--libgo/go/image/geom.go223
-rw-r--r--libgo/go/image/image.go506
-rw-r--r--libgo/go/image/jpeg/huffman.go190
-rw-r--r--libgo/go/image/jpeg/idct.go190
-rw-r--r--libgo/go/image/jpeg/reader.go455
-rw-r--r--libgo/go/image/names.go67
-rw-r--r--libgo/go/image/png/reader.go588
-rw-r--r--libgo/go/image/png/reader_test.go190
-rw-r--r--libgo/go/image/png/testdata/pngsuite/README9
-rw-r--r--libgo/go/image/png/testdata/pngsuite/README.original85
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn0g01.pngbin0 -> 164 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn0g01.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn0g02.pngbin0 -> 104 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn0g02.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn0g04.pngbin0 -> 145 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn0g04.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn0g08.pngbin0 -> 138 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn0g08.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn0g16.pngbin0 -> 167 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn0g16.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn2c08.pngbin0 -> 145 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn2c08.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn2c16.pngbin0 -> 302 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn2c16.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn3p01.pngbin0 -> 112 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn3p01.sng45
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn3p02.pngbin0 -> 146 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn3p02.sng50
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn3p04.pngbin0 -> 216 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn3p04.sng61
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn3p08.pngbin0 -> 1286 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn3p08.sng299
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn4a08.pngbin0 -> 126 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn4a08.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn4a16.pngbin0 -> 2206 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn4a16.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn6a08.pngbin0 -> 184 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn6a08.sng41
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn6a16.pngbin0 -> 3435 bytes
-rw-r--r--libgo/go/image/png/testdata/pngsuite/basn6a16.sng41
-rw-r--r--libgo/go/image/png/writer.go437
-rw-r--r--libgo/go/image/png/writer_test.go86
-rw-r--r--libgo/go/index/suffixarray/qsufsort.go164
-rw-r--r--libgo/go/index/suffixarray/suffixarray.go182
-rw-r--r--libgo/go/index/suffixarray/suffixarray_test.go234
-rw-r--r--libgo/go/io/io.go369
-rw-r--r--libgo/go/io/io_test.go156
-rw-r--r--libgo/go/io/ioutil/ioutil.go90
-rw-r--r--libgo/go/io/ioutil/ioutil_test.go92
-rw-r--r--libgo/go/io/ioutil/tempfile.go60
-rw-r--r--libgo/go/io/ioutil/tempfile_test.go33
-rw-r--r--libgo/go/io/multi.go60
-rw-r--r--libgo/go/io/multi_test.go88
-rw-r--r--libgo/go/io/pipe.go305
-rw-r--r--libgo/go/io/pipe_test.go271
-rw-r--r--libgo/go/json/decode.go861
-rw-r--r--libgo/go/json/decode_test.go517
-rw-r--r--libgo/go/json/encode.go332
-rw-r--r--libgo/go/json/indent.go116
-rw-r--r--libgo/go/json/scanner.go618
-rw-r--r--libgo/go/json/scanner_test.go260
-rw-r--r--libgo/go/json/stream.go184
-rw-r--r--libgo/go/json/stream_test.go122
-rw-r--r--libgo/go/log/log.go278
-rw-r--r--libgo/go/log/log_test.go86
-rw-r--r--libgo/go/math/acosh.go62
-rw-r--r--libgo/go/math/all_test.go2737
-rw-r--r--libgo/go/math/asin.go50
-rw-r--r--libgo/go/math/asinh.go72
-rw-r--r--libgo/go/math/atan.go62
-rw-r--r--libgo/go/math/atan2.go71
-rw-r--r--libgo/go/math/atanh.go79
-rw-r--r--libgo/go/math/bits.go59
-rw-r--r--libgo/go/math/cbrt.go79
-rw-r--r--libgo/go/math/const.go53
-rw-r--r--libgo/go/math/copysign.go12
-rw-r--r--libgo/go/math/erf.go340
-rw-r--r--libgo/go/math/exp.go14
-rw-r--r--libgo/go/math/exp2.go10
-rw-r--r--libgo/go/math/exp_port.go192
-rw-r--r--libgo/go/math/exp_test.go10
-rw-r--r--libgo/go/math/expm1.go238
-rw-r--r--libgo/go/math/fabs.go21
-rw-r--r--libgo/go/math/fdim.go29
-rw-r--r--libgo/go/math/floor.go53
-rw-r--r--libgo/go/math/fmod.go48
-rw-r--r--libgo/go/math/frexp.go33
-rw-r--r--libgo/go/math/gamma.go188
-rw-r--r--libgo/go/math/hypot.go41
-rw-r--r--libgo/go/math/hypot_port.go63
-rw-r--r--libgo/go/math/hypot_test.go9
-rw-r--r--libgo/go/math/j0.go433
-rw-r--r--libgo/go/math/j1.go426
-rw-r--r--libgo/go/math/jn.go310
-rw-r--r--libgo/go/math/ldexp.go45
-rw-r--r--libgo/go/math/lgamma.go350
-rw-r--r--libgo/go/math/log.go123
-rw-r--r--libgo/go/math/log10.go13
-rw-r--r--libgo/go/math/log10_decl.go8
-rw-r--r--libgo/go/math/log1p.go200
-rw-r--r--libgo/go/math/logb.go54
-rw-r--r--libgo/go/math/modf.go33
-rw-r--r--libgo/go/math/nextafter.go29
-rw-r--r--libgo/go/math/pow.go139
-rw-r--r--libgo/go/math/pow10.go30
-rw-r--r--libgo/go/math/remainder.go85
-rw-r--r--libgo/go/math/signbit.go10
-rw-r--r--libgo/go/math/sin.go66
-rw-r--r--libgo/go/math/sincos.go13
-rw-r--r--libgo/go/math/sinh.go68
-rw-r--r--libgo/go/math/sqrt.go28
-rw-r--r--libgo/go/math/sqrt_decl.go7
-rw-r--r--libgo/go/math/sqrt_port.go143
-rw-r--r--libgo/go/math/sqrt_test.go9
-rw-r--r--libgo/go/math/tan.go65
-rw-r--r--libgo/go/math/tanh.go28
-rw-r--r--libgo/go/math/unsafe.go21
-rw-r--r--libgo/go/mime/grammar.go36
-rw-r--r--libgo/go/mime/mediatype.go120
-rw-r--r--libgo/go/mime/mediatype_test.go117
-rw-r--r--libgo/go/mime/mime_test.go27
-rw-r--r--libgo/go/mime/multipart/multipart.go280
-rw-r--r--libgo/go/mime/multipart/multipart_test.go204
-rw-r--r--libgo/go/mime/test.types8
-rw-r--r--libgo/go/mime/type.go104
-rw-r--r--libgo/go/net/dial.go179
-rw-r--r--libgo/go/net/dialgoogle_test.go107
-rw-r--r--libgo/go/net/dict/dict.go212
-rw-r--r--libgo/go/net/dnsclient.go417
-rw-r--r--libgo/go/net/dnsconfig.go120
-rw-r--r--libgo/go/net/dnsmsg.go743
-rw-r--r--libgo/go/net/dnsname_test.go69
-rw-r--r--libgo/go/net/fd.go612
-rw-r--r--libgo/go/net/fd_linux.go149
-rw-r--r--libgo/go/net/fd_rtems.go137
-rw-r--r--libgo/go/net/fd_windows.go555
-rw-r--r--libgo/go/net/hosts.go86
-rw-r--r--libgo/go/net/hosts_test.go54
-rw-r--r--libgo/go/net/hosts_testdata12
-rw-r--r--libgo/go/net/ip.go446
-rw-r--r--libgo/go/net/ip_test.go94
-rw-r--r--libgo/go/net/ipraw_test.go117
-rw-r--r--libgo/go/net/iprawsock.go358
-rw-r--r--libgo/go/net/ipsock.go236
-rw-r--r--libgo/go/net/net.go192
-rw-r--r--libgo/go/net/net_test.go126
-rw-r--r--libgo/go/net/newpollserver.go41
-rw-r--r--libgo/go/net/newpollserver_rtems.go78
-rw-r--r--libgo/go/net/parse.go214
-rw-r--r--libgo/go/net/parse_test.go50
-rw-r--r--libgo/go/net/pipe.go62
-rw-r--r--libgo/go/net/pipe_test.go57
-rw-r--r--libgo/go/net/port.go70
-rw-r--r--libgo/go/net/port_test.go53
-rw-r--r--libgo/go/net/resolv_windows.go112
-rw-r--r--libgo/go/net/server_test.go203
-rw-r--r--libgo/go/net/sock.go181
-rw-r--r--libgo/go/net/srv_test.go22
-rw-r--r--libgo/go/net/tcpsock.go293
-rw-r--r--libgo/go/net/textproto/pipeline.go117
-rw-r--r--libgo/go/net/textproto/reader.go492
-rw-r--r--libgo/go/net/textproto/reader_test.go140
-rw-r--r--libgo/go/net/textproto/textproto.go122
-rw-r--r--libgo/go/net/textproto/writer.go119
-rw-r--r--libgo/go/net/textproto/writer_test.go35
-rw-r--r--libgo/go/net/timeout_test.go57
-rw-r--r--libgo/go/net/udpsock.go281
-rw-r--r--libgo/go/net/unixsock.go449
-rw-r--r--libgo/go/netchan/common.go325
-rw-r--r--libgo/go/netchan/export.go390
-rw-r--r--libgo/go/netchan/import.go243
-rw-r--r--libgo/go/netchan/netchan_test.go515
-rw-r--r--libgo/go/os/dir.go72
-rw-r--r--libgo/go/os/dir_largefile.go12
-rw-r--r--libgo/go/os/dir_regfile.go12
-rw-r--r--libgo/go/os/env.go73
-rw-r--r--libgo/go/os/env_test.go59
-rw-r--r--libgo/go/os/env_unix.go96
-rw-r--r--libgo/go/os/env_windows.go127
-rw-r--r--libgo/go/os/error.go113
-rw-r--r--libgo/go/os/exec.go154
-rw-r--r--libgo/go/os/file.go438
-rw-r--r--libgo/go/os/file_unix.go110
-rw-r--r--libgo/go/os/getwd.go92
-rw-r--r--libgo/go/os/inotify/inotify_linux.go291
-rw-r--r--libgo/go/os/inotify/inotify_linux_test.go99
-rw-r--r--libgo/go/os/os_test.go882
-rw-r--r--libgo/go/os/path.go116
-rw-r--r--libgo/go/os/path_test.go181
-rw-r--r--libgo/go/os/proc.go35
-rw-r--r--libgo/go/os/signal/mkunix.sh24
-rw-r--r--libgo/go/os/signal/signal.go48
-rw-r--r--libgo/go/os/signal/signal_test.go19
-rw-r--r--libgo/go/os/stat.go40
-rw-r--r--libgo/go/os/sys_bsd.go19
-rw-r--r--libgo/go/os/sys_linux.go28
-rw-r--r--libgo/go/os/sys_uname.go25
-rw-r--r--libgo/go/os/time.go20
-rw-r--r--libgo/go/os/types.go56
-rw-r--r--libgo/go/patch/apply.go54
-rw-r--r--libgo/go/patch/git.go121
-rw-r--r--libgo/go/patch/patch.go322
-rw-r--r--libgo/go/patch/patch_test.go390
-rw-r--r--libgo/go/patch/textdiff.go171
-rw-r--r--libgo/go/path/match.go278
-rw-r--r--libgo/go/path/match_test.go106
-rw-r--r--libgo/go/path/path.go212
-rw-r--r--libgo/go/path/path_test.go345
-rw-r--r--libgo/go/path/path_unix.go11
-rw-r--r--libgo/go/path/path_windows.go11
-rw-r--r--libgo/go/rand/exp.go223
-rw-r--r--libgo/go/rand/normal.go158
-rw-r--r--libgo/go/rand/rand.go179
-rw-r--r--libgo/go/rand/rand_test.go350
-rw-r--r--libgo/go/rand/rng.go246
-rw-r--r--libgo/go/rand/zipf.go73
-rw-r--r--libgo/go/reflect/all_test.go1392
-rw-r--r--libgo/go/reflect/deepequal.go135
-rw-r--r--libgo/go/reflect/tostring_test.go96
-rw-r--r--libgo/go/reflect/type.go743
-rw-r--r--libgo/go/reflect/value.go1242
-rw-r--r--libgo/go/regexp/all_test.go426
-rw-r--r--libgo/go/regexp/find_test.go459
-rw-r--r--libgo/go/regexp/regexp.go1337
-rw-r--r--libgo/go/rpc/client.go250
-rw-r--r--libgo/go/rpc/debug.go90
-rw-r--r--libgo/go/rpc/jsonrpc/all_test.go156
-rw-r--r--libgo/go/rpc/jsonrpc/client.go121
-rw-r--r--libgo/go/rpc/jsonrpc/server.go133
-rw-r--r--libgo/go/rpc/server.go530
-rw-r--r--libgo/go/rpc/server_test.go384
-rw-r--r--libgo/go/runtime/chan_defs.go56
-rw-r--r--libgo/go/runtime/debug.go159
-rw-r--r--libgo/go/runtime/debug/stack.go90
-rw-r--r--libgo/go/runtime/debug/stack_test.go55
-rw-r--r--libgo/go/runtime/error.go133
-rw-r--r--libgo/go/runtime/export_test.go17
-rw-r--r--libgo/go/runtime/extern.go163
-rw-r--r--libgo/go/runtime/hashmap_defs.go51
-rw-r--r--libgo/go/runtime/iface_defs.go18
-rw-r--r--libgo/go/runtime/malloc_defs.go130
-rw-r--r--libgo/go/runtime/mheapmap32_defs.go23
-rw-r--r--libgo/go/runtime/mheapmap64_defs.go31
-rw-r--r--libgo/go/runtime/pprof/pprof.go108
-rw-r--r--libgo/go/runtime/runtime_defs.go200
-rw-r--r--libgo/go/runtime/sig.go16
-rw-r--r--libgo/go/runtime/softfloat64.go498
-rw-r--r--libgo/go/runtime/softfloat64_test.go198
-rw-r--r--libgo/go/runtime/type.go206
-rw-r--r--libgo/go/scanner/scanner.go644
-rw-r--r--libgo/go/scanner/scanner_test.go482
-rw-r--r--libgo/go/smtp/auth.go69
-rw-r--r--libgo/go/smtp/smtp.go295
-rw-r--r--libgo/go/smtp/smtp_test.go182
-rw-r--r--libgo/go/sort/search.go110
-rw-r--r--libgo/go/sort/search_test.go137
-rw-r--r--libgo/go/sort/sort.go206
-rw-r--r--libgo/go/sort/sort_test.go267
-rw-r--r--libgo/go/strconv/atob.go28
-rw-r--r--libgo/go/strconv/atob_test.go56
-rw-r--r--libgo/go/strconv/atof.go413
-rw-r--r--libgo/go/strconv/atof_test.go183
-rw-r--r--libgo/go/strconv/atoi.go202
-rw-r--r--libgo/go/strconv/atoi_test.go303
-rw-r--r--libgo/go/strconv/decimal.go371
-rw-r--r--libgo/go/strconv/decimal_test.go117
-rw-r--r--libgo/go/strconv/fp_test.go149
-rw-r--r--libgo/go/strconv/ftoa.go405
-rw-r--r--libgo/go/strconv/ftoa_test.go145
-rw-r--r--libgo/go/strconv/internal_test.go15
-rw-r--r--libgo/go/strconv/itoa.go57
-rw-r--r--libgo/go/strconv/itoa_test.go174
-rw-r--r--libgo/go/strconv/quote.go264
-rw-r--r--libgo/go/strconv/quote_test.go170
-rw-r--r--libgo/go/strconv/testfp.txt181
-rw-r--r--libgo/go/strings/reader.go61
-rw-r--r--libgo/go/strings/strings.go559
-rw-r--r--libgo/go/strings/strings_test.go776
-rw-r--r--libgo/go/sync/cas.c15
-rw-r--r--libgo/go/sync/mutex.go61
-rw-r--r--libgo/go/sync/mutex_test.go91
-rw-r--r--libgo/go/sync/once.go35
-rw-r--r--libgo/go/sync/once_test.go37
-rw-r--r--libgo/go/sync/rwmutex.go75
-rw-r--r--libgo/go/sync/rwmutex_test.go114
-rw-r--r--libgo/go/sync/xadd_test.go9
-rw-r--r--libgo/go/syslog/syslog.go150
-rw-r--r--libgo/go/syslog/syslog_c.c19
-rw-r--r--libgo/go/syslog/syslog_solaris.go37
-rw-r--r--libgo/go/syslog/syslog_test.go95
-rw-r--r--libgo/go/syslog/syslog_unix.go31
-rw-r--r--libgo/go/tabwriter/tabwriter.go586
-rw-r--r--libgo/go/tabwriter/tabwriter_test.go625
-rw-r--r--libgo/go/template/format.go77
-rw-r--r--libgo/go/template/template.go992
-rw-r--r--libgo/go/template/template_test.go660
-rw-r--r--libgo/go/testing/benchmark.go195
-rw-r--r--libgo/go/testing/iotest/logger.go55
-rw-r--r--libgo/go/testing/iotest/reader.go69
-rw-r--r--libgo/go/testing/iotest/writer.go38
-rw-r--r--libgo/go/testing/quick/quick.go364
-rw-r--r--libgo/go/testing/quick/quick_test.go147
-rw-r--r--libgo/go/testing/script/script.go359
-rw-r--r--libgo/go/testing/script/script_test.go75
-rw-r--r--libgo/go/testing/testing.go174
-rw-r--r--libgo/go/time/format.go618
-rw-r--r--libgo/go/time/sleep.go151
-rw-r--r--libgo/go/time/sleep_test.go134
-rw-r--r--libgo/go/time/tick.go171
-rw-r--r--libgo/go/time/tick_test.go45
-rw-r--r--libgo/go/time/time.go229
-rw-r--r--libgo/go/time/time_test.go341
-rw-r--r--libgo/go/time/zoneinfo_unix.go267
-rw-r--r--libgo/go/time/zoneinfo_windows.go192
-rw-r--r--libgo/go/try/try.go174
-rw-r--r--libgo/go/try/try_test.go60
-rw-r--r--libgo/go/unicode/casetables.go21
-rw-r--r--libgo/go/unicode/digit.go13
-rw-r--r--libgo/go/unicode/digit_test.go126
-rw-r--r--libgo/go/unicode/letter.go241
-rw-r--r--libgo/go/unicode/letter_test.go377
-rw-r--r--libgo/go/unicode/script_test.go247
-rw-r--r--libgo/go/unicode/tables.go4238
-rw-r--r--libgo/go/utf16/utf16.go101
-rw-r--r--libgo/go/utf16/utf16_test.go118
-rw-r--r--libgo/go/utf8/string.go211
-rw-r--r--libgo/go/utf8/string_test.go109
-rw-r--r--libgo/go/utf8/utf8.go356
-rw-r--r--libgo/go/utf8/utf8_test.go315
-rw-r--r--libgo/go/websocket/client.go321
-rw-r--r--libgo/go/websocket/server.go219
-rw-r--r--libgo/go/websocket/websocket.go189
-rw-r--r--libgo/go/websocket/websocket_test.go272
-rw-r--r--libgo/go/xml/embed_test.go124
-rw-r--r--libgo/go/xml/read.go620
-rw-r--r--libgo/go/xml/read_test.go329
-rw-r--r--libgo/go/xml/xml.go1617
-rw-r--r--libgo/go/xml/xml_test.go439
-rw-r--r--libgo/merge.sh173
-rwxr-xr-xlibgo/mksysinfo.sh419
-rw-r--r--libgo/runtime/array.h28
-rw-r--r--libgo/runtime/chan.goc39
-rw-r--r--libgo/runtime/channel.h147
-rw-r--r--libgo/runtime/defs.h12
-rw-r--r--libgo/runtime/go-alloc.h11
-rw-r--r--libgo/runtime/go-append.c67
-rw-r--r--libgo/runtime/go-assert-interface.c49
-rw-r--r--libgo/runtime/go-assert.c18
-rw-r--r--libgo/runtime/go-assert.h18
-rw-r--r--libgo/runtime/go-breakpoint.c15
-rw-r--r--libgo/runtime/go-byte-array-to-string.c24
-rw-r--r--libgo/runtime/go-caller.c51
-rw-r--r--libgo/runtime/go-can-convert-interface.c76
-rw-r--r--libgo/runtime/go-cgo.c42
-rw-r--r--libgo/runtime/go-chan-cap.c41
-rw-r--r--libgo/runtime/go-chan-len.c41
-rw-r--r--libgo/runtime/go-check-interface.c46
-rw-r--r--libgo/runtime/go-close.c33
-rw-r--r--libgo/runtime/go-closed.c34
-rw-r--r--libgo/runtime/go-construct-map.c32
-rw-r--r--libgo/runtime/go-convert-interface.c138
-rw-r--r--libgo/runtime/go-copy.c21
-rw-r--r--libgo/runtime/go-defer.c69
-rw-r--r--libgo/runtime/go-defer.h36
-rw-r--r--libgo/runtime/go-deferred-recover.c92
-rw-r--r--libgo/runtime/go-eface-compare.c32
-rw-r--r--libgo/runtime/go-eface-val-compare.c32
-rw-r--r--libgo/runtime/go-getgoroot.c26
-rw-r--r--libgo/runtime/go-go.c656
-rw-r--r--libgo/runtime/go-gomaxprocs.c15
-rw-r--r--libgo/runtime/go-int-array-to-string.c85
-rw-r--r--libgo/runtime/go-int-to-string.c60
-rw-r--r--libgo/runtime/go-interface-compare.c31
-rw-r--r--libgo/runtime/go-interface-eface-compare.c32
-rw-r--r--libgo/runtime/go-interface-val-compare.c32
-rw-r--r--libgo/runtime/go-lock-os-thread.c24
-rw-r--r--libgo/runtime/go-main.c89
-rw-r--r--libgo/runtime/go-map-delete.c52
-rw-r--r--libgo/runtime/go-map-index.c127
-rw-r--r--libgo/runtime/go-map-len.c21
-rw-r--r--libgo/runtime/go-map-range.c102
-rw-r--r--libgo/runtime/go-nanotime.c22
-rw-r--r--libgo/runtime/go-new-channel.c57
-rw-r--r--libgo/runtime/go-new-map.c125
-rw-r--r--libgo/runtime/go-new.c21
-rw-r--r--libgo/runtime/go-note.c74
-rw-r--r--libgo/runtime/go-panic-defer.c13
-rw-r--r--libgo/runtime/go-panic.c121
-rw-r--r--libgo/runtime/go-panic.h94
-rw-r--r--libgo/runtime/go-print.c93
-rw-r--r--libgo/runtime/go-rec-big.c34
-rw-r--r--libgo/runtime/go-rec-nb-big.c39
-rw-r--r--libgo/runtime/go-rec-nb-small.c127
-rw-r--r--libgo/runtime/go-rec-small.c289
-rw-r--r--libgo/runtime/go-recover.c69
-rw-r--r--libgo/runtime/go-reflect-call.c375
-rw-r--r--libgo/runtime/go-reflect-chan.c148
-rw-r--r--libgo/runtime/go-reflect-map.c139
-rw-r--r--libgo/runtime/go-reflect.c186
-rw-r--r--libgo/runtime/go-rune.c77
-rw-r--r--libgo/runtime/go-runtime-error.c84
-rw-r--r--libgo/runtime/go-sched.c15
-rw-r--r--libgo/runtime/go-select.c758
-rw-r--r--libgo/runtime/go-semacquire.c151
-rw-r--r--libgo/runtime/go-send-big.c31
-rw-r--r--libgo/runtime/go-send-nb-big.c30
-rw-r--r--libgo/runtime/go-send-nb-small.c112
-rw-r--r--libgo/runtime/go-send-small.c165
-rw-r--r--libgo/runtime/go-signal.c200
-rw-r--r--libgo/runtime/go-signal.h7
-rw-r--r--libgo/runtime/go-strcmp.c27
-rw-r--r--libgo/runtime/go-string-to-byte-array.c24
-rw-r--r--libgo/runtime/go-string-to-int-array.c50
-rw-r--r--libgo/runtime/go-string.h42
-rw-r--r--libgo/runtime/go-strplus.c30
-rw-r--r--libgo/runtime/go-strslice.c26
-rw-r--r--libgo/runtime/go-trampoline.c53
-rw-r--r--libgo/runtime/go-type-eface.c55
-rw-r--r--libgo/runtime/go-type-error.c28
-rw-r--r--libgo/runtime/go-type-identity.c50
-rw-r--r--libgo/runtime/go-type-interface.c55
-rw-r--r--libgo/runtime/go-type-string.c45
-rw-r--r--libgo/runtime/go-type.h309
-rw-r--r--libgo/runtime/go-typedesc-equal.c38
-rw-r--r--libgo/runtime/go-typestring.c18
-rw-r--r--libgo/runtime/go-unreflect.c30
-rw-r--r--libgo/runtime/go-unsafe-new.c27
-rw-r--r--libgo/runtime/go-unsafe-newarray.c28
-rw-r--r--libgo/runtime/go-unsafe-pointer.c97
-rw-r--r--libgo/runtime/go-unwind.c426
-rw-r--r--libgo/runtime/goc2c.c735
-rw-r--r--libgo/runtime/iface.goc131
-rw-r--r--libgo/runtime/interface.h57
-rw-r--r--libgo/runtime/malloc.goc357
-rw-r--r--libgo/runtime/malloc.h399
-rw-r--r--libgo/runtime/map.goc69
-rw-r--r--libgo/runtime/map.h86
-rw-r--r--libgo/runtime/mcache.c131
-rw-r--r--libgo/runtime/mcentral.c209
-rw-r--r--libgo/runtime/mem.c76
-rw-r--r--libgo/runtime/mem_posix_memalign.c38
-rw-r--r--libgo/runtime/mfinal.c217
-rw-r--r--libgo/runtime/mfixalloc.c62
-rw-r--r--libgo/runtime/mgc0.c392
-rw-r--r--libgo/runtime/mheap.c350
-rw-r--r--libgo/runtime/mheapmap32.c99
-rw-r--r--libgo/runtime/mheapmap32.h41
-rw-r--r--libgo/runtime/mheapmap64.c120
-rw-r--r--libgo/runtime/mheapmap64.h60
-rw-r--r--libgo/runtime/mprof.goc305
-rw-r--r--libgo/runtime/msize.c169
-rw-r--r--libgo/runtime/proc.c16
-rw-r--r--libgo/runtime/reflect.goc35
-rw-r--r--libgo/runtime/rtems-task-variable-add.c24
-rw-r--r--libgo/runtime/runtime.h196
-rw-r--r--libgo/runtime/sigqueue.goc113
-rw-r--r--libgo/runtime/string.goc57
-rw-r--r--libgo/runtime/thread.c118
-rw-r--r--libgo/syscalls/errno.c25
-rw-r--r--libgo/syscalls/errstr.go24
-rw-r--r--libgo/syscalls/errstr_decl.go9
-rw-r--r--libgo/syscalls/errstr_decl_linux.go9
-rw-r--r--libgo/syscalls/errstr_decl_rtems.go10
-rw-r--r--libgo/syscalls/errstr_rtems.go26
-rw-r--r--libgo/syscalls/exec.go248
-rw-r--r--libgo/syscalls/exec_helpers.go154
-rw-r--r--libgo/syscalls/exec_stubs.go25
-rw-r--r--libgo/syscalls/sleep_rtems.go19
-rw-r--r--libgo/syscalls/sleep_select.go13
-rw-r--r--libgo/syscalls/socket.go383
-rw-r--r--libgo/syscalls/socket_bsd.go74
-rw-r--r--libgo/syscalls/socket_epoll.go50
-rw-r--r--libgo/syscalls/socket_linux.go75
-rw-r--r--libgo/syscalls/socket_solaris.go76
-rw-r--r--libgo/syscalls/stringbyte.go24
-rw-r--r--libgo/syscalls/syscall.go48
-rw-r--r--libgo/syscalls/syscall_linux.go188
-rw-r--r--libgo/syscalls/syscall_linux_386.go15
-rw-r--r--libgo/syscalls/syscall_linux_amd64.go15
-rw-r--r--libgo/syscalls/syscall_rtems.go7
-rw-r--r--libgo/syscalls/syscall_solaris.go7
-rw-r--r--libgo/syscalls/syscall_solaris_386.go20
-rw-r--r--libgo/syscalls/syscall_solaris_amd64.go21
-rw-r--r--libgo/syscalls/syscall_solaris_sparc.go17
-rw-r--r--libgo/syscalls/syscall_solaris_sparc64.go21
-rw-r--r--libgo/syscalls/syscall_stubs.go33
-rw-r--r--libgo/syscalls/syscall_uname.go7
-rw-r--r--libgo/syscalls/syscall_unix.go24
-rw-r--r--libgo/syscalls/sysfile_largefile.go13
-rw-r--r--libgo/syscalls/sysfile_posix.go427
-rw-r--r--libgo/syscalls/sysfile_regfile.go13
-rw-r--r--libgo/syscalls/sysfile_stat_largefile.go12
-rw-r--r--libgo/syscalls/sysfile_stat_regfile.go12
-rw-r--r--libgo/testsuite/Makefile.am21
-rw-r--r--libgo/testsuite/Makefile.in413
-rw-r--r--libgo/testsuite/config/default.exp17
-rwxr-xr-xlibgo/testsuite/gotest343
-rw-r--r--libgo/testsuite/lib/libgo.exp50
-rw-r--r--libgo/testsuite/libgo.testmain/testmain.exp60
958 files changed, 242071 insertions, 0 deletions
diff --git a/libgo/LICENSE b/libgo/LICENSE
new file mode 100644
index 000000000..6a66aea5e
--- /dev/null
+++ b/libgo/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/libgo/MERGE b/libgo/MERGE
new file mode 100644
index 000000000..97e6655a6
--- /dev/null
+++ b/libgo/MERGE
@@ -0,0 +1,4 @@
+559f12e8fcd5
+
+The first line of this file holds the Mercurial revision number of the
+last merge done from the master library sources.
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
new file mode 100644
index 000000000..e19d229a9
--- /dev/null
+++ b/libgo/Makefile.am
@@ -0,0 +1,2803 @@
+# Makefile.am -- Go library Makefile.
+
+# 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.
+
+# Process this file with autoreconf to produce Makefile.in.
+
+# Go support.
+SUFFIXES = .c .go .gox .o .obj .lo .a
+
+if LIBGO_IS_RTEMS
+subdirs = testsuite
+endif
+
+SUBDIRS = ${subdirs}
+
+gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+
+MAINT_CHARSET = latin1
+
+mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
+PWD_COMMAND = $${PWDCMD-pwd}
+STAMP = echo timestamp >
+
+toolexecdir = $(glibgo_toolexecdir)
+toolexeclibdir = $(glibgo_toolexeclibdir)
+
+LIBFFI = @LIBFFI@
+LIBFFIINCS = @LIBFFIINCS@
+
+WARN_CFLAGS = $(WARN_FLAGS) $(WERROR)
+
+# -I/-D flags to pass when compiling.
+AM_CPPFLAGS = -I $(srcdir)/runtime $(LIBFFIINCS) $(PTHREAD_CFLAGS)
+
+ACLOCAL_AMFLAGS = -I ./config -I ../config
+
+AM_CFLAGS = -fexceptions -fplan9-extensions $(SPLIT_STACK) $(WARN_CFLAGS) \
+ $(STRINGOPS_FLAG) \
+ -I $(srcdir)/../gcc -I $(MULTIBUILDTOP)../../gcc/include
+
+if USING_SPLIT_STACK
+AM_LDFLAGS = -XCClinker $(SPLIT_STACK)
+endif
+
+# Multilib support.
+MAKEOVERRIDES=
+
+# Work around what appears to be a GNU make handling MAKEFLAGS
+# values defined in terms of make variables, as is the case for CC and
+# friends when we are called from the top level Makefile.
+AM_MAKEFLAGS = \
+ "AR_FLAGS=$(AR_FLAGS)" \
+ "CC_FOR_BUILD=$(CC_FOR_BUILD)" \
+ "CC_FOR_TARGET=$(CC_FOR_TARGET)" \
+ "CFLAGS=$(CFLAGS)" \
+ "CXXFLAGS=$(CXXFLAGS)" \
+ "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
+ "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
+ "GOC_FOR_TARGET=$(GOC_FOR_TARGET)" \
+ "GOC=$(GOC)" \
+ "GOCFLAGS=$(GOCFLAGS)" \
+ "INSTALL=$(INSTALL)" \
+ "INSTALL_DATA=$(INSTALL_DATA)" \
+ "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
+ "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
+ "LDFLAGS=$(LDFLAGS)" \
+ "LIBCFLAGS=$(LIBCFLAGS)" \
+ "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
+ "MAKE=$(MAKE)" \
+ "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
+ "PICFLAG=$(PICFLAG)" \
+ "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
+ "SHELL=$(SHELL)" \
+ "RUNTESTFLAGS=$(RUNTESTFLAGS)" \
+ "exec_prefix=$(exec_prefix)" \
+ "infodir=$(infodir)" \
+ "libdir=$(libdir)" \
+ "includedir=$(includedir)" \
+ "prefix=$(prefix)" \
+ "tooldir=$(tooldir)" \
+ "gxx_include_dir=$(gxx_include_dir)" \
+ "AR=$(AR)" \
+ "AS=$(AS)" \
+ "LD=$(LD)" \
+ "RANLIB=$(RANLIB)" \
+ "NM=$(NM)" \
+ "NM_FOR_BUILD=$(NM_FOR_BUILD)" \
+ "NM_FOR_TARGET=$(NM_FOR_TARGET)" \
+ "DESTDIR=$(DESTDIR)" \
+ "WERROR=$(WERROR)"
+
+# Subdir rules rely on $(FLAGS_TO_PASS)
+FLAGS_TO_PASS = $(AM_MAKEFLAGS)
+
+toolexeclib_LTLIBRARIES = libgo.la
+toolexeclib_LIBRARIES = libgobegin.a
+
+toolexeclibgodir = $(toolexeclibdir)/go/$(gcc_version)/$(target_alias)
+
+toolexeclibgo_DATA = \
+ asn1.gox \
+ big.gox \
+ bufio.gox \
+ bytes.gox \
+ cmath.gox \
+ ebnf.gox \
+ exec.gox \
+ expvar.gox \
+ flag.gox \
+ fmt.gox \
+ gob.gox \
+ hash.gox \
+ html.gox \
+ http.gox \
+ image.gox \
+ io.gox \
+ json.gox \
+ log.gox \
+ math.gox \
+ mime.gox \
+ net.gox \
+ netchan.gox \
+ os.gox \
+ patch.gox \
+ path.gox \
+ rand.gox \
+ reflect.gox \
+ regexp.gox \
+ rpc.gox \
+ runtime.gox \
+ scanner.gox \
+ smtp.gox \
+ sort.gox \
+ strconv.gox \
+ strings.gox \
+ sync.gox \
+ syscall.gox \
+ syslog.gox \
+ tabwriter.gox \
+ template.gox \
+ testing.gox \
+ time.gox \
+ try.gox \
+ unicode.gox \
+ utf16.gox \
+ utf8.gox \
+ websocket.gox \
+ xml.gox
+
+toolexeclibgoarchivedir = $(toolexeclibgodir)/archive
+
+toolexeclibgoarchive_DATA = \
+ archive/tar.gox \
+ archive/zip.gox
+
+toolexeclibgocompressdir = $(toolexeclibgodir)/compress
+
+toolexeclibgocompress_DATA = \
+ compress/flate.gox \
+ compress/gzip.gox \
+ compress/zlib.gox
+
+toolexeclibgocontainerdir = $(toolexeclibgodir)/container
+
+toolexeclibgocontainer_DATA = \
+ container/heap.gox \
+ container/list.gox \
+ container/ring.gox \
+ container/vector.gox
+
+toolexeclibgocryptodir = $(toolexeclibgodir)/crypto
+
+toolexeclibgocrypto_DATA = \
+ crypto/aes.gox \
+ crypto/block.gox \
+ crypto/blowfish.gox \
+ crypto/cast5.gox \
+ crypto/cipher.gox \
+ crypto/elliptic.gox \
+ crypto/hmac.gox \
+ crypto/md4.gox \
+ crypto/md5.gox \
+ crypto/ocsp.gox \
+ crypto/rand.gox \
+ crypto/rc4.gox \
+ crypto/ripemd160.gox \
+ crypto/rsa.gox \
+ crypto/sha1.gox \
+ crypto/sha256.gox \
+ crypto/sha512.gox \
+ crypto/subtle.gox \
+ crypto/tls.gox \
+ crypto/twofish.gox \
+ crypto/x509.gox \
+ crypto/xtea.gox
+
+toolexeclibgocryptoopenpgpdir = $(toolexeclibgocryptodir)/openpgp
+
+toolexeclibgocryptoopenpgp_DATA = \
+ crypto/openpgp/armor.gox \
+ crypto/openpgp/error.gox \
+ crypto/openpgp/s2k.gox
+
+toolexeclibgodebugdir = $(toolexeclibgodir)/debug
+
+toolexeclibgodebug_DATA = \
+ debug/dwarf.gox \
+ debug/elf.gox \
+ debug/gosym.gox \
+ debug/macho.gox \
+ debug/pe.gox \
+ debug/proc.gox
+
+toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
+
+toolexeclibgoencoding_DATA = \
+ encoding/ascii85.gox \
+ encoding/base32.gox \
+ encoding/base64.gox \
+ encoding/binary.gox \
+ encoding/line.gox \
+ encoding/git85.gox \
+ encoding/hex.gox \
+ encoding/pem.gox
+
+toolexeclibgoexpdir = $(toolexeclibgodir)/exp
+
+toolexeclibgoexp_DATA = \
+ exp/datafmt.gox \
+ exp/draw.gox \
+ exp/eval.gox
+
+toolexeclibgogodir = $(toolexeclibgodir)/go
+
+toolexeclibgogo_DATA = \
+ go/ast.gox \
+ go/doc.gox \
+ go/parser.gox \
+ go/printer.gox \
+ go/scanner.gox \
+ go/token.gox \
+ go/typechecker.gox
+
+toolexeclibgohashdir = $(toolexeclibgodir)/hash
+
+toolexeclibgohash_DATA = \
+ hash/adler32.gox \
+ hash/crc32.gox \
+ hash/crc64.gox
+
+toolexeclibgohttpdir = $(toolexeclibgodir)/http
+
+toolexeclibgohttp_DATA = \
+ http/pprof.gox
+
+toolexeclibgoimagedir = $(toolexeclibgodir)/image
+
+toolexeclibgoimage_DATA = \
+ image/jpeg.gox \
+ image/png.gox
+
+toolexeclibgoindexdir = $(toolexeclibgodir)/index
+
+toolexeclibgoindex_DATA = \
+ index/suffixarray.gox
+
+toolexeclibgoiodir = $(toolexeclibgodir)/io
+
+toolexeclibgoio_DATA = \
+ io/ioutil.gox
+
+toolexeclibgomimedir = $(toolexeclibgodir)/mime
+
+toolexeclibgomime_DATA = \
+ mime/multipart.gox
+
+toolexeclibgonetdir = $(toolexeclibgodir)/net
+
+toolexeclibgonet_DATA = \
+ net/dict.gox \
+ net/textproto.gox
+
+toolexeclibgoosdir = $(toolexeclibgodir)/os
+
+if LIBGO_IS_LINUX
+# os_inotify_gox = os/inotify.gox
+os_inotify_gox =
+else
+os_inotify_gox =
+endif
+
+toolexeclibgoos_DATA = \
+ $(os_inotify_gox) \
+ os/signal.gox
+
+toolexeclibgorpcdir = $(toolexeclibgodir)/rpc
+
+toolexeclibgorpc_DATA = \
+ rpc/jsonrpc.gox
+
+toolexeclibgoruntimedir = $(toolexeclibgodir)/runtime
+
+toolexeclibgoruntime_DATA = \
+ runtime/debug.gox \
+ runtime/pprof.gox
+
+toolexeclibgotestingdir = $(toolexeclibgodir)/testing
+
+toolexeclibgotesting_DATA = \
+ testing/iotest.gox \
+ testing/quick.gox \
+ testing/script.gox
+
+if HAVE_SYS_MMAN_H
+runtime_mem_file = runtime/mem.c
+else
+runtime_mem_file = runtime/mem_posix_memalign.c
+endif
+
+if LIBGO_IS_RTEMS
+rtems_task_variable_add_file = runtime/rtems-task-variable-add.c
+else
+rtems_task_variable_add_file =
+endif
+
+runtime_files = \
+ runtime/go-append.c \
+ runtime/go-assert.c \
+ runtime/go-assert-interface.c \
+ runtime/go-byte-array-to-string.c \
+ runtime/go-breakpoint.c \
+ runtime/go-caller.c \
+ runtime/go-can-convert-interface.c \
+ runtime/go-cgo.c \
+ runtime/go-chan-cap.c \
+ runtime/go-chan-len.c \
+ runtime/go-check-interface.c \
+ runtime/go-close.c \
+ runtime/go-closed.c \
+ runtime/go-construct-map.c \
+ runtime/go-convert-interface.c \
+ runtime/go-copy.c \
+ runtime/go-defer.c \
+ runtime/go-deferred-recover.c \
+ runtime/go-eface-compare.c \
+ runtime/go-eface-val-compare.c \
+ runtime/go-getgoroot.c \
+ runtime/go-go.c \
+ runtime/go-gomaxprocs.c \
+ runtime/go-int-array-to-string.c \
+ runtime/go-int-to-string.c \
+ runtime/go-interface-compare.c \
+ runtime/go-interface-eface-compare.c \
+ runtime/go-interface-val-compare.c \
+ runtime/go-lock-os-thread.c \
+ runtime/go-map-delete.c \
+ runtime/go-map-index.c \
+ runtime/go-map-len.c \
+ runtime/go-map-range.c \
+ runtime/go-nanotime.c \
+ runtime/go-new-channel.c \
+ runtime/go-new-map.c \
+ runtime/go-new.c \
+ runtime/go-note.c \
+ runtime/go-panic.c \
+ runtime/go-panic-defer.c \
+ runtime/go-print.c \
+ runtime/go-rec-big.c \
+ runtime/go-rec-nb-big.c \
+ runtime/go-rec-nb-small.c \
+ runtime/go-rec-small.c \
+ runtime/go-recover.c \
+ runtime/go-reflect.c \
+ runtime/go-reflect-call.c \
+ runtime/go-reflect-chan.c \
+ runtime/go-reflect-map.c \
+ runtime/go-rune.c \
+ runtime/go-runtime-error.c \
+ runtime/go-sched.c \
+ runtime/go-select.c \
+ runtime/go-semacquire.c \
+ runtime/go-send-big.c \
+ runtime/go-send-nb-big.c \
+ runtime/go-send-nb-small.c \
+ runtime/go-send-small.c \
+ runtime/go-signal.c \
+ runtime/go-strcmp.c \
+ runtime/go-string-to-byte-array.c \
+ runtime/go-string-to-int-array.c \
+ runtime/go-strplus.c \
+ runtime/go-strslice.c \
+ runtime/go-trampoline.c \
+ runtime/go-type-eface.c \
+ runtime/go-type-error.c \
+ runtime/go-type-identity.c \
+ runtime/go-type-interface.c \
+ runtime/go-type-string.c \
+ runtime/go-typedesc-equal.c \
+ runtime/go-typestring.c \
+ runtime/go-unreflect.c \
+ runtime/go-unsafe-new.c \
+ runtime/go-unsafe-newarray.c \
+ runtime/go-unsafe-pointer.c \
+ runtime/go-unwind.c \
+ runtime/mcache.c \
+ runtime/mcentral.c \
+ $(runtime_mem_file) \
+ runtime/mfinal.c \
+ runtime/mfixalloc.c \
+ runtime/mgc0.c \
+ runtime/mheap.c \
+ runtime/mheapmap32.c \
+ runtime/mheapmap64.c \
+ runtime/msize.c \
+ runtime/proc.c \
+ runtime/thread.c \
+ $(rtems_task_variable_add_file) \
+ chan.c \
+ iface.c \
+ malloc.c \
+ map.c \
+ mprof.c \
+ reflect.c \
+ sigqueue.c \
+ string.c
+
+goc2c.$(OBJEXT): runtime/goc2c.c
+ $(CC_FOR_BUILD) -c $(CFLAGS_FOR_BUILD) $<
+
+goc2c: goc2c.$(OBJEXT)
+ $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $<
+
+malloc.c: $(srcdir)/runtime/malloc.goc goc2c
+ ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+ mv -f $@.tmp $@
+
+mprof.c: $(srcdir)/runtime/mprof.goc goc2c
+ ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+ mv -f $@.tmp $@
+
+reflect.c: $(srcdir)/runtime/reflect.goc goc2c
+ ./goc2c --gcc --go-prefix libgo_reflect $< > $@.tmp
+ mv -f $@.tmp $@
+
+sigqueue.c: $(srcdir)/runtime/sigqueue.goc goc2c
+ ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+ mv -f $@.tmp $@
+
+%.c: $(srcdir)/runtime/%.goc goc2c
+ ./goc2c --gcc $< > $@.tmp
+ mv -f $@.tmp $@
+
+go_asn1_files = \
+ go/asn1/asn1.go \
+ go/asn1/common.go \
+ go/asn1/marshal.go
+
+go_big_files = \
+ go/big/arith.go \
+ go/big/int.go \
+ go/big/nat.go \
+ go/big/rat.go
+
+go_bufio_files = \
+ go/bufio/bufio.go
+
+go_bytes_files = \
+ go/bytes/buffer.go \
+ go/bytes/bytes.go \
+ go/bytes/bytes_decl.go
+go_bytes_c_files = \
+ go/bytes/indexbyte.c
+
+go_cmath_files = \
+ go/cmath/abs.go \
+ go/cmath/asin.go \
+ go/cmath/conj.go \
+ go/cmath/exp.go \
+ go/cmath/isinf.go \
+ go/cmath/isnan.go \
+ go/cmath/log.go \
+ go/cmath/phase.go \
+ go/cmath/polar.go \
+ go/cmath/pow.go \
+ go/cmath/rect.go \
+ go/cmath/sin.go \
+ go/cmath/sqrt.go \
+ go/cmath/tan.go
+
+go_ebnf_files = \
+ go/ebnf/ebnf.go \
+ go/ebnf/parser.go
+
+go_exec_files = \
+ go/exec/exec.go \
+ go/exec/lp_unix.go
+
+go_expvar_files = \
+ go/expvar/expvar.go
+
+go_flag_files = \
+ go/flag/flag.go
+
+go_fmt_files = \
+ go/fmt/doc.go \
+ go/fmt/format.go \
+ go/fmt/print.go \
+ go/fmt/scan.go
+
+go_gob_files = \
+ go/gob/decode.go \
+ go/gob/decoder.go \
+ go/gob/doc.go \
+ go/gob/encode.go \
+ go/gob/encoder.go \
+ go/gob/error.go \
+ go/gob/type.go
+
+go_hash_files = \
+ go/hash/hash.go
+
+go_html_files = \
+ go/html/doc.go \
+ go/html/entity.go \
+ go/html/escape.go \
+ go/html/parse.go \
+ go/html/token.go
+
+go_http_files = \
+ go/http/chunked.go \
+ go/http/client.go \
+ go/http/dump.go \
+ go/http/fs.go \
+ go/http/lex.go \
+ go/http/persist.go \
+ go/http/request.go \
+ go/http/response.go \
+ go/http/server.go \
+ go/http/status.go \
+ go/http/transfer.go \
+ go/http/url.go
+
+go_image_files = \
+ go/image/color.go \
+ go/image/format.go \
+ go/image/geom.go \
+ go/image/image.go \
+ go/image/names.go
+
+go_io_files = \
+ go/io/multi.go \
+ go/io/io.go \
+ go/io/pipe.go
+
+go_json_files = \
+ go/json/decode.go \
+ go/json/encode.go \
+ go/json/indent.go \
+ go/json/scanner.go \
+ go/json/stream.go
+
+go_log_files = \
+ go/log/log.go
+
+go_math_files = \
+ go/math/acosh.go \
+ go/math/asin.go \
+ go/math/asinh.go \
+ go/math/atan.go \
+ go/math/atanh.go \
+ go/math/atan2.go \
+ go/math/bits.go \
+ go/math/cbrt.go \
+ go/math/const.go \
+ go/math/copysign.go \
+ go/math/erf.go \
+ go/math/exp.go \
+ go/math/exp_port.go \
+ go/math/exp2.go \
+ go/math/expm1.go \
+ go/math/fabs.go \
+ go/math/fdim.go \
+ go/math/floor.go \
+ go/math/fmod.go \
+ go/math/frexp.go \
+ go/math/gamma.go \
+ go/math/hypot.go \
+ go/math/hypot_port.go \
+ go/math/j0.go \
+ go/math/j1.go \
+ go/math/jn.go \
+ go/math/ldexp.go \
+ go/math/lgamma.go \
+ go/math/log.go \
+ go/math/log1p.go \
+ go/math/log10.go \
+ go/math/logb.go \
+ go/math/modf.go \
+ go/math/nextafter.go \
+ go/math/pow.go \
+ go/math/pow10.go \
+ go/math/remainder.go \
+ go/math/signbit.go \
+ go/math/sin.go \
+ go/math/sincos.go \
+ go/math/sinh.go \
+ go/math/sqrt.go \
+ go/math/sqrt_port.go \
+ go/math/tan.go \
+ go/math/tanh.go \
+ go/math/unsafe.go
+
+go_mime_files = \
+ go/mime/grammar.go \
+ go/mime/mediatype.go \
+ go/mime/type.go
+
+if LIBGO_IS_RTEMS
+go_net_fd_os_file = go/net/fd_rtems.go
+go_net_newpollserver_file = go/net/newpollserver_rtems.go
+else # !LIBGO_IS_RTEMS
+if LIBGO_IS_LINUX
+go_net_fd_os_file = go/net/fd_linux.go
+go_net_newpollserver_file = go/net/newpollserver.go
+else # !LIBGO_IS_LINUX && !LIBGO_IS_RTEMS
+# By default use select with pipes. Most systems should have
+# something better.
+go_net_fd_os_file = go/net/fd_rtems.go
+go_net_newpollserver_file = go/net/newpollserver.go
+endif # !LIBGO_IS_LINUX
+endif # !LIBGO_IS_RTEMS
+
+go_net_files = \
+ go/net/dial.go \
+ go/net/dnsclient.go \
+ go/net/dnsconfig.go \
+ go/net/dnsmsg.go \
+ $(go_net_newpollserver_file) \
+ go/net/fd.go \
+ $(go_net_fd_os_file) \
+ go/net/hosts.go \
+ go/net/ip.go \
+ go/net/iprawsock.go \
+ go/net/ipsock.go \
+ go/net/net.go \
+ go/net/parse.go \
+ go/net/pipe.go \
+ go/net/port.go \
+ go/net/sock.go \
+ go/net/tcpsock.go \
+ go/net/udpsock.go \
+ go/net/unixsock.go
+
+go_netchan_files = \
+ go/netchan/common.go \
+ go/netchan/export.go \
+ go/netchan/import.go
+
+if LIBGO_IS_SOLARIS
+if LIBGO_IS_386
+go_os_dir_file = go/os/dir_largefile.go
+else
+go_os_dir_file = go/os/dir_regfile.go
+endif
+else
+if LIBGO_IS_LINUX
+go_os_dir_file = go/os/dir_largefile.go
+else
+go_os_dir_file = go/os/dir_regfile.go
+endif
+endif
+
+if LIBGO_IS_LINUX
+go_os_sys_file = go/os/sys_linux.go
+else
+if LIBGO_IS_SOLARIS
+go_os_sys_file = go/os/sys_uname.go
+else
+if LIBGO_IS_RTEMS
+go_os_sys_file = go/os/sys_uname.go
+else
+go_os_sys_file = go/os/sys_bsd.go
+endif
+endif
+endif
+
+go_os_files = \
+ $(go_os_dir_file) \
+ go/os/dir.go \
+ go/os/env.go \
+ go/os/env_unix.go \
+ go/os/error.go \
+ go/os/exec.go \
+ go/os/file.go \
+ go/os/file_unix.go \
+ go/os/getwd.go \
+ go/os/path.go \
+ go/os/proc.go \
+ go/os/stat.go \
+ $(go_os_sys_file) \
+ go/os/time.go \
+ go/os/types.go
+
+go_patch_files = \
+ go/patch/apply.go \
+ go/patch/git.go \
+ go/patch/patch.go \
+ go/patch/textdiff.go
+
+go_path_files = \
+ go/path/match.go \
+ go/path/path.go \
+ go/path/path_unix.go
+
+go_rand_files = \
+ go/rand/exp.go \
+ go/rand/normal.go \
+ go/rand/rand.go \
+ go/rand/rng.go \
+ go/rand/zipf.go
+
+go_reflect_files = \
+ go/reflect/deepequal.go \
+ go/reflect/type.go \
+ go/reflect/value.go
+
+go_regexp_files = \
+ go/regexp/regexp.go
+
+go_rpc_files = \
+ go/rpc/client.go \
+ go/rpc/debug.go \
+ go/rpc/server.go
+
+go_runtime_files = \
+ go/runtime/debug.go \
+ go/runtime/error.go \
+ go/runtime/extern.go \
+ go/runtime/malloc_defs.go \
+ go/runtime/runtime_defs.go \
+ go/runtime/sig.go \
+ go/runtime/softfloat64.go \
+ go/runtime/type.go \
+ version.go
+
+version.go: s-version; @true
+s-version: Makefile
+ rm -f version.go.tmp
+ echo "package runtime" > version.go.tmp
+ echo 'const defaultGoroot = "$(prefix)"' >> version.go.tmp
+ echo 'const theVersion = "'`$(CC) --version | sed 1q`'"' >> version.go.tmp
+ echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
+ echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
+ $(SHELL) $(srcdir)/../move-if-change version.go.tmp version.go
+ $(STAMP) $@
+
+go_scanner_files = \
+ go/scanner/scanner.go
+
+go_smtp_files = \
+ go/smtp/auth.go \
+ go/smtp/smtp.go
+
+go_sort_files = \
+ go/sort/search.go \
+ go/sort/sort.go
+
+go_strconv_files = \
+ go/strconv/atob.go \
+ go/strconv/atof.go \
+ go/strconv/atoi.go \
+ go/strconv/decimal.go \
+ go/strconv/ftoa.go \
+ go/strconv/itoa.go \
+ go/strconv/quote.go
+
+go_strings_files = \
+ go/strings/reader.go \
+ go/strings/strings.go
+
+go_sync_files = \
+ go/sync/mutex.go \
+ go/sync/once.go \
+ go/sync/rwmutex.go
+go_sync_c_files = \
+ go/sync/cas.c
+
+if LIBGO_IS_SOLARIS
+go_syslog_file = go/syslog/syslog_solaris.go
+else
+go_syslog_file = go/syslog/syslog_unix.go
+endif
+
+go_syslog_files = \
+ go/syslog/syslog.go \
+ $(go_syslog_file)
+go_syslog_c_files = \
+ go/syslog/syslog_c.c
+
+go_tabwriter_files = \
+ go/tabwriter/tabwriter.go
+
+go_template_files = \
+ go/template/format.go \
+ go/template/template.go
+
+go_testing_files = \
+ go/testing/benchmark.go \
+ go/testing/testing.go
+
+go_time_files = \
+ go/time/format.go \
+ go/time/sleep.go \
+ go/time/tick.go \
+ go/time/time.go \
+ go/time/zoneinfo_unix.go
+
+go_try_files = \
+ go/try/try.go
+
+go_unicode_files = \
+ go/unicode/casetables.go \
+ go/unicode/digit.go \
+ go/unicode/letter.go \
+ go/unicode/tables.go
+
+go_utf16_files = \
+ go/utf16/utf16.go
+
+go_utf8_files = \
+ go/utf8/string.go \
+ go/utf8/utf8.go
+
+go_websocket_files = \
+ go/websocket/client.go \
+ go/websocket/server.go \
+ go/websocket/websocket.go
+
+go_xml_files = \
+ go/xml/read.go \
+ go/xml/xml.go
+
+go_archive_tar_files = \
+ go/archive/tar/common.go \
+ go/archive/tar/reader.go \
+ go/archive/tar/writer.go
+
+go_archive_zip_files = \
+ go/archive/zip/reader.go \
+ go/archive/zip/struct.go
+
+go_compress_flate_files = \
+ go/compress/flate/deflate.go \
+ go/compress/flate/huffman_bit_writer.go \
+ go/compress/flate/huffman_code.go \
+ go/compress/flate/inflate.go \
+ go/compress/flate/reverse_bits.go \
+ go/compress/flate/token.go \
+ go/compress/flate/util.go
+
+go_compress_gzip_files = \
+ go/compress/gzip/gzip.go \
+ go/compress/gzip/gunzip.go
+
+go_compress_zlib_files = \
+ go/compress/zlib/reader.go \
+ go/compress/zlib/writer.go
+
+go_container_heap_files = \
+ go/container/heap/heap.go
+
+go_container_list_files = \
+ go/container/list/list.go
+
+go_container_ring_files = \
+ go/container/ring/ring.go
+
+go_container_vector_files = \
+ go/container/vector/defs.go \
+ go/container/vector/intvector.go \
+ go/container/vector/stringvector.go \
+ go/container/vector/vector.go
+
+go_crypto_aes_files = \
+ go/crypto/aes/block.go \
+ go/crypto/aes/cipher.go \
+ go/crypto/aes/const.go
+go_crypto_block_files = \
+ go/crypto/block/cbc.go \
+ go/crypto/block/cfb.go \
+ go/crypto/block/cmac.go \
+ go/crypto/block/cipher.go \
+ go/crypto/block/ctr.go \
+ go/crypto/block/eax.go \
+ go/crypto/block/ecb.go \
+ go/crypto/block/ofb.go \
+ go/crypto/block/xor.go
+go_crypto_blowfish_files = \
+ go/crypto/blowfish/block.go \
+ go/crypto/blowfish/const.go \
+ go/crypto/blowfish/cipher.go
+go_crypto_cast5_files = \
+ go/crypto/cast5/cast5.go
+go_crypto_cipher_files = \
+ go/crypto/cipher/cbc.go \
+ go/crypto/cipher/cfb.go \
+ go/crypto/cipher/cipher.go \
+ go/crypto/cipher/ctr.go \
+ go/crypto/cipher/io.go \
+ go/crypto/cipher/ocfb.go \
+ go/crypto/cipher/ofb.go
+go_crypto_elliptic_files = \
+ go/crypto/elliptic/elliptic.go
+go_crypto_hmac_files = \
+ go/crypto/hmac/hmac.go
+go_crypto_md4_files = \
+ go/crypto/md4/md4.go \
+ go/crypto/md4/md4block.go
+go_crypto_md5_files = \
+ go/crypto/md5/md5.go \
+ go/crypto/md5/md5block.go
+go_crypto_ocsp_files = \
+ go/crypto/ocsp/ocsp.go
+go_crypto_rand_files = \
+ go/crypto/rand/rand.go \
+ go/crypto/rand/rand_unix.go
+go_crypto_rc4_files = \
+ go/crypto/rc4/rc4.go
+go_crypto_ripemd160_files = \
+ go/crypto/ripemd160/ripemd160.go \
+ go/crypto/ripemd160/ripemd160block.go
+go_crypto_rsa_files = \
+ go/crypto/rsa/pkcs1v15.go \
+ go/crypto/rsa/rsa.go
+go_crypto_sha1_files = \
+ go/crypto/sha1/sha1.go \
+ go/crypto/sha1/sha1block.go
+go_crypto_sha256_files = \
+ go/crypto/sha256/sha256.go \
+ go/crypto/sha256/sha256block.go
+go_crypto_sha512_files = \
+ go/crypto/sha512/sha512.go \
+ go/crypto/sha512/sha512block.go
+go_crypto_subtle_files = \
+ go/crypto/subtle/constant_time.go
+go_crypto_tls_files = \
+ go/crypto/tls/alert.go \
+ go/crypto/tls/ca_set.go \
+ go/crypto/tls/cipher_suites.go \
+ go/crypto/tls/common.go \
+ go/crypto/tls/conn.go \
+ go/crypto/tls/handshake_client.go \
+ go/crypto/tls/handshake_messages.go \
+ go/crypto/tls/handshake_server.go \
+ go/crypto/tls/key_agreement.go \
+ go/crypto/tls/prf.go \
+ go/crypto/tls/tls.go
+go_crypto_twofish_files = \
+ go/crypto/twofish/twofish.go
+go_crypto_x509_files = \
+ go/crypto/x509/x509.go
+go_crypto_xtea_files = \
+ go/crypto/xtea/block.go \
+ go/crypto/xtea/cipher.go
+
+go_crypto_openpgp_armor_files = \
+ go/crypto/openpgp/armor/armor.go \
+ go/crypto/openpgp/armor/encode.go
+go_crypto_openpgp_error_files = \
+ go/crypto/openpgp/error/error.go
+go_crypto_openpgp_s2k_files = \
+ go/crypto/openpgp/s2k/s2k.go
+
+go_debug_dwarf_files = \
+ go/debug/dwarf/buf.go \
+ go/debug/dwarf/const.go \
+ go/debug/dwarf/entry.go \
+ go/debug/dwarf/open.go \
+ go/debug/dwarf/type.go \
+ go/debug/dwarf/unit.go
+go_debug_elf_files = \
+ go/debug/elf/elf.go \
+ go/debug/elf/file.go
+go_debug_gosym_files = \
+ go/debug/gosym/pclntab.go \
+ go/debug/gosym/symtab.go
+go_debug_macho_files = \
+ go/debug/macho/file.go \
+ go/debug/macho/macho.go
+go_debug_pe_files = \
+ go/debug/pe/file.go \
+ go/debug/pe/pe.go
+
+go_debug_proc_files = \
+ go/debug/proc/proc.go \
+ go/debug/proc/proc_$(GOOS).go \
+ $(GO_DEBUG_PROC_REGS_OS_ARCH_FILE)
+
+go_encoding_ascii85_files = \
+ go/encoding/ascii85/ascii85.go
+go_encoding_base32_files = \
+ go/encoding/base32/base32.go
+go_encoding_base64_files = \
+ go/encoding/base64/base64.go
+go_encoding_binary_files = \
+ go/encoding/binary/binary.go
+go_encoding_git85_files = \
+ go/encoding/git85/git.go
+go_encoding_hex_files = \
+ go/encoding/hex/hex.go
+go_encoding_line_files = \
+ go/encoding/line/line.go
+go_encoding_pem_files = \
+ go/encoding/pem/pem.go
+
+go_exp_datafmt_files = \
+ go/exp/datafmt/datafmt.go \
+ go/exp/datafmt/parser.go
+go_exp_draw_files = \
+ go/exp/draw/draw.go \
+ go/exp/draw/event.go
+go_exp_eval_files = \
+ go/exp/eval/abort.go \
+ go/exp/eval/bridge.go \
+ go/exp/eval/compiler.go \
+ go/exp/eval/expr.go \
+ go/exp/eval/expr1.go \
+ go/exp/eval/func.go \
+ go/exp/eval/scope.go \
+ go/exp/eval/stmt.go \
+ go/exp/eval/type.go \
+ go/exp/eval/typec.go \
+ go/exp/eval/value.go \
+ go/exp/eval/world.go
+
+go_go_ast_files = \
+ go/go/ast/ast.go \
+ go/go/ast/filter.go \
+ go/go/ast/print.go \
+ go/go/ast/scope.go \
+ go/go/ast/walk.go
+go_go_doc_files = \
+ go/go/doc/comment.go \
+ go/go/doc/doc.go
+go_go_parser_files = \
+ go/go/parser/interface.go \
+ go/go/parser/parser.go
+go_go_printer_files = \
+ go/go/printer/nodes.go \
+ go/go/printer/printer.go
+go_go_scanner_files = \
+ go/go/scanner/errors.go \
+ go/go/scanner/scanner.go
+go_go_token_files = \
+ go/go/token/position.go \
+ go/go/token/token.go
+go_go_typechecker_files = \
+ go/go/typechecker/scope.go \
+ go/go/typechecker/typechecker.go \
+ go/go/typechecker/universe.go
+
+go_hash_adler32_files = \
+ go/hash/adler32/adler32.go
+go_hash_crc32_files = \
+ go/hash/crc32/crc32.go
+go_hash_crc64_files = \
+ go/hash/crc64/crc64.go
+
+go_http_pprof_files = \
+ go/http/pprof/pprof.go
+
+go_image_jpeg_files = \
+ go/image/jpeg/huffman.go \
+ go/image/jpeg/idct.go \
+ go/image/jpeg/reader.go
+
+go_image_png_files = \
+ go/image/png/reader.go \
+ go/image/png/writer.go
+
+go_index_suffixarray_files = \
+ go/index/suffixarray/qsufsort.go \
+ go/index/suffixarray/suffixarray.go
+
+go_io_ioutil_files = \
+ go/io/ioutil/ioutil.go \
+ go/io/ioutil/tempfile.go
+
+go_mime_multipart_files = \
+ go/mime/multipart/multipart.go
+
+go_net_dict_files = \
+ go/net/dict/dict.go
+
+go_net_textproto_files = \
+ go/net/textproto/pipeline.go \
+ go/net/textproto/reader.go \
+ go/net/textproto/textproto.go \
+ go/net/textproto/writer.go
+
+go_os_inotify_files = \
+ go/os/inotify/inotify_linux.go
+
+go_os_signal_files = \
+ go/os/signal/signal.go \
+ unix.go
+
+go_rpc_jsonrpc_files = \
+ go/rpc/jsonrpc/client.go \
+ go/rpc/jsonrpc/server.go
+
+go_runtime_debug_files = \
+ go/runtime/debug/stack.go
+go_runtime_pprof_files = \
+ go/runtime/pprof/pprof.go
+
+go_testing_iotest_files = \
+ go/testing/iotest/logger.go \
+ go/testing/iotest/reader.go \
+ go/testing/iotest/writer.go
+go_testing_quick_files = \
+ go/testing/quick/quick.go
+go_testing_script_files = \
+ go/testing/script/script.go
+
+# Define Syscall and Syscall6.
+if LIBGO_IS_RTEMS
+syscall_syscall_file = syscalls/syscall_stubs.go
+else
+syscall_syscall_file = syscalls/syscall.go
+endif
+
+# Declare libc functions that vary for largefile systems.
+if LIBGO_IS_LINUX
+# Always use lseek64 on GNU/Linux.
+syscall_filesize_file = syscalls/sysfile_largefile.go
+syscall_stat_file = syscalls/sysfile_stat_largefile.go
+else # !LIBGO_IS_LINUX
+if LIBGO_IS_SOLARIS
+# FIXME: Same for sparc vs. sparc64. Introduce new/additional conditional?
+if LIBGO_IS_386
+# Use lseek64 on 386 Solaris.
+syscall_filesize_file = syscalls/sysfile_largefile.go
+syscall_stat_file = syscalls/sysfile_stat_largefile.go
+else # !LIBGO_IS_LINUX && LIBGO_IS_SOLARIS && !LIBGO_IS_386
+# Use lseek on amd64 Solaris.
+syscall_filesize_file = syscalls/sysfile_regfile.go
+syscall_stat_file = syscalls/sysfile_stat_regfile.go
+endif # !LIBGO_IS_386
+else # !LIBGO_IS_LINUX && !LIBGO_IS_SOLARIS
+# Use lseek by default.
+syscall_filesize_file = syscalls/sysfile_regfile.go
+syscall_stat_file = syscalls/sysfile_stat_regfile.go
+endif # !LIBGO_IS_SOLARIS
+endif # !LIBGO_IS_LINUX
+
+
+# Define ForkExec, PtraceForkExec, Exec, and Wait4.
+if LIBGO_IS_RTEMS
+syscall_exec_os_file = syscalls/exec_stubs.go
+else
+syscall_exec_os_file = syscalls/exec.go
+endif
+
+# Define Sleep.
+if LIBGO_IS_RTEMS
+syscall_sleep_file = syscalls/sleep_rtems.go
+else
+syscall_sleep_file = syscalls/sleep_select.go
+endif
+
+# Define Errstr.
+if LIBGO_IS_RTEMS
+syscall_errstr_file = syscalls/errstr_rtems.go
+else
+syscall_errstr_file = syscalls/errstr.go
+endif
+
+# Declare libc_strerror_r which is the Go name for strerror_r.
+if LIBGO_IS_RTEMS
+# RTEMS uses newlib in which strerror_r returns char *.
+syscall_errstr_decl_file = syscalls/errstr_decl_rtems.go
+else
+if LIBGO_IS_LINUX
+# In Linux the POSIX strerror_r is called __xpg_strerror_r.
+syscall_errstr_decl_file = syscalls/errstr_decl_linux.go
+else
+# On other systems we hope strerror_r is just strerror_r.
+syscall_errstr_decl_file = syscalls/errstr_decl.go
+endif
+endif
+
+# Define socket sizes and types.
+if LIBGO_IS_LINUX
+syscall_socket_os_file = syscalls/socket_linux.go
+else
+if LIBGO_IS_SOLARIS
+syscall_socket_os_file = syscalls/socket_solaris.go
+else
+syscall_socket_os_file = syscalls/socket_bsd.go
+endif
+endif
+
+# Support for epoll.
+if LIBGO_IS_LINUX
+syscall_socket_epoll_file = syscalls/socket_epoll.go
+else
+syscall_socket_epoll_file =
+endif
+
+# Support for uname.
+if LIBGO_IS_SOLARIS
+if LIBGO_IS_386
+# 32-bit Solaris 2/x86 needs _nuname, handled in syscall_solaris_386.go.
+syscall_uname_file =
+else # !LIBGO_IS_386 && LIBGO_IS_SOLARIS
+syscall_uname_file = syscalls/syscall_uname.go
+endif
+else # !LIBGO_IS_SOLARIS
+syscall_uname_file = syscalls/syscall_uname.go
+endif
+
+syscall_arch.go: s-syscall_arch; @true
+s-syscall_arch: Makefile
+ rm -f syscall_arch.go.tmp
+ echo "package syscall" > syscall_arch.go.tmp
+ echo 'const ARCH = "'$(GOARCH)'"' >> syscall_arch.go.tmp
+ echo 'const OS = "'$(GOOS)'"' >> syscall_arch.go.tmp
+ $(SHELL) $(srcdir)/../move-if-change syscall_arch.go.tmp syscall_arch.go
+ $(STAMP) $@
+
+go_syscall_files = \
+ $(syscall_errstr_file) \
+ $(syscall_errstr_decl_file) \
+ syscalls/exec_helpers.go \
+ $(syscall_exec_os_file) \
+ $(syscall_filesize_file) \
+ $(syscall_stat_file) \
+ $(syscall_sleep_file) \
+ syscalls/socket.go \
+ $(syscall_socket_os_file) \
+ $(syscall_socket_epoll_file) \
+ $(syscall_syscall_file) \
+ $(syscall_uname_file) \
+ syscalls/syscall_unix.go \
+ syscalls/stringbyte.go \
+ syscalls/syscall_$(GOOS).go \
+ $(GO_SYSCALLS_SYSCALL_OS_ARCH_FILE) \
+ syscalls/sysfile_posix.go \
+ sysinfo.go \
+ syscall_arch.go
+go_syscall_c_files = \
+ syscalls/errno.c
+
+if LIBGO_IS_LINUX
+# os_lib_inotify_lo = os/inotify.lo
+os_lib_inotify_lo =
+else
+os_lib_inotify_lo =
+endif
+
+libgo_go_objs = \
+ asn1/asn1.lo \
+ big/big.lo \
+ bufio/bufio.lo \
+ bytes/bytes.lo \
+ bytes/index.lo \
+ cmath/cmath.lo \
+ ebnf/ebnf.lo \
+ exec/exec.lo \
+ expvar/expvar.lo \
+ flag/flag.lo \
+ fmt/fmt.lo \
+ gob/gob.lo \
+ hash/hash.lo \
+ html/html.lo \
+ http/http.lo \
+ image/image.lo \
+ io/io.lo \
+ json/json.lo \
+ log/log.lo \
+ math/math.lo \
+ mime/mime.lo \
+ net/net.lo \
+ netchan/netchan.lo \
+ os/os.lo \
+ patch/patch.lo \
+ path/path.lo \
+ rand/rand.lo \
+ reflect/reflect.lo \
+ regexp/regexp.lo \
+ rpc/rpc.lo \
+ runtime/runtime.lo \
+ scanner/scanner.lo \
+ smtp/smtp.lo \
+ sort/sort.lo \
+ strconv/strconv.lo \
+ strings/strings.lo \
+ sync/mutex.lo \
+ sync/cas.lo \
+ syslog/syslog.lo \
+ syslog/syslog_c.lo \
+ tabwriter/tabwriter.lo \
+ template/template.lo \
+ time/time.lo \
+ try/try.lo \
+ unicode/unicode.lo \
+ utf16/utf16.lo \
+ utf8/utf8.lo \
+ websocket/websocket.lo \
+ xml/xml.lo \
+ archive/tar.lo \
+ archive/zip.lo \
+ compress/flate.lo \
+ compress/gzip.lo \
+ compress/zlib.lo \
+ container/heap.lo \
+ container/list.lo \
+ container/ring.lo \
+ container/vector.lo \
+ crypto/aes.lo \
+ crypto/block.lo \
+ crypto/blowfish.lo \
+ crypto/cast5.lo \
+ crypto/cipher.lo \
+ crypto/elliptic.lo \
+ crypto/hmac.lo \
+ crypto/md4.lo \
+ crypto/md5.lo \
+ crypto/ocsp.lo \
+ crypto/rand.lo \
+ crypto/rc4.lo \
+ crypto/ripemd160.lo \
+ crypto/rsa.lo \
+ crypto/sha1.lo \
+ crypto/sha256.lo \
+ crypto/sha512.lo \
+ crypto/subtle.lo \
+ crypto/tls.lo \
+ crypto/twofish.lo \
+ crypto/x509.lo \
+ crypto/xtea.lo \
+ crypto/openpgp/armor.lo \
+ crypto/openpgp/error.lo \
+ crypto/openpgp/s2k.lo \
+ debug/dwarf.lo \
+ debug/elf.lo \
+ debug/gosym.lo \
+ debug/macho.lo \
+ debug/pe.lo \
+ debug/proc.lo \
+ encoding/ascii85.lo \
+ encoding/base32.lo \
+ encoding/base64.lo \
+ encoding/binary.lo \
+ encoding/git85.lo \
+ encoding/hex.lo \
+ encoding/line.lo \
+ encoding/pem.lo \
+ exp/datafmt.lo \
+ exp/draw.lo \
+ exp/eval.lo \
+ go/ast.lo \
+ go/doc.lo \
+ go/parser.lo \
+ go/printer.lo \
+ go/scanner.lo \
+ go/token.lo \
+ go/typechecker.lo \
+ hash/adler32.lo \
+ hash/crc32.lo \
+ hash/crc64.lo \
+ http/pprof.lo \
+ image/jpeg.lo \
+ image/png.lo \
+ index/suffixarray.lo \
+ io/ioutil.lo \
+ mime/multipart.lo \
+ net/dict.lo \
+ net/textproto.lo \
+ $(os_lib_inotify_lo) \
+ os/signal.lo \
+ rpc/jsonrpc.lo \
+ runtime/debug.lo \
+ runtime/pprof.lo \
+ syscalls/syscall.lo \
+ syscalls/errno.lo \
+ testing/testing.lo \
+ testing/iotest.lo \
+ testing/quick.lo \
+ testing/script.lo
+
+libgo_la_SOURCES = $(runtime_files)
+
+libgo_la_LIBADD = \
+ $(libgo_go_objs) $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
+
+libgobegin_a_SOURCES = \
+ runtime/go-main.c
+
+LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
+
+GOCFLAGS = $(CFLAGS)
+AM_GOCFLAGS = $(STRINGOPS_FLAG)
+GOCOMPILE = $(GOC) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_GOCFLAGS) $(GOCFLAGS)
+
+LTGOCOMPILE = $(LIBTOOL) --tag GO --mode=compile $(GOC) $(INCLUDES) \
+ $(AM_GOCFLAGS) $(GOCFLAGS)
+
+GOLINK = $(LIBTOOL) --tag GO --mode-link $(GOC) \
+ $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_GOCFLAGS) $(LTLDFLAGS) -o $@
+
+# Build the .go files for a package, generating a .lo file.
+BUILDPACKAGE = \
+ $(MKDIR_P) $(@D); \
+ files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
+ $(LTGOCOMPILE) -I . -c -fgo-prefix="libgo_$(@D)" -o $@ $$files
+
+if LIBGO_IS_RTEMS
+use_dejagnu = yes
+else
+use_dejagnu = no
+endif
+
+# Check a package.
+CHECK = \
+ @GC="$(GOC) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs -Wl,-R,`${PWD_COMMAND}`/.libs"; \
+ export GC; \
+ RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
+ export RUNTESTFLAGS; \
+ MAKE="$(MAKE)"; \
+ export MAKE; \
+ rm -f $@-log; \
+ prefix=`if test "$(@D)" = "regexp"; then echo regexp-test; else dirname $(@D); fi`; \
+ test "$${prefix}" != "." || prefix="$(@D)"; \
+ if test "$(use_dejagnu)" = "yes"; then \
+ $(SHELL) $(srcdir)/testsuite/gotest --dejagnu=yes --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --prefix="libgo_$${prefix}" --pkgfiles="$(go_$(subst /,_,$(@D))_files)"; \
+ else \
+ if $(SHELL) $(srcdir)/testsuite/gotest --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --prefix="libgo_$${prefix}" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" >>$@-log 2>&1; then \
+ echo "PASS: $(@D)"; \
+ else \
+ echo "FAIL: $(@D)"; \
+ cat $@-log; \
+ exit 1; \
+ fi; \
+ fi
+
+# Build all packages before checking any.
+CHECK_DEPS = libgo.la libgobegin.a \
+ $(toolexeclib_DATA) \
+ $(toolexeclibarchive_DATA) \
+ $(toolexeclibcompress_DATA) \
+ $(toolexeclibcontainer_DATA) \
+ $(toolexeclibcrypto_DATA) \
+ $(toolexeclibdebug_DATA) \
+ $(toolexeclibencoding_DATA) \
+ $(toolexeclibexp_DATA) \
+ $(toolexeclibgo_DATA) \
+ $(toolexeclibhash_DATA) \
+ $(toolexeclibhttp_DATA) \
+ $(toolexeclibimage_DATA) \
+ $(toolexeclibio_DATA) \
+ $(toolexeclibos_DATA) \
+ $(toolexeclibrpc_DATA) \
+ $(toolexeclibruntime_DATA) \
+ $(toolexeclibtesting_DATA)
+
+asn1/asn1.lo: $(go_asn1_files) bytes.gox fmt.gox io.gox os.gox reflect.gox \
+ strconv.gox strings.gox time.gox
+ $(BUILDPACKAGE)
+asn1/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: asn1/check
+
+big/big.lo: $(go_big_files) fmt.gox rand.gox strings.gox
+ $(BUILDPACKAGE)
+big/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: big/check
+
+bufio/bufio.lo: $(go_bufio_files) bytes.gox io.gox os.gox strconv.gox utf8.gox
+ $(BUILDPACKAGE)
+bufio/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: bufio/check
+
+bytes/bytes.lo: $(go_bytes_files) io.gox os.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+bytes/index.lo: $(go_bytes_c_files) bytes/bytes.lo
+ $(LTCOMPILE) -c -o bytes/index.lo $(srcdir)/go/bytes/indexbyte.c
+bytes/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: bytes/check
+
+cmath/cmath.lo: $(go_cmath_files) math.gox
+ $(BUILDPACKAGE)
+cmath/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: cmath/check
+
+ebnf/ebnf.lo: $(go_ebnf_files) container/vector.gox go/scanner.gox \
+ go/token.gox os.gox strconv.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+ebnf/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: ebnf/check
+
+exec/exec.lo: $(go_exec_files) os.gox strings.gox
+ $(BUILDPACKAGE)
+exec/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: exec/check
+
+expvar/expvar.lo: $(go_expvar_files) bytes.gox fmt.gox http.gox json.gox \
+ log.gox os.gox runtime.gox strconv.gox sync.gox
+ $(BUILDPACKAGE)
+expvar/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: expvar/check
+
+flag/flag.lo: $(go_flag_files) fmt.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+flag/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: flag/check
+
+fmt/fmt.lo: $(go_fmt_files) bytes.gox io.gox os.gox reflect.gox strconv.gox \
+ strings.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+fmt/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: fmt/check
+
+gob/gob.lo: $(go_gob_files) bytes.gox fmt.gox io.gox math.gox os.gox \
+ reflect.gox runtime.gox strings.gox sync.gox unicode.gox \
+ utf8.gox
+ $(BUILDPACKAGE)
+gob/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: gob/check
+
+hash/hash.lo: $(go_hash_files) io.gox
+ $(BUILDPACKAGE)
+hash/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: hash/check
+
+html/html.lo: $(go_html_files) bytes.gox io.gox os.gox strconv.gox strings.gox \
+ utf8.gox
+ $(BUILDPACKAGE)
+html/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: html/check
+
+http/http.lo: $(go_http_files) bufio.gox bytes.gox container/list.gox \
+ container/vector.gox crypto/rand.gox crypto/tls.gox \
+ encoding/base64.gox fmt.gox io.gox io/ioutil.gox log.gox \
+ mime.gox mime/multipart.gox net.gox os.gox path.gox sort.gox \
+ strconv.gox strings.gox sync.gox time.gox utf8.gox
+ $(BUILDPACKAGE)
+http/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: http/check
+
+image/image.lo: $(go_image_files) bufio.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+image/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: image/check
+
+io/io.lo: $(go_io_files) os.gox runtime.gox sync.gox
+ $(BUILDPACKAGE)
+io/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: io/check
+
+json/json.lo: $(go_json_files) bytes.gox container/vector.gox fmt.gox io.gox \
+ math.gox os.gox reflect.gox runtime.gox strconv.gox \
+ strings.gox unicode.gox utf16.gox utf8.gox
+ $(BUILDPACKAGE)
+json/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: json/check
+
+log/log.lo: $(go_log_files) bytes.gox fmt.gox io.gox runtime.gox os.gox \
+ sync.gox time.gox
+ $(BUILDPACKAGE)
+log/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: log/check
+
+math/math.lo: $(go_math_files)
+ $(BUILDPACKAGE)
+math/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: math/check
+
+mime/mime.lo: $(go_mime_files) bufio.gox bytes.gox os.gox strings.gox \
+ sync.gox unicode.gox
+ $(BUILDPACKAGE)
+mime/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: mime/check
+
+net/net.lo: $(go_net_files) bytes.gox fmt.gox io.gox os.gox reflect.gox \
+ strconv.gox strings.gox sync.gox syscall.gox
+ $(BUILDPACKAGE)
+net/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: net/check
+
+netchan/netchan.lo: $(go_netchan_files) gob.gox log.gox net.gox os.gox \
+ reflect.gox strconv.gox sync.gox time.gox
+ $(BUILDPACKAGE)
+netchan/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: netchan/check
+
+os/os.lo: $(go_os_files) sync.gox syscall.gox
+ $(BUILDPACKAGE)
+os/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: os/check
+
+patch/patch.lo: $(go_patch_files) bytes.gox compress/zlib.gox \
+ crypto/sha1.gox encoding/git85.gox fmt.gox io.gox os.gox \
+ path.gox strings.gox
+ $(BUILDPACKAGE)
+patch/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: patch/check
+
+path/path.lo: $(go_path_files) io/ioutil.gox os.gox sort.gox strings.gox \
+ utf8.gox
+ $(BUILDPACKAGE)
+path/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: path/check
+
+rand/rand.lo: $(go_rand_files) math.gox sync.gox
+ $(BUILDPACKAGE)
+rand/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: rand/check
+
+reflect/reflect.lo: $(go_reflect_files) math.gox runtime.gox strconv.gox \
+ sync.gox
+ $(BUILDPACKAGE)
+reflect/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: reflect/check
+
+regexp/regexp.lo: $(go_regexp_files) bytes.gox io.gox os.gox strings.gox \
+ utf8.gox
+ $(BUILDPACKAGE)
+regexp/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: regexp/check
+
+rpc/rpc.lo: $(go_rpc_files) bufio.gox fmt.gox gob.gox http.gox io.gox log.gox \
+ net.gox os.gox reflect.gox sort.gox strings.gox strconv.gox \
+ sync.gox template.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+rpc/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: rpc/check
+
+runtime/runtime.lo: $(go_runtime_files)
+ $(BUILDPACKAGE)
+runtime/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: runtime/check
+
+scanner/scanner.lo: $(go_scanner_files) bytes.gox fmt.gox io.gox os.gox \
+ unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+scanner/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: scanner/check
+
+smtp/smtp.lo: $(go_smtp_files) crypto/tls.gox encoding/base64.gox io.gox \
+ net.gox net/textproto.gox os.gox strings.gox
+ $(BUILDPACKAGE)
+smtp/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: smtp/check
+
+sort/sort.lo: $(go_sort_files)
+ $(BUILDPACKAGE)
+sort/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: sort/check
+
+strconv/strconv.lo: $(go_strconv_files) bytes.gox math.gox os.gox strings.gox \
+ unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+strconv/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: strconv/check
+
+strings/strings.lo: $(go_strings_files) os.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+strings/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: strings/check
+
+sync/mutex.lo: $(go_sync_files) runtime.gox
+ $(BUILDPACKAGE)
+sync/cas.lo: $(go_sync_c_files) sync/mutex.lo
+ $(LTCOMPILE) -c -o sync/cas.lo $(srcdir)/go/sync/cas.c
+sync/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: sync/check
+
+syslog/syslog.lo: $(go_syslog_files) fmt.gox log.gox net.gox os.gox syscall.gox
+ $(BUILDPACKAGE)
+syslog/syslog_c.lo: $(go_syslog_c_files) syslog/syslog.lo
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syslog/syslog_c.c
+syslog/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: syslog/check
+
+tabwriter/tabwriter.lo: $(go_tabwriter_files) bytes.gox io.gox os.gox utf8.gox
+ $(BUILDPACKAGE)
+tabwriter/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: tabwriter/check
+
+template/template.lo: $(go_template_files) bytes.gox fmt.gox io.gox os.gox \
+ reflect.gox runtime.gox strings.gox container/vector.gox
+ $(BUILDPACKAGE)
+template/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: template/check
+
+testing/testing.lo: $(go_testing_files) flag.gox fmt.gox os.gox regexp.gox \
+ runtime.gox time.gox
+ $(BUILDPACKAGE)
+testing/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: testing/check
+
+time/time.lo: $(go_time_files) bytes.gox container/heap.gox io/ioutil.gox \
+ os.gox strconv.gox sync.gox syscall.gox
+ $(BUILDPACKAGE)
+time/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: time/check
+
+try/try.lo: $(go_try_files) fmt.gox io.gox os.gox reflect.gox unicode.gox
+ $(BUILDPACKAGE)
+try/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: try/check
+
+unicode/unicode.lo: $(go_unicode_files)
+ $(BUILDPACKAGE)
+unicode/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: unicode/check
+
+utf16/utf16.lo: $(go_utf16_files) unicode.gox
+ $(BUILDPACKAGE)
+utf16/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: utf16/check
+
+utf8/utf8.lo: $(go_utf8_files) unicode.gox
+ $(BUILDPACKAGE)
+utf8/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: utf8/check
+
+websocket/websocket.lo: $(go_websocket_files) bufio.gox bytes.gox \
+ container/vector.gox crypto/md5.gox crypto/tls.gox \
+ encoding/binary.gox fmt.gox http.gox io.gox net.gox os.gox \
+ rand.gox strings.gox
+ $(BUILDPACKAGE)
+websocket/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: websocket/check
+
+xml/xml.lo: $(go_xml_files) bufio.gox bytes.gox fmt.gox io.gox os.gox \
+ reflect.gox strconv.gox strings.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+xml/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: xml/check
+
+archive/tar.lo: $(go_archive_tar_files) bytes.gox io.gox os.gox strconv.gox \
+ strings.gox
+ $(BUILDPACKAGE)
+archive/tar/check: $(CHECK_DEPS)
+ @$(MKDIR_P) archive/tar
+ $(CHECK)
+.PHONY: archive/tar/check
+
+archive/zip.lo: $(go_archive_zip_files) bufio.gox bytes.gox \
+ compress/flate.gox hash.gox hash/crc32.gox \
+ encoding/binary.gox io.gox os.gox
+ $(BUILDPACKAGE)
+archive/zip/check: $(CHECK_DEPS)
+ @$(MKDIR_P) archive/zip
+ $(CHECK)
+.PHONY: archive/zip/check
+
+compress/flate.lo: $(go_compress_flate_files) bufio.gox io.gox math.gox \
+ os.gox sort.gox strconv.gox
+ $(BUILDPACKAGE)
+compress/flate/check: $(CHECK_DEPS)
+ @$(MKDIR_P) compress/flate
+ $(CHECK)
+.PHONY: compress/flate/check
+
+compress/gzip.lo: $(go_compress_gzip_files) bufio.gox compress/flate.gox \
+ hash.gox hash/crc32.gox io.gox os.gox
+ $(BUILDPACKAGE)
+compress/gzip/check: $(CHECK_DEPS)
+ @$(MKDIR_P) compress/gzip
+ $(CHECK)
+.PHONY: compress/gzip/check
+
+compress/zlib.lo: $(go_compress_zlib_files) bufio.gox compress/flate.gox \
+ hash.gox hash/adler32.gox io.gox os.gox
+ $(BUILDPACKAGE)
+compress/zlib/check: $(CHECK_DEPS)
+ @$(MKDIR_P) compress/zlib
+ $(CHECK)
+.PHONY: compress/zlib/check
+
+container/heap.lo: $(go_container_heap_files) sort.gox
+ $(BUILDPACKAGE)
+container/heap/check: $(CHECK_DEPS)
+ @$(MKDIR_P) container/heap
+ $(CHECK)
+.PHONY: container/heap/check
+
+container/list.lo: $(go_container_list_files)
+ $(BUILDPACKAGE)
+container/list/check: $(CHECK_DEPS)
+ @$(MKDIR_P) container/list
+ $(CHECK)
+.PHONY: container/list/check
+
+container/ring.lo: $(go_container_ring_files)
+ $(BUILDPACKAGE)
+container/ring/check: $(CHECK_DEPS)
+ @$(MKDIR_P) container/ring
+ $(CHECK)
+.PHONY: container/ring/check
+
+container/vector.lo: $(go_container_vector_files)
+ $(BUILDPACKAGE)
+container/vector/check: $(CHECK_DEPS)
+ @$(MKDIR_P) container/vector
+ $(CHECK)
+.PHONY: container/vector/check
+
+crypto/aes.lo: $(go_crypto_aes_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/aes/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/aes
+ $(CHECK)
+.PHONY: crypto/aes/check
+
+crypto/block.lo: $(go_crypto_block_files) fmt.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/block/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/block
+ $(CHECK)
+.PHONY: crypto/block/check
+
+crypto/blowfish.lo: $(go_crypto_blowfish_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/blowfish/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/blowfish
+ $(CHECK)
+.PHONY: crypto/blowfish/check
+
+crypto/cast5.lo: $(go_crypto_cast5_files) os.gox
+ $(BUILDPACKAGE)
+crypt/cast5/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/cast5
+ $(CHECK)
+.PHONY: crypto/cast5/check
+
+crypto/cipher.lo: $(go_crypto_cipher_files) io.gox os.gox
+ $(BUILDPACKAGE)
+crypto/cipher/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/cipher
+ $(CHECK)
+.PHONY: crypto/cipher/check
+
+crypto/elliptic.lo: $(go_crypto_elliptic_files) big.gox io.gox os.gox sync.gox
+ $(BUILDPACKAGE)
+crypto/elliptic/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/elliptic
+ $(CHECK)
+.PHONY: crypto/elliptic/check
+
+crypto/hmac.lo: $(go_crypto_hmac_files) crypto/md5.gox crypto/sha1.gox \
+ crypto/sha256.gox hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/hmac/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/hmac
+ $(CHECK)
+.PHONY: crypto/hmac/check
+
+crypto/md4.lo: $(go_crypto_md4_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/md4/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/md4
+ $(CHECK)
+.PHONY: crypto/md4/check
+
+crypto/md5.lo: $(go_crypto_md5_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/md5/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/md5
+ $(CHECK)
+.PHONY: crypto/md5/check
+
+crypto/ocsp.lo: $(go_crypto_ocsp_files) asn1.gox crypto/rsa.gox \
+ crypto/sha1.gox crypto/x509.gox os.gox time.gox
+ $(BUILDPACKAGE)
+crypto/ocsp/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/ocsp
+ $(CHECK)
+.PHONY: crypto/ocsp/check
+
+crypto/rand.lo: $(go_crypto_rand_files) crypto/aes.gox io.gox os.gox sync.gox \
+ time.gox
+ $(BUILDPACKAGE)
+crypto/rand/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/rand
+ $(CHECK)
+.PHONY: crypto/rand/check
+
+crypto/rc4.lo: $(go_crypto_rc4_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/rc4/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/rc4
+ $(CHECK)
+.PHONY: crypto/rc4/check
+
+crypto/ripemd160.lo: $(go_crypto_ripemd160_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/ripemd160/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/ripemd160
+ $(CHECK)
+.PHONY: crypto/ripemd160/check
+
+crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto/sha1.gox \
+ crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox
+ $(BUILDPACKAGE)
+crypto/rsa/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/rsa
+ $(CHECK)
+.PHONY: crypto/rsa/check
+
+crypto/sha1.lo: $(go_crypto_sha1_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/sha1/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/sha1
+ $(CHECK)
+.PHONY: crypto/sha1/check
+
+crypto/sha256.lo: $(go_crypto_sha256_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/sha256/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/sha256
+ $(CHECK)
+.PHONY: crypto/sha256/check
+
+crypto/sha512.lo: $(go_crypto_sha512_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/sha512/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/sha512
+ $(CHECK)
+.PHONY: crypto/sha512/check
+
+crypto/subtle.lo: $(go_crypto_subtle_files)
+ $(BUILDPACKAGE)
+crypto/subtle/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/subtle
+ $(CHECK)
+.PHONY: crypto/subtle/check
+
+crypto/tls.lo: $(go_crypto_tls_files) big.gox bufio.gox bytes.gox \
+ container/list.gox crypto/aes.gox crypto/cipher.gox \
+ crypto/elliptic.gox crypto/hmac.gox crypto/md5.gox \
+ crypto/rc4.gox crypto/rand.gox crypto/rsa.gox crypto/sha1.gox \
+ crypto/subtle.gox crypto/rsa.gox crypto/sha1.gox \
+ crypto/x509.gox encoding/pem.gox fmt.gox hash.gox io.gox \
+ io/ioutil.gox net.gox os.gox strings.gox sync.gox time.gox
+ $(BUILDPACKAGE)
+crypto/tls/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/tls
+ $(CHECK)
+.PHONY: crypto/tls/check
+
+crypto/twofish.lo: $(go_crypto_twofish_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/twofish/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/twofish
+ $(CHECK)
+.PHONY: crypto/twofish/check
+
+crypto/x509.lo: $(go_crypto_x509_files) asn1.gox big.gox container/vector.gox \
+ crypto/rsa.gox crypto/sha1.gox hash.gox os.gox strings.gox \
+ time.gox
+ $(BUILDPACKAGE)
+crypto/x509/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/x509
+ $(CHECK)
+.PHONY: crypto/x509/check
+
+crypto/xtea.lo: $(go_crypto_xtea_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/xtea/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/xtea
+ $(CHECK)
+.PHONY: crypto/xtea/check
+
+crypto/openpgp/armor.lo: $(go_crypto_openpgp_armor_files) bytes.gox \
+ crypto/openpgp/error.gox encoding/base64.gox \
+ encoding/line.gox io.gox os.gox
+ $(BUILDPACKAGE)
+crypto/openpgp/armor/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/openpgp/armor
+ $(CHECK)
+.PHONY: crypto/openpgp/armor/check
+
+crypto/openpgp/error.lo: $(go_crypto_openpgp_error_files)
+ $(BUILDPACKAGE)
+crypto/openpgp/error/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/openpgp/error
+ $(CHECK)
+.PHONY: crypto/openpgp/error/check
+
+crypto/openpgp/s2k.lo: $(go_crypto_openpgp_s2k_files) crypto/md5.gox \
+ crypto/openpgp/error.gox crypto/ripemd160.gox crypto/sha1.gox \
+ crypto/sha256.gox crypto/sha512.gox hash.gox io.gox os.gox
+ $(BUILDPACKAGE)
+crypto/openpgp/s2k/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/openpgp/s2k
+ $(CHECK)
+.PHONY: crypto/openpgp/s2k/check
+
+debug/dwarf.lo: $(go_debug_dwarf_files) encoding/binary.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+debug/dwarf/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/dwarf
+ $(CHECK)
+.PHONY: debug/dwarf/check
+
+debug/elf.lo: $(go_debug_elf_files) bytes.gox debug/dwarf.gox \
+ encoding/binary.gox fmt.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+debug/elf/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/elf
+ $(CHECK)
+.PHONY: debug/elf/check
+
+debug/gosym.lo: $(go_debug_gosym_files) encoding/binary.gox fmt.gox os.gox \
+ strconv.gox strings.gox
+ $(BUILDPACKAGE)
+debug/gosym/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/gosym
+ $(CHECK)
+.PHONY: debug/gosym/check
+
+debug/macho.lo: $(go_debug_macho_files) bytes.gox debug/dwarf.gox \
+ encoding/binary.gox fmt.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+debug/macho/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/macho
+ $(CHECK)
+.PHONY: debug/macho/check
+
+debug/pe.lo: $(go_debug_pe_files) debug/dwarf.gox \
+ encoding/binary.gox fmt.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+debug/pe/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/pe
+ $(CHECK)
+.PHONY: debug/pe/check
+
+debug/proc.lo: $(go_debug_proc_files) container/vector.gox fmt.gox \
+ io/ioutil.gox os.gox runtime.gox strconv.gox strings.gox \
+ sync.gox syscall.gox
+ $(BUILDPACKAGE)
+debug/proc/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/proc
+ $(CHECK)
+.PHONY: debug/proc/check
+
+encoding/ascii85.lo: $(go_encoding_ascii85_files) io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+encoding/ascii85/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/ascii85
+ $(CHECK)
+.PHONY: encoding/ascii85/check
+
+encoding/base32.lo: $(go_encoding_base32_files) io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+encoding/base32/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/base32
+ $(CHECK)
+.PHONY: encoding/base32/check
+
+encoding/base64.lo: $(go_encoding_base64_files) io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+encoding/base64/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/base64
+ $(CHECK)
+.PHONY: encoding/base64/check
+
+encoding/binary.lo: $(go_encoding_binary_files) io.gox math.gox os.gox \
+ reflect.gox
+ $(BUILDPACKAGE)
+encoding/binary/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/binary
+ $(CHECK)
+.PHONY: encoding/binary/check
+
+encoding/git85.lo: $(go_encoding_git85_files) bytes.gox io.gox os.gox \
+ strconv.gox
+ $(BUILDPACKAGE)
+encoding/git85/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/git85
+ $(CHECK)
+.PHONY: encoding/git85/check
+
+encoding/hex.lo: $(go_encoding_hex_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+encoding/hex/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/hex
+ $(CHECK)
+.PHONY: encoding/hex/check
+
+encoding/line.lo: $(go_encoding_line_files) io.gox os.gox
+ $(BUILDPACKAGE)
+encoding/line/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/line
+ $(CHECK)
+.PHONY: encoding/line/check
+
+encoding/pem.lo: $(go_encoding_pem_files) bytes.gox encoding/base64.gox
+ $(BUILDPACKAGE)
+encoding/pem/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/pem
+ $(CHECK)
+.PHONY: encoding/pem/check
+
+exp/datafmt.lo: $(go_exp_datafmt_files) bytes.gox container/vector.gox \
+ fmt.gox go/scanner.gox go/token.gox io.gox os.gox reflect.gox \
+ runtime.gox strconv.gox strings.gox
+ $(BUILDPACKAGE)
+exp/datafmt/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/datafmt
+ $(CHECK)
+.PHONY: exp/datafmt/check
+
+exp/draw.lo: $(go_exp_draw_files) image.gox os.gox
+ $(BUILDPACKAGE)
+exp/draw/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/draw
+ $(CHECK)
+.PHONY: exp/draw/check
+
+exp/eval.lo: $(go_exp_eval_files) big.gox go/ast.gox go/parser.gox \
+ go/scanner.gox go/token.gox fmt.gox log.gox strconv.gox \
+ strings.gox os.gox reflect.gox runtime.gox sort.gox template.gox
+ $(BUILDPACKAGE)
+exp/eval/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/eval
+ $(CHECK)
+.PHONY: exp/eval/check
+
+go/ast.lo: $(go_go_ast_files) fmt.gox go/token.gox io.gox os.gox reflect.gox \
+ unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+go/ast/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/ast
+ $(CHECK)
+.PHONY: go/ast/check
+
+go/doc.lo: $(go_go_doc_files) go/ast.gox go/token.gox io.gox regexp.gox \
+ sort.gox strings.gox template.gox
+ $(BUILDPACKAGE)
+go/doc/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/doc
+ $(CHECK)
+.PHONY: go/doc/check
+
+go/parser.lo: $(go_go_parser_files) bytes.gox fmt.gox go/ast.gox \
+ go/scanner.gox go/token.gox io.gox io/ioutil.gox os.gox \
+ path.gox strings.gox
+ $(BUILDPACKAGE)
+go/parser/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/parser
+ $(CHECK)
+.PHONY: go/parser/check
+
+go/printer.lo: $(go_go_printer_files) bytes.gox fmt.gox go/ast.gox \
+ go/token.gox io.gox os.gox reflect.gox runtime.gox \
+ strings.gox tabwriter.gox
+ $(BUILDPACKAGE)
+go/printer/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/printer
+ $(CHECK)
+.PHONY: go/printer/check
+
+go/scanner.lo: $(go_go_scanner_files) bytes.gox container/vector.gox fmt.gox \
+ go/token.gox io.gox os.gox path.gox sort.gox strconv.gox \
+ unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+go/scanner/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/scanner
+ $(CHECK)
+.PHONY: go/scanner/check
+
+go/token.lo: $(go_go_token_files) fmt.gox strconv.gox
+ $(BUILDPACKAGE)
+go/token/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/token
+ $(CHECK)
+.PHONY: go/token/check
+
+go/typechecker.lo: $(go_go_typechecker_files) fmt.gox go/ast.gox go/token.gox \
+ go/scanner.gox os.gox
+ $(BUILDPACKAGE)
+go/typechecker/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/typechecker
+ $(CHECK)
+.PHONY: go/typechecker/check
+
+hash/adler32.lo: $(go_hash_adler32_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+hash/adler32/check: $(CHECK_DEPS)
+ @$(MKDIR_P) hash/adler32
+ $(CHECK)
+.PHONY: hash/adler32/check
+
+hash/crc32.lo: $(go_hash_crc32_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+hash/crc32/check: $(CHECK_DEPS)
+ @$(MKDIR_P) hash/crc32
+ $(CHECK)
+.PHONY: hash/crc32/check
+
+hash/crc64.lo: $(go_hash_crc64_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+hash/crc64/check: $(CHECK_DEPS)
+ @$(MKDIR_P) hash/crc64
+ $(CHECK)
+.PHONY: hash/crc64/check
+
+http/pprof.lo: $(go_http_pprof_files) bufio.gox fmt.gox http.gox os.gox \
+ runtime.gox runtime/pprof.gox strconv.gox strings.gox
+ $(BUILDPACKAGE)
+http/pprof/check: $(CHECK_DEPS)
+ @$(MKDIR_P) http/pprof
+ $(CHECK)
+.PHONY: http/pprof/check
+
+image/jpeg.lo: $(go_image_jpeg_files) bufio.gox image.gox io.gox os.gox
+ $(BUILDPACKAGE)
+image/jpeg/check: $(CHECK_DEPS)
+ @$(MKDIR_P) image/jpeg
+ $(CHECK)
+.PHONY: image/jpeg/check
+
+image/png.lo: $(go_image_png_files) bufio.gox compress/zlib.gox fmt.gox \
+ hash.gox hash/crc32.gox image.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+image/png/check: $(CHECK_DEPS)
+ @$(MKDIR_P) image/png
+ $(CHECK)
+.PHONY: image/png/check
+
+index/suffixarray.lo: $(go_index_suffixarray_files) bytes.gox regexp.gox \
+ sort.gox
+ $(BUILDPACKAGE)
+index/suffixarray/check: $(CHECK_DEPS)
+ @$(MKDIR_P) index/suffixarray
+ $(CHECK)
+.PHONY: index/suffixarray/check
+
+io/ioutil.lo: $(go_io_ioutil_files) bytes.gox io.gox os.gox sort.gox \
+ strconv.gox
+ $(BUILDPACKAGE)
+io/ioutil/check: $(CHECK_DEPS)
+ @$(MKDIR_P) io/ioutil
+ $(CHECK)
+.PHONY: io/ioutil/check
+
+mime/multipart.lo: $(go_mime_multipart_files) bufio.gox bytes.gox io.gox \
+ mime.gox os.gox regexp.gox strings.gox
+ $(BUILDPACKAGE)
+mime/multipart/check: $(CHECK_DEPS)
+ @$(MKDIR_P) mime/multipart
+ $(CHECK)
+.PHONY: mime/multipart/check
+
+net/dict.lo: $(go_net_dict_files) container/vector.gox net/textproto.gox \
+ os.gox strconv.gox strings.gox
+ $(BUILDPACKAGE)
+
+net/textproto.lo: $(go_net_textproto_files) bufio.gox bytes.gox \
+ container/vector.gox fmt.gox io.gox io/ioutil.gox net.gox \
+ os.gox strconv.gox sync.gox
+ $(BUILDPACKAGE)
+net/textproto/check: $(CHECK_DEPS)
+ @$(MKDIR_P) net/textproto
+ $(CHECK)
+.PHONY: net/textproto/check
+
+os/inotify.lo: $(go_os_inotify_files) fmt.gox os.gox strings.gox syscall.gox
+ $(BUILDPACKAGE)
+os/inotify/check: $(CHECK_DEPS)
+ @$(MKDIR_P) os/inotify
+ $(CHECK)
+.PHONY: os/inotify/check
+
+os/signal.lo: $(go_os_signal_files) runtime.gox strconv.gox
+ $(BUILDPACKAGE)
+os/signal/check: $(CHECK_DEPS)
+ @$(MKDIR_P) os/signal
+ $(CHECK)
+.PHONY: os/signal/check
+
+unix.go: $(srcdir)/go/os/signal/mkunix.sh sysinfo.go
+ $(SHELL) $(srcdir)/go/os/signal/mkunix.sh sysinfo.go > $@.tmp
+ mv -f $@.tmp $@
+
+rpc/jsonrpc.lo: $(go_rpc_jsonrpc_files) fmt.gox io.gox json.gox net.gox \
+ os.gox rpc.gox sync.gox
+ $(BUILDPACKAGE)
+rpc/jsonrpc/check: $(CHECK_DEPS)
+ @$(MKDIR_P) rpc/jsonrpc
+ $(CHECK)
+.PHONY: rpc/jsonrpc/check
+
+runtime/debug.lo: $(go_runtime_debug_files) bytes.gox fmt.gox io/ioutil.gox \
+ os.gox runtime.gox
+ $(BUILDPACKAGE)
+runtime/debug/check: $(CHECK_DEPS)
+ @$(MKDIR_P) runtime/debug
+ $(CHECK)
+.PHONY: runtime/debug/check
+
+runtime/pprof.lo: $(go_runtime_pprof_files) bufio.gox fmt.gox io.gox os.gox \
+ runtime.gox
+ $(BUILDPACKAGE)
+runtime/pprof/check: $(CHECK_DEPS)
+ @$(MKDIR_P) runtime/pprof
+ $(CHECK)
+.PHONY: runtime/pprof/check
+
+testing/iotest.lo: $(go_testing_iotest_files) io.gox log.gox os.gox
+ $(BUILDPACKAGE)
+testing/iotest/check: $(CHECK_DEPS)
+ @$(MKDIR_P) testing/iotest
+ $(CHECK)
+.PHONY: testing/iotest/check
+
+testing/quick.lo: $(go_testing_quick_files) flag.gox fmt.gox math.gox os.gox \
+ rand.gox reflect.gox strings.gox
+ $(BUILDPACKAGE)
+testing/quick/check: $(CHECK_DEPS)
+ @$(MKDIR_P) testing/quick
+ $(CHECK)
+.PHONY: testing/quick/check
+
+testing/script.lo: $(go_testing_script_files) fmt.gox os.gox rand.gox \
+ reflect.gox strings.gox
+ $(BUILDPACKAGE)
+testing/script/check: $(CHECK_DEPS)
+ @$(MKDIR_P) testing/script
+ $(CHECK)
+.PHONY: testing/script/check
+
+sysinfo.go: s-sysinfo; @true
+s-sysinfo: $(srcdir)/mksysinfo.sh config.h
+ CC="$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS)" $(SHELL) $(srcdir)/mksysinfo.sh
+ $(SHELL) $(srcdir)/../move-if-change tmp-sysinfo.go sysinfo.go
+ $(STAMP) $@
+
+syscalls/syscall.lo: $(go_syscall_files) sync.gox
+ $(BUILDPACKAGE)
+syscalls/errno.lo: $(go_syscall_c_files) syscalls/syscall.lo
+ $(LTCOMPILE) -c -o $@ $(srcdir)/syscalls/errno.c
+
+# How to build a .gox file from a .lo file.
+BUILDGOX = \
+ f=`echo $< | sed -e 's/.lo$$/.o/'`; \
+ $(OBJCOPY) -j .go_export $$f $@.tmp && mv -f $@.tmp $@
+
+asn1.gox: asn1/asn1.lo
+ $(BUILDGOX)
+big.gox: big/big.lo
+ $(BUILDGOX)
+bufio.gox: bufio/bufio.lo
+ $(BUILDGOX)
+bytes.gox: bytes/bytes.lo
+ $(BUILDGOX)
+cmath.gox: cmath/cmath.lo
+ $(BUILDGOX)
+ebnf.gox: ebnf/ebnf.lo
+ $(BUILDGOX)
+exec.gox: exec/exec.lo
+ $(BUILDGOX)
+expvar.gox: expvar/expvar.lo
+ $(BUILDGOX)
+flag.gox: flag/flag.lo
+ $(BUILDGOX)
+fmt.gox: fmt/fmt.lo
+ $(BUILDGOX)
+gob.gox: gob/gob.lo
+ $(BUILDGOX)
+hash.gox: hash/hash.lo
+ $(BUILDGOX)
+html.gox: html/html.lo
+ $(BUILDGOX)
+http.gox: http/http.lo
+ $(BUILDGOX)
+image.gox: image/image.lo
+ $(BUILDGOX)
+io.gox: io/io.lo
+ $(BUILDGOX)
+json.gox: json/json.lo
+ $(BUILDGOX)
+log.gox: log/log.lo
+ $(BUILDGOX)
+math.gox: math/math.lo
+ $(BUILDGOX)
+mime.gox: mime/mime.lo
+ $(BUILDGOX)
+net.gox: net/net.lo
+ $(BUILDGOX)
+netchan.gox: netchan/netchan.lo
+ $(BUILDGOX)
+os.gox: os/os.lo
+ $(BUILDGOX)
+patch.gox: patch/patch.lo
+ $(BUILDGOX)
+path.gox: path/path.lo
+ $(BUILDGOX)
+rand.gox: rand/rand.lo
+ $(BUILDGOX)
+reflect.gox: reflect/reflect.lo
+ $(BUILDGOX)
+regexp.gox: regexp/regexp.lo
+ $(BUILDGOX)
+rpc.gox: rpc/rpc.lo
+ $(BUILDGOX)
+runtime.gox: runtime/runtime.lo
+ $(BUILDGOX)
+scanner.gox: scanner/scanner.lo
+ $(BUILDGOX)
+smtp.gox: smtp/smtp.lo
+ $(BUILDGOX)
+sort.gox: sort/sort.lo
+ $(BUILDGOX)
+strconv.gox: strconv/strconv.lo
+ $(BUILDGOX)
+strings.gox: strings/strings.lo
+ $(BUILDGOX)
+sync.gox: sync/mutex.lo
+ $(BUILDGOX)
+syslog.gox: syslog/syslog.lo
+ $(BUILDGOX)
+syscall.gox: syscalls/syscall.lo
+ $(BUILDGOX)
+tabwriter.gox: tabwriter/tabwriter.lo
+ $(BUILDGOX)
+template.gox: template/template.lo
+ $(BUILDGOX)
+testing.gox: testing/testing.lo
+ $(BUILDGOX)
+time.gox: time/time.lo
+ $(BUILDGOX)
+try.gox: try/try.lo
+ $(BUILDGOX)
+unicode.gox: unicode/unicode.lo
+ $(BUILDGOX)
+utf16.gox: utf16/utf16.lo
+ $(BUILDGOX)
+utf8.gox: utf8/utf8.lo
+ $(BUILDGOX)
+websocket.gox: websocket/websocket.lo
+ $(BUILDGOX)
+xml.gox: xml/xml.lo
+ $(BUILDGOX)
+
+archive/tar.gox: archive/tar.lo
+ $(BUILDGOX)
+archive/zip.gox: archive/zip.lo
+ $(BUILDGOX)
+
+compress/flate.gox: compress/flate.lo
+ $(BUILDGOX)
+compress/gzip.gox: compress/gzip.lo
+ $(BUILDGOX)
+compress/zlib.gox: compress/zlib.lo
+ $(BUILDGOX)
+
+container/heap.gox: container/heap.lo
+ $(BUILDGOX)
+container/list.gox: container/list.lo
+ $(BUILDGOX)
+container/ring.gox: container/ring.lo
+ $(BUILDGOX)
+container/vector.gox: container/vector.lo
+ $(BUILDGOX)
+
+crypto/aes.gox: crypto/aes.lo
+ $(BUILDGOX)
+crypto/block.gox: crypto/block.lo
+ $(BUILDGOX)
+crypto/blowfish.gox: crypto/blowfish.lo
+ $(BUILDGOX)
+crypto/cast5.gox: crypto/cast5.lo
+ $(BUILDGOX)
+crypto/cipher.gox: crypto/cipher.lo
+ $(BUILDGOX)
+crypto/elliptic.gox: crypto/elliptic.lo
+ $(BUILDGOX)
+crypto/hmac.gox: crypto/hmac.lo
+ $(BUILDGOX)
+crypto/md4.gox: crypto/md4.lo
+ $(BUILDGOX)
+crypto/md5.gox: crypto/md5.lo
+ $(BUILDGOX)
+crypto/ocsp.gox: crypto/ocsp.lo
+ $(BUILDGOX)
+crypto/rand.gox: crypto/rand.lo
+ $(BUILDGOX)
+crypto/rc4.gox: crypto/rc4.lo
+ $(BUILDGOX)
+crypto/ripemd160.gox: crypto/ripemd160.lo
+ $(BUILDGOX)
+crypto/rsa.gox: crypto/rsa.lo
+ $(BUILDGOX)
+crypto/sha1.gox: crypto/sha1.lo
+ $(BUILDGOX)
+crypto/sha256.gox: crypto/sha256.lo
+ $(BUILDGOX)
+crypto/sha512.gox: crypto/sha512.lo
+ $(BUILDGOX)
+crypto/subtle.gox: crypto/subtle.lo
+ $(BUILDGOX)
+crypto/tls.gox: crypto/tls.lo
+ $(BUILDGOX)
+crypto/twofish.gox: crypto/twofish.lo
+ $(BUILDGOX)
+crypto/x509.gox: crypto/x509.lo
+ $(BUILDGOX)
+crypto/xtea.gox: crypto/xtea.lo
+ $(BUILDGOX)
+
+crypto/openpgp/armor.gox: crypto/openpgp/armor.lo
+ $(BUILDGOX)
+crypto/openpgp/error.gox: crypto/openpgp/error.lo
+ $(BUILDGOX)
+crypto/openpgp/s2k.gox: crypto/openpgp/s2k.lo
+ $(BUILDGOX)
+
+debug/dwarf.gox: debug/dwarf.lo
+ $(BUILDGOX)
+debug/elf.gox: debug/elf.lo
+ $(BUILDGOX)
+debug/gosym.gox: debug/gosym.lo
+ $(BUILDGOX)
+debug/macho.gox: debug/macho.lo
+ $(BUILDGOX)
+debug/pe.gox: debug/pe.lo
+ $(BUILDGOX)
+debug/proc.gox: debug/proc.lo
+ $(BUILDGOX)
+
+encoding/ascii85.gox: encoding/ascii85.lo
+ $(BUILDGOX)
+encoding/base32.gox: encoding/base32.lo
+ $(BUILDGOX)
+encoding/base64.gox: encoding/base64.lo
+ $(BUILDGOX)
+encoding/binary.gox: encoding/binary.lo
+ $(BUILDGOX)
+encoding/git85.gox: encoding/git85.lo
+ $(BUILDGOX)
+encoding/hex.gox: encoding/hex.lo
+ $(BUILDGOX)
+encoding/line.gox: encoding/line.lo
+ $(BUILDGOX)
+encoding/pem.gox: encoding/pem.lo
+ $(BUILDGOX)
+
+exp/datafmt.gox: exp/datafmt.lo
+ $(BUILDGOX)
+exp/draw.gox: exp/draw.lo
+ $(BUILDGOX)
+exp/eval.gox: exp/eval.lo
+ $(BUILDGOX)
+
+go/ast.gox: go/ast.lo
+ $(BUILDGOX)
+go/doc.gox: go/doc.lo
+ $(BUILDGOX)
+go/parser.gox: go/parser.lo
+ $(BUILDGOX)
+go/printer.gox: go/printer.lo
+ $(BUILDGOX)
+go/scanner.gox: go/scanner.lo
+ $(BUILDGOX)
+go/token.gox: go/token.lo
+ $(BUILDGOX)
+go/typechecker.gox: go/typechecker.lo
+ $(BUILDGOX)
+
+hash/adler32.gox: hash/adler32.lo
+ $(BUILDGOX)
+hash/crc32.gox: hash/crc32.lo
+ $(BUILDGOX)
+hash/crc64.gox: hash/crc64.lo
+ $(BUILDGOX)
+
+http/pprof.gox: http/pprof.lo
+ $(BUILDGOX)
+
+image/jpeg.gox: image/jpeg.lo
+ $(BUILDGOX)
+image/png.gox: image/png.lo
+ $(BUILDGOX)
+
+index/suffixarray.gox: index/suffixarray.lo
+ $(BUILDGOX)
+
+io/ioutil.gox: io/ioutil.lo
+ $(BUILDGOX)
+
+mime/multipart.gox: mime/multipart.lo
+ $(BUILDGOX)
+
+net/dict.gox: net/dict.lo
+ $(BUILDGOX)
+net/textproto.gox: net/textproto.lo
+ $(BUILDGOX)
+
+os/inotify.gox: os/inotify.lo
+ $(BUILDGOX)
+os/signal.gox: os/signal.lo
+ $(BUILDGOX)
+
+rpc/jsonrpc.gox: rpc/jsonrpc.lo
+ $(BUILDGOX)
+
+runtime/debug.gox: runtime/debug.lo
+ $(BUILDGOX)
+runtime/pprof.gox: runtime/pprof.lo
+ $(BUILDGOX)
+
+testing/iotest.gox: testing/iotest.lo
+ $(BUILDGOX)
+testing/quick.gox: testing/quick.lo
+ $(BUILDGOX)
+testing/script.gox: testing/script.lo
+ $(BUILDGOX)
+
+if LIBGO_IS_LINUX
+# os_inotify_check = os/inotify/check
+os_inotify_check =
+else
+os_inotify_check =
+endif
+
+TEST_PACKAGES = \
+ asn1/check \
+ big/check \
+ bufio/check \
+ bytes/check \
+ cmath/check \
+ ebnf/check \
+ exec/check \
+ expvar/check \
+ flag/check \
+ fmt/check \
+ gob/check \
+ html/check \
+ $(if $(GCCGO_RUN_ALL_TESTS),http/check) \
+ io/check \
+ json/check \
+ log/check \
+ math/check \
+ mime/check \
+ $(if $(GCCGO_RUN_ALL_TESTS),net/check) \
+ netchan/check \
+ os/check \
+ patch/check \
+ path/check \
+ rand/check \
+ reflect/check \
+ regexp/check \
+ rpc/check \
+ runtime/check \
+ scanner/check \
+ smtp/check \
+ sort/check \
+ strconv/check \
+ strings/check \
+ sync/check \
+ $(if $(GCCGO_RUN_ALL_TESTS),syslog/check) \
+ tabwriter/check \
+ template/check \
+ time/check \
+ try/check \
+ unicode/check \
+ utf16/check \
+ utf8/check \
+ websocket/check \
+ xml/check \
+ archive/tar/check \
+ archive/zip/check \
+ compress/flate/check \
+ compress/gzip/check \
+ compress/zlib/check \
+ container/heap/check \
+ container/list/check \
+ container/ring/check \
+ container/vector/check \
+ crypto/aes/check \
+ crypto/block/check \
+ crypto/blowfish/check \
+ crypto/cast5/check \
+ crypto/cipher/check \
+ crypto/elliptic/check \
+ crypto/hmac/check \
+ crypto/md4/check \
+ crypto/md5/check \
+ crypto/ocsp/check \
+ crypto/rand/check \
+ crypto/rc4/check \
+ crypto/ripemd160/check \
+ crypto/rsa/check \
+ crypto/sha1/check \
+ crypto/sha256/check \
+ crypto/sha512/check \
+ crypto/subtle/check \
+ crypto/tls/check \
+ crypto/twofish/check \
+ crypto/x509/check \
+ crypto/xtea/check \
+ crypto/openpgp/armor/check \
+ crypto/openpgp/s2k/check \
+ debug/dwarf/check \
+ debug/elf/check \
+ debug/macho/check \
+ debug/pe/check \
+ encoding/ascii85/check \
+ encoding/base32/check \
+ encoding/base64/check \
+ encoding/binary/check \
+ encoding/git85/check \
+ encoding/hex/check \
+ encoding/line/check \
+ encoding/pem/check \
+ exp/datafmt/check \
+ exp/draw/check \
+ exp/eval/check \
+ go/parser/check \
+ go/printer/check \
+ go/scanner/check \
+ go/token/check \
+ go/typechecker/check \
+ hash/adler32/check \
+ hash/crc32/check \
+ hash/crc64/check \
+ image/png/check \
+ index/suffixarray/check \
+ io/ioutil/check \
+ mime/multipart/check \
+ net/textproto/check \
+ $(os_inotify_check) \
+ os/signal/check \
+ rpc/jsonrpc/check \
+ testing/quick/check \
+ testing/script/check
+
+check-recursive: $(TEST_PACKAGES)
+
+mostlyclean-local:
+ find . -name '*.lo' -print | xargs $(LIBTOOL) --mode=clean rm -f
+ find . -name '*.$(OBJEXT)' -print | xargs rm -f
+
+clean-local:
+ find . -name '*.la' -print | xargs $(LIBTOOL) --mode=clean rm -f
+ find . -name '*.a' -print | xargs rm -f
+
+CLEANFILES = *.go *.gox goc2c *.c s-version
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
new file mode 100644
index 000000000..2fa67318d
--- /dev/null
+++ b/libgo/Makefile.in
@@ -0,0 +1,4789 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am -- Go library Makefile.
+
+# 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.
+
+# Process this file with autoreconf to produce Makefile.in.
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = .
+DIST_COMMON = README $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/configure $(am__configure_deps) \
+ $(srcdir)/config.h.in $(srcdir)/../mkinstalldirs \
+ $(srcdir)/../depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
+ $(top_srcdir)/../config/lead-dot.m4 \
+ $(top_srcdir)/../config/multi.m4 \
+ $(top_srcdir)/../config/override.m4 \
+ $(top_srcdir)/../config/unwind_ipinfo.m4 \
+ $(top_srcdir)/config/go.m4 $(top_srcdir)/config/libtool.m4 \
+ $(top_srcdir)/config/ltoptions.m4 \
+ $(top_srcdir)/config/ltsugar.m4 \
+ $(top_srcdir)/config/ltversion.m4 \
+ $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
+ "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" \
+ "$(DESTDIR)$(toolexeclibgoarchivedir)" \
+ "$(DESTDIR)$(toolexeclibgocompressdir)" \
+ "$(DESTDIR)$(toolexeclibgocontainerdir)" \
+ "$(DESTDIR)$(toolexeclibgocryptodir)" \
+ "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" \
+ "$(DESTDIR)$(toolexeclibgodebugdir)" \
+ "$(DESTDIR)$(toolexeclibgoencodingdir)" \
+ "$(DESTDIR)$(toolexeclibgoexpdir)" \
+ "$(DESTDIR)$(toolexeclibgogodir)" \
+ "$(DESTDIR)$(toolexeclibgohashdir)" \
+ "$(DESTDIR)$(toolexeclibgohttpdir)" \
+ "$(DESTDIR)$(toolexeclibgoimagedir)" \
+ "$(DESTDIR)$(toolexeclibgoindexdir)" \
+ "$(DESTDIR)$(toolexeclibgoiodir)" \
+ "$(DESTDIR)$(toolexeclibgomimedir)" \
+ "$(DESTDIR)$(toolexeclibgonetdir)" \
+ "$(DESTDIR)$(toolexeclibgoosdir)" \
+ "$(DESTDIR)$(toolexeclibgorpcdir)" \
+ "$(DESTDIR)$(toolexeclibgoruntimedir)" \
+ "$(DESTDIR)$(toolexeclibgotestingdir)"
+LIBRARIES = $(toolexeclib_LIBRARIES)
+ARFLAGS = cru
+libgobegin_a_AR = $(AR) $(ARFLAGS)
+libgobegin_a_LIBADD =
+am_libgobegin_a_OBJECTS = go-main.$(OBJEXT)
+libgobegin_a_OBJECTS = $(am_libgobegin_a_OBJECTS)
+LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+am__DEPENDENCIES_2 = asn1/asn1.lo big/big.lo bufio/bufio.lo \
+ bytes/bytes.lo bytes/index.lo cmath/cmath.lo ebnf/ebnf.lo \
+ exec/exec.lo expvar/expvar.lo flag/flag.lo fmt/fmt.lo \
+ gob/gob.lo hash/hash.lo html/html.lo http/http.lo \
+ image/image.lo io/io.lo json/json.lo log/log.lo math/math.lo \
+ mime/mime.lo net/net.lo netchan/netchan.lo os/os.lo \
+ patch/patch.lo path/path.lo rand/rand.lo reflect/reflect.lo \
+ regexp/regexp.lo rpc/rpc.lo runtime/runtime.lo \
+ scanner/scanner.lo smtp/smtp.lo sort/sort.lo \
+ strconv/strconv.lo strings/strings.lo sync/mutex.lo \
+ sync/cas.lo syslog/syslog.lo syslog/syslog_c.lo \
+ tabwriter/tabwriter.lo template/template.lo time/time.lo \
+ try/try.lo unicode/unicode.lo utf16/utf16.lo utf8/utf8.lo \
+ websocket/websocket.lo xml/xml.lo archive/tar.lo \
+ archive/zip.lo compress/flate.lo compress/gzip.lo \
+ compress/zlib.lo container/heap.lo container/list.lo \
+ container/ring.lo container/vector.lo crypto/aes.lo \
+ crypto/block.lo crypto/blowfish.lo crypto/cast5.lo \
+ crypto/cipher.lo crypto/elliptic.lo crypto/hmac.lo \
+ crypto/md4.lo crypto/md5.lo crypto/ocsp.lo crypto/rand.lo \
+ crypto/rc4.lo crypto/ripemd160.lo crypto/rsa.lo crypto/sha1.lo \
+ crypto/sha256.lo crypto/sha512.lo crypto/subtle.lo \
+ crypto/tls.lo crypto/twofish.lo crypto/x509.lo crypto/xtea.lo \
+ crypto/openpgp/armor.lo crypto/openpgp/error.lo \
+ crypto/openpgp/s2k.lo debug/dwarf.lo debug/elf.lo \
+ debug/gosym.lo debug/macho.lo debug/pe.lo debug/proc.lo \
+ encoding/ascii85.lo encoding/base32.lo encoding/base64.lo \
+ encoding/binary.lo encoding/git85.lo encoding/hex.lo \
+ encoding/line.lo encoding/pem.lo exp/datafmt.lo exp/draw.lo \
+ exp/eval.lo go/ast.lo go/doc.lo go/parser.lo go/printer.lo \
+ go/scanner.lo go/token.lo go/typechecker.lo hash/adler32.lo \
+ hash/crc32.lo hash/crc64.lo http/pprof.lo image/jpeg.lo \
+ image/png.lo index/suffixarray.lo io/ioutil.lo \
+ mime/multipart.lo net/dict.lo net/textproto.lo \
+ $(am__DEPENDENCIES_1) os/signal.lo rpc/jsonrpc.lo \
+ runtime/debug.lo runtime/pprof.lo syscalls/syscall.lo \
+ syscalls/errno.lo testing/testing.lo testing/iotest.lo \
+ testing/quick.lo testing/script.lo
+libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+@HAVE_SYS_MMAN_H_FALSE@am__objects_1 = mem_posix_memalign.lo
+@HAVE_SYS_MMAN_H_TRUE@am__objects_1 = mem.lo
+@LIBGO_IS_RTEMS_TRUE@am__objects_2 = rtems-task-variable-add.lo
+am__objects_3 = go-append.lo go-assert.lo go-assert-interface.lo \
+ go-byte-array-to-string.lo go-breakpoint.lo go-caller.lo \
+ go-can-convert-interface.lo go-cgo.lo go-chan-cap.lo \
+ go-chan-len.lo go-check-interface.lo go-close.lo go-closed.lo \
+ go-construct-map.lo go-convert-interface.lo go-copy.lo \
+ go-defer.lo go-deferred-recover.lo go-eface-compare.lo \
+ go-eface-val-compare.lo go-getgoroot.lo go-go.lo \
+ go-gomaxprocs.lo go-int-array-to-string.lo go-int-to-string.lo \
+ go-interface-compare.lo go-interface-eface-compare.lo \
+ go-interface-val-compare.lo go-lock-os-thread.lo \
+ go-map-delete.lo go-map-index.lo go-map-len.lo go-map-range.lo \
+ go-nanotime.lo go-new-channel.lo go-new-map.lo go-new.lo \
+ go-note.lo go-panic.lo go-panic-defer.lo go-print.lo \
+ go-rec-big.lo go-rec-nb-big.lo go-rec-nb-small.lo \
+ go-rec-small.lo go-recover.lo go-reflect.lo go-reflect-call.lo \
+ go-reflect-chan.lo go-reflect-map.lo go-rune.lo \
+ go-runtime-error.lo go-sched.lo go-select.lo go-semacquire.lo \
+ go-send-big.lo go-send-nb-big.lo go-send-nb-small.lo \
+ go-send-small.lo go-signal.lo go-strcmp.lo \
+ go-string-to-byte-array.lo go-string-to-int-array.lo \
+ go-strplus.lo go-strslice.lo go-trampoline.lo go-type-eface.lo \
+ go-type-error.lo go-type-identity.lo go-type-interface.lo \
+ go-type-string.lo go-typedesc-equal.lo go-typestring.lo \
+ go-unreflect.lo go-unsafe-new.lo go-unsafe-newarray.lo \
+ go-unsafe-pointer.lo go-unwind.lo mcache.lo mcentral.lo \
+ $(am__objects_1) mfinal.lo mfixalloc.lo mgc0.lo mheap.lo \
+ mheapmap32.lo mheapmap64.lo msize.lo proc.lo thread.lo \
+ $(am__objects_2) chan.lo iface.lo malloc.lo map.lo mprof.lo \
+ reflect.lo sigqueue.lo string.lo
+am_libgo_la_OBJECTS = $(am__objects_3)
+libgo_la_OBJECTS = $(am_libgo_la_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libgobegin_a_SOURCES) $(libgo_la_SOURCES)
+MULTISRCTOP =
+MULTIBUILDTOP =
+MULTIDIRS =
+MULTISUBDIR =
+MULTIDO = true
+MULTICLEAN = true
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+DATA = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
+ $(toolexeclibgocompress_DATA) $(toolexeclibgocontainer_DATA) \
+ $(toolexeclibgocrypto_DATA) $(toolexeclibgocryptoopenpgp_DATA) \
+ $(toolexeclibgodebug_DATA) $(toolexeclibgoencoding_DATA) \
+ $(toolexeclibgoexp_DATA) $(toolexeclibgogo_DATA) \
+ $(toolexeclibgohash_DATA) $(toolexeclibgohttp_DATA) \
+ $(toolexeclibgoimage_DATA) $(toolexeclibgoindex_DATA) \
+ $(toolexeclibgoio_DATA) $(toolexeclibgomime_DATA) \
+ $(toolexeclibgonet_DATA) $(toolexeclibgoos_DATA) \
+ $(toolexeclibgorpc_DATA) $(toolexeclibgoruntime_DATA) \
+ $(toolexeclibgotesting_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = testsuite
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GOARCH = @GOARCH@
+GOC = @GOC@
+GOCFLAGS = $(CFLAGS)
+GOOS = @GOOS@
+GO_DEBUG_PROC_REGS_OS_ARCH_FILE = @GO_DEBUG_PROC_REGS_OS_ARCH_FILE@
+GO_SYSCALLS_SYSCALL_OS_ARCH_FILE = @GO_SYSCALLS_SYSCALL_OS_ARCH_FILE@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBFFI = @LIBFFI@
+LIBFFIINCS = @LIBFFIINCS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NET_LIBS = @NET_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJCOPY = @OBJCOPY@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPLIT_STACK = @SPLIT_STACK@
+STRINGOPS_FLAG = @STRINGOPS_FLAG@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_FLAGS = @WARN_FLAGS@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_shared = @enable_shared@
+enable_static = @enable_static@
+exec_prefix = @exec_prefix@
+glibgo_prefixdir = @glibgo_prefixdir@
+glibgo_toolexecdir = @glibgo_toolexecdir@
+glibgo_toolexeclibdir = @glibgo_toolexeclibdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libtool_VERSION = @libtool_VERSION@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+multi_basedir = @multi_basedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Go support.
+SUFFIXES = .c .go .gox .o .obj .lo .a
+@LIBGO_IS_RTEMS_TRUE@subdirs = testsuite
+SUBDIRS = ${subdirs}
+gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+MAINT_CHARSET = latin1
+mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
+PWD_COMMAND = $${PWDCMD-pwd}
+STAMP = echo timestamp >
+toolexecdir = $(glibgo_toolexecdir)
+toolexeclibdir = $(glibgo_toolexeclibdir)
+WARN_CFLAGS = $(WARN_FLAGS) $(WERROR)
+
+# -I/-D flags to pass when compiling.
+AM_CPPFLAGS = -I $(srcdir)/runtime $(LIBFFIINCS) $(PTHREAD_CFLAGS)
+ACLOCAL_AMFLAGS = -I ./config -I ../config
+AM_CFLAGS = -fexceptions -fplan9-extensions $(SPLIT_STACK) $(WARN_CFLAGS) \
+ $(STRINGOPS_FLAG) \
+ -I $(srcdir)/../gcc -I $(MULTIBUILDTOP)../../gcc/include
+
+@USING_SPLIT_STACK_TRUE@AM_LDFLAGS = -XCClinker $(SPLIT_STACK)
+
+# Multilib support.
+MAKEOVERRIDES =
+
+# Work around what appears to be a GNU make handling MAKEFLAGS
+# values defined in terms of make variables, as is the case for CC and
+# friends when we are called from the top level Makefile.
+AM_MAKEFLAGS = \
+ "AR_FLAGS=$(AR_FLAGS)" \
+ "CC_FOR_BUILD=$(CC_FOR_BUILD)" \
+ "CC_FOR_TARGET=$(CC_FOR_TARGET)" \
+ "CFLAGS=$(CFLAGS)" \
+ "CXXFLAGS=$(CXXFLAGS)" \
+ "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
+ "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
+ "GOC_FOR_TARGET=$(GOC_FOR_TARGET)" \
+ "GOC=$(GOC)" \
+ "GOCFLAGS=$(GOCFLAGS)" \
+ "INSTALL=$(INSTALL)" \
+ "INSTALL_DATA=$(INSTALL_DATA)" \
+ "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
+ "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
+ "LDFLAGS=$(LDFLAGS)" \
+ "LIBCFLAGS=$(LIBCFLAGS)" \
+ "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
+ "MAKE=$(MAKE)" \
+ "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
+ "PICFLAG=$(PICFLAG)" \
+ "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
+ "SHELL=$(SHELL)" \
+ "RUNTESTFLAGS=$(RUNTESTFLAGS)" \
+ "exec_prefix=$(exec_prefix)" \
+ "infodir=$(infodir)" \
+ "libdir=$(libdir)" \
+ "includedir=$(includedir)" \
+ "prefix=$(prefix)" \
+ "tooldir=$(tooldir)" \
+ "gxx_include_dir=$(gxx_include_dir)" \
+ "AR=$(AR)" \
+ "AS=$(AS)" \
+ "LD=$(LD)" \
+ "RANLIB=$(RANLIB)" \
+ "NM=$(NM)" \
+ "NM_FOR_BUILD=$(NM_FOR_BUILD)" \
+ "NM_FOR_TARGET=$(NM_FOR_TARGET)" \
+ "DESTDIR=$(DESTDIR)" \
+ "WERROR=$(WERROR)"
+
+
+# Subdir rules rely on $(FLAGS_TO_PASS)
+FLAGS_TO_PASS = $(AM_MAKEFLAGS)
+toolexeclib_LTLIBRARIES = libgo.la
+toolexeclib_LIBRARIES = libgobegin.a
+toolexeclibgodir = $(toolexeclibdir)/go/$(gcc_version)/$(target_alias)
+toolexeclibgo_DATA = \
+ asn1.gox \
+ big.gox \
+ bufio.gox \
+ bytes.gox \
+ cmath.gox \
+ ebnf.gox \
+ exec.gox \
+ expvar.gox \
+ flag.gox \
+ fmt.gox \
+ gob.gox \
+ hash.gox \
+ html.gox \
+ http.gox \
+ image.gox \
+ io.gox \
+ json.gox \
+ log.gox \
+ math.gox \
+ mime.gox \
+ net.gox \
+ netchan.gox \
+ os.gox \
+ patch.gox \
+ path.gox \
+ rand.gox \
+ reflect.gox \
+ regexp.gox \
+ rpc.gox \
+ runtime.gox \
+ scanner.gox \
+ smtp.gox \
+ sort.gox \
+ strconv.gox \
+ strings.gox \
+ sync.gox \
+ syscall.gox \
+ syslog.gox \
+ tabwriter.gox \
+ template.gox \
+ testing.gox \
+ time.gox \
+ try.gox \
+ unicode.gox \
+ utf16.gox \
+ utf8.gox \
+ websocket.gox \
+ xml.gox
+
+toolexeclibgoarchivedir = $(toolexeclibgodir)/archive
+toolexeclibgoarchive_DATA = \
+ archive/tar.gox \
+ archive/zip.gox
+
+toolexeclibgocompressdir = $(toolexeclibgodir)/compress
+toolexeclibgocompress_DATA = \
+ compress/flate.gox \
+ compress/gzip.gox \
+ compress/zlib.gox
+
+toolexeclibgocontainerdir = $(toolexeclibgodir)/container
+toolexeclibgocontainer_DATA = \
+ container/heap.gox \
+ container/list.gox \
+ container/ring.gox \
+ container/vector.gox
+
+toolexeclibgocryptodir = $(toolexeclibgodir)/crypto
+toolexeclibgocrypto_DATA = \
+ crypto/aes.gox \
+ crypto/block.gox \
+ crypto/blowfish.gox \
+ crypto/cast5.gox \
+ crypto/cipher.gox \
+ crypto/elliptic.gox \
+ crypto/hmac.gox \
+ crypto/md4.gox \
+ crypto/md5.gox \
+ crypto/ocsp.gox \
+ crypto/rand.gox \
+ crypto/rc4.gox \
+ crypto/ripemd160.gox \
+ crypto/rsa.gox \
+ crypto/sha1.gox \
+ crypto/sha256.gox \
+ crypto/sha512.gox \
+ crypto/subtle.gox \
+ crypto/tls.gox \
+ crypto/twofish.gox \
+ crypto/x509.gox \
+ crypto/xtea.gox
+
+toolexeclibgocryptoopenpgpdir = $(toolexeclibgocryptodir)/openpgp
+toolexeclibgocryptoopenpgp_DATA = \
+ crypto/openpgp/armor.gox \
+ crypto/openpgp/error.gox \
+ crypto/openpgp/s2k.gox
+
+toolexeclibgodebugdir = $(toolexeclibgodir)/debug
+toolexeclibgodebug_DATA = \
+ debug/dwarf.gox \
+ debug/elf.gox \
+ debug/gosym.gox \
+ debug/macho.gox \
+ debug/pe.gox \
+ debug/proc.gox
+
+toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
+toolexeclibgoencoding_DATA = \
+ encoding/ascii85.gox \
+ encoding/base32.gox \
+ encoding/base64.gox \
+ encoding/binary.gox \
+ encoding/line.gox \
+ encoding/git85.gox \
+ encoding/hex.gox \
+ encoding/pem.gox
+
+toolexeclibgoexpdir = $(toolexeclibgodir)/exp
+toolexeclibgoexp_DATA = \
+ exp/datafmt.gox \
+ exp/draw.gox \
+ exp/eval.gox
+
+toolexeclibgogodir = $(toolexeclibgodir)/go
+toolexeclibgogo_DATA = \
+ go/ast.gox \
+ go/doc.gox \
+ go/parser.gox \
+ go/printer.gox \
+ go/scanner.gox \
+ go/token.gox \
+ go/typechecker.gox
+
+toolexeclibgohashdir = $(toolexeclibgodir)/hash
+toolexeclibgohash_DATA = \
+ hash/adler32.gox \
+ hash/crc32.gox \
+ hash/crc64.gox
+
+toolexeclibgohttpdir = $(toolexeclibgodir)/http
+toolexeclibgohttp_DATA = \
+ http/pprof.gox
+
+toolexeclibgoimagedir = $(toolexeclibgodir)/image
+toolexeclibgoimage_DATA = \
+ image/jpeg.gox \
+ image/png.gox
+
+toolexeclibgoindexdir = $(toolexeclibgodir)/index
+toolexeclibgoindex_DATA = \
+ index/suffixarray.gox
+
+toolexeclibgoiodir = $(toolexeclibgodir)/io
+toolexeclibgoio_DATA = \
+ io/ioutil.gox
+
+toolexeclibgomimedir = $(toolexeclibgodir)/mime
+toolexeclibgomime_DATA = \
+ mime/multipart.gox
+
+toolexeclibgonetdir = $(toolexeclibgodir)/net
+toolexeclibgonet_DATA = \
+ net/dict.gox \
+ net/textproto.gox
+
+toolexeclibgoosdir = $(toolexeclibgodir)/os
+@LIBGO_IS_LINUX_FALSE@os_inotify_gox =
+
+# os_inotify_gox = os/inotify.gox
+@LIBGO_IS_LINUX_TRUE@os_inotify_gox =
+toolexeclibgoos_DATA = \
+ $(os_inotify_gox) \
+ os/signal.gox
+
+toolexeclibgorpcdir = $(toolexeclibgodir)/rpc
+toolexeclibgorpc_DATA = \
+ rpc/jsonrpc.gox
+
+toolexeclibgoruntimedir = $(toolexeclibgodir)/runtime
+toolexeclibgoruntime_DATA = \
+ runtime/debug.gox \
+ runtime/pprof.gox
+
+toolexeclibgotestingdir = $(toolexeclibgodir)/testing
+toolexeclibgotesting_DATA = \
+ testing/iotest.gox \
+ testing/quick.gox \
+ testing/script.gox
+
+@HAVE_SYS_MMAN_H_FALSE@runtime_mem_file = runtime/mem_posix_memalign.c
+@HAVE_SYS_MMAN_H_TRUE@runtime_mem_file = runtime/mem.c
+@LIBGO_IS_RTEMS_FALSE@rtems_task_variable_add_file =
+@LIBGO_IS_RTEMS_TRUE@rtems_task_variable_add_file = runtime/rtems-task-variable-add.c
+runtime_files = \
+ runtime/go-append.c \
+ runtime/go-assert.c \
+ runtime/go-assert-interface.c \
+ runtime/go-byte-array-to-string.c \
+ runtime/go-breakpoint.c \
+ runtime/go-caller.c \
+ runtime/go-can-convert-interface.c \
+ runtime/go-cgo.c \
+ runtime/go-chan-cap.c \
+ runtime/go-chan-len.c \
+ runtime/go-check-interface.c \
+ runtime/go-close.c \
+ runtime/go-closed.c \
+ runtime/go-construct-map.c \
+ runtime/go-convert-interface.c \
+ runtime/go-copy.c \
+ runtime/go-defer.c \
+ runtime/go-deferred-recover.c \
+ runtime/go-eface-compare.c \
+ runtime/go-eface-val-compare.c \
+ runtime/go-getgoroot.c \
+ runtime/go-go.c \
+ runtime/go-gomaxprocs.c \
+ runtime/go-int-array-to-string.c \
+ runtime/go-int-to-string.c \
+ runtime/go-interface-compare.c \
+ runtime/go-interface-eface-compare.c \
+ runtime/go-interface-val-compare.c \
+ runtime/go-lock-os-thread.c \
+ runtime/go-map-delete.c \
+ runtime/go-map-index.c \
+ runtime/go-map-len.c \
+ runtime/go-map-range.c \
+ runtime/go-nanotime.c \
+ runtime/go-new-channel.c \
+ runtime/go-new-map.c \
+ runtime/go-new.c \
+ runtime/go-note.c \
+ runtime/go-panic.c \
+ runtime/go-panic-defer.c \
+ runtime/go-print.c \
+ runtime/go-rec-big.c \
+ runtime/go-rec-nb-big.c \
+ runtime/go-rec-nb-small.c \
+ runtime/go-rec-small.c \
+ runtime/go-recover.c \
+ runtime/go-reflect.c \
+ runtime/go-reflect-call.c \
+ runtime/go-reflect-chan.c \
+ runtime/go-reflect-map.c \
+ runtime/go-rune.c \
+ runtime/go-runtime-error.c \
+ runtime/go-sched.c \
+ runtime/go-select.c \
+ runtime/go-semacquire.c \
+ runtime/go-send-big.c \
+ runtime/go-send-nb-big.c \
+ runtime/go-send-nb-small.c \
+ runtime/go-send-small.c \
+ runtime/go-signal.c \
+ runtime/go-strcmp.c \
+ runtime/go-string-to-byte-array.c \
+ runtime/go-string-to-int-array.c \
+ runtime/go-strplus.c \
+ runtime/go-strslice.c \
+ runtime/go-trampoline.c \
+ runtime/go-type-eface.c \
+ runtime/go-type-error.c \
+ runtime/go-type-identity.c \
+ runtime/go-type-interface.c \
+ runtime/go-type-string.c \
+ runtime/go-typedesc-equal.c \
+ runtime/go-typestring.c \
+ runtime/go-unreflect.c \
+ runtime/go-unsafe-new.c \
+ runtime/go-unsafe-newarray.c \
+ runtime/go-unsafe-pointer.c \
+ runtime/go-unwind.c \
+ runtime/mcache.c \
+ runtime/mcentral.c \
+ $(runtime_mem_file) \
+ runtime/mfinal.c \
+ runtime/mfixalloc.c \
+ runtime/mgc0.c \
+ runtime/mheap.c \
+ runtime/mheapmap32.c \
+ runtime/mheapmap64.c \
+ runtime/msize.c \
+ runtime/proc.c \
+ runtime/thread.c \
+ $(rtems_task_variable_add_file) \
+ chan.c \
+ iface.c \
+ malloc.c \
+ map.c \
+ mprof.c \
+ reflect.c \
+ sigqueue.c \
+ string.c
+
+go_asn1_files = \
+ go/asn1/asn1.go \
+ go/asn1/common.go \
+ go/asn1/marshal.go
+
+go_big_files = \
+ go/big/arith.go \
+ go/big/int.go \
+ go/big/nat.go \
+ go/big/rat.go
+
+go_bufio_files = \
+ go/bufio/bufio.go
+
+go_bytes_files = \
+ go/bytes/buffer.go \
+ go/bytes/bytes.go \
+ go/bytes/bytes_decl.go
+
+go_bytes_c_files = \
+ go/bytes/indexbyte.c
+
+go_cmath_files = \
+ go/cmath/abs.go \
+ go/cmath/asin.go \
+ go/cmath/conj.go \
+ go/cmath/exp.go \
+ go/cmath/isinf.go \
+ go/cmath/isnan.go \
+ go/cmath/log.go \
+ go/cmath/phase.go \
+ go/cmath/polar.go \
+ go/cmath/pow.go \
+ go/cmath/rect.go \
+ go/cmath/sin.go \
+ go/cmath/sqrt.go \
+ go/cmath/tan.go
+
+go_ebnf_files = \
+ go/ebnf/ebnf.go \
+ go/ebnf/parser.go
+
+go_exec_files = \
+ go/exec/exec.go \
+ go/exec/lp_unix.go
+
+go_expvar_files = \
+ go/expvar/expvar.go
+
+go_flag_files = \
+ go/flag/flag.go
+
+go_fmt_files = \
+ go/fmt/doc.go \
+ go/fmt/format.go \
+ go/fmt/print.go \
+ go/fmt/scan.go
+
+go_gob_files = \
+ go/gob/decode.go \
+ go/gob/decoder.go \
+ go/gob/doc.go \
+ go/gob/encode.go \
+ go/gob/encoder.go \
+ go/gob/error.go \
+ go/gob/type.go
+
+go_hash_files = \
+ go/hash/hash.go
+
+go_html_files = \
+ go/html/doc.go \
+ go/html/entity.go \
+ go/html/escape.go \
+ go/html/parse.go \
+ go/html/token.go
+
+go_http_files = \
+ go/http/chunked.go \
+ go/http/client.go \
+ go/http/dump.go \
+ go/http/fs.go \
+ go/http/lex.go \
+ go/http/persist.go \
+ go/http/request.go \
+ go/http/response.go \
+ go/http/server.go \
+ go/http/status.go \
+ go/http/transfer.go \
+ go/http/url.go
+
+go_image_files = \
+ go/image/color.go \
+ go/image/format.go \
+ go/image/geom.go \
+ go/image/image.go \
+ go/image/names.go
+
+go_io_files = \
+ go/io/multi.go \
+ go/io/io.go \
+ go/io/pipe.go
+
+go_json_files = \
+ go/json/decode.go \
+ go/json/encode.go \
+ go/json/indent.go \
+ go/json/scanner.go \
+ go/json/stream.go
+
+go_log_files = \
+ go/log/log.go
+
+go_math_files = \
+ go/math/acosh.go \
+ go/math/asin.go \
+ go/math/asinh.go \
+ go/math/atan.go \
+ go/math/atanh.go \
+ go/math/atan2.go \
+ go/math/bits.go \
+ go/math/cbrt.go \
+ go/math/const.go \
+ go/math/copysign.go \
+ go/math/erf.go \
+ go/math/exp.go \
+ go/math/exp_port.go \
+ go/math/exp2.go \
+ go/math/expm1.go \
+ go/math/fabs.go \
+ go/math/fdim.go \
+ go/math/floor.go \
+ go/math/fmod.go \
+ go/math/frexp.go \
+ go/math/gamma.go \
+ go/math/hypot.go \
+ go/math/hypot_port.go \
+ go/math/j0.go \
+ go/math/j1.go \
+ go/math/jn.go \
+ go/math/ldexp.go \
+ go/math/lgamma.go \
+ go/math/log.go \
+ go/math/log1p.go \
+ go/math/log10.go \
+ go/math/logb.go \
+ go/math/modf.go \
+ go/math/nextafter.go \
+ go/math/pow.go \
+ go/math/pow10.go \
+ go/math/remainder.go \
+ go/math/signbit.go \
+ go/math/sin.go \
+ go/math/sincos.go \
+ go/math/sinh.go \
+ go/math/sqrt.go \
+ go/math/sqrt_port.go \
+ go/math/tan.go \
+ go/math/tanh.go \
+ go/math/unsafe.go
+
+go_mime_files = \
+ go/mime/grammar.go \
+ go/mime/mediatype.go \
+ go/mime/type.go
+
+# By default use select with pipes. Most systems should have
+# something better.
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_rtems.go
+@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_linux.go
+@LIBGO_IS_RTEMS_TRUE@go_net_fd_os_file = go/net/fd_rtems.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
+@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
+@LIBGO_IS_RTEMS_TRUE@go_net_newpollserver_file = go/net/newpollserver_rtems.go
+go_net_files = \
+ go/net/dial.go \
+ go/net/dnsclient.go \
+ go/net/dnsconfig.go \
+ go/net/dnsmsg.go \
+ $(go_net_newpollserver_file) \
+ go/net/fd.go \
+ $(go_net_fd_os_file) \
+ go/net/hosts.go \
+ go/net/ip.go \
+ go/net/iprawsock.go \
+ go/net/ipsock.go \
+ go/net/net.go \
+ go/net/parse.go \
+ go/net/pipe.go \
+ go/net/port.go \
+ go/net/sock.go \
+ go/net/tcpsock.go \
+ go/net/udpsock.go \
+ go/net/unixsock.go
+
+go_netchan_files = \
+ go/netchan/common.go \
+ go/netchan/export.go \
+ go/netchan/import.go
+
+@LIBGO_IS_386_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_os_dir_file = go/os/dir_regfile.go
+@LIBGO_IS_386_TRUE@@LIBGO_IS_SOLARIS_TRUE@go_os_dir_file = go/os/dir_largefile.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_dir_file = go/os/dir_regfile.go
+@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_os_dir_file = go/os/dir_largefile.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_sys_file = go/os/sys_bsd.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_os_sys_file = go/os/sys_uname.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_os_sys_file = go/os/sys_uname.go
+@LIBGO_IS_LINUX_TRUE@go_os_sys_file = go/os/sys_linux.go
+go_os_files = \
+ $(go_os_dir_file) \
+ go/os/dir.go \
+ go/os/env.go \
+ go/os/env_unix.go \
+ go/os/error.go \
+ go/os/exec.go \
+ go/os/file.go \
+ go/os/file_unix.go \
+ go/os/getwd.go \
+ go/os/path.go \
+ go/os/proc.go \
+ go/os/stat.go \
+ $(go_os_sys_file) \
+ go/os/time.go \
+ go/os/types.go
+
+go_patch_files = \
+ go/patch/apply.go \
+ go/patch/git.go \
+ go/patch/patch.go \
+ go/patch/textdiff.go
+
+go_path_files = \
+ go/path/match.go \
+ go/path/path.go \
+ go/path/path_unix.go
+
+go_rand_files = \
+ go/rand/exp.go \
+ go/rand/normal.go \
+ go/rand/rand.go \
+ go/rand/rng.go \
+ go/rand/zipf.go
+
+go_reflect_files = \
+ go/reflect/deepequal.go \
+ go/reflect/type.go \
+ go/reflect/value.go
+
+go_regexp_files = \
+ go/regexp/regexp.go
+
+go_rpc_files = \
+ go/rpc/client.go \
+ go/rpc/debug.go \
+ go/rpc/server.go
+
+go_runtime_files = \
+ go/runtime/debug.go \
+ go/runtime/error.go \
+ go/runtime/extern.go \
+ go/runtime/malloc_defs.go \
+ go/runtime/runtime_defs.go \
+ go/runtime/sig.go \
+ go/runtime/softfloat64.go \
+ go/runtime/type.go \
+ version.go
+
+go_scanner_files = \
+ go/scanner/scanner.go
+
+go_smtp_files = \
+ go/smtp/auth.go \
+ go/smtp/smtp.go
+
+go_sort_files = \
+ go/sort/search.go \
+ go/sort/sort.go
+
+go_strconv_files = \
+ go/strconv/atob.go \
+ go/strconv/atof.go \
+ go/strconv/atoi.go \
+ go/strconv/decimal.go \
+ go/strconv/ftoa.go \
+ go/strconv/itoa.go \
+ go/strconv/quote.go
+
+go_strings_files = \
+ go/strings/reader.go \
+ go/strings/strings.go
+
+go_sync_files = \
+ go/sync/mutex.go \
+ go/sync/once.go \
+ go/sync/rwmutex.go
+
+go_sync_c_files = \
+ go/sync/cas.c
+
+@LIBGO_IS_SOLARIS_FALSE@go_syslog_file = go/syslog/syslog_unix.go
+@LIBGO_IS_SOLARIS_TRUE@go_syslog_file = go/syslog/syslog_solaris.go
+go_syslog_files = \
+ go/syslog/syslog.go \
+ $(go_syslog_file)
+
+go_syslog_c_files = \
+ go/syslog/syslog_c.c
+
+go_tabwriter_files = \
+ go/tabwriter/tabwriter.go
+
+go_template_files = \
+ go/template/format.go \
+ go/template/template.go
+
+go_testing_files = \
+ go/testing/benchmark.go \
+ go/testing/testing.go
+
+go_time_files = \
+ go/time/format.go \
+ go/time/sleep.go \
+ go/time/tick.go \
+ go/time/time.go \
+ go/time/zoneinfo_unix.go
+
+go_try_files = \
+ go/try/try.go
+
+go_unicode_files = \
+ go/unicode/casetables.go \
+ go/unicode/digit.go \
+ go/unicode/letter.go \
+ go/unicode/tables.go
+
+go_utf16_files = \
+ go/utf16/utf16.go
+
+go_utf8_files = \
+ go/utf8/string.go \
+ go/utf8/utf8.go
+
+go_websocket_files = \
+ go/websocket/client.go \
+ go/websocket/server.go \
+ go/websocket/websocket.go
+
+go_xml_files = \
+ go/xml/read.go \
+ go/xml/xml.go
+
+go_archive_tar_files = \
+ go/archive/tar/common.go \
+ go/archive/tar/reader.go \
+ go/archive/tar/writer.go
+
+go_archive_zip_files = \
+ go/archive/zip/reader.go \
+ go/archive/zip/struct.go
+
+go_compress_flate_files = \
+ go/compress/flate/deflate.go \
+ go/compress/flate/huffman_bit_writer.go \
+ go/compress/flate/huffman_code.go \
+ go/compress/flate/inflate.go \
+ go/compress/flate/reverse_bits.go \
+ go/compress/flate/token.go \
+ go/compress/flate/util.go
+
+go_compress_gzip_files = \
+ go/compress/gzip/gzip.go \
+ go/compress/gzip/gunzip.go
+
+go_compress_zlib_files = \
+ go/compress/zlib/reader.go \
+ go/compress/zlib/writer.go
+
+go_container_heap_files = \
+ go/container/heap/heap.go
+
+go_container_list_files = \
+ go/container/list/list.go
+
+go_container_ring_files = \
+ go/container/ring/ring.go
+
+go_container_vector_files = \
+ go/container/vector/defs.go \
+ go/container/vector/intvector.go \
+ go/container/vector/stringvector.go \
+ go/container/vector/vector.go
+
+go_crypto_aes_files = \
+ go/crypto/aes/block.go \
+ go/crypto/aes/cipher.go \
+ go/crypto/aes/const.go
+
+go_crypto_block_files = \
+ go/crypto/block/cbc.go \
+ go/crypto/block/cfb.go \
+ go/crypto/block/cmac.go \
+ go/crypto/block/cipher.go \
+ go/crypto/block/ctr.go \
+ go/crypto/block/eax.go \
+ go/crypto/block/ecb.go \
+ go/crypto/block/ofb.go \
+ go/crypto/block/xor.go
+
+go_crypto_blowfish_files = \
+ go/crypto/blowfish/block.go \
+ go/crypto/blowfish/const.go \
+ go/crypto/blowfish/cipher.go
+
+go_crypto_cast5_files = \
+ go/crypto/cast5/cast5.go
+
+go_crypto_cipher_files = \
+ go/crypto/cipher/cbc.go \
+ go/crypto/cipher/cfb.go \
+ go/crypto/cipher/cipher.go \
+ go/crypto/cipher/ctr.go \
+ go/crypto/cipher/io.go \
+ go/crypto/cipher/ocfb.go \
+ go/crypto/cipher/ofb.go
+
+go_crypto_elliptic_files = \
+ go/crypto/elliptic/elliptic.go
+
+go_crypto_hmac_files = \
+ go/crypto/hmac/hmac.go
+
+go_crypto_md4_files = \
+ go/crypto/md4/md4.go \
+ go/crypto/md4/md4block.go
+
+go_crypto_md5_files = \
+ go/crypto/md5/md5.go \
+ go/crypto/md5/md5block.go
+
+go_crypto_ocsp_files = \
+ go/crypto/ocsp/ocsp.go
+
+go_crypto_rand_files = \
+ go/crypto/rand/rand.go \
+ go/crypto/rand/rand_unix.go
+
+go_crypto_rc4_files = \
+ go/crypto/rc4/rc4.go
+
+go_crypto_ripemd160_files = \
+ go/crypto/ripemd160/ripemd160.go \
+ go/crypto/ripemd160/ripemd160block.go
+
+go_crypto_rsa_files = \
+ go/crypto/rsa/pkcs1v15.go \
+ go/crypto/rsa/rsa.go
+
+go_crypto_sha1_files = \
+ go/crypto/sha1/sha1.go \
+ go/crypto/sha1/sha1block.go
+
+go_crypto_sha256_files = \
+ go/crypto/sha256/sha256.go \
+ go/crypto/sha256/sha256block.go
+
+go_crypto_sha512_files = \
+ go/crypto/sha512/sha512.go \
+ go/crypto/sha512/sha512block.go
+
+go_crypto_subtle_files = \
+ go/crypto/subtle/constant_time.go
+
+go_crypto_tls_files = \
+ go/crypto/tls/alert.go \
+ go/crypto/tls/ca_set.go \
+ go/crypto/tls/cipher_suites.go \
+ go/crypto/tls/common.go \
+ go/crypto/tls/conn.go \
+ go/crypto/tls/handshake_client.go \
+ go/crypto/tls/handshake_messages.go \
+ go/crypto/tls/handshake_server.go \
+ go/crypto/tls/key_agreement.go \
+ go/crypto/tls/prf.go \
+ go/crypto/tls/tls.go
+
+go_crypto_twofish_files = \
+ go/crypto/twofish/twofish.go
+
+go_crypto_x509_files = \
+ go/crypto/x509/x509.go
+
+go_crypto_xtea_files = \
+ go/crypto/xtea/block.go \
+ go/crypto/xtea/cipher.go
+
+go_crypto_openpgp_armor_files = \
+ go/crypto/openpgp/armor/armor.go \
+ go/crypto/openpgp/armor/encode.go
+
+go_crypto_openpgp_error_files = \
+ go/crypto/openpgp/error/error.go
+
+go_crypto_openpgp_s2k_files = \
+ go/crypto/openpgp/s2k/s2k.go
+
+go_debug_dwarf_files = \
+ go/debug/dwarf/buf.go \
+ go/debug/dwarf/const.go \
+ go/debug/dwarf/entry.go \
+ go/debug/dwarf/open.go \
+ go/debug/dwarf/type.go \
+ go/debug/dwarf/unit.go
+
+go_debug_elf_files = \
+ go/debug/elf/elf.go \
+ go/debug/elf/file.go
+
+go_debug_gosym_files = \
+ go/debug/gosym/pclntab.go \
+ go/debug/gosym/symtab.go
+
+go_debug_macho_files = \
+ go/debug/macho/file.go \
+ go/debug/macho/macho.go
+
+go_debug_pe_files = \
+ go/debug/pe/file.go \
+ go/debug/pe/pe.go
+
+go_debug_proc_files = \
+ go/debug/proc/proc.go \
+ go/debug/proc/proc_$(GOOS).go \
+ $(GO_DEBUG_PROC_REGS_OS_ARCH_FILE)
+
+go_encoding_ascii85_files = \
+ go/encoding/ascii85/ascii85.go
+
+go_encoding_base32_files = \
+ go/encoding/base32/base32.go
+
+go_encoding_base64_files = \
+ go/encoding/base64/base64.go
+
+go_encoding_binary_files = \
+ go/encoding/binary/binary.go
+
+go_encoding_git85_files = \
+ go/encoding/git85/git.go
+
+go_encoding_hex_files = \
+ go/encoding/hex/hex.go
+
+go_encoding_line_files = \
+ go/encoding/line/line.go
+
+go_encoding_pem_files = \
+ go/encoding/pem/pem.go
+
+go_exp_datafmt_files = \
+ go/exp/datafmt/datafmt.go \
+ go/exp/datafmt/parser.go
+
+go_exp_draw_files = \
+ go/exp/draw/draw.go \
+ go/exp/draw/event.go
+
+go_exp_eval_files = \
+ go/exp/eval/abort.go \
+ go/exp/eval/bridge.go \
+ go/exp/eval/compiler.go \
+ go/exp/eval/expr.go \
+ go/exp/eval/expr1.go \
+ go/exp/eval/func.go \
+ go/exp/eval/scope.go \
+ go/exp/eval/stmt.go \
+ go/exp/eval/type.go \
+ go/exp/eval/typec.go \
+ go/exp/eval/value.go \
+ go/exp/eval/world.go
+
+go_go_ast_files = \
+ go/go/ast/ast.go \
+ go/go/ast/filter.go \
+ go/go/ast/print.go \
+ go/go/ast/scope.go \
+ go/go/ast/walk.go
+
+go_go_doc_files = \
+ go/go/doc/comment.go \
+ go/go/doc/doc.go
+
+go_go_parser_files = \
+ go/go/parser/interface.go \
+ go/go/parser/parser.go
+
+go_go_printer_files = \
+ go/go/printer/nodes.go \
+ go/go/printer/printer.go
+
+go_go_scanner_files = \
+ go/go/scanner/errors.go \
+ go/go/scanner/scanner.go
+
+go_go_token_files = \
+ go/go/token/position.go \
+ go/go/token/token.go
+
+go_go_typechecker_files = \
+ go/go/typechecker/scope.go \
+ go/go/typechecker/typechecker.go \
+ go/go/typechecker/universe.go
+
+go_hash_adler32_files = \
+ go/hash/adler32/adler32.go
+
+go_hash_crc32_files = \
+ go/hash/crc32/crc32.go
+
+go_hash_crc64_files = \
+ go/hash/crc64/crc64.go
+
+go_http_pprof_files = \
+ go/http/pprof/pprof.go
+
+go_image_jpeg_files = \
+ go/image/jpeg/huffman.go \
+ go/image/jpeg/idct.go \
+ go/image/jpeg/reader.go
+
+go_image_png_files = \
+ go/image/png/reader.go \
+ go/image/png/writer.go
+
+go_index_suffixarray_files = \
+ go/index/suffixarray/qsufsort.go \
+ go/index/suffixarray/suffixarray.go
+
+go_io_ioutil_files = \
+ go/io/ioutil/ioutil.go \
+ go/io/ioutil/tempfile.go
+
+go_mime_multipart_files = \
+ go/mime/multipart/multipart.go
+
+go_net_dict_files = \
+ go/net/dict/dict.go
+
+go_net_textproto_files = \
+ go/net/textproto/pipeline.go \
+ go/net/textproto/reader.go \
+ go/net/textproto/textproto.go \
+ go/net/textproto/writer.go
+
+go_os_inotify_files = \
+ go/os/inotify/inotify_linux.go
+
+go_os_signal_files = \
+ go/os/signal/signal.go \
+ unix.go
+
+go_rpc_jsonrpc_files = \
+ go/rpc/jsonrpc/client.go \
+ go/rpc/jsonrpc/server.go
+
+go_runtime_debug_files = \
+ go/runtime/debug/stack.go
+
+go_runtime_pprof_files = \
+ go/runtime/pprof/pprof.go
+
+go_testing_iotest_files = \
+ go/testing/iotest/logger.go \
+ go/testing/iotest/reader.go \
+ go/testing/iotest/writer.go
+
+go_testing_quick_files = \
+ go/testing/quick/quick.go
+
+go_testing_script_files = \
+ go/testing/script/script.go
+
+@LIBGO_IS_RTEMS_FALSE@syscall_syscall_file = syscalls/syscall.go
+
+# Define Syscall and Syscall6.
+@LIBGO_IS_RTEMS_TRUE@syscall_syscall_file = syscalls/syscall_stubs.go
+# Use lseek on amd64 Solaris.
+@LIBGO_IS_386_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@syscall_filesize_file = syscalls/sysfile_regfile.go
+# FIXME: Same for sparc vs. sparc64. Introduce new/additional conditional?
+# Use lseek64 on 386 Solaris.
+@LIBGO_IS_386_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@syscall_filesize_file = syscalls/sysfile_largefile.go
+# Use lseek by default.
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@syscall_filesize_file = syscalls/sysfile_regfile.go
+
+# Declare libc functions that vary for largefile systems.
+# Always use lseek64 on GNU/Linux.
+@LIBGO_IS_LINUX_TRUE@syscall_filesize_file = syscalls/sysfile_largefile.go
+@LIBGO_IS_386_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@syscall_stat_file = syscalls/sysfile_stat_regfile.go
+@LIBGO_IS_386_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@syscall_stat_file = syscalls/sysfile_stat_largefile.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@syscall_stat_file = syscalls/sysfile_stat_regfile.go
+@LIBGO_IS_LINUX_TRUE@syscall_stat_file = syscalls/sysfile_stat_largefile.go
+@LIBGO_IS_RTEMS_FALSE@syscall_exec_os_file = syscalls/exec.go
+
+# Define ForkExec, PtraceForkExec, Exec, and Wait4.
+@LIBGO_IS_RTEMS_TRUE@syscall_exec_os_file = syscalls/exec_stubs.go
+@LIBGO_IS_RTEMS_FALSE@syscall_sleep_file = syscalls/sleep_select.go
+
+# Define Sleep.
+@LIBGO_IS_RTEMS_TRUE@syscall_sleep_file = syscalls/sleep_rtems.go
+@LIBGO_IS_RTEMS_FALSE@syscall_errstr_file = syscalls/errstr.go
+
+# Define Errstr.
+@LIBGO_IS_RTEMS_TRUE@syscall_errstr_file = syscalls/errstr_rtems.go
+# On other systems we hope strerror_r is just strerror_r.
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@syscall_errstr_decl_file = syscalls/errstr_decl.go
+# In Linux the POSIX strerror_r is called __xpg_strerror_r.
+@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@syscall_errstr_decl_file = syscalls/errstr_decl_linux.go
+
+# Declare libc_strerror_r which is the Go name for strerror_r.
+# RTEMS uses newlib in which strerror_r returns char *.
+@LIBGO_IS_RTEMS_TRUE@syscall_errstr_decl_file = syscalls/errstr_decl_rtems.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@syscall_socket_os_file = syscalls/socket_bsd.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@syscall_socket_os_file = syscalls/socket_solaris.go
+
+# Define socket sizes and types.
+@LIBGO_IS_LINUX_TRUE@syscall_socket_os_file = syscalls/socket_linux.go
+@LIBGO_IS_LINUX_FALSE@syscall_socket_epoll_file =
+
+# Support for epoll.
+@LIBGO_IS_LINUX_TRUE@syscall_socket_epoll_file = syscalls/socket_epoll.go
+@LIBGO_IS_386_FALSE@@LIBGO_IS_SOLARIS_TRUE@syscall_uname_file = syscalls/syscall_uname.go
+
+# Support for uname.
+# 32-bit Solaris 2/x86 needs _nuname, handled in syscall_solaris_386.go.
+@LIBGO_IS_386_TRUE@@LIBGO_IS_SOLARIS_TRUE@syscall_uname_file =
+@LIBGO_IS_SOLARIS_FALSE@syscall_uname_file = syscalls/syscall_uname.go
+go_syscall_files = \
+ $(syscall_errstr_file) \
+ $(syscall_errstr_decl_file) \
+ syscalls/exec_helpers.go \
+ $(syscall_exec_os_file) \
+ $(syscall_filesize_file) \
+ $(syscall_stat_file) \
+ $(syscall_sleep_file) \
+ syscalls/socket.go \
+ $(syscall_socket_os_file) \
+ $(syscall_socket_epoll_file) \
+ $(syscall_syscall_file) \
+ $(syscall_uname_file) \
+ syscalls/syscall_unix.go \
+ syscalls/stringbyte.go \
+ syscalls/syscall_$(GOOS).go \
+ $(GO_SYSCALLS_SYSCALL_OS_ARCH_FILE) \
+ syscalls/sysfile_posix.go \
+ sysinfo.go \
+ syscall_arch.go
+
+go_syscall_c_files = \
+ syscalls/errno.c
+
+@LIBGO_IS_LINUX_FALSE@os_lib_inotify_lo =
+
+# os_lib_inotify_lo = os/inotify.lo
+@LIBGO_IS_LINUX_TRUE@os_lib_inotify_lo =
+libgo_go_objs = \
+ asn1/asn1.lo \
+ big/big.lo \
+ bufio/bufio.lo \
+ bytes/bytes.lo \
+ bytes/index.lo \
+ cmath/cmath.lo \
+ ebnf/ebnf.lo \
+ exec/exec.lo \
+ expvar/expvar.lo \
+ flag/flag.lo \
+ fmt/fmt.lo \
+ gob/gob.lo \
+ hash/hash.lo \
+ html/html.lo \
+ http/http.lo \
+ image/image.lo \
+ io/io.lo \
+ json/json.lo \
+ log/log.lo \
+ math/math.lo \
+ mime/mime.lo \
+ net/net.lo \
+ netchan/netchan.lo \
+ os/os.lo \
+ patch/patch.lo \
+ path/path.lo \
+ rand/rand.lo \
+ reflect/reflect.lo \
+ regexp/regexp.lo \
+ rpc/rpc.lo \
+ runtime/runtime.lo \
+ scanner/scanner.lo \
+ smtp/smtp.lo \
+ sort/sort.lo \
+ strconv/strconv.lo \
+ strings/strings.lo \
+ sync/mutex.lo \
+ sync/cas.lo \
+ syslog/syslog.lo \
+ syslog/syslog_c.lo \
+ tabwriter/tabwriter.lo \
+ template/template.lo \
+ time/time.lo \
+ try/try.lo \
+ unicode/unicode.lo \
+ utf16/utf16.lo \
+ utf8/utf8.lo \
+ websocket/websocket.lo \
+ xml/xml.lo \
+ archive/tar.lo \
+ archive/zip.lo \
+ compress/flate.lo \
+ compress/gzip.lo \
+ compress/zlib.lo \
+ container/heap.lo \
+ container/list.lo \
+ container/ring.lo \
+ container/vector.lo \
+ crypto/aes.lo \
+ crypto/block.lo \
+ crypto/blowfish.lo \
+ crypto/cast5.lo \
+ crypto/cipher.lo \
+ crypto/elliptic.lo \
+ crypto/hmac.lo \
+ crypto/md4.lo \
+ crypto/md5.lo \
+ crypto/ocsp.lo \
+ crypto/rand.lo \
+ crypto/rc4.lo \
+ crypto/ripemd160.lo \
+ crypto/rsa.lo \
+ crypto/sha1.lo \
+ crypto/sha256.lo \
+ crypto/sha512.lo \
+ crypto/subtle.lo \
+ crypto/tls.lo \
+ crypto/twofish.lo \
+ crypto/x509.lo \
+ crypto/xtea.lo \
+ crypto/openpgp/armor.lo \
+ crypto/openpgp/error.lo \
+ crypto/openpgp/s2k.lo \
+ debug/dwarf.lo \
+ debug/elf.lo \
+ debug/gosym.lo \
+ debug/macho.lo \
+ debug/pe.lo \
+ debug/proc.lo \
+ encoding/ascii85.lo \
+ encoding/base32.lo \
+ encoding/base64.lo \
+ encoding/binary.lo \
+ encoding/git85.lo \
+ encoding/hex.lo \
+ encoding/line.lo \
+ encoding/pem.lo \
+ exp/datafmt.lo \
+ exp/draw.lo \
+ exp/eval.lo \
+ go/ast.lo \
+ go/doc.lo \
+ go/parser.lo \
+ go/printer.lo \
+ go/scanner.lo \
+ go/token.lo \
+ go/typechecker.lo \
+ hash/adler32.lo \
+ hash/crc32.lo \
+ hash/crc64.lo \
+ http/pprof.lo \
+ image/jpeg.lo \
+ image/png.lo \
+ index/suffixarray.lo \
+ io/ioutil.lo \
+ mime/multipart.lo \
+ net/dict.lo \
+ net/textproto.lo \
+ $(os_lib_inotify_lo) \
+ os/signal.lo \
+ rpc/jsonrpc.lo \
+ runtime/debug.lo \
+ runtime/pprof.lo \
+ syscalls/syscall.lo \
+ syscalls/errno.lo \
+ testing/testing.lo \
+ testing/iotest.lo \
+ testing/quick.lo \
+ testing/script.lo
+
+libgo_la_SOURCES = $(runtime_files)
+libgo_la_LIBADD = \
+ $(libgo_go_objs) $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
+
+libgobegin_a_SOURCES = \
+ runtime/go-main.c
+
+LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
+AM_GOCFLAGS = $(STRINGOPS_FLAG)
+GOCOMPILE = $(GOC) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_GOCFLAGS) $(GOCFLAGS)
+LTGOCOMPILE = $(LIBTOOL) --tag GO --mode=compile $(GOC) $(INCLUDES) \
+ $(AM_GOCFLAGS) $(GOCFLAGS)
+
+GOLINK = $(LIBTOOL) --tag GO --mode-link $(GOC) \
+ $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_GOCFLAGS) $(LTLDFLAGS) -o $@
+
+
+# Build the .go files for a package, generating a .lo file.
+BUILDPACKAGE = \
+ $(MKDIR_P) $(@D); \
+ files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
+ $(LTGOCOMPILE) -I . -c -fgo-prefix="libgo_$(@D)" -o $@ $$files
+
+@LIBGO_IS_RTEMS_FALSE@use_dejagnu = no
+@LIBGO_IS_RTEMS_TRUE@use_dejagnu = yes
+
+# Check a package.
+CHECK = \
+ @GC="$(GOC) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs -Wl,-R,`${PWD_COMMAND}`/.libs"; \
+ export GC; \
+ RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
+ export RUNTESTFLAGS; \
+ MAKE="$(MAKE)"; \
+ export MAKE; \
+ rm -f $@-log; \
+ prefix=`if test "$(@D)" = "regexp"; then echo regexp-test; else dirname $(@D); fi`; \
+ test "$${prefix}" != "." || prefix="$(@D)"; \
+ if test "$(use_dejagnu)" = "yes"; then \
+ $(SHELL) $(srcdir)/testsuite/gotest --dejagnu=yes --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --prefix="libgo_$${prefix}" --pkgfiles="$(go_$(subst /,_,$(@D))_files)"; \
+ else \
+ if $(SHELL) $(srcdir)/testsuite/gotest --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --prefix="libgo_$${prefix}" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" >>$@-log 2>&1; then \
+ echo "PASS: $(@D)"; \
+ else \
+ echo "FAIL: $(@D)"; \
+ cat $@-log; \
+ exit 1; \
+ fi; \
+ fi
+
+
+# Build all packages before checking any.
+CHECK_DEPS = libgo.la libgobegin.a \
+ $(toolexeclib_DATA) \
+ $(toolexeclibarchive_DATA) \
+ $(toolexeclibcompress_DATA) \
+ $(toolexeclibcontainer_DATA) \
+ $(toolexeclibcrypto_DATA) \
+ $(toolexeclibdebug_DATA) \
+ $(toolexeclibencoding_DATA) \
+ $(toolexeclibexp_DATA) \
+ $(toolexeclibgo_DATA) \
+ $(toolexeclibhash_DATA) \
+ $(toolexeclibhttp_DATA) \
+ $(toolexeclibimage_DATA) \
+ $(toolexeclibio_DATA) \
+ $(toolexeclibos_DATA) \
+ $(toolexeclibrpc_DATA) \
+ $(toolexeclibruntime_DATA) \
+ $(toolexeclibtesting_DATA)
+
+
+# How to build a .gox file from a .lo file.
+BUILDGOX = \
+ f=`echo $< | sed -e 's/.lo$$/.o/'`; \
+ $(OBJCOPY) -j .go_export $$f $@.tmp && mv -f $@.tmp $@
+
+@LIBGO_IS_LINUX_FALSE@os_inotify_check =
+
+# os_inotify_check = os/inotify/check
+@LIBGO_IS_LINUX_TRUE@os_inotify_check =
+TEST_PACKAGES = \
+ asn1/check \
+ big/check \
+ bufio/check \
+ bytes/check \
+ cmath/check \
+ ebnf/check \
+ exec/check \
+ expvar/check \
+ flag/check \
+ fmt/check \
+ gob/check \
+ html/check \
+ $(if $(GCCGO_RUN_ALL_TESTS),http/check) \
+ io/check \
+ json/check \
+ log/check \
+ math/check \
+ mime/check \
+ $(if $(GCCGO_RUN_ALL_TESTS),net/check) \
+ netchan/check \
+ os/check \
+ patch/check \
+ path/check \
+ rand/check \
+ reflect/check \
+ regexp/check \
+ rpc/check \
+ runtime/check \
+ scanner/check \
+ smtp/check \
+ sort/check \
+ strconv/check \
+ strings/check \
+ sync/check \
+ $(if $(GCCGO_RUN_ALL_TESTS),syslog/check) \
+ tabwriter/check \
+ template/check \
+ time/check \
+ try/check \
+ unicode/check \
+ utf16/check \
+ utf8/check \
+ websocket/check \
+ xml/check \
+ archive/tar/check \
+ archive/zip/check \
+ compress/flate/check \
+ compress/gzip/check \
+ compress/zlib/check \
+ container/heap/check \
+ container/list/check \
+ container/ring/check \
+ container/vector/check \
+ crypto/aes/check \
+ crypto/block/check \
+ crypto/blowfish/check \
+ crypto/cast5/check \
+ crypto/cipher/check \
+ crypto/elliptic/check \
+ crypto/hmac/check \
+ crypto/md4/check \
+ crypto/md5/check \
+ crypto/ocsp/check \
+ crypto/rand/check \
+ crypto/rc4/check \
+ crypto/ripemd160/check \
+ crypto/rsa/check \
+ crypto/sha1/check \
+ crypto/sha256/check \
+ crypto/sha512/check \
+ crypto/subtle/check \
+ crypto/tls/check \
+ crypto/twofish/check \
+ crypto/x509/check \
+ crypto/xtea/check \
+ crypto/openpgp/armor/check \
+ crypto/openpgp/s2k/check \
+ debug/dwarf/check \
+ debug/elf/check \
+ debug/macho/check \
+ debug/pe/check \
+ encoding/ascii85/check \
+ encoding/base32/check \
+ encoding/base64/check \
+ encoding/binary/check \
+ encoding/git85/check \
+ encoding/hex/check \
+ encoding/line/check \
+ encoding/pem/check \
+ exp/datafmt/check \
+ exp/draw/check \
+ exp/eval/check \
+ go/parser/check \
+ go/printer/check \
+ go/scanner/check \
+ go/token/check \
+ go/typechecker/check \
+ hash/adler32/check \
+ hash/crc32/check \
+ hash/crc64/check \
+ image/png/check \
+ index/suffixarray/check \
+ io/ioutil/check \
+ mime/multipart/check \
+ net/textproto/check \
+ $(os_inotify_check) \
+ os/signal/check \
+ rpc/jsonrpc/check \
+ testing/quick/check \
+ testing/script/check
+
+CLEANFILES = *.go *.gox goc2c *.c s-version
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .go .gox .o .obj .lo .a
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+install-toolexeclibLIBRARIES: $(toolexeclib_LIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)"
+ @list='$(toolexeclib_LIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(INSTALL_DATA) $$list2 '$(DESTDIR)$(toolexeclibdir)'"; \
+ $(INSTALL_DATA) $$list2 "$(DESTDIR)$(toolexeclibdir)" || exit $$?; }
+ @$(POST_INSTALL)
+ @list='$(toolexeclib_LIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+ for p in $$list; do \
+ if test -f $$p; then \
+ $(am__strip_dir) \
+ echo " ( cd '$(DESTDIR)$(toolexeclibdir)' && $(RANLIB) $$f )"; \
+ ( cd "$(DESTDIR)$(toolexeclibdir)" && $(RANLIB) $$f ) || exit $$?; \
+ else :; fi; \
+ done
+
+uninstall-toolexeclibLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclib_LIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibdir)' && rm -f "$$files" )"; \
+ cd "$(DESTDIR)$(toolexeclibdir)" && rm -f $$files
+
+clean-toolexeclibLIBRARIES:
+ -test -z "$(toolexeclib_LIBRARIES)" || rm -f $(toolexeclib_LIBRARIES)
+libgobegin.a: $(libgobegin_a_OBJECTS) $(libgobegin_a_DEPENDENCIES)
+ -rm -f libgobegin.a
+ $(libgobegin_a_AR) libgobegin.a $(libgobegin_a_OBJECTS) $(libgobegin_a_LIBADD)
+ $(RANLIB) libgobegin.a
+install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)"
+ @list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(toolexeclibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(toolexeclibdir)"; \
+ }
+
+uninstall-toolexeclibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(toolexeclibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(toolexeclibdir)/$$f"; \
+ done
+
+clean-toolexeclibLTLIBRARIES:
+ -test -z "$(toolexeclib_LTLIBRARIES)" || rm -f $(toolexeclib_LTLIBRARIES)
+ @list='$(toolexeclib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgo.la: $(libgo_la_OBJECTS) $(libgo_la_DEPENDENCIES)
+ $(LINK) -rpath $(toolexeclibdir) $(libgo_la_OBJECTS) $(libgo_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-append.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-assert-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-assert.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-breakpoint.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-byte-array-to-string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-caller.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-can-convert-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cgo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-chan-cap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-chan-len.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-check-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-close.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-closed.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-construct-map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-convert-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-copy.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-defer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-deferred-recover.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-compare.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-val-compare.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-getgoroot.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-go.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-gomaxprocs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-array-to-string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-to-string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-interface-compare.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-interface-eface-compare.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-interface-val-compare.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-lock-os-thread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-delete.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-index.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-len.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-map-range.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-nanotime.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-channel.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-note.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-panic-defer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-panic.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-print.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-big.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-nb-big.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-nb-small.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rec-small.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-recover.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-call.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-chan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect-map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-reflect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-rune.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-runtime-error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-sched.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-select.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-semacquire.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-big.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-nb-big.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-nb-small.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-send-small.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-signal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strcmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-string-to-byte-array.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-string-to-int-array.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strplus.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strslice.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-trampoline.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-eface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-identity.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-typedesc-equal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-typestring.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unreflect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-new.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-newarray.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-pointer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unwind.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcentral.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem_posix_memalign.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mfinal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mfixalloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mgc0.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheapmap32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheapmap64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mprof.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msize.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reflect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtems-task-variable-add.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sigqueue.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+go-main.o: runtime/go-main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-main.o -MD -MP -MF $(DEPDIR)/go-main.Tpo -c -o go-main.o `test -f 'runtime/go-main.c' || echo '$(srcdir)/'`runtime/go-main.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-main.Tpo $(DEPDIR)/go-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-main.c' object='go-main.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-main.o `test -f 'runtime/go-main.c' || echo '$(srcdir)/'`runtime/go-main.c
+
+go-main.obj: runtime/go-main.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-main.obj -MD -MP -MF $(DEPDIR)/go-main.Tpo -c -o go-main.obj `if test -f 'runtime/go-main.c'; then $(CYGPATH_W) 'runtime/go-main.c'; else $(CYGPATH_W) '$(srcdir)/runtime/go-main.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-main.Tpo $(DEPDIR)/go-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-main.c' object='go-main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-main.obj `if test -f 'runtime/go-main.c'; then $(CYGPATH_W) 'runtime/go-main.c'; else $(CYGPATH_W) '$(srcdir)/runtime/go-main.c'; fi`
+
+go-append.lo: runtime/go-append.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-append.lo -MD -MP -MF $(DEPDIR)/go-append.Tpo -c -o go-append.lo `test -f 'runtime/go-append.c' || echo '$(srcdir)/'`runtime/go-append.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-append.Tpo $(DEPDIR)/go-append.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-append.c' object='go-append.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-append.lo `test -f 'runtime/go-append.c' || echo '$(srcdir)/'`runtime/go-append.c
+
+go-assert.lo: runtime/go-assert.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-assert.lo -MD -MP -MF $(DEPDIR)/go-assert.Tpo -c -o go-assert.lo `test -f 'runtime/go-assert.c' || echo '$(srcdir)/'`runtime/go-assert.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-assert.Tpo $(DEPDIR)/go-assert.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-assert.c' object='go-assert.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-assert.lo `test -f 'runtime/go-assert.c' || echo '$(srcdir)/'`runtime/go-assert.c
+
+go-assert-interface.lo: runtime/go-assert-interface.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-assert-interface.lo -MD -MP -MF $(DEPDIR)/go-assert-interface.Tpo -c -o go-assert-interface.lo `test -f 'runtime/go-assert-interface.c' || echo '$(srcdir)/'`runtime/go-assert-interface.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-assert-interface.Tpo $(DEPDIR)/go-assert-interface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-assert-interface.c' object='go-assert-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-assert-interface.lo `test -f 'runtime/go-assert-interface.c' || echo '$(srcdir)/'`runtime/go-assert-interface.c
+
+go-byte-array-to-string.lo: runtime/go-byte-array-to-string.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-byte-array-to-string.lo -MD -MP -MF $(DEPDIR)/go-byte-array-to-string.Tpo -c -o go-byte-array-to-string.lo `test -f 'runtime/go-byte-array-to-string.c' || echo '$(srcdir)/'`runtime/go-byte-array-to-string.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-byte-array-to-string.Tpo $(DEPDIR)/go-byte-array-to-string.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-byte-array-to-string.c' object='go-byte-array-to-string.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-byte-array-to-string.lo `test -f 'runtime/go-byte-array-to-string.c' || echo '$(srcdir)/'`runtime/go-byte-array-to-string.c
+
+go-breakpoint.lo: runtime/go-breakpoint.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-breakpoint.lo -MD -MP -MF $(DEPDIR)/go-breakpoint.Tpo -c -o go-breakpoint.lo `test -f 'runtime/go-breakpoint.c' || echo '$(srcdir)/'`runtime/go-breakpoint.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-breakpoint.Tpo $(DEPDIR)/go-breakpoint.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-breakpoint.c' object='go-breakpoint.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-breakpoint.lo `test -f 'runtime/go-breakpoint.c' || echo '$(srcdir)/'`runtime/go-breakpoint.c
+
+go-caller.lo: runtime/go-caller.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-caller.lo -MD -MP -MF $(DEPDIR)/go-caller.Tpo -c -o go-caller.lo `test -f 'runtime/go-caller.c' || echo '$(srcdir)/'`runtime/go-caller.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-caller.Tpo $(DEPDIR)/go-caller.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-caller.c' object='go-caller.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-caller.lo `test -f 'runtime/go-caller.c' || echo '$(srcdir)/'`runtime/go-caller.c
+
+go-can-convert-interface.lo: runtime/go-can-convert-interface.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-can-convert-interface.lo -MD -MP -MF $(DEPDIR)/go-can-convert-interface.Tpo -c -o go-can-convert-interface.lo `test -f 'runtime/go-can-convert-interface.c' || echo '$(srcdir)/'`runtime/go-can-convert-interface.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-can-convert-interface.Tpo $(DEPDIR)/go-can-convert-interface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-can-convert-interface.c' object='go-can-convert-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-can-convert-interface.lo `test -f 'runtime/go-can-convert-interface.c' || echo '$(srcdir)/'`runtime/go-can-convert-interface.c
+
+go-cgo.lo: runtime/go-cgo.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-cgo.lo -MD -MP -MF $(DEPDIR)/go-cgo.Tpo -c -o go-cgo.lo `test -f 'runtime/go-cgo.c' || echo '$(srcdir)/'`runtime/go-cgo.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-cgo.Tpo $(DEPDIR)/go-cgo.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-cgo.c' object='go-cgo.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-cgo.lo `test -f 'runtime/go-cgo.c' || echo '$(srcdir)/'`runtime/go-cgo.c
+
+go-chan-cap.lo: runtime/go-chan-cap.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-chan-cap.lo -MD -MP -MF $(DEPDIR)/go-chan-cap.Tpo -c -o go-chan-cap.lo `test -f 'runtime/go-chan-cap.c' || echo '$(srcdir)/'`runtime/go-chan-cap.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-chan-cap.Tpo $(DEPDIR)/go-chan-cap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-chan-cap.c' object='go-chan-cap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-chan-cap.lo `test -f 'runtime/go-chan-cap.c' || echo '$(srcdir)/'`runtime/go-chan-cap.c
+
+go-chan-len.lo: runtime/go-chan-len.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-chan-len.lo -MD -MP -MF $(DEPDIR)/go-chan-len.Tpo -c -o go-chan-len.lo `test -f 'runtime/go-chan-len.c' || echo '$(srcdir)/'`runtime/go-chan-len.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-chan-len.Tpo $(DEPDIR)/go-chan-len.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-chan-len.c' object='go-chan-len.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-chan-len.lo `test -f 'runtime/go-chan-len.c' || echo '$(srcdir)/'`runtime/go-chan-len.c
+
+go-check-interface.lo: runtime/go-check-interface.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-check-interface.lo -MD -MP -MF $(DEPDIR)/go-check-interface.Tpo -c -o go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-check-interface.Tpo $(DEPDIR)/go-check-interface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-check-interface.c' object='go-check-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-check-interface.lo `test -f 'runtime/go-check-interface.c' || echo '$(srcdir)/'`runtime/go-check-interface.c
+
+go-close.lo: runtime/go-close.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-close.lo -MD -MP -MF $(DEPDIR)/go-close.Tpo -c -o go-close.lo `test -f 'runtime/go-close.c' || echo '$(srcdir)/'`runtime/go-close.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-close.Tpo $(DEPDIR)/go-close.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-close.c' object='go-close.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-close.lo `test -f 'runtime/go-close.c' || echo '$(srcdir)/'`runtime/go-close.c
+
+go-closed.lo: runtime/go-closed.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-closed.lo -MD -MP -MF $(DEPDIR)/go-closed.Tpo -c -o go-closed.lo `test -f 'runtime/go-closed.c' || echo '$(srcdir)/'`runtime/go-closed.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-closed.Tpo $(DEPDIR)/go-closed.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-closed.c' object='go-closed.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-closed.lo `test -f 'runtime/go-closed.c' || echo '$(srcdir)/'`runtime/go-closed.c
+
+go-construct-map.lo: runtime/go-construct-map.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-construct-map.lo -MD -MP -MF $(DEPDIR)/go-construct-map.Tpo -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-construct-map.Tpo $(DEPDIR)/go-construct-map.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-construct-map.c' object='go-construct-map.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c
+
+go-convert-interface.lo: runtime/go-convert-interface.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-convert-interface.lo -MD -MP -MF $(DEPDIR)/go-convert-interface.Tpo -c -o go-convert-interface.lo `test -f 'runtime/go-convert-interface.c' || echo '$(srcdir)/'`runtime/go-convert-interface.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-convert-interface.Tpo $(DEPDIR)/go-convert-interface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-convert-interface.c' object='go-convert-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-convert-interface.lo `test -f 'runtime/go-convert-interface.c' || echo '$(srcdir)/'`runtime/go-convert-interface.c
+
+go-copy.lo: runtime/go-copy.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-copy.lo -MD -MP -MF $(DEPDIR)/go-copy.Tpo -c -o go-copy.lo `test -f 'runtime/go-copy.c' || echo '$(srcdir)/'`runtime/go-copy.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-copy.Tpo $(DEPDIR)/go-copy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-copy.c' object='go-copy.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-copy.lo `test -f 'runtime/go-copy.c' || echo '$(srcdir)/'`runtime/go-copy.c
+
+go-defer.lo: runtime/go-defer.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-defer.lo -MD -MP -MF $(DEPDIR)/go-defer.Tpo -c -o go-defer.lo `test -f 'runtime/go-defer.c' || echo '$(srcdir)/'`runtime/go-defer.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-defer.Tpo $(DEPDIR)/go-defer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-defer.c' object='go-defer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-defer.lo `test -f 'runtime/go-defer.c' || echo '$(srcdir)/'`runtime/go-defer.c
+
+go-deferred-recover.lo: runtime/go-deferred-recover.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-deferred-recover.lo -MD -MP -MF $(DEPDIR)/go-deferred-recover.Tpo -c -o go-deferred-recover.lo `test -f 'runtime/go-deferred-recover.c' || echo '$(srcdir)/'`runtime/go-deferred-recover.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-deferred-recover.Tpo $(DEPDIR)/go-deferred-recover.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-deferred-recover.c' object='go-deferred-recover.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-deferred-recover.lo `test -f 'runtime/go-deferred-recover.c' || echo '$(srcdir)/'`runtime/go-deferred-recover.c
+
+go-eface-compare.lo: runtime/go-eface-compare.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-eface-compare.lo -MD -MP -MF $(DEPDIR)/go-eface-compare.Tpo -c -o go-eface-compare.lo `test -f 'runtime/go-eface-compare.c' || echo '$(srcdir)/'`runtime/go-eface-compare.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-eface-compare.Tpo $(DEPDIR)/go-eface-compare.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-eface-compare.c' object='go-eface-compare.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-eface-compare.lo `test -f 'runtime/go-eface-compare.c' || echo '$(srcdir)/'`runtime/go-eface-compare.c
+
+go-eface-val-compare.lo: runtime/go-eface-val-compare.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-eface-val-compare.lo -MD -MP -MF $(DEPDIR)/go-eface-val-compare.Tpo -c -o go-eface-val-compare.lo `test -f 'runtime/go-eface-val-compare.c' || echo '$(srcdir)/'`runtime/go-eface-val-compare.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-eface-val-compare.Tpo $(DEPDIR)/go-eface-val-compare.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-eface-val-compare.c' object='go-eface-val-compare.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-eface-val-compare.lo `test -f 'runtime/go-eface-val-compare.c' || echo '$(srcdir)/'`runtime/go-eface-val-compare.c
+
+go-getgoroot.lo: runtime/go-getgoroot.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-getgoroot.lo -MD -MP -MF $(DEPDIR)/go-getgoroot.Tpo -c -o go-getgoroot.lo `test -f 'runtime/go-getgoroot.c' || echo '$(srcdir)/'`runtime/go-getgoroot.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-getgoroot.Tpo $(DEPDIR)/go-getgoroot.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-getgoroot.c' object='go-getgoroot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-getgoroot.lo `test -f 'runtime/go-getgoroot.c' || echo '$(srcdir)/'`runtime/go-getgoroot.c
+
+go-go.lo: runtime/go-go.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-go.lo -MD -MP -MF $(DEPDIR)/go-go.Tpo -c -o go-go.lo `test -f 'runtime/go-go.c' || echo '$(srcdir)/'`runtime/go-go.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-go.Tpo $(DEPDIR)/go-go.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-go.c' object='go-go.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-go.lo `test -f 'runtime/go-go.c' || echo '$(srcdir)/'`runtime/go-go.c
+
+go-gomaxprocs.lo: runtime/go-gomaxprocs.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-gomaxprocs.lo -MD -MP -MF $(DEPDIR)/go-gomaxprocs.Tpo -c -o go-gomaxprocs.lo `test -f 'runtime/go-gomaxprocs.c' || echo '$(srcdir)/'`runtime/go-gomaxprocs.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-gomaxprocs.Tpo $(DEPDIR)/go-gomaxprocs.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-gomaxprocs.c' object='go-gomaxprocs.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-gomaxprocs.lo `test -f 'runtime/go-gomaxprocs.c' || echo '$(srcdir)/'`runtime/go-gomaxprocs.c
+
+go-int-array-to-string.lo: runtime/go-int-array-to-string.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-int-array-to-string.lo -MD -MP -MF $(DEPDIR)/go-int-array-to-string.Tpo -c -o go-int-array-to-string.lo `test -f 'runtime/go-int-array-to-string.c' || echo '$(srcdir)/'`runtime/go-int-array-to-string.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-int-array-to-string.Tpo $(DEPDIR)/go-int-array-to-string.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-int-array-to-string.c' object='go-int-array-to-string.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-int-array-to-string.lo `test -f 'runtime/go-int-array-to-string.c' || echo '$(srcdir)/'`runtime/go-int-array-to-string.c
+
+go-int-to-string.lo: runtime/go-int-to-string.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-int-to-string.lo -MD -MP -MF $(DEPDIR)/go-int-to-string.Tpo -c -o go-int-to-string.lo `test -f 'runtime/go-int-to-string.c' || echo '$(srcdir)/'`runtime/go-int-to-string.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-int-to-string.Tpo $(DEPDIR)/go-int-to-string.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-int-to-string.c' object='go-int-to-string.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-int-to-string.lo `test -f 'runtime/go-int-to-string.c' || echo '$(srcdir)/'`runtime/go-int-to-string.c
+
+go-interface-compare.lo: runtime/go-interface-compare.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-interface-compare.lo -MD -MP -MF $(DEPDIR)/go-interface-compare.Tpo -c -o go-interface-compare.lo `test -f 'runtime/go-interface-compare.c' || echo '$(srcdir)/'`runtime/go-interface-compare.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-interface-compare.Tpo $(DEPDIR)/go-interface-compare.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-interface-compare.c' object='go-interface-compare.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-interface-compare.lo `test -f 'runtime/go-interface-compare.c' || echo '$(srcdir)/'`runtime/go-interface-compare.c
+
+go-interface-eface-compare.lo: runtime/go-interface-eface-compare.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-interface-eface-compare.lo -MD -MP -MF $(DEPDIR)/go-interface-eface-compare.Tpo -c -o go-interface-eface-compare.lo `test -f 'runtime/go-interface-eface-compare.c' || echo '$(srcdir)/'`runtime/go-interface-eface-compare.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-interface-eface-compare.Tpo $(DEPDIR)/go-interface-eface-compare.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-interface-eface-compare.c' object='go-interface-eface-compare.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-interface-eface-compare.lo `test -f 'runtime/go-interface-eface-compare.c' || echo '$(srcdir)/'`runtime/go-interface-eface-compare.c
+
+go-interface-val-compare.lo: runtime/go-interface-val-compare.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-interface-val-compare.lo -MD -MP -MF $(DEPDIR)/go-interface-val-compare.Tpo -c -o go-interface-val-compare.lo `test -f 'runtime/go-interface-val-compare.c' || echo '$(srcdir)/'`runtime/go-interface-val-compare.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-interface-val-compare.Tpo $(DEPDIR)/go-interface-val-compare.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-interface-val-compare.c' object='go-interface-val-compare.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-interface-val-compare.lo `test -f 'runtime/go-interface-val-compare.c' || echo '$(srcdir)/'`runtime/go-interface-val-compare.c
+
+go-lock-os-thread.lo: runtime/go-lock-os-thread.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-lock-os-thread.lo -MD -MP -MF $(DEPDIR)/go-lock-os-thread.Tpo -c -o go-lock-os-thread.lo `test -f 'runtime/go-lock-os-thread.c' || echo '$(srcdir)/'`runtime/go-lock-os-thread.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-lock-os-thread.Tpo $(DEPDIR)/go-lock-os-thread.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-lock-os-thread.c' object='go-lock-os-thread.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-lock-os-thread.lo `test -f 'runtime/go-lock-os-thread.c' || echo '$(srcdir)/'`runtime/go-lock-os-thread.c
+
+go-map-delete.lo: runtime/go-map-delete.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-delete.lo -MD -MP -MF $(DEPDIR)/go-map-delete.Tpo -c -o go-map-delete.lo `test -f 'runtime/go-map-delete.c' || echo '$(srcdir)/'`runtime/go-map-delete.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-map-delete.Tpo $(DEPDIR)/go-map-delete.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-map-delete.c' object='go-map-delete.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-delete.lo `test -f 'runtime/go-map-delete.c' || echo '$(srcdir)/'`runtime/go-map-delete.c
+
+go-map-index.lo: runtime/go-map-index.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-index.lo -MD -MP -MF $(DEPDIR)/go-map-index.Tpo -c -o go-map-index.lo `test -f 'runtime/go-map-index.c' || echo '$(srcdir)/'`runtime/go-map-index.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-map-index.Tpo $(DEPDIR)/go-map-index.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-map-index.c' object='go-map-index.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-index.lo `test -f 'runtime/go-map-index.c' || echo '$(srcdir)/'`runtime/go-map-index.c
+
+go-map-len.lo: runtime/go-map-len.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-len.lo -MD -MP -MF $(DEPDIR)/go-map-len.Tpo -c -o go-map-len.lo `test -f 'runtime/go-map-len.c' || echo '$(srcdir)/'`runtime/go-map-len.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-map-len.Tpo $(DEPDIR)/go-map-len.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-map-len.c' object='go-map-len.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-len.lo `test -f 'runtime/go-map-len.c' || echo '$(srcdir)/'`runtime/go-map-len.c
+
+go-map-range.lo: runtime/go-map-range.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-map-range.lo -MD -MP -MF $(DEPDIR)/go-map-range.Tpo -c -o go-map-range.lo `test -f 'runtime/go-map-range.c' || echo '$(srcdir)/'`runtime/go-map-range.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-map-range.Tpo $(DEPDIR)/go-map-range.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-map-range.c' object='go-map-range.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-map-range.lo `test -f 'runtime/go-map-range.c' || echo '$(srcdir)/'`runtime/go-map-range.c
+
+go-nanotime.lo: runtime/go-nanotime.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-nanotime.lo -MD -MP -MF $(DEPDIR)/go-nanotime.Tpo -c -o go-nanotime.lo `test -f 'runtime/go-nanotime.c' || echo '$(srcdir)/'`runtime/go-nanotime.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-nanotime.Tpo $(DEPDIR)/go-nanotime.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-nanotime.c' object='go-nanotime.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-nanotime.lo `test -f 'runtime/go-nanotime.c' || echo '$(srcdir)/'`runtime/go-nanotime.c
+
+go-new-channel.lo: runtime/go-new-channel.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-channel.lo -MD -MP -MF $(DEPDIR)/go-new-channel.Tpo -c -o go-new-channel.lo `test -f 'runtime/go-new-channel.c' || echo '$(srcdir)/'`runtime/go-new-channel.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new-channel.Tpo $(DEPDIR)/go-new-channel.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-new-channel.c' object='go-new-channel.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-new-channel.lo `test -f 'runtime/go-new-channel.c' || echo '$(srcdir)/'`runtime/go-new-channel.c
+
+go-new-map.lo: runtime/go-new-map.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-map.lo -MD -MP -MF $(DEPDIR)/go-new-map.Tpo -c -o go-new-map.lo `test -f 'runtime/go-new-map.c' || echo '$(srcdir)/'`runtime/go-new-map.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new-map.Tpo $(DEPDIR)/go-new-map.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-new-map.c' object='go-new-map.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-new-map.lo `test -f 'runtime/go-new-map.c' || echo '$(srcdir)/'`runtime/go-new-map.c
+
+go-new.lo: runtime/go-new.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new.lo -MD -MP -MF $(DEPDIR)/go-new.Tpo -c -o go-new.lo `test -f 'runtime/go-new.c' || echo '$(srcdir)/'`runtime/go-new.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new.Tpo $(DEPDIR)/go-new.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-new.c' object='go-new.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-new.lo `test -f 'runtime/go-new.c' || echo '$(srcdir)/'`runtime/go-new.c
+
+go-note.lo: runtime/go-note.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-note.lo -MD -MP -MF $(DEPDIR)/go-note.Tpo -c -o go-note.lo `test -f 'runtime/go-note.c' || echo '$(srcdir)/'`runtime/go-note.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-note.Tpo $(DEPDIR)/go-note.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-note.c' object='go-note.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-note.lo `test -f 'runtime/go-note.c' || echo '$(srcdir)/'`runtime/go-note.c
+
+go-panic.lo: runtime/go-panic.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-panic.lo -MD -MP -MF $(DEPDIR)/go-panic.Tpo -c -o go-panic.lo `test -f 'runtime/go-panic.c' || echo '$(srcdir)/'`runtime/go-panic.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-panic.Tpo $(DEPDIR)/go-panic.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-panic.c' object='go-panic.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-panic.lo `test -f 'runtime/go-panic.c' || echo '$(srcdir)/'`runtime/go-panic.c
+
+go-panic-defer.lo: runtime/go-panic-defer.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-panic-defer.lo -MD -MP -MF $(DEPDIR)/go-panic-defer.Tpo -c -o go-panic-defer.lo `test -f 'runtime/go-panic-defer.c' || echo '$(srcdir)/'`runtime/go-panic-defer.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-panic-defer.Tpo $(DEPDIR)/go-panic-defer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-panic-defer.c' object='go-panic-defer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-panic-defer.lo `test -f 'runtime/go-panic-defer.c' || echo '$(srcdir)/'`runtime/go-panic-defer.c
+
+go-print.lo: runtime/go-print.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-print.lo -MD -MP -MF $(DEPDIR)/go-print.Tpo -c -o go-print.lo `test -f 'runtime/go-print.c' || echo '$(srcdir)/'`runtime/go-print.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-print.Tpo $(DEPDIR)/go-print.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-print.c' object='go-print.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-print.lo `test -f 'runtime/go-print.c' || echo '$(srcdir)/'`runtime/go-print.c
+
+go-rec-big.lo: runtime/go-rec-big.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-big.lo -MD -MP -MF $(DEPDIR)/go-rec-big.Tpo -c -o go-rec-big.lo `test -f 'runtime/go-rec-big.c' || echo '$(srcdir)/'`runtime/go-rec-big.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-big.Tpo $(DEPDIR)/go-rec-big.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-big.c' object='go-rec-big.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-big.lo `test -f 'runtime/go-rec-big.c' || echo '$(srcdir)/'`runtime/go-rec-big.c
+
+go-rec-nb-big.lo: runtime/go-rec-nb-big.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-nb-big.lo -MD -MP -MF $(DEPDIR)/go-rec-nb-big.Tpo -c -o go-rec-nb-big.lo `test -f 'runtime/go-rec-nb-big.c' || echo '$(srcdir)/'`runtime/go-rec-nb-big.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-nb-big.Tpo $(DEPDIR)/go-rec-nb-big.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-nb-big.c' object='go-rec-nb-big.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-nb-big.lo `test -f 'runtime/go-rec-nb-big.c' || echo '$(srcdir)/'`runtime/go-rec-nb-big.c
+
+go-rec-nb-small.lo: runtime/go-rec-nb-small.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-nb-small.lo -MD -MP -MF $(DEPDIR)/go-rec-nb-small.Tpo -c -o go-rec-nb-small.lo `test -f 'runtime/go-rec-nb-small.c' || echo '$(srcdir)/'`runtime/go-rec-nb-small.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-nb-small.Tpo $(DEPDIR)/go-rec-nb-small.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-nb-small.c' object='go-rec-nb-small.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-nb-small.lo `test -f 'runtime/go-rec-nb-small.c' || echo '$(srcdir)/'`runtime/go-rec-nb-small.c
+
+go-rec-small.lo: runtime/go-rec-small.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rec-small.lo -MD -MP -MF $(DEPDIR)/go-rec-small.Tpo -c -o go-rec-small.lo `test -f 'runtime/go-rec-small.c' || echo '$(srcdir)/'`runtime/go-rec-small.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rec-small.Tpo $(DEPDIR)/go-rec-small.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rec-small.c' object='go-rec-small.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rec-small.lo `test -f 'runtime/go-rec-small.c' || echo '$(srcdir)/'`runtime/go-rec-small.c
+
+go-recover.lo: runtime/go-recover.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-recover.lo -MD -MP -MF $(DEPDIR)/go-recover.Tpo -c -o go-recover.lo `test -f 'runtime/go-recover.c' || echo '$(srcdir)/'`runtime/go-recover.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-recover.Tpo $(DEPDIR)/go-recover.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-recover.c' object='go-recover.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-recover.lo `test -f 'runtime/go-recover.c' || echo '$(srcdir)/'`runtime/go-recover.c
+
+go-reflect.lo: runtime/go-reflect.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect.lo -MD -MP -MF $(DEPDIR)/go-reflect.Tpo -c -o go-reflect.lo `test -f 'runtime/go-reflect.c' || echo '$(srcdir)/'`runtime/go-reflect.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect.Tpo $(DEPDIR)/go-reflect.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-reflect.c' object='go-reflect.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect.lo `test -f 'runtime/go-reflect.c' || echo '$(srcdir)/'`runtime/go-reflect.c
+
+go-reflect-call.lo: runtime/go-reflect-call.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-call.lo -MD -MP -MF $(DEPDIR)/go-reflect-call.Tpo -c -o go-reflect-call.lo `test -f 'runtime/go-reflect-call.c' || echo '$(srcdir)/'`runtime/go-reflect-call.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect-call.Tpo $(DEPDIR)/go-reflect-call.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-reflect-call.c' object='go-reflect-call.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-call.lo `test -f 'runtime/go-reflect-call.c' || echo '$(srcdir)/'`runtime/go-reflect-call.c
+
+go-reflect-chan.lo: runtime/go-reflect-chan.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-chan.lo -MD -MP -MF $(DEPDIR)/go-reflect-chan.Tpo -c -o go-reflect-chan.lo `test -f 'runtime/go-reflect-chan.c' || echo '$(srcdir)/'`runtime/go-reflect-chan.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect-chan.Tpo $(DEPDIR)/go-reflect-chan.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-reflect-chan.c' object='go-reflect-chan.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-chan.lo `test -f 'runtime/go-reflect-chan.c' || echo '$(srcdir)/'`runtime/go-reflect-chan.c
+
+go-reflect-map.lo: runtime/go-reflect-map.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-reflect-map.lo -MD -MP -MF $(DEPDIR)/go-reflect-map.Tpo -c -o go-reflect-map.lo `test -f 'runtime/go-reflect-map.c' || echo '$(srcdir)/'`runtime/go-reflect-map.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-reflect-map.Tpo $(DEPDIR)/go-reflect-map.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-reflect-map.c' object='go-reflect-map.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-reflect-map.lo `test -f 'runtime/go-reflect-map.c' || echo '$(srcdir)/'`runtime/go-reflect-map.c
+
+go-rune.lo: runtime/go-rune.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-rune.lo -MD -MP -MF $(DEPDIR)/go-rune.Tpo -c -o go-rune.lo `test -f 'runtime/go-rune.c' || echo '$(srcdir)/'`runtime/go-rune.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rune.Tpo $(DEPDIR)/go-rune.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rune.c' object='go-rune.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-rune.lo `test -f 'runtime/go-rune.c' || echo '$(srcdir)/'`runtime/go-rune.c
+
+go-runtime-error.lo: runtime/go-runtime-error.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-runtime-error.lo -MD -MP -MF $(DEPDIR)/go-runtime-error.Tpo -c -o go-runtime-error.lo `test -f 'runtime/go-runtime-error.c' || echo '$(srcdir)/'`runtime/go-runtime-error.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-runtime-error.Tpo $(DEPDIR)/go-runtime-error.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-runtime-error.c' object='go-runtime-error.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-runtime-error.lo `test -f 'runtime/go-runtime-error.c' || echo '$(srcdir)/'`runtime/go-runtime-error.c
+
+go-sched.lo: runtime/go-sched.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-sched.lo -MD -MP -MF $(DEPDIR)/go-sched.Tpo -c -o go-sched.lo `test -f 'runtime/go-sched.c' || echo '$(srcdir)/'`runtime/go-sched.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-sched.Tpo $(DEPDIR)/go-sched.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-sched.c' object='go-sched.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-sched.lo `test -f 'runtime/go-sched.c' || echo '$(srcdir)/'`runtime/go-sched.c
+
+go-select.lo: runtime/go-select.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-select.lo -MD -MP -MF $(DEPDIR)/go-select.Tpo -c -o go-select.lo `test -f 'runtime/go-select.c' || echo '$(srcdir)/'`runtime/go-select.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-select.Tpo $(DEPDIR)/go-select.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-select.c' object='go-select.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-select.lo `test -f 'runtime/go-select.c' || echo '$(srcdir)/'`runtime/go-select.c
+
+go-semacquire.lo: runtime/go-semacquire.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-semacquire.lo -MD -MP -MF $(DEPDIR)/go-semacquire.Tpo -c -o go-semacquire.lo `test -f 'runtime/go-semacquire.c' || echo '$(srcdir)/'`runtime/go-semacquire.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-semacquire.Tpo $(DEPDIR)/go-semacquire.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-semacquire.c' object='go-semacquire.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-semacquire.lo `test -f 'runtime/go-semacquire.c' || echo '$(srcdir)/'`runtime/go-semacquire.c
+
+go-send-big.lo: runtime/go-send-big.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-big.lo -MD -MP -MF $(DEPDIR)/go-send-big.Tpo -c -o go-send-big.lo `test -f 'runtime/go-send-big.c' || echo '$(srcdir)/'`runtime/go-send-big.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-big.Tpo $(DEPDIR)/go-send-big.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-big.c' object='go-send-big.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-big.lo `test -f 'runtime/go-send-big.c' || echo '$(srcdir)/'`runtime/go-send-big.c
+
+go-send-nb-big.lo: runtime/go-send-nb-big.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-nb-big.lo -MD -MP -MF $(DEPDIR)/go-send-nb-big.Tpo -c -o go-send-nb-big.lo `test -f 'runtime/go-send-nb-big.c' || echo '$(srcdir)/'`runtime/go-send-nb-big.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-nb-big.Tpo $(DEPDIR)/go-send-nb-big.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-nb-big.c' object='go-send-nb-big.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-nb-big.lo `test -f 'runtime/go-send-nb-big.c' || echo '$(srcdir)/'`runtime/go-send-nb-big.c
+
+go-send-nb-small.lo: runtime/go-send-nb-small.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-nb-small.lo -MD -MP -MF $(DEPDIR)/go-send-nb-small.Tpo -c -o go-send-nb-small.lo `test -f 'runtime/go-send-nb-small.c' || echo '$(srcdir)/'`runtime/go-send-nb-small.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-nb-small.Tpo $(DEPDIR)/go-send-nb-small.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-nb-small.c' object='go-send-nb-small.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-nb-small.lo `test -f 'runtime/go-send-nb-small.c' || echo '$(srcdir)/'`runtime/go-send-nb-small.c
+
+go-send-small.lo: runtime/go-send-small.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-send-small.lo -MD -MP -MF $(DEPDIR)/go-send-small.Tpo -c -o go-send-small.lo `test -f 'runtime/go-send-small.c' || echo '$(srcdir)/'`runtime/go-send-small.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-send-small.Tpo $(DEPDIR)/go-send-small.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-send-small.c' object='go-send-small.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-send-small.lo `test -f 'runtime/go-send-small.c' || echo '$(srcdir)/'`runtime/go-send-small.c
+
+go-signal.lo: runtime/go-signal.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-signal.lo -MD -MP -MF $(DEPDIR)/go-signal.Tpo -c -o go-signal.lo `test -f 'runtime/go-signal.c' || echo '$(srcdir)/'`runtime/go-signal.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-signal.Tpo $(DEPDIR)/go-signal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-signal.c' object='go-signal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-signal.lo `test -f 'runtime/go-signal.c' || echo '$(srcdir)/'`runtime/go-signal.c
+
+go-strcmp.lo: runtime/go-strcmp.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-strcmp.lo -MD -MP -MF $(DEPDIR)/go-strcmp.Tpo -c -o go-strcmp.lo `test -f 'runtime/go-strcmp.c' || echo '$(srcdir)/'`runtime/go-strcmp.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-strcmp.Tpo $(DEPDIR)/go-strcmp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-strcmp.c' object='go-strcmp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strcmp.lo `test -f 'runtime/go-strcmp.c' || echo '$(srcdir)/'`runtime/go-strcmp.c
+
+go-string-to-byte-array.lo: runtime/go-string-to-byte-array.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-string-to-byte-array.lo -MD -MP -MF $(DEPDIR)/go-string-to-byte-array.Tpo -c -o go-string-to-byte-array.lo `test -f 'runtime/go-string-to-byte-array.c' || echo '$(srcdir)/'`runtime/go-string-to-byte-array.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-string-to-byte-array.Tpo $(DEPDIR)/go-string-to-byte-array.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-string-to-byte-array.c' object='go-string-to-byte-array.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-string-to-byte-array.lo `test -f 'runtime/go-string-to-byte-array.c' || echo '$(srcdir)/'`runtime/go-string-to-byte-array.c
+
+go-string-to-int-array.lo: runtime/go-string-to-int-array.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-string-to-int-array.lo -MD -MP -MF $(DEPDIR)/go-string-to-int-array.Tpo -c -o go-string-to-int-array.lo `test -f 'runtime/go-string-to-int-array.c' || echo '$(srcdir)/'`runtime/go-string-to-int-array.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-string-to-int-array.Tpo $(DEPDIR)/go-string-to-int-array.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-string-to-int-array.c' object='go-string-to-int-array.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-string-to-int-array.lo `test -f 'runtime/go-string-to-int-array.c' || echo '$(srcdir)/'`runtime/go-string-to-int-array.c
+
+go-strplus.lo: runtime/go-strplus.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-strplus.lo -MD -MP -MF $(DEPDIR)/go-strplus.Tpo -c -o go-strplus.lo `test -f 'runtime/go-strplus.c' || echo '$(srcdir)/'`runtime/go-strplus.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-strplus.Tpo $(DEPDIR)/go-strplus.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-strplus.c' object='go-strplus.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strplus.lo `test -f 'runtime/go-strplus.c' || echo '$(srcdir)/'`runtime/go-strplus.c
+
+go-strslice.lo: runtime/go-strslice.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-strslice.lo -MD -MP -MF $(DEPDIR)/go-strslice.Tpo -c -o go-strslice.lo `test -f 'runtime/go-strslice.c' || echo '$(srcdir)/'`runtime/go-strslice.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-strslice.Tpo $(DEPDIR)/go-strslice.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-strslice.c' object='go-strslice.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-strslice.lo `test -f 'runtime/go-strslice.c' || echo '$(srcdir)/'`runtime/go-strslice.c
+
+go-trampoline.lo: runtime/go-trampoline.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-trampoline.lo -MD -MP -MF $(DEPDIR)/go-trampoline.Tpo -c -o go-trampoline.lo `test -f 'runtime/go-trampoline.c' || echo '$(srcdir)/'`runtime/go-trampoline.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-trampoline.Tpo $(DEPDIR)/go-trampoline.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-trampoline.c' object='go-trampoline.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-trampoline.lo `test -f 'runtime/go-trampoline.c' || echo '$(srcdir)/'`runtime/go-trampoline.c
+
+go-type-eface.lo: runtime/go-type-eface.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-eface.lo -MD -MP -MF $(DEPDIR)/go-type-eface.Tpo -c -o go-type-eface.lo `test -f 'runtime/go-type-eface.c' || echo '$(srcdir)/'`runtime/go-type-eface.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-eface.Tpo $(DEPDIR)/go-type-eface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-eface.c' object='go-type-eface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-eface.lo `test -f 'runtime/go-type-eface.c' || echo '$(srcdir)/'`runtime/go-type-eface.c
+
+go-type-error.lo: runtime/go-type-error.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-error.lo -MD -MP -MF $(DEPDIR)/go-type-error.Tpo -c -o go-type-error.lo `test -f 'runtime/go-type-error.c' || echo '$(srcdir)/'`runtime/go-type-error.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-error.Tpo $(DEPDIR)/go-type-error.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-error.c' object='go-type-error.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-error.lo `test -f 'runtime/go-type-error.c' || echo '$(srcdir)/'`runtime/go-type-error.c
+
+go-type-identity.lo: runtime/go-type-identity.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-identity.lo -MD -MP -MF $(DEPDIR)/go-type-identity.Tpo -c -o go-type-identity.lo `test -f 'runtime/go-type-identity.c' || echo '$(srcdir)/'`runtime/go-type-identity.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-identity.Tpo $(DEPDIR)/go-type-identity.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-identity.c' object='go-type-identity.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-identity.lo `test -f 'runtime/go-type-identity.c' || echo '$(srcdir)/'`runtime/go-type-identity.c
+
+go-type-interface.lo: runtime/go-type-interface.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-interface.lo -MD -MP -MF $(DEPDIR)/go-type-interface.Tpo -c -o go-type-interface.lo `test -f 'runtime/go-type-interface.c' || echo '$(srcdir)/'`runtime/go-type-interface.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-interface.Tpo $(DEPDIR)/go-type-interface.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-interface.c' object='go-type-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-interface.lo `test -f 'runtime/go-type-interface.c' || echo '$(srcdir)/'`runtime/go-type-interface.c
+
+go-type-string.lo: runtime/go-type-string.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-string.lo -MD -MP -MF $(DEPDIR)/go-type-string.Tpo -c -o go-type-string.lo `test -f 'runtime/go-type-string.c' || echo '$(srcdir)/'`runtime/go-type-string.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-string.Tpo $(DEPDIR)/go-type-string.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-string.c' object='go-type-string.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-string.lo `test -f 'runtime/go-type-string.c' || echo '$(srcdir)/'`runtime/go-type-string.c
+
+go-typedesc-equal.lo: runtime/go-typedesc-equal.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-typedesc-equal.lo -MD -MP -MF $(DEPDIR)/go-typedesc-equal.Tpo -c -o go-typedesc-equal.lo `test -f 'runtime/go-typedesc-equal.c' || echo '$(srcdir)/'`runtime/go-typedesc-equal.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-typedesc-equal.Tpo $(DEPDIR)/go-typedesc-equal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-typedesc-equal.c' object='go-typedesc-equal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-typedesc-equal.lo `test -f 'runtime/go-typedesc-equal.c' || echo '$(srcdir)/'`runtime/go-typedesc-equal.c
+
+go-typestring.lo: runtime/go-typestring.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-typestring.lo -MD -MP -MF $(DEPDIR)/go-typestring.Tpo -c -o go-typestring.lo `test -f 'runtime/go-typestring.c' || echo '$(srcdir)/'`runtime/go-typestring.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-typestring.Tpo $(DEPDIR)/go-typestring.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-typestring.c' object='go-typestring.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-typestring.lo `test -f 'runtime/go-typestring.c' || echo '$(srcdir)/'`runtime/go-typestring.c
+
+go-unreflect.lo: runtime/go-unreflect.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unreflect.lo -MD -MP -MF $(DEPDIR)/go-unreflect.Tpo -c -o go-unreflect.lo `test -f 'runtime/go-unreflect.c' || echo '$(srcdir)/'`runtime/go-unreflect.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unreflect.Tpo $(DEPDIR)/go-unreflect.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-unreflect.c' object='go-unreflect.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unreflect.lo `test -f 'runtime/go-unreflect.c' || echo '$(srcdir)/'`runtime/go-unreflect.c
+
+go-unsafe-new.lo: runtime/go-unsafe-new.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unsafe-new.lo -MD -MP -MF $(DEPDIR)/go-unsafe-new.Tpo -c -o go-unsafe-new.lo `test -f 'runtime/go-unsafe-new.c' || echo '$(srcdir)/'`runtime/go-unsafe-new.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unsafe-new.Tpo $(DEPDIR)/go-unsafe-new.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-unsafe-new.c' object='go-unsafe-new.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsafe-new.lo `test -f 'runtime/go-unsafe-new.c' || echo '$(srcdir)/'`runtime/go-unsafe-new.c
+
+go-unsafe-newarray.lo: runtime/go-unsafe-newarray.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unsafe-newarray.lo -MD -MP -MF $(DEPDIR)/go-unsafe-newarray.Tpo -c -o go-unsafe-newarray.lo `test -f 'runtime/go-unsafe-newarray.c' || echo '$(srcdir)/'`runtime/go-unsafe-newarray.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unsafe-newarray.Tpo $(DEPDIR)/go-unsafe-newarray.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-unsafe-newarray.c' object='go-unsafe-newarray.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsafe-newarray.lo `test -f 'runtime/go-unsafe-newarray.c' || echo '$(srcdir)/'`runtime/go-unsafe-newarray.c
+
+go-unsafe-pointer.lo: runtime/go-unsafe-pointer.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unsafe-pointer.lo -MD -MP -MF $(DEPDIR)/go-unsafe-pointer.Tpo -c -o go-unsafe-pointer.lo `test -f 'runtime/go-unsafe-pointer.c' || echo '$(srcdir)/'`runtime/go-unsafe-pointer.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unsafe-pointer.Tpo $(DEPDIR)/go-unsafe-pointer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-unsafe-pointer.c' object='go-unsafe-pointer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsafe-pointer.lo `test -f 'runtime/go-unsafe-pointer.c' || echo '$(srcdir)/'`runtime/go-unsafe-pointer.c
+
+go-unwind.lo: runtime/go-unwind.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unwind.lo -MD -MP -MF $(DEPDIR)/go-unwind.Tpo -c -o go-unwind.lo `test -f 'runtime/go-unwind.c' || echo '$(srcdir)/'`runtime/go-unwind.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unwind.Tpo $(DEPDIR)/go-unwind.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-unwind.c' object='go-unwind.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unwind.lo `test -f 'runtime/go-unwind.c' || echo '$(srcdir)/'`runtime/go-unwind.c
+
+mcache.lo: runtime/mcache.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mcache.lo -MD -MP -MF $(DEPDIR)/mcache.Tpo -c -o mcache.lo `test -f 'runtime/mcache.c' || echo '$(srcdir)/'`runtime/mcache.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mcache.Tpo $(DEPDIR)/mcache.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mcache.c' object='mcache.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mcache.lo `test -f 'runtime/mcache.c' || echo '$(srcdir)/'`runtime/mcache.c
+
+mcentral.lo: runtime/mcentral.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mcentral.lo -MD -MP -MF $(DEPDIR)/mcentral.Tpo -c -o mcentral.lo `test -f 'runtime/mcentral.c' || echo '$(srcdir)/'`runtime/mcentral.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mcentral.Tpo $(DEPDIR)/mcentral.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mcentral.c' object='mcentral.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mcentral.lo `test -f 'runtime/mcentral.c' || echo '$(srcdir)/'`runtime/mcentral.c
+
+mem_posix_memalign.lo: runtime/mem_posix_memalign.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mem_posix_memalign.lo -MD -MP -MF $(DEPDIR)/mem_posix_memalign.Tpo -c -o mem_posix_memalign.lo `test -f 'runtime/mem_posix_memalign.c' || echo '$(srcdir)/'`runtime/mem_posix_memalign.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mem_posix_memalign.Tpo $(DEPDIR)/mem_posix_memalign.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mem_posix_memalign.c' object='mem_posix_memalign.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mem_posix_memalign.lo `test -f 'runtime/mem_posix_memalign.c' || echo '$(srcdir)/'`runtime/mem_posix_memalign.c
+
+mem.lo: runtime/mem.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mem.lo -MD -MP -MF $(DEPDIR)/mem.Tpo -c -o mem.lo `test -f 'runtime/mem.c' || echo '$(srcdir)/'`runtime/mem.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mem.Tpo $(DEPDIR)/mem.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mem.c' object='mem.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mem.lo `test -f 'runtime/mem.c' || echo '$(srcdir)/'`runtime/mem.c
+
+mfinal.lo: runtime/mfinal.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mfinal.lo -MD -MP -MF $(DEPDIR)/mfinal.Tpo -c -o mfinal.lo `test -f 'runtime/mfinal.c' || echo '$(srcdir)/'`runtime/mfinal.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mfinal.Tpo $(DEPDIR)/mfinal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mfinal.c' object='mfinal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mfinal.lo `test -f 'runtime/mfinal.c' || echo '$(srcdir)/'`runtime/mfinal.c
+
+mfixalloc.lo: runtime/mfixalloc.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mfixalloc.lo -MD -MP -MF $(DEPDIR)/mfixalloc.Tpo -c -o mfixalloc.lo `test -f 'runtime/mfixalloc.c' || echo '$(srcdir)/'`runtime/mfixalloc.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mfixalloc.Tpo $(DEPDIR)/mfixalloc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mfixalloc.c' object='mfixalloc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mfixalloc.lo `test -f 'runtime/mfixalloc.c' || echo '$(srcdir)/'`runtime/mfixalloc.c
+
+mgc0.lo: runtime/mgc0.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mgc0.lo -MD -MP -MF $(DEPDIR)/mgc0.Tpo -c -o mgc0.lo `test -f 'runtime/mgc0.c' || echo '$(srcdir)/'`runtime/mgc0.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mgc0.Tpo $(DEPDIR)/mgc0.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mgc0.c' object='mgc0.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mgc0.lo `test -f 'runtime/mgc0.c' || echo '$(srcdir)/'`runtime/mgc0.c
+
+mheap.lo: runtime/mheap.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mheap.lo -MD -MP -MF $(DEPDIR)/mheap.Tpo -c -o mheap.lo `test -f 'runtime/mheap.c' || echo '$(srcdir)/'`runtime/mheap.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mheap.Tpo $(DEPDIR)/mheap.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mheap.c' object='mheap.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mheap.lo `test -f 'runtime/mheap.c' || echo '$(srcdir)/'`runtime/mheap.c
+
+mheapmap32.lo: runtime/mheapmap32.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mheapmap32.lo -MD -MP -MF $(DEPDIR)/mheapmap32.Tpo -c -o mheapmap32.lo `test -f 'runtime/mheapmap32.c' || echo '$(srcdir)/'`runtime/mheapmap32.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mheapmap32.Tpo $(DEPDIR)/mheapmap32.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mheapmap32.c' object='mheapmap32.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mheapmap32.lo `test -f 'runtime/mheapmap32.c' || echo '$(srcdir)/'`runtime/mheapmap32.c
+
+mheapmap64.lo: runtime/mheapmap64.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mheapmap64.lo -MD -MP -MF $(DEPDIR)/mheapmap64.Tpo -c -o mheapmap64.lo `test -f 'runtime/mheapmap64.c' || echo '$(srcdir)/'`runtime/mheapmap64.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mheapmap64.Tpo $(DEPDIR)/mheapmap64.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mheapmap64.c' object='mheapmap64.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mheapmap64.lo `test -f 'runtime/mheapmap64.c' || echo '$(srcdir)/'`runtime/mheapmap64.c
+
+msize.lo: runtime/msize.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT msize.lo -MD -MP -MF $(DEPDIR)/msize.Tpo -c -o msize.lo `test -f 'runtime/msize.c' || echo '$(srcdir)/'`runtime/msize.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/msize.Tpo $(DEPDIR)/msize.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/msize.c' object='msize.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o msize.lo `test -f 'runtime/msize.c' || echo '$(srcdir)/'`runtime/msize.c
+
+proc.lo: runtime/proc.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proc.lo -MD -MP -MF $(DEPDIR)/proc.Tpo -c -o proc.lo `test -f 'runtime/proc.c' || echo '$(srcdir)/'`runtime/proc.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/proc.Tpo $(DEPDIR)/proc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/proc.c' object='proc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc.lo `test -f 'runtime/proc.c' || echo '$(srcdir)/'`runtime/proc.c
+
+thread.lo: runtime/thread.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread.lo -MD -MP -MF $(DEPDIR)/thread.Tpo -c -o thread.lo `test -f 'runtime/thread.c' || echo '$(srcdir)/'`runtime/thread.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/thread.Tpo $(DEPDIR)/thread.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/thread.c' object='thread.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread.lo `test -f 'runtime/thread.c' || echo '$(srcdir)/'`runtime/thread.c
+
+rtems-task-variable-add.lo: runtime/rtems-task-variable-add.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rtems-task-variable-add.lo -MD -MP -MF $(DEPDIR)/rtems-task-variable-add.Tpo -c -o rtems-task-variable-add.lo `test -f 'runtime/rtems-task-variable-add.c' || echo '$(srcdir)/'`runtime/rtems-task-variable-add.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rtems-task-variable-add.Tpo $(DEPDIR)/rtems-task-variable-add.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/rtems-task-variable-add.c' object='rtems-task-variable-add.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rtems-task-variable-add.lo `test -f 'runtime/rtems-task-variable-add.c' || echo '$(srcdir)/'`runtime/rtems-task-variable-add.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool config.lt
+
+# GNU Make needs to see an explicit $(MAKE) variable in the command it
+# runs to enable its job server during parallel builds. Hence the
+# comments below.
+all-multi:
+ $(MULTIDO) $(AM_MAKEFLAGS) DO=all multi-do # $(MAKE)
+install-multi:
+ $(MULTIDO) $(AM_MAKEFLAGS) DO=install multi-do # $(MAKE)
+
+mostlyclean-multi:
+ $(MULTICLEAN) $(AM_MAKEFLAGS) DO=mostlyclean multi-clean # $(MAKE)
+clean-multi:
+ $(MULTICLEAN) $(AM_MAKEFLAGS) DO=clean multi-clean # $(MAKE)
+distclean-multi:
+ $(MULTICLEAN) $(AM_MAKEFLAGS) DO=distclean multi-clean # $(MAKE)
+maintainer-clean-multi:
+ $(MULTICLEAN) $(AM_MAKEFLAGS) DO=maintainer-clean multi-clean # $(MAKE)
+install-toolexeclibgoDATA: $(toolexeclibgo_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgodir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgodir)"
+ @list='$(toolexeclibgo_DATA)'; test -n "$(toolexeclibgodir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgodir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgodir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgo_DATA)'; test -n "$(toolexeclibgodir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgodir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgodir)" && rm -f $$files
+install-toolexeclibgoarchiveDATA: $(toolexeclibgoarchive_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoarchivedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoarchivedir)"
+ @list='$(toolexeclibgoarchive_DATA)'; test -n "$(toolexeclibgoarchivedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoarchivedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoarchivedir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoarchiveDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoarchive_DATA)'; test -n "$(toolexeclibgoarchivedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoarchivedir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoarchivedir)" && rm -f $$files
+install-toolexeclibgocompressDATA: $(toolexeclibgocompress_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgocompressdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgocompressdir)"
+ @list='$(toolexeclibgocompress_DATA)'; test -n "$(toolexeclibgocompressdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgocompressdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgocompressdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgocompressDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgocompress_DATA)'; test -n "$(toolexeclibgocompressdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgocompressdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgocompressdir)" && rm -f $$files
+install-toolexeclibgocontainerDATA: $(toolexeclibgocontainer_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgocontainerdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgocontainerdir)"
+ @list='$(toolexeclibgocontainer_DATA)'; test -n "$(toolexeclibgocontainerdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgocontainerdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgocontainerdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgocontainerDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgocontainer_DATA)'; test -n "$(toolexeclibgocontainerdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgocontainerdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgocontainerdir)" && rm -f $$files
+install-toolexeclibgocryptoDATA: $(toolexeclibgocrypto_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgocryptodir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgocryptodir)"
+ @list='$(toolexeclibgocrypto_DATA)'; test -n "$(toolexeclibgocryptodir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgocryptodir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgocryptodir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgocryptoDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgocrypto_DATA)'; test -n "$(toolexeclibgocryptodir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgocryptodir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgocryptodir)" && rm -f $$files
+install-toolexeclibgocryptoopenpgpDATA: $(toolexeclibgocryptoopenpgp_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgocryptoopenpgpdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)"
+ @list='$(toolexeclibgocryptoopenpgp_DATA)'; test -n "$(toolexeclibgocryptoopenpgpdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgocryptoopenpgpDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgocryptoopenpgp_DATA)'; test -n "$(toolexeclibgocryptoopenpgpdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" && rm -f $$files
+install-toolexeclibgodebugDATA: $(toolexeclibgodebug_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgodebugdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgodebugdir)"
+ @list='$(toolexeclibgodebug_DATA)'; test -n "$(toolexeclibgodebugdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgodebugdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgodebugdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgodebugDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgodebug_DATA)'; test -n "$(toolexeclibgodebugdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgodebugdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgodebugdir)" && rm -f $$files
+install-toolexeclibgoencodingDATA: $(toolexeclibgoencoding_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoencodingdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoencodingdir)"
+ @list='$(toolexeclibgoencoding_DATA)'; test -n "$(toolexeclibgoencodingdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoencodingdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoencodingdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoencodingDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoencoding_DATA)'; test -n "$(toolexeclibgoencodingdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoencodingdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoencodingdir)" && rm -f $$files
+install-toolexeclibgoexpDATA: $(toolexeclibgoexp_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoexpdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexpdir)"
+ @list='$(toolexeclibgoexp_DATA)'; test -n "$(toolexeclibgoexpdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoexpdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexpdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoexpDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoexp_DATA)'; test -n "$(toolexeclibgoexpdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoexpdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoexpdir)" && rm -f $$files
+install-toolexeclibgogoDATA: $(toolexeclibgogo_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgogodir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgogodir)"
+ @list='$(toolexeclibgogo_DATA)'; test -n "$(toolexeclibgogodir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgogodir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgogodir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgogoDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgogo_DATA)'; test -n "$(toolexeclibgogodir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgogodir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgogodir)" && rm -f $$files
+install-toolexeclibgohashDATA: $(toolexeclibgohash_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgohashdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgohashdir)"
+ @list='$(toolexeclibgohash_DATA)'; test -n "$(toolexeclibgohashdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgohashdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgohashdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgohashDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgohash_DATA)'; test -n "$(toolexeclibgohashdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgohashdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgohashdir)" && rm -f $$files
+install-toolexeclibgohttpDATA: $(toolexeclibgohttp_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgohttpdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgohttpdir)"
+ @list='$(toolexeclibgohttp_DATA)'; test -n "$(toolexeclibgohttpdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgohttpdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgohttpdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgohttpDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgohttp_DATA)'; test -n "$(toolexeclibgohttpdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgohttpdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgohttpdir)" && rm -f $$files
+install-toolexeclibgoimageDATA: $(toolexeclibgoimage_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoimagedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoimagedir)"
+ @list='$(toolexeclibgoimage_DATA)'; test -n "$(toolexeclibgoimagedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoimagedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoimagedir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoimageDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoimage_DATA)'; test -n "$(toolexeclibgoimagedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoimagedir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoimagedir)" && rm -f $$files
+install-toolexeclibgoindexDATA: $(toolexeclibgoindex_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoindexdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoindexdir)"
+ @list='$(toolexeclibgoindex_DATA)'; test -n "$(toolexeclibgoindexdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoindexdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoindexdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoindexDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoindex_DATA)'; test -n "$(toolexeclibgoindexdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoindexdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoindexdir)" && rm -f $$files
+install-toolexeclibgoioDATA: $(toolexeclibgoio_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoiodir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoiodir)"
+ @list='$(toolexeclibgoio_DATA)'; test -n "$(toolexeclibgoiodir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoiodir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoiodir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoioDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoio_DATA)'; test -n "$(toolexeclibgoiodir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoiodir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoiodir)" && rm -f $$files
+install-toolexeclibgomimeDATA: $(toolexeclibgomime_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgomimedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgomimedir)"
+ @list='$(toolexeclibgomime_DATA)'; test -n "$(toolexeclibgomimedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgomimedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgomimedir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgomimeDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgomime_DATA)'; test -n "$(toolexeclibgomimedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgomimedir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgomimedir)" && rm -f $$files
+install-toolexeclibgonetDATA: $(toolexeclibgonet_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgonetdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgonetdir)"
+ @list='$(toolexeclibgonet_DATA)'; test -n "$(toolexeclibgonetdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgonetdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgonetdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgonetDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgonet_DATA)'; test -n "$(toolexeclibgonetdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgonetdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgonetdir)" && rm -f $$files
+install-toolexeclibgoosDATA: $(toolexeclibgoos_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoosdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoosdir)"
+ @list='$(toolexeclibgoos_DATA)'; test -n "$(toolexeclibgoosdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoosdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoosdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoosDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoos_DATA)'; test -n "$(toolexeclibgoosdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoosdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoosdir)" && rm -f $$files
+install-toolexeclibgorpcDATA: $(toolexeclibgorpc_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgorpcdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgorpcdir)"
+ @list='$(toolexeclibgorpc_DATA)'; test -n "$(toolexeclibgorpcdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgorpcdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgorpcdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgorpcDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgorpc_DATA)'; test -n "$(toolexeclibgorpcdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgorpcdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgorpcdir)" && rm -f $$files
+install-toolexeclibgoruntimeDATA: $(toolexeclibgoruntime_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoruntimedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoruntimedir)"
+ @list='$(toolexeclibgoruntime_DATA)'; test -n "$(toolexeclibgoruntimedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoruntimedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoruntimedir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoruntimeDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoruntime_DATA)'; test -n "$(toolexeclibgoruntimedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoruntimedir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoruntimedir)" && rm -f $$files
+install-toolexeclibgotestingDATA: $(toolexeclibgotesting_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgotestingdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgotestingdir)"
+ @list='$(toolexeclibgotesting_DATA)'; test -n "$(toolexeclibgotestingdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgotestingdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgotestingdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgotestingDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgotesting_DATA)'; test -n "$(toolexeclibgotestingdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgotestingdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgotestingdir)" && rm -f $$files
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) all-multi $(DATA) \
+ config.h
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohttpdir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgorpcdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgotestingdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-multi clean-recursive
+
+clean-am: clean-generic clean-libtool clean-local \
+ clean-toolexeclibLIBRARIES clean-toolexeclibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-multi distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-multi install-toolexeclibLIBRARIES \
+ install-toolexeclibLTLIBRARIES install-toolexeclibgoDATA \
+ install-toolexeclibgoarchiveDATA \
+ install-toolexeclibgocompressDATA \
+ install-toolexeclibgocontainerDATA \
+ install-toolexeclibgocryptoDATA \
+ install-toolexeclibgocryptoopenpgpDATA \
+ install-toolexeclibgodebugDATA \
+ install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \
+ install-toolexeclibgogoDATA install-toolexeclibgohashDATA \
+ install-toolexeclibgohttpDATA install-toolexeclibgoimageDATA \
+ install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \
+ install-toolexeclibgomimeDATA install-toolexeclibgonetDATA \
+ install-toolexeclibgoosDATA install-toolexeclibgorpcDATA \
+ install-toolexeclibgoruntimeDATA \
+ install-toolexeclibgotestingDATA
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-multi maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-multi mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool mostlyclean-local
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-toolexeclibLIBRARIES \
+ uninstall-toolexeclibLTLIBRARIES uninstall-toolexeclibgoDATA \
+ uninstall-toolexeclibgoarchiveDATA \
+ uninstall-toolexeclibgocompressDATA \
+ uninstall-toolexeclibgocontainerDATA \
+ uninstall-toolexeclibgocryptoDATA \
+ uninstall-toolexeclibgocryptoopenpgpDATA \
+ uninstall-toolexeclibgodebugDATA \
+ uninstall-toolexeclibgoencodingDATA \
+ uninstall-toolexeclibgoexpDATA uninstall-toolexeclibgogoDATA \
+ uninstall-toolexeclibgohashDATA \
+ uninstall-toolexeclibgohttpDATA \
+ uninstall-toolexeclibgoimageDATA \
+ uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \
+ uninstall-toolexeclibgomimeDATA uninstall-toolexeclibgonetDATA \
+ uninstall-toolexeclibgoosDATA uninstall-toolexeclibgorpcDATA \
+ uninstall-toolexeclibgoruntimeDATA \
+ uninstall-toolexeclibgotestingDATA
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all all-multi \
+ clean-multi ctags-recursive distclean-multi install-am \
+ install-multi install-strip maintainer-clean-multi \
+ mostlyclean-multi tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am all-multi am--refresh check check-am clean \
+ clean-generic clean-libtool clean-local clean-multi \
+ clean-toolexeclibLIBRARIES clean-toolexeclibLTLIBRARIES ctags \
+ ctags-recursive distclean distclean-compile distclean-generic \
+ distclean-hdr distclean-libtool distclean-multi distclean-tags \
+ dvi dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-multi \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip install-toolexeclibLIBRARIES \
+ install-toolexeclibLTLIBRARIES install-toolexeclibgoDATA \
+ install-toolexeclibgoarchiveDATA \
+ install-toolexeclibgocompressDATA \
+ install-toolexeclibgocontainerDATA \
+ install-toolexeclibgocryptoDATA \
+ install-toolexeclibgocryptoopenpgpDATA \
+ install-toolexeclibgodebugDATA \
+ install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \
+ install-toolexeclibgogoDATA install-toolexeclibgohashDATA \
+ install-toolexeclibgohttpDATA install-toolexeclibgoimageDATA \
+ install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \
+ install-toolexeclibgomimeDATA install-toolexeclibgonetDATA \
+ install-toolexeclibgoosDATA install-toolexeclibgorpcDATA \
+ install-toolexeclibgoruntimeDATA \
+ install-toolexeclibgotestingDATA installcheck installcheck-am \
+ installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic maintainer-clean-multi mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ mostlyclean-local mostlyclean-multi pdf pdf-am ps ps-am tags \
+ tags-recursive uninstall uninstall-am \
+ uninstall-toolexeclibLIBRARIES \
+ uninstall-toolexeclibLTLIBRARIES uninstall-toolexeclibgoDATA \
+ uninstall-toolexeclibgoarchiveDATA \
+ uninstall-toolexeclibgocompressDATA \
+ uninstall-toolexeclibgocontainerDATA \
+ uninstall-toolexeclibgocryptoDATA \
+ uninstall-toolexeclibgocryptoopenpgpDATA \
+ uninstall-toolexeclibgodebugDATA \
+ uninstall-toolexeclibgoencodingDATA \
+ uninstall-toolexeclibgoexpDATA uninstall-toolexeclibgogoDATA \
+ uninstall-toolexeclibgohashDATA \
+ uninstall-toolexeclibgohttpDATA \
+ uninstall-toolexeclibgoimageDATA \
+ uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \
+ uninstall-toolexeclibgomimeDATA uninstall-toolexeclibgonetDATA \
+ uninstall-toolexeclibgoosDATA uninstall-toolexeclibgorpcDATA \
+ uninstall-toolexeclibgoruntimeDATA \
+ uninstall-toolexeclibgotestingDATA
+
+
+goc2c.$(OBJEXT): runtime/goc2c.c
+ $(CC_FOR_BUILD) -c $(CFLAGS_FOR_BUILD) $<
+
+goc2c: goc2c.$(OBJEXT)
+ $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $<
+
+malloc.c: $(srcdir)/runtime/malloc.goc goc2c
+ ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+ mv -f $@.tmp $@
+
+mprof.c: $(srcdir)/runtime/mprof.goc goc2c
+ ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+ mv -f $@.tmp $@
+
+reflect.c: $(srcdir)/runtime/reflect.goc goc2c
+ ./goc2c --gcc --go-prefix libgo_reflect $< > $@.tmp
+ mv -f $@.tmp $@
+
+sigqueue.c: $(srcdir)/runtime/sigqueue.goc goc2c
+ ./goc2c --gcc --go-prefix libgo_runtime $< > $@.tmp
+ mv -f $@.tmp $@
+
+%.c: $(srcdir)/runtime/%.goc goc2c
+ ./goc2c --gcc $< > $@.tmp
+ mv -f $@.tmp $@
+
+version.go: s-version; @true
+s-version: Makefile
+ rm -f version.go.tmp
+ echo "package runtime" > version.go.tmp
+ echo 'const defaultGoroot = "$(prefix)"' >> version.go.tmp
+ echo 'const theVersion = "'`$(CC) --version | sed 1q`'"' >> version.go.tmp
+ echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
+ echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
+ $(SHELL) $(srcdir)/../move-if-change version.go.tmp version.go
+ $(STAMP) $@
+
+syscall_arch.go: s-syscall_arch; @true
+s-syscall_arch: Makefile
+ rm -f syscall_arch.go.tmp
+ echo "package syscall" > syscall_arch.go.tmp
+ echo 'const ARCH = "'$(GOARCH)'"' >> syscall_arch.go.tmp
+ echo 'const OS = "'$(GOOS)'"' >> syscall_arch.go.tmp
+ $(SHELL) $(srcdir)/../move-if-change syscall_arch.go.tmp syscall_arch.go
+ $(STAMP) $@
+
+asn1/asn1.lo: $(go_asn1_files) bytes.gox fmt.gox io.gox os.gox reflect.gox \
+ strconv.gox strings.gox time.gox
+ $(BUILDPACKAGE)
+asn1/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: asn1/check
+
+big/big.lo: $(go_big_files) fmt.gox rand.gox strings.gox
+ $(BUILDPACKAGE)
+big/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: big/check
+
+bufio/bufio.lo: $(go_bufio_files) bytes.gox io.gox os.gox strconv.gox utf8.gox
+ $(BUILDPACKAGE)
+bufio/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: bufio/check
+
+bytes/bytes.lo: $(go_bytes_files) io.gox os.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+bytes/index.lo: $(go_bytes_c_files) bytes/bytes.lo
+ $(LTCOMPILE) -c -o bytes/index.lo $(srcdir)/go/bytes/indexbyte.c
+bytes/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: bytes/check
+
+cmath/cmath.lo: $(go_cmath_files) math.gox
+ $(BUILDPACKAGE)
+cmath/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: cmath/check
+
+ebnf/ebnf.lo: $(go_ebnf_files) container/vector.gox go/scanner.gox \
+ go/token.gox os.gox strconv.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+ebnf/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: ebnf/check
+
+exec/exec.lo: $(go_exec_files) os.gox strings.gox
+ $(BUILDPACKAGE)
+exec/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: exec/check
+
+expvar/expvar.lo: $(go_expvar_files) bytes.gox fmt.gox http.gox json.gox \
+ log.gox os.gox runtime.gox strconv.gox sync.gox
+ $(BUILDPACKAGE)
+expvar/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: expvar/check
+
+flag/flag.lo: $(go_flag_files) fmt.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+flag/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: flag/check
+
+fmt/fmt.lo: $(go_fmt_files) bytes.gox io.gox os.gox reflect.gox strconv.gox \
+ strings.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+fmt/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: fmt/check
+
+gob/gob.lo: $(go_gob_files) bytes.gox fmt.gox io.gox math.gox os.gox \
+ reflect.gox runtime.gox strings.gox sync.gox unicode.gox \
+ utf8.gox
+ $(BUILDPACKAGE)
+gob/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: gob/check
+
+hash/hash.lo: $(go_hash_files) io.gox
+ $(BUILDPACKAGE)
+hash/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: hash/check
+
+html/html.lo: $(go_html_files) bytes.gox io.gox os.gox strconv.gox strings.gox \
+ utf8.gox
+ $(BUILDPACKAGE)
+html/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: html/check
+
+http/http.lo: $(go_http_files) bufio.gox bytes.gox container/list.gox \
+ container/vector.gox crypto/rand.gox crypto/tls.gox \
+ encoding/base64.gox fmt.gox io.gox io/ioutil.gox log.gox \
+ mime.gox mime/multipart.gox net.gox os.gox path.gox sort.gox \
+ strconv.gox strings.gox sync.gox time.gox utf8.gox
+ $(BUILDPACKAGE)
+http/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: http/check
+
+image/image.lo: $(go_image_files) bufio.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+image/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: image/check
+
+io/io.lo: $(go_io_files) os.gox runtime.gox sync.gox
+ $(BUILDPACKAGE)
+io/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: io/check
+
+json/json.lo: $(go_json_files) bytes.gox container/vector.gox fmt.gox io.gox \
+ math.gox os.gox reflect.gox runtime.gox strconv.gox \
+ strings.gox unicode.gox utf16.gox utf8.gox
+ $(BUILDPACKAGE)
+json/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: json/check
+
+log/log.lo: $(go_log_files) bytes.gox fmt.gox io.gox runtime.gox os.gox \
+ sync.gox time.gox
+ $(BUILDPACKAGE)
+log/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: log/check
+
+math/math.lo: $(go_math_files)
+ $(BUILDPACKAGE)
+math/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: math/check
+
+mime/mime.lo: $(go_mime_files) bufio.gox bytes.gox os.gox strings.gox \
+ sync.gox unicode.gox
+ $(BUILDPACKAGE)
+mime/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: mime/check
+
+net/net.lo: $(go_net_files) bytes.gox fmt.gox io.gox os.gox reflect.gox \
+ strconv.gox strings.gox sync.gox syscall.gox
+ $(BUILDPACKAGE)
+net/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: net/check
+
+netchan/netchan.lo: $(go_netchan_files) gob.gox log.gox net.gox os.gox \
+ reflect.gox strconv.gox sync.gox time.gox
+ $(BUILDPACKAGE)
+netchan/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: netchan/check
+
+os/os.lo: $(go_os_files) sync.gox syscall.gox
+ $(BUILDPACKAGE)
+os/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: os/check
+
+patch/patch.lo: $(go_patch_files) bytes.gox compress/zlib.gox \
+ crypto/sha1.gox encoding/git85.gox fmt.gox io.gox os.gox \
+ path.gox strings.gox
+ $(BUILDPACKAGE)
+patch/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: patch/check
+
+path/path.lo: $(go_path_files) io/ioutil.gox os.gox sort.gox strings.gox \
+ utf8.gox
+ $(BUILDPACKAGE)
+path/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: path/check
+
+rand/rand.lo: $(go_rand_files) math.gox sync.gox
+ $(BUILDPACKAGE)
+rand/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: rand/check
+
+reflect/reflect.lo: $(go_reflect_files) math.gox runtime.gox strconv.gox \
+ sync.gox
+ $(BUILDPACKAGE)
+reflect/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: reflect/check
+
+regexp/regexp.lo: $(go_regexp_files) bytes.gox io.gox os.gox strings.gox \
+ utf8.gox
+ $(BUILDPACKAGE)
+regexp/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: regexp/check
+
+rpc/rpc.lo: $(go_rpc_files) bufio.gox fmt.gox gob.gox http.gox io.gox log.gox \
+ net.gox os.gox reflect.gox sort.gox strings.gox strconv.gox \
+ sync.gox template.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+rpc/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: rpc/check
+
+runtime/runtime.lo: $(go_runtime_files)
+ $(BUILDPACKAGE)
+runtime/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: runtime/check
+
+scanner/scanner.lo: $(go_scanner_files) bytes.gox fmt.gox io.gox os.gox \
+ unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+scanner/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: scanner/check
+
+smtp/smtp.lo: $(go_smtp_files) crypto/tls.gox encoding/base64.gox io.gox \
+ net.gox net/textproto.gox os.gox strings.gox
+ $(BUILDPACKAGE)
+smtp/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: smtp/check
+
+sort/sort.lo: $(go_sort_files)
+ $(BUILDPACKAGE)
+sort/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: sort/check
+
+strconv/strconv.lo: $(go_strconv_files) bytes.gox math.gox os.gox strings.gox \
+ unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+strconv/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: strconv/check
+
+strings/strings.lo: $(go_strings_files) os.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+strings/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: strings/check
+
+sync/mutex.lo: $(go_sync_files) runtime.gox
+ $(BUILDPACKAGE)
+sync/cas.lo: $(go_sync_c_files) sync/mutex.lo
+ $(LTCOMPILE) -c -o sync/cas.lo $(srcdir)/go/sync/cas.c
+sync/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: sync/check
+
+syslog/syslog.lo: $(go_syslog_files) fmt.gox log.gox net.gox os.gox syscall.gox
+ $(BUILDPACKAGE)
+syslog/syslog_c.lo: $(go_syslog_c_files) syslog/syslog.lo
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syslog/syslog_c.c
+syslog/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: syslog/check
+
+tabwriter/tabwriter.lo: $(go_tabwriter_files) bytes.gox io.gox os.gox utf8.gox
+ $(BUILDPACKAGE)
+tabwriter/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: tabwriter/check
+
+template/template.lo: $(go_template_files) bytes.gox fmt.gox io.gox os.gox \
+ reflect.gox runtime.gox strings.gox container/vector.gox
+ $(BUILDPACKAGE)
+template/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: template/check
+
+testing/testing.lo: $(go_testing_files) flag.gox fmt.gox os.gox regexp.gox \
+ runtime.gox time.gox
+ $(BUILDPACKAGE)
+testing/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: testing/check
+
+time/time.lo: $(go_time_files) bytes.gox container/heap.gox io/ioutil.gox \
+ os.gox strconv.gox sync.gox syscall.gox
+ $(BUILDPACKAGE)
+time/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: time/check
+
+try/try.lo: $(go_try_files) fmt.gox io.gox os.gox reflect.gox unicode.gox
+ $(BUILDPACKAGE)
+try/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: try/check
+
+unicode/unicode.lo: $(go_unicode_files)
+ $(BUILDPACKAGE)
+unicode/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: unicode/check
+
+utf16/utf16.lo: $(go_utf16_files) unicode.gox
+ $(BUILDPACKAGE)
+utf16/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: utf16/check
+
+utf8/utf8.lo: $(go_utf8_files) unicode.gox
+ $(BUILDPACKAGE)
+utf8/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: utf8/check
+
+websocket/websocket.lo: $(go_websocket_files) bufio.gox bytes.gox \
+ container/vector.gox crypto/md5.gox crypto/tls.gox \
+ encoding/binary.gox fmt.gox http.gox io.gox net.gox os.gox \
+ rand.gox strings.gox
+ $(BUILDPACKAGE)
+websocket/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: websocket/check
+
+xml/xml.lo: $(go_xml_files) bufio.gox bytes.gox fmt.gox io.gox os.gox \
+ reflect.gox strconv.gox strings.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+xml/check: $(CHECK_DEPS)
+ $(CHECK)
+.PHONY: xml/check
+
+archive/tar.lo: $(go_archive_tar_files) bytes.gox io.gox os.gox strconv.gox \
+ strings.gox
+ $(BUILDPACKAGE)
+archive/tar/check: $(CHECK_DEPS)
+ @$(MKDIR_P) archive/tar
+ $(CHECK)
+.PHONY: archive/tar/check
+
+archive/zip.lo: $(go_archive_zip_files) bufio.gox bytes.gox \
+ compress/flate.gox hash.gox hash/crc32.gox \
+ encoding/binary.gox io.gox os.gox
+ $(BUILDPACKAGE)
+archive/zip/check: $(CHECK_DEPS)
+ @$(MKDIR_P) archive/zip
+ $(CHECK)
+.PHONY: archive/zip/check
+
+compress/flate.lo: $(go_compress_flate_files) bufio.gox io.gox math.gox \
+ os.gox sort.gox strconv.gox
+ $(BUILDPACKAGE)
+compress/flate/check: $(CHECK_DEPS)
+ @$(MKDIR_P) compress/flate
+ $(CHECK)
+.PHONY: compress/flate/check
+
+compress/gzip.lo: $(go_compress_gzip_files) bufio.gox compress/flate.gox \
+ hash.gox hash/crc32.gox io.gox os.gox
+ $(BUILDPACKAGE)
+compress/gzip/check: $(CHECK_DEPS)
+ @$(MKDIR_P) compress/gzip
+ $(CHECK)
+.PHONY: compress/gzip/check
+
+compress/zlib.lo: $(go_compress_zlib_files) bufio.gox compress/flate.gox \
+ hash.gox hash/adler32.gox io.gox os.gox
+ $(BUILDPACKAGE)
+compress/zlib/check: $(CHECK_DEPS)
+ @$(MKDIR_P) compress/zlib
+ $(CHECK)
+.PHONY: compress/zlib/check
+
+container/heap.lo: $(go_container_heap_files) sort.gox
+ $(BUILDPACKAGE)
+container/heap/check: $(CHECK_DEPS)
+ @$(MKDIR_P) container/heap
+ $(CHECK)
+.PHONY: container/heap/check
+
+container/list.lo: $(go_container_list_files)
+ $(BUILDPACKAGE)
+container/list/check: $(CHECK_DEPS)
+ @$(MKDIR_P) container/list
+ $(CHECK)
+.PHONY: container/list/check
+
+container/ring.lo: $(go_container_ring_files)
+ $(BUILDPACKAGE)
+container/ring/check: $(CHECK_DEPS)
+ @$(MKDIR_P) container/ring
+ $(CHECK)
+.PHONY: container/ring/check
+
+container/vector.lo: $(go_container_vector_files)
+ $(BUILDPACKAGE)
+container/vector/check: $(CHECK_DEPS)
+ @$(MKDIR_P) container/vector
+ $(CHECK)
+.PHONY: container/vector/check
+
+crypto/aes.lo: $(go_crypto_aes_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/aes/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/aes
+ $(CHECK)
+.PHONY: crypto/aes/check
+
+crypto/block.lo: $(go_crypto_block_files) fmt.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/block/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/block
+ $(CHECK)
+.PHONY: crypto/block/check
+
+crypto/blowfish.lo: $(go_crypto_blowfish_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/blowfish/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/blowfish
+ $(CHECK)
+.PHONY: crypto/blowfish/check
+
+crypto/cast5.lo: $(go_crypto_cast5_files) os.gox
+ $(BUILDPACKAGE)
+crypt/cast5/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/cast5
+ $(CHECK)
+.PHONY: crypto/cast5/check
+
+crypto/cipher.lo: $(go_crypto_cipher_files) io.gox os.gox
+ $(BUILDPACKAGE)
+crypto/cipher/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/cipher
+ $(CHECK)
+.PHONY: crypto/cipher/check
+
+crypto/elliptic.lo: $(go_crypto_elliptic_files) big.gox io.gox os.gox sync.gox
+ $(BUILDPACKAGE)
+crypto/elliptic/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/elliptic
+ $(CHECK)
+.PHONY: crypto/elliptic/check
+
+crypto/hmac.lo: $(go_crypto_hmac_files) crypto/md5.gox crypto/sha1.gox \
+ crypto/sha256.gox hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/hmac/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/hmac
+ $(CHECK)
+.PHONY: crypto/hmac/check
+
+crypto/md4.lo: $(go_crypto_md4_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/md4/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/md4
+ $(CHECK)
+.PHONY: crypto/md4/check
+
+crypto/md5.lo: $(go_crypto_md5_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/md5/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/md5
+ $(CHECK)
+.PHONY: crypto/md5/check
+
+crypto/ocsp.lo: $(go_crypto_ocsp_files) asn1.gox crypto/rsa.gox \
+ crypto/sha1.gox crypto/x509.gox os.gox time.gox
+ $(BUILDPACKAGE)
+crypto/ocsp/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/ocsp
+ $(CHECK)
+.PHONY: crypto/ocsp/check
+
+crypto/rand.lo: $(go_crypto_rand_files) crypto/aes.gox io.gox os.gox sync.gox \
+ time.gox
+ $(BUILDPACKAGE)
+crypto/rand/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/rand
+ $(CHECK)
+.PHONY: crypto/rand/check
+
+crypto/rc4.lo: $(go_crypto_rc4_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/rc4/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/rc4
+ $(CHECK)
+.PHONY: crypto/rc4/check
+
+crypto/ripemd160.lo: $(go_crypto_ripemd160_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/ripemd160/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/ripemd160
+ $(CHECK)
+.PHONY: crypto/ripemd160/check
+
+crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto/sha1.gox \
+ crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox
+ $(BUILDPACKAGE)
+crypto/rsa/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/rsa
+ $(CHECK)
+.PHONY: crypto/rsa/check
+
+crypto/sha1.lo: $(go_crypto_sha1_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/sha1/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/sha1
+ $(CHECK)
+.PHONY: crypto/sha1/check
+
+crypto/sha256.lo: $(go_crypto_sha256_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/sha256/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/sha256
+ $(CHECK)
+.PHONY: crypto/sha256/check
+
+crypto/sha512.lo: $(go_crypto_sha512_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+crypto/sha512/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/sha512
+ $(CHECK)
+.PHONY: crypto/sha512/check
+
+crypto/subtle.lo: $(go_crypto_subtle_files)
+ $(BUILDPACKAGE)
+crypto/subtle/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/subtle
+ $(CHECK)
+.PHONY: crypto/subtle/check
+
+crypto/tls.lo: $(go_crypto_tls_files) big.gox bufio.gox bytes.gox \
+ container/list.gox crypto/aes.gox crypto/cipher.gox \
+ crypto/elliptic.gox crypto/hmac.gox crypto/md5.gox \
+ crypto/rc4.gox crypto/rand.gox crypto/rsa.gox crypto/sha1.gox \
+ crypto/subtle.gox crypto/rsa.gox crypto/sha1.gox \
+ crypto/x509.gox encoding/pem.gox fmt.gox hash.gox io.gox \
+ io/ioutil.gox net.gox os.gox strings.gox sync.gox time.gox
+ $(BUILDPACKAGE)
+crypto/tls/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/tls
+ $(CHECK)
+.PHONY: crypto/tls/check
+
+crypto/twofish.lo: $(go_crypto_twofish_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/twofish/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/twofish
+ $(CHECK)
+.PHONY: crypto/twofish/check
+
+crypto/x509.lo: $(go_crypto_x509_files) asn1.gox big.gox container/vector.gox \
+ crypto/rsa.gox crypto/sha1.gox hash.gox os.gox strings.gox \
+ time.gox
+ $(BUILDPACKAGE)
+crypto/x509/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/x509
+ $(CHECK)
+.PHONY: crypto/x509/check
+
+crypto/xtea.lo: $(go_crypto_xtea_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+crypto/xtea/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/xtea
+ $(CHECK)
+.PHONY: crypto/xtea/check
+
+crypto/openpgp/armor.lo: $(go_crypto_openpgp_armor_files) bytes.gox \
+ crypto/openpgp/error.gox encoding/base64.gox \
+ encoding/line.gox io.gox os.gox
+ $(BUILDPACKAGE)
+crypto/openpgp/armor/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/openpgp/armor
+ $(CHECK)
+.PHONY: crypto/openpgp/armor/check
+
+crypto/openpgp/error.lo: $(go_crypto_openpgp_error_files)
+ $(BUILDPACKAGE)
+crypto/openpgp/error/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/openpgp/error
+ $(CHECK)
+.PHONY: crypto/openpgp/error/check
+
+crypto/openpgp/s2k.lo: $(go_crypto_openpgp_s2k_files) crypto/md5.gox \
+ crypto/openpgp/error.gox crypto/ripemd160.gox crypto/sha1.gox \
+ crypto/sha256.gox crypto/sha512.gox hash.gox io.gox os.gox
+ $(BUILDPACKAGE)
+crypto/openpgp/s2k/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/openpgp/s2k
+ $(CHECK)
+.PHONY: crypto/openpgp/s2k/check
+
+debug/dwarf.lo: $(go_debug_dwarf_files) encoding/binary.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+debug/dwarf/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/dwarf
+ $(CHECK)
+.PHONY: debug/dwarf/check
+
+debug/elf.lo: $(go_debug_elf_files) bytes.gox debug/dwarf.gox \
+ encoding/binary.gox fmt.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+debug/elf/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/elf
+ $(CHECK)
+.PHONY: debug/elf/check
+
+debug/gosym.lo: $(go_debug_gosym_files) encoding/binary.gox fmt.gox os.gox \
+ strconv.gox strings.gox
+ $(BUILDPACKAGE)
+debug/gosym/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/gosym
+ $(CHECK)
+.PHONY: debug/gosym/check
+
+debug/macho.lo: $(go_debug_macho_files) bytes.gox debug/dwarf.gox \
+ encoding/binary.gox fmt.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+debug/macho/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/macho
+ $(CHECK)
+.PHONY: debug/macho/check
+
+debug/pe.lo: $(go_debug_pe_files) debug/dwarf.gox \
+ encoding/binary.gox fmt.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+debug/pe/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/pe
+ $(CHECK)
+.PHONY: debug/pe/check
+
+debug/proc.lo: $(go_debug_proc_files) container/vector.gox fmt.gox \
+ io/ioutil.gox os.gox runtime.gox strconv.gox strings.gox \
+ sync.gox syscall.gox
+ $(BUILDPACKAGE)
+debug/proc/check: $(CHECK_DEPS)
+ @$(MKDIR_P) debug/proc
+ $(CHECK)
+.PHONY: debug/proc/check
+
+encoding/ascii85.lo: $(go_encoding_ascii85_files) io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+encoding/ascii85/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/ascii85
+ $(CHECK)
+.PHONY: encoding/ascii85/check
+
+encoding/base32.lo: $(go_encoding_base32_files) io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+encoding/base32/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/base32
+ $(CHECK)
+.PHONY: encoding/base32/check
+
+encoding/base64.lo: $(go_encoding_base64_files) io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+encoding/base64/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/base64
+ $(CHECK)
+.PHONY: encoding/base64/check
+
+encoding/binary.lo: $(go_encoding_binary_files) io.gox math.gox os.gox \
+ reflect.gox
+ $(BUILDPACKAGE)
+encoding/binary/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/binary
+ $(CHECK)
+.PHONY: encoding/binary/check
+
+encoding/git85.lo: $(go_encoding_git85_files) bytes.gox io.gox os.gox \
+ strconv.gox
+ $(BUILDPACKAGE)
+encoding/git85/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/git85
+ $(CHECK)
+.PHONY: encoding/git85/check
+
+encoding/hex.lo: $(go_encoding_hex_files) os.gox strconv.gox
+ $(BUILDPACKAGE)
+encoding/hex/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/hex
+ $(CHECK)
+.PHONY: encoding/hex/check
+
+encoding/line.lo: $(go_encoding_line_files) io.gox os.gox
+ $(BUILDPACKAGE)
+encoding/line/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/line
+ $(CHECK)
+.PHONY: encoding/line/check
+
+encoding/pem.lo: $(go_encoding_pem_files) bytes.gox encoding/base64.gox
+ $(BUILDPACKAGE)
+encoding/pem/check: $(CHECK_DEPS)
+ @$(MKDIR_P) encoding/pem
+ $(CHECK)
+.PHONY: encoding/pem/check
+
+exp/datafmt.lo: $(go_exp_datafmt_files) bytes.gox container/vector.gox \
+ fmt.gox go/scanner.gox go/token.gox io.gox os.gox reflect.gox \
+ runtime.gox strconv.gox strings.gox
+ $(BUILDPACKAGE)
+exp/datafmt/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/datafmt
+ $(CHECK)
+.PHONY: exp/datafmt/check
+
+exp/draw.lo: $(go_exp_draw_files) image.gox os.gox
+ $(BUILDPACKAGE)
+exp/draw/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/draw
+ $(CHECK)
+.PHONY: exp/draw/check
+
+exp/eval.lo: $(go_exp_eval_files) big.gox go/ast.gox go/parser.gox \
+ go/scanner.gox go/token.gox fmt.gox log.gox strconv.gox \
+ strings.gox os.gox reflect.gox runtime.gox sort.gox template.gox
+ $(BUILDPACKAGE)
+exp/eval/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/eval
+ $(CHECK)
+.PHONY: exp/eval/check
+
+go/ast.lo: $(go_go_ast_files) fmt.gox go/token.gox io.gox os.gox reflect.gox \
+ unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+go/ast/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/ast
+ $(CHECK)
+.PHONY: go/ast/check
+
+go/doc.lo: $(go_go_doc_files) go/ast.gox go/token.gox io.gox regexp.gox \
+ sort.gox strings.gox template.gox
+ $(BUILDPACKAGE)
+go/doc/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/doc
+ $(CHECK)
+.PHONY: go/doc/check
+
+go/parser.lo: $(go_go_parser_files) bytes.gox fmt.gox go/ast.gox \
+ go/scanner.gox go/token.gox io.gox io/ioutil.gox os.gox \
+ path.gox strings.gox
+ $(BUILDPACKAGE)
+go/parser/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/parser
+ $(CHECK)
+.PHONY: go/parser/check
+
+go/printer.lo: $(go_go_printer_files) bytes.gox fmt.gox go/ast.gox \
+ go/token.gox io.gox os.gox reflect.gox runtime.gox \
+ strings.gox tabwriter.gox
+ $(BUILDPACKAGE)
+go/printer/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/printer
+ $(CHECK)
+.PHONY: go/printer/check
+
+go/scanner.lo: $(go_go_scanner_files) bytes.gox container/vector.gox fmt.gox \
+ go/token.gox io.gox os.gox path.gox sort.gox strconv.gox \
+ unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+go/scanner/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/scanner
+ $(CHECK)
+.PHONY: go/scanner/check
+
+go/token.lo: $(go_go_token_files) fmt.gox strconv.gox
+ $(BUILDPACKAGE)
+go/token/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/token
+ $(CHECK)
+.PHONY: go/token/check
+
+go/typechecker.lo: $(go_go_typechecker_files) fmt.gox go/ast.gox go/token.gox \
+ go/scanner.gox os.gox
+ $(BUILDPACKAGE)
+go/typechecker/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/typechecker
+ $(CHECK)
+.PHONY: go/typechecker/check
+
+hash/adler32.lo: $(go_hash_adler32_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+hash/adler32/check: $(CHECK_DEPS)
+ @$(MKDIR_P) hash/adler32
+ $(CHECK)
+.PHONY: hash/adler32/check
+
+hash/crc32.lo: $(go_hash_crc32_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+hash/crc32/check: $(CHECK_DEPS)
+ @$(MKDIR_P) hash/crc32
+ $(CHECK)
+.PHONY: hash/crc32/check
+
+hash/crc64.lo: $(go_hash_crc64_files) hash.gox os.gox
+ $(BUILDPACKAGE)
+hash/crc64/check: $(CHECK_DEPS)
+ @$(MKDIR_P) hash/crc64
+ $(CHECK)
+.PHONY: hash/crc64/check
+
+http/pprof.lo: $(go_http_pprof_files) bufio.gox fmt.gox http.gox os.gox \
+ runtime.gox runtime/pprof.gox strconv.gox strings.gox
+ $(BUILDPACKAGE)
+http/pprof/check: $(CHECK_DEPS)
+ @$(MKDIR_P) http/pprof
+ $(CHECK)
+.PHONY: http/pprof/check
+
+image/jpeg.lo: $(go_image_jpeg_files) bufio.gox image.gox io.gox os.gox
+ $(BUILDPACKAGE)
+image/jpeg/check: $(CHECK_DEPS)
+ @$(MKDIR_P) image/jpeg
+ $(CHECK)
+.PHONY: image/jpeg/check
+
+image/png.lo: $(go_image_png_files) bufio.gox compress/zlib.gox fmt.gox \
+ hash.gox hash/crc32.gox image.gox io.gox os.gox strconv.gox
+ $(BUILDPACKAGE)
+image/png/check: $(CHECK_DEPS)
+ @$(MKDIR_P) image/png
+ $(CHECK)
+.PHONY: image/png/check
+
+index/suffixarray.lo: $(go_index_suffixarray_files) bytes.gox regexp.gox \
+ sort.gox
+ $(BUILDPACKAGE)
+index/suffixarray/check: $(CHECK_DEPS)
+ @$(MKDIR_P) index/suffixarray
+ $(CHECK)
+.PHONY: index/suffixarray/check
+
+io/ioutil.lo: $(go_io_ioutil_files) bytes.gox io.gox os.gox sort.gox \
+ strconv.gox
+ $(BUILDPACKAGE)
+io/ioutil/check: $(CHECK_DEPS)
+ @$(MKDIR_P) io/ioutil
+ $(CHECK)
+.PHONY: io/ioutil/check
+
+mime/multipart.lo: $(go_mime_multipart_files) bufio.gox bytes.gox io.gox \
+ mime.gox os.gox regexp.gox strings.gox
+ $(BUILDPACKAGE)
+mime/multipart/check: $(CHECK_DEPS)
+ @$(MKDIR_P) mime/multipart
+ $(CHECK)
+.PHONY: mime/multipart/check
+
+net/dict.lo: $(go_net_dict_files) container/vector.gox net/textproto.gox \
+ os.gox strconv.gox strings.gox
+ $(BUILDPACKAGE)
+
+net/textproto.lo: $(go_net_textproto_files) bufio.gox bytes.gox \
+ container/vector.gox fmt.gox io.gox io/ioutil.gox net.gox \
+ os.gox strconv.gox sync.gox
+ $(BUILDPACKAGE)
+net/textproto/check: $(CHECK_DEPS)
+ @$(MKDIR_P) net/textproto
+ $(CHECK)
+.PHONY: net/textproto/check
+
+os/inotify.lo: $(go_os_inotify_files) fmt.gox os.gox strings.gox syscall.gox
+ $(BUILDPACKAGE)
+os/inotify/check: $(CHECK_DEPS)
+ @$(MKDIR_P) os/inotify
+ $(CHECK)
+.PHONY: os/inotify/check
+
+os/signal.lo: $(go_os_signal_files) runtime.gox strconv.gox
+ $(BUILDPACKAGE)
+os/signal/check: $(CHECK_DEPS)
+ @$(MKDIR_P) os/signal
+ $(CHECK)
+.PHONY: os/signal/check
+
+unix.go: $(srcdir)/go/os/signal/mkunix.sh sysinfo.go
+ $(SHELL) $(srcdir)/go/os/signal/mkunix.sh sysinfo.go > $@.tmp
+ mv -f $@.tmp $@
+
+rpc/jsonrpc.lo: $(go_rpc_jsonrpc_files) fmt.gox io.gox json.gox net.gox \
+ os.gox rpc.gox sync.gox
+ $(BUILDPACKAGE)
+rpc/jsonrpc/check: $(CHECK_DEPS)
+ @$(MKDIR_P) rpc/jsonrpc
+ $(CHECK)
+.PHONY: rpc/jsonrpc/check
+
+runtime/debug.lo: $(go_runtime_debug_files) bytes.gox fmt.gox io/ioutil.gox \
+ os.gox runtime.gox
+ $(BUILDPACKAGE)
+runtime/debug/check: $(CHECK_DEPS)
+ @$(MKDIR_P) runtime/debug
+ $(CHECK)
+.PHONY: runtime/debug/check
+
+runtime/pprof.lo: $(go_runtime_pprof_files) bufio.gox fmt.gox io.gox os.gox \
+ runtime.gox
+ $(BUILDPACKAGE)
+runtime/pprof/check: $(CHECK_DEPS)
+ @$(MKDIR_P) runtime/pprof
+ $(CHECK)
+.PHONY: runtime/pprof/check
+
+testing/iotest.lo: $(go_testing_iotest_files) io.gox log.gox os.gox
+ $(BUILDPACKAGE)
+testing/iotest/check: $(CHECK_DEPS)
+ @$(MKDIR_P) testing/iotest
+ $(CHECK)
+.PHONY: testing/iotest/check
+
+testing/quick.lo: $(go_testing_quick_files) flag.gox fmt.gox math.gox os.gox \
+ rand.gox reflect.gox strings.gox
+ $(BUILDPACKAGE)
+testing/quick/check: $(CHECK_DEPS)
+ @$(MKDIR_P) testing/quick
+ $(CHECK)
+.PHONY: testing/quick/check
+
+testing/script.lo: $(go_testing_script_files) fmt.gox os.gox rand.gox \
+ reflect.gox strings.gox
+ $(BUILDPACKAGE)
+testing/script/check: $(CHECK_DEPS)
+ @$(MKDIR_P) testing/script
+ $(CHECK)
+.PHONY: testing/script/check
+
+sysinfo.go: s-sysinfo; @true
+s-sysinfo: $(srcdir)/mksysinfo.sh config.h
+ CC="$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS)" $(SHELL) $(srcdir)/mksysinfo.sh
+ $(SHELL) $(srcdir)/../move-if-change tmp-sysinfo.go sysinfo.go
+ $(STAMP) $@
+
+syscalls/syscall.lo: $(go_syscall_files) sync.gox
+ $(BUILDPACKAGE)
+syscalls/errno.lo: $(go_syscall_c_files) syscalls/syscall.lo
+ $(LTCOMPILE) -c -o $@ $(srcdir)/syscalls/errno.c
+
+asn1.gox: asn1/asn1.lo
+ $(BUILDGOX)
+big.gox: big/big.lo
+ $(BUILDGOX)
+bufio.gox: bufio/bufio.lo
+ $(BUILDGOX)
+bytes.gox: bytes/bytes.lo
+ $(BUILDGOX)
+cmath.gox: cmath/cmath.lo
+ $(BUILDGOX)
+ebnf.gox: ebnf/ebnf.lo
+ $(BUILDGOX)
+exec.gox: exec/exec.lo
+ $(BUILDGOX)
+expvar.gox: expvar/expvar.lo
+ $(BUILDGOX)
+flag.gox: flag/flag.lo
+ $(BUILDGOX)
+fmt.gox: fmt/fmt.lo
+ $(BUILDGOX)
+gob.gox: gob/gob.lo
+ $(BUILDGOX)
+hash.gox: hash/hash.lo
+ $(BUILDGOX)
+html.gox: html/html.lo
+ $(BUILDGOX)
+http.gox: http/http.lo
+ $(BUILDGOX)
+image.gox: image/image.lo
+ $(BUILDGOX)
+io.gox: io/io.lo
+ $(BUILDGOX)
+json.gox: json/json.lo
+ $(BUILDGOX)
+log.gox: log/log.lo
+ $(BUILDGOX)
+math.gox: math/math.lo
+ $(BUILDGOX)
+mime.gox: mime/mime.lo
+ $(BUILDGOX)
+net.gox: net/net.lo
+ $(BUILDGOX)
+netchan.gox: netchan/netchan.lo
+ $(BUILDGOX)
+os.gox: os/os.lo
+ $(BUILDGOX)
+patch.gox: patch/patch.lo
+ $(BUILDGOX)
+path.gox: path/path.lo
+ $(BUILDGOX)
+rand.gox: rand/rand.lo
+ $(BUILDGOX)
+reflect.gox: reflect/reflect.lo
+ $(BUILDGOX)
+regexp.gox: regexp/regexp.lo
+ $(BUILDGOX)
+rpc.gox: rpc/rpc.lo
+ $(BUILDGOX)
+runtime.gox: runtime/runtime.lo
+ $(BUILDGOX)
+scanner.gox: scanner/scanner.lo
+ $(BUILDGOX)
+smtp.gox: smtp/smtp.lo
+ $(BUILDGOX)
+sort.gox: sort/sort.lo
+ $(BUILDGOX)
+strconv.gox: strconv/strconv.lo
+ $(BUILDGOX)
+strings.gox: strings/strings.lo
+ $(BUILDGOX)
+sync.gox: sync/mutex.lo
+ $(BUILDGOX)
+syslog.gox: syslog/syslog.lo
+ $(BUILDGOX)
+syscall.gox: syscalls/syscall.lo
+ $(BUILDGOX)
+tabwriter.gox: tabwriter/tabwriter.lo
+ $(BUILDGOX)
+template.gox: template/template.lo
+ $(BUILDGOX)
+testing.gox: testing/testing.lo
+ $(BUILDGOX)
+time.gox: time/time.lo
+ $(BUILDGOX)
+try.gox: try/try.lo
+ $(BUILDGOX)
+unicode.gox: unicode/unicode.lo
+ $(BUILDGOX)
+utf16.gox: utf16/utf16.lo
+ $(BUILDGOX)
+utf8.gox: utf8/utf8.lo
+ $(BUILDGOX)
+websocket.gox: websocket/websocket.lo
+ $(BUILDGOX)
+xml.gox: xml/xml.lo
+ $(BUILDGOX)
+
+archive/tar.gox: archive/tar.lo
+ $(BUILDGOX)
+archive/zip.gox: archive/zip.lo
+ $(BUILDGOX)
+
+compress/flate.gox: compress/flate.lo
+ $(BUILDGOX)
+compress/gzip.gox: compress/gzip.lo
+ $(BUILDGOX)
+compress/zlib.gox: compress/zlib.lo
+ $(BUILDGOX)
+
+container/heap.gox: container/heap.lo
+ $(BUILDGOX)
+container/list.gox: container/list.lo
+ $(BUILDGOX)
+container/ring.gox: container/ring.lo
+ $(BUILDGOX)
+container/vector.gox: container/vector.lo
+ $(BUILDGOX)
+
+crypto/aes.gox: crypto/aes.lo
+ $(BUILDGOX)
+crypto/block.gox: crypto/block.lo
+ $(BUILDGOX)
+crypto/blowfish.gox: crypto/blowfish.lo
+ $(BUILDGOX)
+crypto/cast5.gox: crypto/cast5.lo
+ $(BUILDGOX)
+crypto/cipher.gox: crypto/cipher.lo
+ $(BUILDGOX)
+crypto/elliptic.gox: crypto/elliptic.lo
+ $(BUILDGOX)
+crypto/hmac.gox: crypto/hmac.lo
+ $(BUILDGOX)
+crypto/md4.gox: crypto/md4.lo
+ $(BUILDGOX)
+crypto/md5.gox: crypto/md5.lo
+ $(BUILDGOX)
+crypto/ocsp.gox: crypto/ocsp.lo
+ $(BUILDGOX)
+crypto/rand.gox: crypto/rand.lo
+ $(BUILDGOX)
+crypto/rc4.gox: crypto/rc4.lo
+ $(BUILDGOX)
+crypto/ripemd160.gox: crypto/ripemd160.lo
+ $(BUILDGOX)
+crypto/rsa.gox: crypto/rsa.lo
+ $(BUILDGOX)
+crypto/sha1.gox: crypto/sha1.lo
+ $(BUILDGOX)
+crypto/sha256.gox: crypto/sha256.lo
+ $(BUILDGOX)
+crypto/sha512.gox: crypto/sha512.lo
+ $(BUILDGOX)
+crypto/subtle.gox: crypto/subtle.lo
+ $(BUILDGOX)
+crypto/tls.gox: crypto/tls.lo
+ $(BUILDGOX)
+crypto/twofish.gox: crypto/twofish.lo
+ $(BUILDGOX)
+crypto/x509.gox: crypto/x509.lo
+ $(BUILDGOX)
+crypto/xtea.gox: crypto/xtea.lo
+ $(BUILDGOX)
+
+crypto/openpgp/armor.gox: crypto/openpgp/armor.lo
+ $(BUILDGOX)
+crypto/openpgp/error.gox: crypto/openpgp/error.lo
+ $(BUILDGOX)
+crypto/openpgp/s2k.gox: crypto/openpgp/s2k.lo
+ $(BUILDGOX)
+
+debug/dwarf.gox: debug/dwarf.lo
+ $(BUILDGOX)
+debug/elf.gox: debug/elf.lo
+ $(BUILDGOX)
+debug/gosym.gox: debug/gosym.lo
+ $(BUILDGOX)
+debug/macho.gox: debug/macho.lo
+ $(BUILDGOX)
+debug/pe.gox: debug/pe.lo
+ $(BUILDGOX)
+debug/proc.gox: debug/proc.lo
+ $(BUILDGOX)
+
+encoding/ascii85.gox: encoding/ascii85.lo
+ $(BUILDGOX)
+encoding/base32.gox: encoding/base32.lo
+ $(BUILDGOX)
+encoding/base64.gox: encoding/base64.lo
+ $(BUILDGOX)
+encoding/binary.gox: encoding/binary.lo
+ $(BUILDGOX)
+encoding/git85.gox: encoding/git85.lo
+ $(BUILDGOX)
+encoding/hex.gox: encoding/hex.lo
+ $(BUILDGOX)
+encoding/line.gox: encoding/line.lo
+ $(BUILDGOX)
+encoding/pem.gox: encoding/pem.lo
+ $(BUILDGOX)
+
+exp/datafmt.gox: exp/datafmt.lo
+ $(BUILDGOX)
+exp/draw.gox: exp/draw.lo
+ $(BUILDGOX)
+exp/eval.gox: exp/eval.lo
+ $(BUILDGOX)
+
+go/ast.gox: go/ast.lo
+ $(BUILDGOX)
+go/doc.gox: go/doc.lo
+ $(BUILDGOX)
+go/parser.gox: go/parser.lo
+ $(BUILDGOX)
+go/printer.gox: go/printer.lo
+ $(BUILDGOX)
+go/scanner.gox: go/scanner.lo
+ $(BUILDGOX)
+go/token.gox: go/token.lo
+ $(BUILDGOX)
+go/typechecker.gox: go/typechecker.lo
+ $(BUILDGOX)
+
+hash/adler32.gox: hash/adler32.lo
+ $(BUILDGOX)
+hash/crc32.gox: hash/crc32.lo
+ $(BUILDGOX)
+hash/crc64.gox: hash/crc64.lo
+ $(BUILDGOX)
+
+http/pprof.gox: http/pprof.lo
+ $(BUILDGOX)
+
+image/jpeg.gox: image/jpeg.lo
+ $(BUILDGOX)
+image/png.gox: image/png.lo
+ $(BUILDGOX)
+
+index/suffixarray.gox: index/suffixarray.lo
+ $(BUILDGOX)
+
+io/ioutil.gox: io/ioutil.lo
+ $(BUILDGOX)
+
+mime/multipart.gox: mime/multipart.lo
+ $(BUILDGOX)
+
+net/dict.gox: net/dict.lo
+ $(BUILDGOX)
+net/textproto.gox: net/textproto.lo
+ $(BUILDGOX)
+
+os/inotify.gox: os/inotify.lo
+ $(BUILDGOX)
+os/signal.gox: os/signal.lo
+ $(BUILDGOX)
+
+rpc/jsonrpc.gox: rpc/jsonrpc.lo
+ $(BUILDGOX)
+
+runtime/debug.gox: runtime/debug.lo
+ $(BUILDGOX)
+runtime/pprof.gox: runtime/pprof.lo
+ $(BUILDGOX)
+
+testing/iotest.gox: testing/iotest.lo
+ $(BUILDGOX)
+testing/quick.gox: testing/quick.lo
+ $(BUILDGOX)
+testing/script.gox: testing/script.lo
+ $(BUILDGOX)
+
+check-recursive: $(TEST_PACKAGES)
+
+mostlyclean-local:
+ find . -name '*.lo' -print | xargs $(LIBTOOL) --mode=clean rm -f
+ find . -name '*.$(OBJEXT)' -print | xargs rm -f
+
+clean-local:
+ find . -name '*.la' -print | xargs $(LIBTOOL) --mode=clean rm -f
+ find . -name '*.a' -print | xargs rm -f
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libgo/PATENTS b/libgo/PATENTS
new file mode 100644
index 000000000..733099041
--- /dev/null
+++ b/libgo/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/libgo/README b/libgo/README
new file mode 100644
index 000000000..732c3526c
--- /dev/null
+++ b/libgo/README
@@ -0,0 +1,45 @@
+See ../README.
+
+This is the runtime support library for the Go programming language.
+This library is intended for use with the Go frontend.
+
+The library has only been tested on GNU/Linux using glibc. It should
+not be difficult to port to other operating systems.
+
+The library has only been tested on x86/x86_64 systems. It should not
+be difficult to port to other architectures.
+
+Directories:
+
+go
+ A copy of the Go library from http://golang.org/, with a few
+ changes for gccgo. Notably, the reflection interface is different.
+
+runtime
+ Runtime functions, written in C, which are called directly by the
+ compiler or by the library.
+
+syscalls
+ System call support.
+
+Contributing
+============
+
+To contribute patches to the files in this directory, please see
+http://golang.org/doc/gccgo_contribute.html .
+
+The master copy of these files is hosted at
+http://code.google.com/p/gofrontend . Changes to these files require
+signing a Google contributor license agreement. If you are the
+copyright holder, you will need to agree to the individual contributor
+license agreement at
+http://code.google.com/legal/individual-cla-v1.0.html. This agreement
+can be completed online.
+
+If your organization is the copyright holder, the organization will
+need to agree to the corporate contributor license agreement at
+http://code.google.com/legal/corporate-cla-v1.0.html.
+
+If the copyright holder for your code has already completed the
+agreement in connection with another Google open source project, it
+does not need to be completed again.
diff --git a/libgo/README.gcc b/libgo/README.gcc
new file mode 100644
index 000000000..d5aabb0f9
--- /dev/null
+++ b/libgo/README.gcc
@@ -0,0 +1,7 @@
+The files in this directory are mirrored from the gofrontend project
+hosted at http://code.google.com/p/gofrontend. These files are the
+ones in the libgo subdirectory of that project.
+
+By default, the networking tests are not run. In order to run all the
+libgo tests, you need to define the environment variable
+GCCGO_RUN_ALL_TESTS to a non-empty string.
diff --git a/libgo/aclocal.m4 b/libgo/aclocal.m4
new file mode 100644
index 000000000..ca453c6f5
--- /dev/null
+++ b/libgo/aclocal.m4
@@ -0,0 +1,981 @@
+# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.64],,
+[m4_warning([this file was generated for autoconf 2.64.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
+
+# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.11'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.11.1], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.11.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 9
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 10
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], UPC, [depcc="$UPC" am_compiler_list=],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 5
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 16
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.62])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES(OBJC)],
+ [define([AC_PROG_OBJC],
+ defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
+dnl The `parallel-tests' driver may need to know about EXEEXT, so add the
+dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro
+dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+])
+
+dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST(install_sh)])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless `enable' is passed literally.
+# For symmetry, `disable' may be passed as well. Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+ [enable], [m4_define([am_maintainer_other], [disable])],
+ [disable], [m4_define([am_maintainer_other], [enable])],
+ [m4_define([am_maintainer_other], [enable])
+ m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles])
+ dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+ AC_ARG_ENABLE([maintainer-mode],
+[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ [USE_MAINTAINER_MODE=$enableval],
+ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST([MAINT])dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 6
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+ [[\\/$]]* | ?:[[\\/]]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([../config/depstand.m4])
+m4_include([../config/lead-dot.m4])
+m4_include([../config/multi.m4])
+m4_include([../config/override.m4])
+m4_include([../config/unwind_ipinfo.m4])
+m4_include([config/go.m4])
+m4_include([config/libtool.m4])
+m4_include([config/ltoptions.m4])
+m4_include([config/ltsugar.m4])
+m4_include([config/ltversion.m4])
+m4_include([config/lt~obsolete.m4])
diff --git a/libgo/config.h.in b/libgo/config.h.in
new file mode 100644
index 000000000..d6f6ac1ae
--- /dev/null
+++ b/libgo/config.h.in
@@ -0,0 +1,133 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define if _Unwind_GetIPInfo is available. */
+#undef HAVE_GETIPINFO
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if the system has the type `off64_t'. */
+#undef HAVE_OFF64_T
+
+/* Define to 1 if you have the `random' function. */
+#undef HAVE_RANDOM
+
+/* Define to 1 if you have the `srandom' function. */
+#undef HAVE_SRANDOM
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strsignal' function. */
+#undef HAVE_STRSIGNAL
+
+/* Define to 1 if the compiler provides the __sync_bool_compare_and_swap
+ function for uint32 */
+#undef HAVE_SYNC_BOOL_COMPARE_AND_SWAP_4
+
+/* Define to 1 if the compiler provides the __sync_fetch_and_add function for
+ uint32 */
+#undef HAVE_SYNC_FETCH_AND_ADD_4
+
+/* Define to 1 if you have the <syscall.h> header file. */
+#undef HAVE_SYSCALL_H
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#undef HAVE_SYS_EPOLL_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/ptrace.h> header file. */
+#undef HAVE_SYS_PTRACE_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#undef HAVE_SYS_SYSCALL_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/user.h> header file. */
+#undef HAVE_SYS_USER_H
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#undef HAVE_SYS_UTSNAME_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if the C++ compiler is configured for setjmp/longjmp exceptions. */
+#undef LIBGO_SJLJ_EXCEPTIONS
+
+/* Define if the linker support split stack adjustments */
+#undef LINKER_SUPPORTS_SPLIT_STACK
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if we're to use libffi. */
+#undef USE_LIBFFI
+
+/* Define if the compiler supports -fsplit-stack */
+#undef USING_SPLIT_STACK
+
+/* Version number of package */
+#undef VERSION
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
diff --git a/libgo/config/README b/libgo/config/README
new file mode 100644
index 000000000..06e8bf515
--- /dev/null
+++ b/libgo/config/README
@@ -0,0 +1,2 @@
+This directory holds files needed temporarily until Go support is
+added to autoconf and libtool.
diff --git a/libgo/config/go.m4 b/libgo/config/go.m4
new file mode 100644
index 000000000..65a27cbdf
--- /dev/null
+++ b/libgo/config/go.m4
@@ -0,0 +1,92 @@
+dnl acinclude.m4 -- configure macros
+
+dnl Copyright 2009 The Go Authors. All rights reserved.
+dnl Use of this source code is governed by a BSD-style
+dnl license that can be found in the LICENSE file.
+
+dnl Go support--this could be in autoconf.
+dnl This version is probably autoconf 2.64 specific.
+
+AC_LANG_DEFINE([Go], [go], [GO], [],
+[ac_ext=go
+ac_compile='$GOC -c $GOCFLAGS conftest.$ac_ext >&AS_MESSAGE_LOG_FD'
+ac_link='$GOC -o conftest$ac_exeext $GOCFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&AS_MESSAGE_LOG_FD'
+ac_compile_gnu=yes
+])
+
+AU_DEFUN([AC_LANG_GO], [AC_LANG(Go)])
+
+m4_define([AC_LANG_PROGRAM(Go)],
+[package main
+$1
+func main() {
+$2
+}])
+
+m4_define([AC_LANG_IO_PROGRAM(Go)],
+[AC_LANG_PROGRAM([import "os"],
+[if f, err := os.Open("conftest.out", os.O_WRONLY), err != nil {
+ os.Exit(1);
+ }
+ if err := f.Close(); err != nil {
+ os.Exit(1);
+ }
+ os.Exit(0);
+])])
+
+m4_define([AC_LANG_CALL(Go)],
+[AC_LANG_PROGRAM([$1
+m4_if([$2], [main], ,
+[func $2();])],[$2();])])
+
+m4_define([AC_LANG_FUNC_LINK_TRY(Go)],
+[AC_LANG_PROGRAM(
+[func $1() int;
+var f := $1;
+], [return f();])])
+
+m4_define([AC_LANG_BOOL_COMPILE_TRY(Go)],
+[AC_LANG_PROGRAM([$1], [var test_array @<:@1 - 2 * !($2)@:>@;
+test_array @<:@0@:>@ = 0
+])])
+
+m4_define([AC_LANG_INT_SAVE(Go)],
+[AC_LANG_PROGRAM([$1
+import os
+func longval() long { return $2 }
+func ulongval() ulong { return $2 }],
+[panic("unimplemented")])])
+
+AC_DEFUN([AC_LANG_COMPILER(Go)],
+[AC_REQUIRE([AC_PROG_GO])])
+
+AN_MAKEVAR([GOC], [AC_PROG_GO])
+AN_PROGRAM([gccgo], [AC_PROG_GO])
+AC_DEFUN([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC], [Go compiler command])dnl
+AC_ARG_VAR([GOCFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+m4_ifval([$1],
+ [AC_CHECK_TOOLS(GOC, [$1])],
+[AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+ if test -n "$ac_tool_prefix"; then
+ AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [$ac_tool_prefix}gccgo])
+ fi
+fi
+if test -z "$GOC"; then
+ AC_CHECK_PROG(GOC, gccgo, gccgo, , , gccgo)
+fi
+])
+
+# Provide some information about the compiler.
+_AS_ECHO_LOG([checking for _AC_LANG compiler version])
+set X $ac_compile
+ac_compiler=$[2]
+_AC_DO_LIMIT([$ac_compiler --version >&AS_MESSAGE_LOG_FD])
+m4_expand_once([_AC_COMPILER_EXEEXT])[]dnl
+m4_expand_once([_AC_COMPILER_OBJEXT])[]dnl
+GOCFLAGS="-g -O2"
+AC_LANG_POP(Go)dnl
+])# AC_PROG_GO
diff --git a/libgo/config/libtool.m4 b/libgo/config/libtool.m4
new file mode 100644
index 000000000..a546739eb
--- /dev/null
+++ b/libgo/config/libtool.m4
@@ -0,0 +1,7516 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 56 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+ [m4_default([$3],
+ [m4_fatal([Libtool version $1 or higher is required],
+ 63)])],
+ [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+ *\ * | *\ *)
+ AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ _LT_PATH_MAGIC
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+ [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME. Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+ [m4_ifval([$1], [$1], [$2])])
+ lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+ m4_ifval([$4],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+ lt_dict_add_subkey([lt_decl_dict], [$2],
+ [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+ [0], [m4_fatal([$0: too few arguments: $#])],
+ [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+ [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+ [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+ m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_if([$2], [],
+ m4_quote(lt_decl_varnames),
+ m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+ lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'. VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly. In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+ [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+# # Some comment about what VAR is for.
+# visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+ [description])))[]dnl
+m4_pushdef([_libtool_name],
+ m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+ [0], [_libtool_name=[$]$1],
+ [1], [_libtool_name=$lt_[]$1],
+ [2], [_libtool_name=$lt_[]$1],
+ [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+ m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'. Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+ dnl If the libtool generation code has been placed in $CONFIG_LT,
+ dnl instead of duplicating it all over again into config.status,
+ dnl then we will have config.status run $CONFIG_LT later, so it
+ dnl needs to know what name is stored there:
+ [AC_CONFIG_COMMANDS([libtool],
+ [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+ dnl If the libtool generation code is destined for config.status,
+ dnl expand the accumulated commands and init code now:
+ [AC_CONFIG_COMMANDS([libtool],
+ [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable. If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins. After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script. The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+ echo
+ AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+ case $[1] in
+ --version | --v* | -V )
+ echo "$lt_cl_version"; exit 0 ;;
+ --help | --h* | -h )
+ echo "$lt_cl_help"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --quiet | --q* | --silent | --s* | -q )
+ lt_cl_silent=: ;;
+
+ -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+ *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+ esac
+ shift
+done
+
+if $lt_cl_silent; then
+ exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure. Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+ lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars. Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+ m4_if(_LT_TAG, [C], [
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+ _LT_PROG_LTMAIN
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ _LT_PROG_XSI_SHELLFNS
+
+ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+# autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+ [C], [_LT_LANG(C)],
+ [C++], [_LT_LANG(CXX)],
+ [Go], [_LT_LANG(GO)],
+ [Java], [_LT_LANG(GCJ)],
+ [Fortran 77], [_LT_LANG(F77)],
+ [Fortran], [_LT_LANG(FC)],
+ [Windows Resource], [_LT_LANG(RC)],
+ [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+ [_LT_LANG($1)],
+ [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+ [LT_SUPPORTED_TAG([$1])dnl
+ m4_append([_LT_TAGS], [$1 ])dnl
+ m4_define([_LT_LANG_]$1[_enabled], [])dnl
+ _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [LT_LANG(CXX)],
+ [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [LT_LANG(F77)],
+ [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+ [LT_LANG(FC)],
+ [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [m4_ifdef([AC_PROG_GCJ],
+ [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([A][M_PROG_GCJ],
+ [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([LT_PROG_GCJ],
+ [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+ [LT_LANG(GO)],
+ [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+ [LT_LANG(RC)],
+ [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+ case $host_os in
+ rhapsody* | darwin*)
+ AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+ AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+ AC_CHECK_TOOL([LIPO], [lipo], [:])
+ AC_CHECK_TOOL([OTOOL], [otool], [:])
+ AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+ _LT_DECL([], [DSYMUTIL], [1],
+ [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+ _LT_DECL([], [NMEDIT], [1],
+ [Tool to change global to local symbols on Mac OS X])
+ _LT_DECL([], [LIPO], [1],
+ [Tool to manipulate fat objects and archives on Mac OS X])
+ _LT_DECL([], [OTOOL], [1],
+ [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+ _LT_DECL([], [OTOOL64], [1],
+ [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+ AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+ [lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi])
+ AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+ [lt_cv_ld_exported_symbols_list],
+ [lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [lt_cv_ld_exported_symbols_list=yes],
+ [lt_cv_ld_exported_symbols_list=no])
+ LDFLAGS="$save_LDFLAGS"
+ ])
+ AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+ [lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+ echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+ $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+ ])
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES
+# --------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+ m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ m4_if([$1], [CXX],
+[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+ fi
+],[])
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX
+# -----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`print -r -- -n 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+case "$ECHO" in
+ printf*) AC_MSG_RESULT([printf]) ;;
+ print*) AC_MSG_RESULT([print -r]) ;;
+ *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test "X`printf %s $ECHO`" = "X$ECHO" \
+ || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AS_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD="${LD-ld}_sol2"
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[AC_CHECK_TOOL(AR, ar, false)
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1])
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+ [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+ [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+ [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ fi
+ $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$5], , :, [$5])
+else
+ m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $3"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ else
+ $2=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$4], , :, [$4])
+else
+ m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+ [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+[#line __oline__ "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}]
+_LT_EOF
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_dlunknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen="shl_load"],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen="dlopen"],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+ [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+ [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+ [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+ [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test "$hard_links" = no; then
+ AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+ [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+ [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+ test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+ test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+ test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+ test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+ [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+ [], [
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+ *) lt_sed_strip_eq="s,=/,/,g" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[[4-9]]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[[45]]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[123]]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+haiku*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[[3-9]]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+ [lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+ [lt_cv_shlibpath_overrides_runpath=yes])])
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+ ])
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[[89]] | openbsd2.[[89]].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+ [Variables whose values should be saved in libtool wrapper scripts and
+ restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+ [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+ [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+ [[List of archive names. First name is the real one, the rest are links.
+ The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+ [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+ [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+ [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+ [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+ [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+ [[As "finish_cmds", except a single script fragment to be evaled but
+ not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+ [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+ [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+ [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="m4_if([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$1; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+ [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+ [AS_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test "$withval" = no || with_gnu_ld=yes],
+ [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[[45]]*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[[3-9]]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+ [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+ [Command to use when deplibs_check_method == "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+ AC_SUBST([DUMPBIN])
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+ [lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+ cat conftest.out >&AS_MESSAGE_LOG_FD
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM="-lm")
+ ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+ esac
+
+ _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+ [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris*)
+ symcode='[[BDRT]]'
+ ;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK ['"\
+" {last_section=section; section=\$ 3};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx]"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+ [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+ [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+ [lt_cv_sys_global_symbol_to_c_name_address], [1],
+ [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+ [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+ [Transform the output of nm in a C name address pair when lib prefix is needed])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+m4_if([$1], [CXX], [
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[[4-9]]*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64 which still supported -KPIC.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+ # IBM XL 8.0, 9.0 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd*)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xcompiler -fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ ccc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ F* | *Sun*Fortran*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ rdos*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+ [How to pass a linker flag through the compiler])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+ [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+ [Additional compiler flags for building library objects])
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+ [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ case $host_os in
+ aix[[4-9]]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global defined
+ # symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+ ;;
+ cygwin* | mingw* | cegcc*)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+], [
+ runpath_var=
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(archive_cmds, $1)=
+ _LT_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_TAGVAR(compiler_needs_object, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(hardcode_automatic, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(inherit_rpath, $1)=no
+ _LT_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_TAGVAR(module_cmds, $1)=
+ _LT_TAGVAR(module_expsym_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+ *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[[3-9]]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ tmp_sharedflag='--shared' ;;
+ xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+ runpath_var=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[[45]]*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ m4_if($1, [], [
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ _LT_LINKER_OPTION([if $CC understands -b],
+ _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+ [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ AC_LINK_IFELSE(int foo(void) {},
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ )
+ LDFLAGS="$save_LDFLAGS"
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ else
+ case $host_os in
+ openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+ [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $_LT_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+ [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+ [$RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+ then
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ ])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+ [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+ [enable_shared_with_static_runtimes], [0],
+ [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+ [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+ [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+ [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+ [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+ [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+ [Commands used to build a loadable module if different from building
+ a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+ [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+ [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+ [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+ [Flag to hardcode $libdir into a binary during linking.
+ This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1],
+ [[If ld is used when linking, flag to hardcode $libdir into a binary
+ during linking. This must work even if $libdir does not exist]])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+ [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary and the resulting library dependency is
+ "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+ library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+ [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+ [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+ [Set to "yes" if building a shared library automatically hardcodes DIR
+ into the library and all subsequent libraries and executables linked
+ against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+ [Set to yes if linker adds runtime paths of dependent libraries
+ to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+ [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [fix_srcfile_path], [1],
+ [Fix the shell variable $srcfile for the compiler])
+_LT_TAGDECL([], [always_export_symbols], [0],
+ [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+ [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+ [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+ [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+ [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [file_list_spec], [1],
+ [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+ LT_SYS_DLOPEN_SELF
+ _LT_CMD_STRIPLIB
+
+ # Report which library types will actually be built
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ AC_PROG_CXXCPP
+else
+ _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ else
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+ fi
+
+ if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+ LT_PATH_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared
+ # libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ freebsd[[12]]*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ freebsd-elf*)
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ gnu*)
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ hpux9*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+ fi
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ ;;
+ xl* | mpixl* | bgxl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=func_echo_all
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+ $RM $lib.exp'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ case $host in
+ osf3*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ fi
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+ '"$_LT_TAGVAR(old_archive_cmds, $1)"
+ _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+ '"$_LT_TAGVAR(reload_cmds, $1)"
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+ test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+ _LT_TAGVAR(GCC, $1)="$GXX"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() { }
+_LT_EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" ||
+ test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+ _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+ _LT_TAGVAR(predep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+ _LT_TAGVAR(postdep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_TAGVAR(predep_objects,$1)=
+ _LT_TAGVAR(postdep_objects,$1)=
+ _LT_TAGVAR(postdeps,$1)=
+ ;;
+
+linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC*)
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+ [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+ [Dependencies to place before and after the objects being linked to
+ create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+ [The library search path used internally by the compiler when linking
+ a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+ _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ CC=${F77-"f77"}
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+ GCC=$G77
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$G77"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC="$lt_save_CC"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+ _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ CC=${FC-"f95"}
+ compiler=$CC
+ GCC=$ac_cv_fc_compiler_gnu
+
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC="$lt_save_CC"
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC="$lt_save_CC"
+])# _LT_LANG_GCJ_CONFIG
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC="$GCC"
+GCC=yes
+CC=${GOC-"gccgo"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC="$lt_save_CC"
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+ :
+ _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+ [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+ [AC_CHECK_TOOL(GCJ, gcj,)
+ test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+# LT_PROG_GO
+# -----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+ [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_XSI_SHELLFNS
+# ---------------------
+# Bourne and XSI compatible variants of some useful shell functions.
+m4_defun([_LT_PROG_XSI_SHELLFNS],
+[case $xsi_shell in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+ func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=${1%%=*}
+ func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=$(( $[*] ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=${#1}
+}
+
+_LT_EOF
+ ;;
+ *) # Bourne compatible functions.
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+}
+
+dnl func_dirname_and_basename
+dnl A portable version of this function is already defined in general.m4sh
+dnl so there is no need for it here.
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[[^=]]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"`
+ func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=`$ECHO "${1}" | $SED 's/\.[[^.]]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=`expr "$[@]"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$[1]+=\$[2]"
+}
+_LT_EOF
+ ;;
+ *)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$[1]=\$$[1]\$[2]"
+}
+
+_LT_EOF
+ ;;
+ esac
+])
diff --git a/libgo/config/ltmain.sh b/libgo/config/ltmain.sh
new file mode 100644
index 000000000..b73de525b
--- /dev/null
+++ b/libgo/config/ltmain.sh
@@ -0,0 +1,8636 @@
+# Generated from ltmain.m4sh.
+
+# libtool (GNU libtool 1.3134 2009-11-29) 2.2.7a
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+# --config show all configuration variables
+# --debug enable verbose shell tracing
+# -n, --dry-run display commands without modifying any files
+# --features display basic configuration information and exit
+# --mode=MODE use operation mode MODE
+# --no-finish let install mode avoid finish commands
+# --preserve-dup-deps don't remove duplicate dependency libraries
+# --quiet, --silent don't print informational messages
+# --no-quiet, --no-silent
+# print informational messages (default)
+# --tag=TAG use configuration variables from tag TAG
+# -v, --verbose print more informational messages than default
+# --no-verbose don't print the extra informational messages
+# --version print version information
+# -h, --help, --help-all print short, long, or detailed help message
+#
+# MODE must be one of the following:
+#
+# clean remove files from the build directory
+# compile compile a source file into a libtool object
+# execute automatically set library path, then run a program
+# finish complete the installation of libtool libraries
+# install install libraries or executables
+# link create a library or an executable
+# uninstall remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE. When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+# host-triplet: $host
+# shell: $SHELL
+# compiler: $LTCC
+# compiler flags: $LTCFLAGS
+# linker: $LD (gnu? $with_gnu_ld)
+# $progname: (GNU libtool 1.3134 2009-11-29) 2.2.7a
+# automake: $automake_version
+# autoconf: $autoconf_version
+#
+# Report bugs to <bug-libtool@gnu.org>.
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION=2.2.7a
+TIMESTAMP=" 1.3134 2009-11-29"
+package_revision=1.3134
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# NLS nuisances: We save the old values to restore during execute mode.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+ eval "if test \"\${$lt_var+set}\" = set; then
+ save_$lt_var=\$$lt_var
+ $lt_var=C
+ export $lt_var
+ lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+ lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+ fi"
+done
+
+$lt_unset CDPATH
+
+
+
+
+
+
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+
+
+: ${CP="cp -f"}
+: ${ECHO=$as_echo}
+: ${EGREP="/bin/grep -E"}
+: ${FGREP="/bin/grep -F"}
+: ${GREP="/bin/grep"}
+: ${LN_S="ln -s"}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SED="/mount/endor/wildenhu/local-x86_64/bin/sed"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" $lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+ func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
+}
+
+# Generated shell functions inserted here.
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+ s@/\./@/@g
+ t dotsl
+ s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+# value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+ # Start from root dir and reassemble the path.
+ func_normal_abspath_result=
+ func_normal_abspath_tpath=$1
+ func_normal_abspath_altnamespace=
+ case $func_normal_abspath_tpath in
+ "")
+ # Empty path, that just means $cwd.
+ func_stripname '' '/' "`pwd`"
+ func_normal_abspath_result=$func_stripname_result
+ return
+ ;;
+ # The next three entries are used to spot a run of precisely
+ # two leading slashes without using negated character classes;
+ # we take advantage of case's first-match behaviour.
+ ///*)
+ # Unusual form of absolute path, do nothing.
+ ;;
+ //*)
+ # Not necessarily an ordinary path; POSIX reserves leading '//'
+ # and for example Cygwin uses it to access remote file shares
+ # over CIFS/SMB, so we conserve a leading double slash if found.
+ func_normal_abspath_altnamespace=/
+ ;;
+ /*)
+ # Absolute path, do nothing.
+ ;;
+ *)
+ # Relative path, prepend $cwd.
+ func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+ ;;
+ esac
+ # Cancel out all the simple stuff to save iterations. We also want
+ # the path to end with a slash for ease of parsing, so make sure
+ # there is one (and only one) here.
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+ while :; do
+ # Processed it all yet?
+ if test "$func_normal_abspath_tpath" = / ; then
+ # If we ascended to the root using ".." the result may be empty now.
+ if test -z "$func_normal_abspath_result" ; then
+ func_normal_abspath_result=/
+ fi
+ break
+ fi
+ func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$pathcar"`
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$pathcdr"`
+ # Figure out what to do with it
+ case $func_normal_abspath_tcomponent in
+ "")
+ # Trailing empty path component, ignore it.
+ ;;
+ ..)
+ # Parent dir; strip last assembled component from result.
+ func_dirname "$func_normal_abspath_result"
+ func_normal_abspath_result=$func_dirname_result
+ ;;
+ *)
+ # Actual path component, append it.
+ func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+ ;;
+ esac
+ done
+ # Restore leading double-slash if one was found on entry.
+ func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+# value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+ func_relative_path_result=
+ func_normal_abspath "$1"
+ func_relative_path_tlibdir=$func_normal_abspath_result
+ func_normal_abspath "$2"
+ func_relative_path_tbindir=$func_normal_abspath_result
+
+ # Ascend the tree starting from libdir
+ while :; do
+ # check if we have found a prefix of bindir
+ case $func_relative_path_tbindir in
+ $func_relative_path_tlibdir)
+ # found an exact match
+ func_relative_path_tcancelled=
+ break
+ ;;
+ $func_relative_path_tlibdir*)
+ # found a matching prefix
+ func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+ func_relative_path_tcancelled=$func_stripname_result
+ if test -z "$func_relative_path_result"; then
+ func_relative_path_result=.
+ fi
+ break
+ ;;
+ *)
+ func_dirname $func_relative_path_tlibdir
+ func_relative_path_tlibdir=${func_dirname_result}
+ if test "x$func_relative_path_tlibdir" = x ; then
+ # Have to descend all the way to the root!
+ func_relative_path_result=../$func_relative_path_result
+ func_relative_path_tcancelled=$func_relative_path_tbindir
+ break
+ fi
+ func_relative_path_result=../$func_relative_path_result
+ ;;
+ esac
+ done
+
+ # Now calculate path; take care to avoid doubling-up slashes.
+ func_stripname '' '/' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ func_stripname '/' '/' "$func_relative_path_tcancelled"
+ if test "x$func_stripname_result" != x ; then
+ func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+ fi
+
+ # Normalisation. If bindir is libdir, return empty string,
+ # else relative path ending with a slash; either way, target
+ # file name can be directly appended.
+ if test ! -z "$func_relative_path_result"; then
+ func_stripname './' '' "$func_relative_path_result/"
+ func_relative_path_result=$func_stripname_result
+ fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+ [\\/]*|[A-Za-z]:\\*) ;;
+ *[\\/]*)
+ progdir=$func_dirname_result
+ progdir=`cd "$progdir" && pwd`
+ progpath="$progdir/$progname"
+ ;;
+ *)
+ save_IFS="$IFS"
+ IFS=:
+ for progdir in $PATH; do
+ IFS="$save_IFS"
+ test -x "$progdir/$progname" && break
+ done
+ IFS="$save_IFS"
+ test -n "$progdir" || progdir=`pwd`
+ progpath="$progdir/$progname"
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same. If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'. `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+ s/$bs4/&\\
+/g
+ s/^$bs2$dollar/$bs&/
+ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+ s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+ $ECHO "$progname${mode+: }$mode: $*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+ $opt_verbose && func_echo ${1+"$@"}
+
+ # A bug in bash halts the script if the last line of a function
+ # fails when set -e is in force, so we need another command to
+ # work around that:
+ :
+}
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+ $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+ $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2
+
+ # bash bug again:
+ :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+ func_error ${1+"$@"}
+ exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+ func_error ${1+"$@"}
+ func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information." ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+ $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+ my_directory_path="$1"
+ my_dir_list=
+
+ if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+ # Protect directory names starting with `-'
+ case $my_directory_path in
+ -*) my_directory_path="./$my_directory_path" ;;
+ esac
+
+ # While some portion of DIR does not yet exist...
+ while test ! -d "$my_directory_path"; do
+ # ...make a list in topmost first order. Use a colon delimited
+ # list incase some portion of path contains whitespace.
+ my_dir_list="$my_directory_path:$my_dir_list"
+
+ # If the last portion added has no slash in it, the list is done
+ case $my_directory_path in */*) ;; *) break ;; esac
+
+ # ...otherwise throw away the child directory and loop
+ my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+ done
+ my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+
+ save_mkdir_p_IFS="$IFS"; IFS=':'
+ for my_dir in $my_dir_list; do
+ IFS="$save_mkdir_p_IFS"
+ # mkdir can fail with a `File exist' error if two processes
+ # try to create one of the directories concurrently. Don't
+ # stop in that case!
+ $MKDIR "$my_dir" 2>/dev/null || :
+ done
+ IFS="$save_mkdir_p_IFS"
+
+ # Bail out if we (or some other process) failed to create a directory.
+ test -d "$my_directory_path" || \
+ func_fatal_error "Failed to create \`$1'"
+ fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible. If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+ my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+ if test "$opt_dry_run" = ":"; then
+ # Return a directory name, but don't create it in dry-run mode
+ my_tmpdir="${my_template}-$$"
+ else
+
+ # If mktemp works, use that first and foremost
+ my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+ if test ! -d "$my_tmpdir"; then
+ # Failing that, at least try and use $RANDOM to avoid a race
+ my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+ save_mktempdir_umask=`umask`
+ umask 0077
+ $MKDIR "$my_tmpdir"
+ umask $save_mktempdir_umask
+ fi
+
+ # If we're not in dry-run mode, bomb out on failure
+ test -d "$my_tmpdir" || \
+ func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+ fi
+
+ $ECHO "$my_tmpdir"
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+ case $1 in
+ *[\\\`\"\$]*)
+ func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+ *)
+ func_quote_for_eval_unquoted_result="$1" ;;
+ esac
+
+ case $func_quote_for_eval_unquoted_result in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting, command substitution and and variable
+ # expansion for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+ ;;
+ *)
+ func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+ esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+ case $1 in
+ *[\\\`\"]*)
+ my_arg=`$ECHO "$1" | $SED \
+ -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+ *)
+ my_arg="$1" ;;
+ esac
+
+ case $my_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting and command substitution for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ my_arg="\"$my_arg\""
+ ;;
+ esac
+
+ func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+ my_cmd="$1"
+ my_fail_exp="${2-:}"
+
+ ${opt_silent-false} || {
+ func_quote_for_expand "$my_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ if ${opt_dry_run-false}; then :; else
+ eval "$my_cmd"
+ my_status=$?
+ if test "$my_status" -eq 0; then :; else
+ eval "(exit $my_status); $my_fail_exp"
+ fi
+ fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it. Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+ my_cmd="$1"
+ my_fail_exp="${2-:}"
+
+ ${opt_silent-false} || {
+ func_quote_for_expand "$my_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ if ${opt_dry_run-false}; then :; else
+ eval "$lt_user_locale
+ $my_cmd"
+ my_status=$?
+ eval "$lt_safe_locale"
+ if test "$my_status" -eq 0; then :; else
+ eval "(exit $my_status); $my_fail_exp"
+ fi
+ fi
+}
+
+
+
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+ $SED -n '/(C)/!b go
+ :more
+ /\./!{
+ N
+ s/\n# //
+ b more
+ }
+ :go
+ /^# '$PROGRAM' (GNU /,/# warranty; / {
+ s/^# //
+ s/^# *$//
+ s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+ p
+ }' < "$progpath"
+ exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+ $SED -n '/^# Usage:/,/^# *-h/ {
+ s/^# //
+ s/^# *$//
+ s/\$progname/'$progname'/
+ p
+ }' < "$progpath"
+ echo
+ $ECHO "run \`$progname --help | more' for full usage"
+ exit $?
+}
+
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+func_help ()
+{
+ $SED -n '/^# Usage:/,/# Report bugs to/ {
+ s/^# //
+ s/^# *$//
+ s*\$progname*'$progname'*
+ s*\$host*'"$host"'*
+ s*\$SHELL*'"$SHELL"'*
+ s*\$LTCC*'"$LTCC"'*
+ s*\$LTCFLAGS*'"$LTCFLAGS"'*
+ s*\$LD*'"$LD"'*
+ s/\$with_gnu_ld/'"$with_gnu_ld"'/
+ s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/
+ s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/
+ p
+ }' < "$progpath"
+ ret=$?
+ if test -z "$1"; then
+ exit $ret
+ fi
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+ func_error "missing argument for $1"
+ exit_cmd=exit
+}
+
+exit_cmd=:
+
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+# $mode is unset
+nonopt=
+execute_dlfiles=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+opt_dry_run=false
+opt_finish=:
+opt_duplicate_deps=false
+opt_silent=false
+opt_debug=:
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+ func_error ${1+"$@"}
+ func_error "See the $PACKAGE documentation for more information."
+ func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+ re_begincf='^# ### BEGIN LIBTOOL'
+ re_endcf='^# ### END LIBTOOL'
+
+ # Default configuration.
+ $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+ done
+
+ exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+ echo "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ echo "enable shared libraries"
+ else
+ echo "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ echo "enable static libraries"
+ else
+ echo "disable static libraries"
+ fi
+
+ exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag. We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+ # Global variable:
+ tagname="$1"
+
+ re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+ re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+ sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+ # Validate tagname.
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ func_fatal_error "invalid tag name: $tagname"
+ ;;
+ esac
+
+ # Don't test for the "default" C tag, as we know it's
+ # there but not specially marked.
+ case $tagname in
+ CC) ;;
+ *)
+ if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+ taglist="$taglist $tagname"
+
+ # Evaluate the configuration. Be careful to quote the path
+ # and the sed script, to avoid splitting on whitespace, but
+ # also don't use non-portable quotes within backquotes within
+ # quotes we have to do it in 2 steps:
+ extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+ eval "$extractedcf"
+ else
+ func_error "ignoring unknown tag $tagname"
+ fi
+ ;;
+ esac
+}
+
+# Parse options once, thoroughly. This comes as soon as possible in
+# the script to make things like `libtool --version' happen quickly.
+{
+
+ # Shorthand for --mode=foo, only valid as the first argument
+ case $1 in
+ clean|clea|cle|cl)
+ shift; set dummy --mode clean ${1+"$@"}; shift
+ ;;
+ compile|compil|compi|comp|com|co|c)
+ shift; set dummy --mode compile ${1+"$@"}; shift
+ ;;
+ execute|execut|execu|exec|exe|ex|e)
+ shift; set dummy --mode execute ${1+"$@"}; shift
+ ;;
+ finish|finis|fini|fin|fi|f)
+ shift; set dummy --mode finish ${1+"$@"}; shift
+ ;;
+ install|instal|insta|inst|ins|in|i)
+ shift; set dummy --mode install ${1+"$@"}; shift
+ ;;
+ link|lin|li|l)
+ shift; set dummy --mode link ${1+"$@"}; shift
+ ;;
+ uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+ shift; set dummy --mode uninstall ${1+"$@"}; shift
+ ;;
+ esac
+
+ # Parse non-mode specific arguments:
+ while test "$#" -gt 0; do
+ opt="$1"
+ shift
+
+ case $opt in
+ --config) func_config ;;
+
+ --debug) preserve_args="$preserve_args $opt"
+ func_echo "enabling shell trace mode"
+ opt_debug='set -x'
+ $opt_debug
+ ;;
+
+ -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break
+ execute_dlfiles="$execute_dlfiles $1"
+ shift
+ ;;
+
+ --dry-run | -n) opt_dry_run=: ;;
+ --features) func_features ;;
+ --finish) mode="finish" ;;
+ --no-finish) opt_finish=false ;;
+
+ --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break
+ case $1 in
+ # Valid mode arguments:
+ clean) ;;
+ compile) ;;
+ execute) ;;
+ finish) ;;
+ install) ;;
+ link) ;;
+ relink) ;;
+ uninstall) ;;
+
+ # Catch anything else as an error
+ *) func_error "invalid argument for $opt"
+ exit_cmd=exit
+ break
+ ;;
+ esac
+
+ mode="$1"
+ shift
+ ;;
+
+ --preserve-dup-deps)
+ opt_duplicate_deps=: ;;
+
+ --quiet|--silent) preserve_args="$preserve_args $opt"
+ opt_silent=:
+ opt_verbose=false
+ ;;
+
+ --no-quiet|--no-silent)
+ preserve_args="$preserve_args $opt"
+ opt_silent=false
+ ;;
+
+ --verbose| -v) preserve_args="$preserve_args $opt"
+ opt_silent=false
+ opt_verbose=:
+ ;;
+
+ --no-verbose) preserve_args="$preserve_args $opt"
+ opt_verbose=false
+ ;;
+
+ --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break
+ preserve_args="$preserve_args $opt $1"
+ func_enable_tag "$1" # tagname is set here
+ shift
+ ;;
+
+ # Separate optargs to long options:
+ -dlopen=*|--mode=*|--tag=*)
+ func_opt_split "$opt"
+ set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"}
+ shift
+ ;;
+
+ -\?|-h) func_usage ;;
+ --help) opt_help=: ;;
+ --help-all) opt_help=': help-all' ;;
+ --version) func_version ;;
+
+ -*) func_fatal_help "unrecognized option \`$opt'" ;;
+
+ *) nonopt="$opt"
+ break
+ ;;
+ esac
+ done
+
+
+ case $host in
+ *cygwin* | *mingw* | *pw32* | *cegcc*)
+ # don't eliminate duplications in $postdeps and $predeps
+ opt_duplicate_compiler_generated_deps=:
+ ;;
+ *)
+ opt_duplicate_compiler_generated_deps=$opt_duplicate_deps
+ ;;
+ esac
+
+ # Having warned about all mis-specified options, bail out if
+ # anything was wrong.
+ $exit_cmd $EXIT_FAILURE
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+ if test "$package_revision" != "$macro_revision"; then
+ if test "$VERSION" != "$macro_version"; then
+ if test -z "$macro_version"; then
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ fi
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+ fi
+
+ exit $EXIT_MISMATCH
+ fi
+}
+
+
+## ----------- ##
+## Main. ##
+## ----------- ##
+
+$opt_help || {
+ # Sanity checks first:
+ func_check_version_match
+
+ if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+ func_fatal_configuration "not configured to build any kind of library"
+ fi
+
+ test -z "$mode" && func_fatal_error "error: you must specify a MODE."
+
+
+ # Darwin sucks
+ eval "std_shrext=\"$shrext_cmds\""
+
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$execute_dlfiles" && test "$mode" != execute; then
+ func_error "unrecognized option \`-dlopen'"
+ $ECHO "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$progname --help --mode=$mode' for more information."
+}
+
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+ test -f "$1" &&
+ $SED -e 4q "$1" 2>/dev/null \
+ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs. To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway. Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+ lalib_p=no
+ if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+ for lalib_p_l in 1 2 3 4
+ do
+ read lalib_p_line
+ case "$lalib_p_line" in
+ \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+ esac
+ done
+ exec 0<&5 5<&-
+ fi
+ test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+ func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+ func_ltwrapper_exec_suffix=
+ case $1 in
+ *.exe) ;;
+ *) func_ltwrapper_exec_suffix=.exe ;;
+ esac
+ $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+ func_ltwrapper_scriptname_result=""
+ if func_ltwrapper_executable_p "$1"; then
+ func_dirname_and_basename "$1" "" "."
+ func_stripname '' '.exe' "$func_basename_result"
+ func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+ fi
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+ func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+ $opt_debug
+ save_ifs=$IFS; IFS='~'
+ for cmd in $1; do
+ IFS=$save_ifs
+ eval "cmd=\"$cmd\""
+ func_show_eval "$cmd" "${2-:}"
+ done
+ IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)! Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+ $opt_debug
+ case $1 in
+ */* | *\\*) . "$1" ;;
+ *) . "./$1" ;;
+ esac
+}
+
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+ $opt_debug
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ func_quote_for_eval "$arg"
+ CC_quoted="$CC_quoted $func_quote_for_eval_result"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ func_quote_for_eval "$arg"
+ CC_quoted="$CC_quoted $func_quote_for_eval_result"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case "$@ " in
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ func_echo "unable to infer tagged configuration"
+ func_fatal_error "specify a tag with \`--tag'"
+# else
+# func_verbose "using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+ write_libobj=${1}
+ if test "$build_libtool_libs" = yes; then
+ write_lobj=\'${2}\'
+ else
+ write_lobj=none
+ fi
+
+ if test "$build_old_libs" = yes; then
+ write_oldobj=\'${3}\'
+ else
+ write_oldobj=none
+ fi
+
+ $opt_dry_run || {
+ cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+ $MV "${write_libobj}T" "${write_libobj}"
+ }
+}
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+ $opt_debug
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile="$nonopt" # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+ pie_flag=
+
+ for arg
+ do
+ case $arg_mode in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg="$arg"
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj="$arg"
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ test -n "$libobj" && \
+ func_fatal_error "you cannot specify \`-o' more than once"
+ arg_mode=target
+ continue
+ ;;
+
+ -pie | -fpie | -fPIE)
+ pie_flag="$pie_flag $arg"
+ continue
+ ;;
+
+ -shared | -static | -prefer-pic | -prefer-non-pic)
+ later="$later $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ lastarg=
+ save_ifs="$IFS"; IFS=','
+ for arg in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$arg"
+ lastarg="$lastarg $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$lastarg"
+ lastarg=$func_stripname_result
+
+ # Add the arguments to base_compile.
+ base_compile="$base_compile $lastarg"
+ continue
+ ;;
+
+ *)
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg="$srcfile"
+ srcfile="$arg"
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ func_quote_for_eval "$lastarg"
+ base_compile="$base_compile $func_quote_for_eval_result"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ func_fatal_error "you must specify an argument for -Xcompile"
+ ;;
+ target)
+ func_fatal_error "you must specify a target with \`-o'"
+ ;;
+ *)
+ # Get the name of the library object.
+ test -z "$libobj" && {
+ func_basename "$srcfile"
+ libobj="$func_basename_result"
+ }
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ case $libobj in
+ *.[cCFSifmso] | \
+ *.ada | *.adb | *.ads | *.asm | \
+ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+ func_xform "$libobj"
+ libobj=$func_xform_result
+ ;;
+ esac
+
+ case $libobj in
+ *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+ *)
+ func_fatal_error "cannot determine name of library object from \`$libobj'"
+ ;;
+ esac
+
+ func_infer_tag $base_compile
+
+ for arg in $later; do
+ case $arg in
+ -shared)
+ test "$build_libtool_libs" != yes && \
+ func_fatal_configuration "can not build a shared library"
+ build_old_libs=no
+ continue
+ ;;
+
+ -static)
+ build_libtool_libs=no
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ func_quote_for_eval "$libobj"
+ test "X$libobj" != "X$func_quote_for_eval_result" \
+ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \
+ && func_warning "libobj name \`$libobj' may not contain shell special characters."
+ func_dirname_and_basename "$obj" "/" ""
+ objname="$func_basename_result"
+ xdir="$func_dirname_result"
+ lobj=${xdir}$objdir/$objname
+
+ test -z "$base_compile" && \
+ func_fatal_help "you must specify a compilation command"
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2* | cegcc*)
+ pic_mode=default
+ ;;
+ esac
+ if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ $ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+ removelist="$removelist $output_obj"
+ $ECHO "$srcfile" > "$lockfile"
+ fi
+
+ $opt_dry_run || $RM $removelist
+ removelist="$removelist $lockfile"
+ trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+ if test -n "$fix_srcfile_path"; then
+ eval "srcfile=\"$fix_srcfile_path\""
+ fi
+ func_quote_for_eval "$srcfile"
+ qsrcfile=$func_quote_for_eval_result
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test "$build_libtool_libs" = yes; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test "$pic_mode" != no; then
+ command="$base_compile $qsrcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ fi
+
+ func_mkdir_p "$xdir$objdir"
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ command="$command -o $lobj"
+ fi
+
+ func_show_eval_locale "$command" \
+ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ func_show_eval '$MV "$output_obj" "$lobj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+
+ # Allow error messages only from the first compilation.
+ if test "$suppress_opt" = yes; then
+ suppress_output=' >/dev/null 2>&1'
+ fi
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test "$build_old_libs" = yes; then
+ if test "$pic_mode" != yes; then
+ # Don't build PIC code
+ command="$base_compile $qsrcfile$pie_flag"
+ else
+ command="$base_compile $qsrcfile $pic_flag"
+ fi
+ if test "$compiler_c_o" = yes; then
+ command="$command -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ command="$command$suppress_output"
+ func_show_eval_locale "$command" \
+ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ func_show_eval '$MV "$output_obj" "$obj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+ fi
+
+ $opt_dry_run || {
+ func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+ # Unlock the critical section if it was locked
+ if test "$need_locks" != no; then
+ removelist=$lockfile
+ $RM "$lockfile"
+ fi
+ }
+
+ exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+ test "$mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+ # We need to display help for each of the modes.
+ case $mode in
+ "")
+ # Generic help is extracted from the usage comments
+ # at the start of this file.
+ func_help
+ ;;
+
+ clean)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ compile)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -no-suppress do not suppress compiler output for multiple passes
+ -prefer-pic try to building PIC objects only
+ -prefer-non-pic try to building non-PIC objects only
+ -shared do not build a \`.o' file suitable for static linking
+ -static only build a \`.o' file suitable for static linking
+ -Wc,FLAG pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+ execute)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+ finish)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+ install)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+ -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+ link)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -bindir BINDIR specify path to binaries directory (for systems where
+ libraries must be found in the PATH setting at runtime)
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE Use a list of object files found in FILE to specify objects
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -shared only do dynamic linking of libtool libraries
+ -shrext SUFFIX override the standard shared library file extension
+ -static do not do any dynamic linking of uninstalled libtool libraries
+ -static-libtool-libs
+ do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+ -weak LIBNAME declare that the target provides the LIBNAME interface
+ -Wc,FLAG
+ -Xcompiler FLAG pass linker-specific FLAG directly to the compiler
+ -Wl,FLAG
+ -Xlinker FLAG pass linker-specific FLAG directly to the linker
+ -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+ uninstall)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ *)
+ func_fatal_help "invalid operation mode \`$mode'"
+ ;;
+ esac
+
+ echo
+ $ECHO "Try \`$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+ if test "$opt_help" = :; then
+ func_mode_help
+ else
+ {
+ func_help noexit
+ for mode in compile link execute install finish uninstall clean; do
+ func_mode_help
+ done
+ } | sed -n '1p; 2,$s/^Usage:/ or: /p'
+ {
+ func_help noexit
+ for mode in compile link execute install finish uninstall clean; do
+ echo
+ func_mode_help
+ done
+ } |
+ sed '1d
+ /^When reporting/,/^Report/{
+ H
+ d
+ }
+ $x
+ /information about other modes/d
+ /more detailed .*MODE/d
+ s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+ fi
+ exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+ $opt_debug
+ # The first argument is the command name.
+ cmd="$nonopt"
+ test -z "$cmd" && \
+ func_fatal_help "you must specify a COMMAND"
+
+ # Handle -dlopen flags immediately.
+ for file in $execute_dlfiles; do
+ test -f "$file" \
+ || func_fatal_help "\`$file' is not a file"
+
+ dir=
+ case $file in
+ *.la)
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+ func_source "$file"
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && \
+ func_warning "\`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+
+ if test -f "$dir/$objdir/$dlname"; then
+ dir="$dir/$objdir"
+ else
+ if test ! -f "$dir/$dlname"; then
+ func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+ ;;
+
+ *)
+ func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval test -z \"\$$shlibpath_var\"; then
+ eval $shlibpath_var=\$dir
+ else
+ eval $shlibpath_var=\$dir:\$$shlibpath_var
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -* | *.la | *.lo ) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if func_ltwrapper_script_p "$file"; then
+ func_source "$file"
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ elif func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ func_source "$func_ltwrapper_scriptname_result"
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ func_quote_for_eval "$file"
+ args="$args $func_quote_for_eval_result"
+ done
+
+ if test "X$opt_dry_run" = Xfalse; then
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+ do
+ eval "if test \"\${save_$lt_var+set}\" = set; then
+ $lt_var=\$save_$lt_var; export $lt_var
+ else
+ $lt_unset $lt_var
+ fi"
+ done
+
+ # Now prepare to actually exec the command.
+ exec_cmd="\$cmd$args"
+ else
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+ echo "export $shlibpath_var"
+ fi
+ $ECHO "$cmd$args"
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test "$mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+ $opt_debug
+ libdirs="$nonopt"
+ admincmds=
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for dir
+ do
+ libdirs="$libdirs $dir"
+ done
+
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $opt_dry_run || eval "$cmds" || admincmds="$admincmds
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ $opt_silent && exit $EXIT_SUCCESS
+
+ echo "----------------------------------------------------------------------"
+ echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $ECHO " $libdir"
+ done
+ echo
+ echo "If you ever happen to want to link against installed libraries"
+ echo "in a given directory, LIBDIR, you must either use libtool, and"
+ echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval "flag=\"$hardcode_libdir_flag_spec\""
+
+ $ECHO " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $ECHO " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ echo
+
+ echo "See any operating system documentation about shared libraries for"
+ case $host in
+ solaris2.[6789]|solaris2.1[0-9])
+ echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+ echo "pages."
+ ;;
+ *)
+ echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ ;;
+ esac
+ echo "----------------------------------------------------------------------"
+ exit $EXIT_SUCCESS
+}
+
+test "$mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+ $opt_debug
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ # Allow the use of GNU shtool's install command.
+ case $nonopt in *shtool*) :;; *) false;; esac; then
+ # Aesthetically quote it.
+ func_quote_for_eval "$nonopt"
+ install_prog="$func_quote_for_eval_result "
+ arg=$1
+ shift
+ else
+ install_prog=
+ arg=$nonopt
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ func_quote_for_eval "$arg"
+ install_prog="$install_prog$func_quote_for_eval_result"
+ install_shared_prog=$install_prog
+ case " $install_prog " in
+ *[\\\ /]cp\ *) install_cp=: ;;
+ *) install_cp=false ;;
+ esac
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ no_mode=:
+ for arg
+ do
+ arg2=
+ if test -n "$dest"; then
+ files="$files $dest"
+ dest=$arg
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=yes ;;
+ -f)
+ if $install_cp; then :; else
+ prev=$arg
+ fi
+ ;;
+ -g | -m | -o)
+ prev=$arg
+ ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*)
+ ;;
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ if test "x$prev" = x-m && test -n "$install_override_mode"; then
+ arg2=$install_override_mode
+ no_mode=false
+ fi
+ prev=
+ else
+ dest=$arg
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ func_quote_for_eval "$arg"
+ install_prog="$install_prog $func_quote_for_eval_result"
+ if test -n "$arg2"; then
+ func_quote_for_eval "$arg2"
+ fi
+ install_shared_prog="$install_shared_prog $func_quote_for_eval_result"
+ done
+
+ test -z "$install_prog" && \
+ func_fatal_help "you must specify an install program"
+
+ test -n "$prev" && \
+ func_fatal_help "the \`$prev' option requires an argument"
+
+ if test -n "$install_override_mode" && $no_mode; then
+ if $install_cp; then :; else
+ func_quote_for_eval "$install_override_mode"
+ install_shared_prog="$install_shared_prog -m $func_quote_for_eval_result"
+ fi
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ func_fatal_help "no file or destination specified"
+ else
+ func_fatal_help "you must specify a destination"
+ fi
+ fi
+
+ # Strip any trailing slash from the destination.
+ func_stripname '' '/' "$dest"
+ dest=$func_stripname_result
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ func_dirname_and_basename "$dest" "" "."
+ destdir="$func_dirname_result"
+ destname="$func_basename_result"
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files; shift
+ test "$#" -gt 1 && \
+ func_fatal_help "\`$dest' is not a directory"
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ func_fatal_help "\`$destdir' must be an absolute directory name"
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ staticlibs="$staticlibs $file"
+ ;;
+
+ *.la)
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "\`$file' is not a valid libtool archive"
+
+ library_names=
+ old_library=
+ relink_command=
+ func_source "$file"
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) current_libdirs="$current_libdirs $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) future_libdirs="$future_libdirs $libdir" ;;
+ esac
+ fi
+
+ func_dirname "$file" "/" ""
+ dir="$func_dirname_result"
+ dir="$dir$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ test "$inst_prefix_dir" = "$destdir" && \
+ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ fi
+
+ func_warning "relinking \`$file'"
+ func_show_eval "$relink_command" \
+ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names; shift
+ if test -n "$1"; then
+ realname="$1"
+ shift
+
+ srcname="$realname"
+ test -n "$relink_command" && srcname="$realname"T
+
+ # Install the shared library and build the symlinks.
+ func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+ 'exit $?'
+ tstripme="$stripme"
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $realname in
+ *.dll.a)
+ tstripme=""
+ ;;
+ esac
+ ;;
+ esac
+ if test -n "$tstripme" && test -n "$striplib"; then
+ func_show_eval "$striplib $destdir/$realname" 'exit $?'
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ # Try `ln -sf' first, because the `ln' binary might depend on
+ # the symlink we replace! Solaris /bin/ln does not understand -f,
+ # so we also need to try rm && ln -s.
+ for linkname
+ do
+ test "$linkname" != "$realname" \
+ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ func_execute_cmds "$postinstall_cmds" 'exit $?'
+ fi
+
+ # Install the pseudo-library for information purposes.
+ func_basename "$file"
+ name="$func_basename_result"
+ instname="$dir/$name"i
+ func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ func_basename "$file"
+ destfile="$func_basename_result"
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ func_lo2o "$destfile"
+ staticdest=$func_lo2o_result
+ ;;
+ *.$objext)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ func_fatal_help "cannot copy a libtool object to \`$destfile'"
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ test -n "$destfile" && \
+ func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ func_lo2o "$file"
+ staticobj=$func_lo2o_result
+ func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ func_basename "$file"
+ destfile="$func_basename_result"
+ destfile="$destdir/$destfile"
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=""
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ stripped_ext=".exe"
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin* | *mingw*)
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ wrapper=$func_ltwrapper_scriptname_result
+ else
+ func_stripname '' '.exe' "$file"
+ wrapper=$func_stripname_result
+ fi
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if func_ltwrapper_script_p "$wrapper"; then
+ notinst_deplibs=
+ relink_command=
+
+ func_source "$wrapper"
+
+ # Check the variables that should have been set.
+ test -z "$generated_by_libtool_version" && \
+ func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+ finalize=yes
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ func_source "$lib"
+ fi
+ libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ func_warning "\`$lib' has not been installed in \`$libdir'"
+ finalize=no
+ fi
+ done
+
+ relink_command=
+ func_source "$wrapper"
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ $opt_dry_run || {
+ if test "$finalize" = yes; then
+ tmpdir=`func_mktempdir`
+ func_basename "$file$stripped_ext"
+ file="$func_basename_result"
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $opt_silent || {
+ func_quote_for_expand "$relink_command"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ if eval "$relink_command"; then :
+ else
+ func_error "error: relink \`$file' with the above command before installing it"
+ $opt_dry_run || ${RM}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ func_warning "cannot relink \`$file'"
+ fi
+ }
+ else
+ # Install the binary that we compiled earlier.
+ file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyway
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ func_stripname '' '.exe' "$destfile"
+ destfile=$func_stripname_result
+ ;;
+ esac
+ ;;
+ esac
+ func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+ $opt_dry_run || if test -n "$outputname"; then
+ ${RM}r "$tmpdir"
+ fi
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ func_basename "$file"
+ name="$func_basename_result"
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+
+ func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ func_show_eval "$old_striplib $oldlib" 'exit $?'
+ fi
+
+ # Do each command in the postinstall commands.
+ func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+ done
+
+ test -n "$future_libdirs" && \
+ func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+ if test -n "$current_libdirs" && $opt_finish; then
+ # Maybe just do a dry run.
+ $opt_dry_run && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+ else
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test "$mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+ $opt_debug
+ my_outputname="$1"
+ my_originator="$2"
+ my_pic_p="${3-no}"
+ my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+ my_dlsyms=
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ my_dlsyms="${my_outputname}S.c"
+ else
+ func_error "not configured to extract global symbols from dlpreopened files"
+ fi
+ fi
+
+ if test -n "$my_dlsyms"; then
+ case $my_dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${my_outputname}.nm"
+
+ func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+ # Parse the name list into a source file.
+ func_verbose "creating $output_objdir/$my_dlsyms"
+
+ $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ func_verbose "generating symbol list for \`$output'"
+
+ $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ for progfile in $progfiles; do
+ func_verbose "extracting global C symbols from \`$progfile'"
+ $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $opt_dry_run || {
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $MV "$nlist"T "$nlist"
+ }
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $opt_dry_run || {
+ $EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T
+ $MV "$nlist"T "$nlist"
+ }
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$outputname.exp"
+ $opt_dry_run || {
+ $RM $export_symbols
+ ${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' < "$nlist" > "$export_symbols"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ echo EXPORTS > "$output_objdir/$outputname.def"
+ cat "$export_symbols" >> "$output_objdir/$outputname.def"
+ ;;
+ esac
+ }
+ else
+ $opt_dry_run || {
+ ${SED} -e 's/\([].[*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/' < "$export_symbols" > "$output_objdir/$outputname.exp"
+ $GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T
+ $MV "$nlist"T "$nlist"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ echo EXPORTS > "$output_objdir/$outputname.def"
+ cat "$nlist" >> "$output_objdir/$outputname.def"
+ ;;
+ esac
+ }
+ fi
+ fi
+
+ for dlprefile in $dlprefiles; do
+ func_verbose "extracting global C symbols from \`$dlprefile'"
+ func_basename "$dlprefile"
+ name="$func_basename_result"
+ $opt_dry_run || {
+ $ECHO ": $name " >> "$nlist"
+ eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ done
+
+ $opt_dry_run || {
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $MV "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if $GREP -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ $GREP -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+ else
+ echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+ fi
+
+ echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols. */
+typedef struct {
+ const char *name;
+ void *address;
+} lt_dlsymlist;
+"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ echo >> "$output_objdir/$my_dlsyms" "\
+/* DATA imports from DLLs on WIN32 con't be const, because
+ runtime relocations are performed -- see ld's documentation
+ on pseudo-relocs. */"
+ lt_dlsym_const= ;;
+ *osf5*)
+ echo >> "$output_objdir/$my_dlsyms" "\
+/* This system does not cope well with relocations in const data */"
+ lt_dlsym_const= ;;
+ *)
+ lt_dlsym_const=const ;;
+ esac
+
+ echo >> "$output_objdir/$my_dlsyms" "\
+extern $lt_dlsym_const lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+$lt_dlsym_const lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+ { \"$my_originator\", (void *) 0 },"
+
+ case $need_lib_prefix in
+ no)
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ *)
+ eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ esac
+ echo >> "$output_objdir/$my_dlsyms" "\
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ } # !$opt_dry_run
+
+ pic_flag_for_symtable=
+ case "$compile_command " in
+ *" -static "*) ;;
+ *)
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+ *-*-hpux*)
+ pic_flag_for_symtable=" $pic_flag" ;;
+ *)
+ if test "X$my_pic_p" != Xno; then
+ pic_flag_for_symtable=" $pic_flag"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ symtab_cflags=
+ for arg in $LTCFLAGS; do
+ case $arg in
+ -pie | -fpie | -fPIE) ;;
+ *) symtab_cflags="$symtab_cflags $arg" ;;
+ esac
+ done
+
+ # Now compile the dynamic symbol file.
+ func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+ # Clean up the generated files.
+ func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+ # Transform the symbol file into the correct name.
+ symfileobj="$output_objdir/${my_outputname}S.$objext"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ if test -f "$output_objdir/$my_outputname.def"; then
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ else
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ fi
+ ;;
+ *)
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ ;;
+ esac
+ ;;
+ *)
+ func_fatal_error "unknown suffix for \`$my_dlsyms'"
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+ fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+ $opt_debug
+ win32_libid_type="unknown"
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ if $OBJDUMP -f "$1" | $SED -e '10q' 2>/dev/null |
+ $EGREP 'file format (pe-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+ win32_nmres=`$NM -f posix -A "$1" |
+ $SED -n -e '
+ 1,100{
+ / I /{
+ s,.*,import,
+ p
+ q
+ }
+ }'`
+ case $win32_nmres in
+ import*) win32_libid_type="x86 archive import";;
+ *) win32_libid_type="x86 archive static";;
+ esac
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $ECHO "$win32_libid_type"
+}
+
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+ $opt_debug
+ f_ex_an_ar_dir="$1"; shift
+ f_ex_an_ar_oldlib="$1"
+ if test "$lock_old_archive_extraction" = yes; then
+ lockfile=$f_ex_an_ar_oldlib.lock
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ fi
+ func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+ 'stat=$?; rm -f "$lockfile"; exit $stat'
+ if test "$lock_old_archive_extraction" = yes; then
+ $opt_dry_run || rm -f "$lockfile"
+ fi
+ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+ fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+ $opt_debug
+ my_gentop="$1"; shift
+ my_oldlibs=${1+"$@"}
+ my_oldobjs=""
+ my_xlib=""
+ my_xabs=""
+ my_xdir=""
+
+ for my_xlib in $my_oldlibs; do
+ # Extract the objects.
+ case $my_xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+ *) my_xabs=`pwd`"/$my_xlib" ;;
+ esac
+ func_basename "$my_xlib"
+ my_xlib="$func_basename_result"
+ my_xlib_u=$my_xlib
+ while :; do
+ case " $extracted_archives " in
+ *" $my_xlib_u "*)
+ func_arith $extracted_serial + 1
+ extracted_serial=$func_arith_result
+ my_xlib_u=lt$extracted_serial-$my_xlib ;;
+ *) break ;;
+ esac
+ done
+ extracted_archives="$extracted_archives $my_xlib_u"
+ my_xdir="$my_gentop/$my_xlib_u"
+
+ func_mkdir_p "$my_xdir"
+
+ case $host in
+ *-darwin*)
+ func_verbose "Extracting $my_xabs"
+ # Do not bother doing anything if just a dry run
+ $opt_dry_run || {
+ darwin_orig_dir=`pwd`
+ cd $my_xdir || exit $?
+ darwin_archive=$my_xabs
+ darwin_curdir=`pwd`
+ darwin_base_archive=`basename "$darwin_archive"`
+ darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+ if test -n "$darwin_arches"; then
+ darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+ darwin_arch=
+ func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+ for darwin_arch in $darwin_arches ; do
+ func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+ cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+ cd "$darwin_curdir"
+ $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+ done # $darwin_arches
+ ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+ darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
+ $LIPO -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ $RM -rf unfat-$$
+ cd "$darwin_orig_dir"
+ else
+ cd $darwin_orig_dir
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ fi # $darwin_arches
+ } # !$opt_dry_run
+ ;;
+ *)
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+
+ func_extract_archives_result="$my_oldobjs"
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable. Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take. If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory. This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+ func_emit_wrapper_arg1=${1-no}
+
+ $ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='$macro_version'
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$ECHO are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ file=\"\$0\""
+
+ qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+ $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+ ECHO=\"$qECHO\"
+ fi\
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+ if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+ # special case for '.'
+ if test \"\$thisdir\" = \".\"; then
+ thisdir=\`pwd\`
+ fi
+ # remove .libs from thisdir
+ case \"\$thisdir\" in
+ *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+ $objdir ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ $ECHO "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" ||
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $MKDIR \"\$progdir\"
+ else
+ $RM \"\$progdir/\$file\"
+ fi"
+
+ $ECHO "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \"\$relink_command\" 2>&1\`; then :
+ else
+ $ECHO \"\$relink_command_output\" >&2
+ $RM \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $RM \"\$progdir/\$program\";
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $RM \"\$progdir/\$file\"
+ fi"
+ else
+ $ECHO "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $ECHO "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $ECHO "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ # fixup the dll searchpath if we need to.
+ if test -n "$dllsearchpath"; then
+ $ECHO "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ $ECHO "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2* | *-cegcc*)
+ $ECHO "\
+ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $ECHO "\
+ exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $ECHO "\
+ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+ exit 1
+ fi
+ else
+ # The program doesn't exist.
+ \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+ \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+ \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+}
+
+
+# func_to_host_path arg
+#
+# Convert paths to host format when used with build tools.
+# Intended for use with "native" mingw (where libtool itself
+# is running under the msys shell), or in the following cross-
+# build environments:
+# $build $host
+# mingw (msys) mingw [e.g. native]
+# cygwin mingw
+# *nix + wine mingw
+# where wine is equipped with the `winepath' executable.
+# In the native mingw case, the (msys) shell automatically
+# converts paths for any non-msys applications it launches,
+# but that facility isn't available from inside the cwrapper.
+# Similar accommodations are necessary for $host mingw and
+# $build cygwin. Calling this function does no harm for other
+# $host/$build combinations not listed above.
+#
+# ARG is the path (on $build) that should be converted to
+# the proper representation for $host. The result is stored
+# in $func_to_host_path_result.
+func_to_host_path ()
+{
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ case $host in
+ *mingw* )
+ lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+ case $build in
+ *mingw* ) # actually, msys
+ # awkward: cmd appends spaces to result
+ func_to_host_path_result=`( cmd //c echo "$1" ) 2>/dev/null |
+ $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+ ;;
+ *cygwin* )
+ func_to_host_path_result=`cygpath -w "$1" |
+ $SED -e "$lt_sed_naive_backslashify"`
+ ;;
+ * )
+ # Unfortunately, winepath does not exit with a non-zero
+ # error code, so we are forced to check the contents of
+ # stdout. On the other hand, if the command is not
+ # found, the shell will set an exit code of 127 and print
+ # *an error message* to stdout. So we must check for both
+ # error code of zero AND non-empty stdout, which explains
+ # the odd construction:
+ func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null`
+ if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then
+ func_to_host_path_result=`$ECHO "$func_to_host_path_tmp1" |
+ $SED -e "$lt_sed_naive_backslashify"`
+ else
+ # Allow warning below.
+ func_to_host_path_result=
+ fi
+ ;;
+ esac
+ if test -z "$func_to_host_path_result" ; then
+ func_error "Could not determine host path corresponding to"
+ func_error " \`$1'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback:
+ func_to_host_path_result="$1"
+ fi
+ ;;
+ esac
+ fi
+}
+# end: func_to_host_path
+
+# func_to_host_pathlist arg
+#
+# Convert pathlists to host format when used with build tools.
+# See func_to_host_path(), above. This function supports the
+# following $build/$host combinations (but does no harm for
+# combinations not listed here):
+# $build $host
+# mingw (msys) mingw [e.g. native]
+# cygwin mingw
+# *nix + wine mingw
+#
+# Path separators are also converted from $build format to
+# $host format. If ARG begins or ends with a path separator
+# character, it is preserved (but converted to $host format)
+# on output.
+#
+# ARG is a pathlist (on $build) that should be converted to
+# the proper representation on $host. The result is stored
+# in $func_to_host_pathlist_result.
+func_to_host_pathlist ()
+{
+ func_to_host_pathlist_result="$1"
+ if test -n "$1"; then
+ case $host in
+ *mingw* )
+ lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+ # Remove leading and trailing path separator characters from
+ # ARG. msys behavior is inconsistent here, cygpath turns them
+ # into '.;' and ';.', and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_pathlist_tmp1=$func_stripname_result
+ case $build in
+ *mingw* ) # Actually, msys.
+ # Awkward: cmd appends spaces to result.
+ func_to_host_pathlist_result=`
+ ( cmd //c echo "$func_to_host_pathlist_tmp1" ) 2>/dev/null |
+ $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+ ;;
+ *cygwin* )
+ func_to_host_pathlist_result=`cygpath -w -p "$func_to_host_pathlist_tmp1" |
+ $SED -e "$lt_sed_naive_backslashify"`
+ ;;
+ * )
+ # unfortunately, winepath doesn't convert pathlists
+ func_to_host_pathlist_result=""
+ func_to_host_pathlist_oldIFS=$IFS
+ IFS=:
+ for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do
+ IFS=$func_to_host_pathlist_oldIFS
+ if test -n "$func_to_host_pathlist_f" ; then
+ func_to_host_path "$func_to_host_pathlist_f"
+ if test -n "$func_to_host_path_result" ; then
+ if test -z "$func_to_host_pathlist_result" ; then
+ func_to_host_pathlist_result="$func_to_host_path_result"
+ else
+ func_append func_to_host_pathlist_result ";$func_to_host_path_result"
+ fi
+ fi
+ fi
+ done
+ IFS=$func_to_host_pathlist_oldIFS
+ ;;
+ esac
+ if test -z "$func_to_host_pathlist_result"; then
+ func_error "Could not determine the host path(s) corresponding to"
+ func_error " \`$1'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback. This may break if $1 contains DOS-style drive
+ # specifications. The fix is not to complicate the expression
+ # below, but for the user to provide a working wine installation
+ # with winepath so that path translation in the cross-to-mingw
+ # case works properly.
+ lt_replace_pathsep_nix_to_dos="s|:|;|g"
+ func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\
+ $SED -e "$lt_replace_pathsep_nix_to_dos"`
+ fi
+ # Now, add the leading and trailing path separators back
+ case "$1" in
+ :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result"
+ ;;
+ esac
+ case "$1" in
+ *: ) func_append func_to_host_pathlist_result ";"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+}
+# end: func_to_host_pathlist
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+ cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+
+ Currently, it simply execs the wrapper *script* "$SHELL $output",
+ but could eventually absorb all of the scripts functionality and
+ exec $objdir/$outputname directly.
+*/
+EOF
+ cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+# include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+# define _INTPTR_T_DEFINED
+# define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+ defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+# define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+# define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#undef LTWRAPPER_DEBUGPRINTF
+#if defined LT_DEBUGWRAPPER
+# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args
+static void
+ltwrapper_debugprintf (const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ (void) vfprintf (stderr, fmt, args);
+ va_end (args);
+}
+#else
+# define LTWRAPPER_DEBUGPRINTF(args)
+#endif
+
+const char *program_name = NULL;
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_fatal (const char *message, ...);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+ cat <<EOF
+const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ func_to_host_pathlist "$temp_rpath"
+ cat <<EOF
+const char * LIB_PATH_VALUE = "$func_to_host_pathlist_result";
+EOF
+ else
+ cat <<"EOF"
+const char * LIB_PATH_VALUE = "";
+EOF
+ fi
+
+ if test -n "$dllsearchpath"; then
+ func_to_host_pathlist "$dllsearchpath:"
+ cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE = "$func_to_host_pathlist_result";
+EOF
+ else
+ cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE = "";
+EOF
+ fi
+
+ if test "$fast_install" = yes; then
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+ else
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+ fi
+
+
+ cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX "--lt-"
+#define LTWRAPPER_OPTION_PREFIX_LENGTH 5
+
+static const size_t opt_prefix_len = LTWRAPPER_OPTION_PREFIX_LENGTH;
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+
+static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script";
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int newargc;
+ char *tmp_pathspec;
+ char *actual_cwrapper_path;
+ char *actual_cwrapper_name;
+ char *target_name;
+ char *lt_argv_zero;
+ intptr_t rval = 127;
+
+ int i;
+
+ program_name = (char *) xstrdup (base_name (argv[0]));
+ LTWRAPPER_DEBUGPRINTF (("(main) argv[0] : %s\n", argv[0]));
+ LTWRAPPER_DEBUGPRINTF (("(main) program_name : %s\n", program_name));
+
+ /* very simple arg parsing; don't want to rely on getopt */
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], dumpscript_opt) == 0)
+ {
+EOF
+ case "$host" in
+ *mingw* | *cygwin* )
+ # make stdout use "unix" line endings
+ echo " setmode(1,_O_BINARY);"
+ ;;
+ esac
+
+ cat <<"EOF"
+ lt_dump_script (stdout);
+ return 0;
+ }
+ }
+
+ newargz = XMALLOC (char *, argc + 1);
+ tmp_pathspec = find_executable (argv[0]);
+ if (tmp_pathspec == NULL)
+ lt_fatal ("Couldn't find %s", argv[0]);
+ LTWRAPPER_DEBUGPRINTF (("(main) found exe (before symlink chase) at : %s\n",
+ tmp_pathspec));
+
+ actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+ LTWRAPPER_DEBUGPRINTF (("(main) found exe (after symlink chase) at : %s\n",
+ actual_cwrapper_path));
+ XFREE (tmp_pathspec);
+
+ actual_cwrapper_name = xstrdup( base_name (actual_cwrapper_path));
+ strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+ /* wrapper name transforms */
+ strendzap (actual_cwrapper_name, ".exe");
+ tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+ XFREE (actual_cwrapper_name);
+ actual_cwrapper_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ /* target_name transforms -- use actual target program name; might have lt- prefix */
+ target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+ strendzap (target_name, ".exe");
+ tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+ XFREE (target_name);
+ target_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ LTWRAPPER_DEBUGPRINTF (("(main) libtool target name: %s\n",
+ target_name));
+EOF
+
+ cat <<EOF
+ newargz[0] =
+ XMALLOC (char, (strlen (actual_cwrapper_path) +
+ strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+ strcpy (newargz[0], actual_cwrapper_path);
+ strcat (newargz[0], "$objdir");
+ strcat (newargz[0], "/");
+EOF
+
+ cat <<"EOF"
+ /* stop here, and copy so we don't have to do this twice */
+ tmp_pathspec = xstrdup (newargz[0]);
+
+ /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+ strcat (newargz[0], actual_cwrapper_name);
+
+ /* DO want the lt- prefix here if it exists, so use target_name */
+ lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+ XFREE (tmp_pathspec);
+ tmp_pathspec = NULL;
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ {
+ char* p;
+ while ((p = strchr (newargz[0], '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ }
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+ XFREE (target_name);
+ XFREE (actual_cwrapper_path);
+ XFREE (actual_cwrapper_name);
+
+ lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+ lt_setenv ("DUALCASE", "1"); /* for MSK sh */
+ lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+ lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+
+ newargc=0;
+ for (i = 1; i < argc; i++)
+ {
+ if (strncmp (argv[i], ltwrapper_option_prefix, opt_prefix_len) == 0)
+ {
+ /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+ namespace, but it is not one of the ones we know about and
+ have already dealt with, above (inluding dump-script), then
+ report an error. Otherwise, targets might begin to believe
+ they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+ namespace. The first time any user complains about this, we'll
+ need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+ or a configure.ac-settable value.
+ */
+ lt_fatal ("Unrecognized option in %s namespace: '%s'",
+ ltwrapper_option_prefix, argv[i]);
+ }
+ /* otherwise ... */
+ newargz[++newargc] = xstrdup (argv[i]);
+ }
+ newargz[++newargc] = NULL;
+
+ LTWRAPPER_DEBUGPRINTF (("(main) lt_argv_zero : %s\n", (lt_argv_zero ? lt_argv_zero : "<NULL>")));
+ for (i = 0; i < newargc; i++)
+ {
+ LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : "<NULL>")));
+ }
+
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ /* execv doesn't actually work on mingw as expected on unix */
+ newargz = prepare_spawn (newargz);
+ rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+ if (rval == -1)
+ {
+ /* failed to start process */
+ LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno));
+ return 127;
+ }
+ return rval;
+EOF
+ ;;
+ *)
+ cat <<"EOF"
+ execv (lt_argv_zero, newargz);
+ return rval; /* =127, but avoids unused variable warning */
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+ void *p = (void *) malloc (num);
+ if (!p)
+ lt_fatal ("Memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+ string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+ const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return base;
+}
+
+int
+check_executable (const char *path)
+{
+ struct stat st;
+
+ LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n",
+ path ? (*path ? path : "EMPTY!") : "NULL!"));
+ if ((!path) || (!*path))
+ return 0;
+
+ if ((stat (path, &st) >= 0)
+ && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ return 1;
+ else
+ return 0;
+}
+
+int
+make_executable (const char *path)
+{
+ int rval = 0;
+ struct stat st;
+
+ LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n",
+ path ? (*path ? path : "EMPTY!") : "NULL!"));
+ if ((!path) || (!*path))
+ return 0;
+
+ if (stat (path, &st) >= 0)
+ {
+ rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+ }
+ return rval;
+}
+
+/* Searches for the full path of the wrapper. Returns
+ newly allocated full path name if found, NULL otherwise
+ Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+ int has_slash = 0;
+ const char *p;
+ const char *p_next;
+ /* static buffer for getcwd */
+ char tmp[LT_PATHMAX + 1];
+ int tmp_len;
+ char *concat_name;
+
+ LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n",
+ wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"));
+
+ if ((wrapper == NULL) || (*wrapper == '\0'))
+ return NULL;
+
+ /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ else
+ {
+#endif
+ if (IS_DIR_SEPARATOR (wrapper[0]))
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ }
+#endif
+
+ for (p = wrapper; *p; p++)
+ if (*p == '/')
+ {
+ has_slash = 1;
+ break;
+ }
+ if (!has_slash)
+ {
+ /* no slashes; search PATH */
+ const char *path = getenv ("PATH");
+ if (path != NULL)
+ {
+ for (p = path; *p; p = p_next)
+ {
+ const char *q;
+ size_t p_len;
+ for (q = p; *q; q++)
+ if (IS_PATH_SEPARATOR (*q))
+ break;
+ p_len = q - p;
+ p_next = (*q == '\0' ? q : q + 1);
+ if (p_len == 0)
+ {
+ /* empty path: current directory */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ tmp_len = strlen (tmp);
+ concat_name =
+ XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+ }
+ else
+ {
+ concat_name =
+ XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, p, p_len);
+ concat_name[p_len] = '/';
+ strcpy (concat_name + p_len + 1, wrapper);
+ }
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ }
+ /* not found in PATH; assume curdir */
+ }
+ /* Relative path | not found in path: prepend cwd */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ tmp_len = strlen (tmp);
+ concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+ return xstrdup (pathspec);
+#else
+ char buf[LT_PATHMAX];
+ struct stat s;
+ char *tmp_pathspec = xstrdup (pathspec);
+ char *p;
+ int has_symlinks = 0;
+ while (strlen (tmp_pathspec) && !has_symlinks)
+ {
+ LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n",
+ tmp_pathspec));
+ if (lstat (tmp_pathspec, &s) == 0)
+ {
+ if (S_ISLNK (s.st_mode) != 0)
+ {
+ has_symlinks = 1;
+ break;
+ }
+
+ /* search backwards for last DIR_SEPARATOR */
+ p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+ while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ p--;
+ if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ {
+ /* no more DIR_SEPARATORS left */
+ break;
+ }
+ *p = '\0';
+ }
+ else
+ {
+ char *errstr = strerror (errno);
+ lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr);
+ }
+ }
+ XFREE (tmp_pathspec);
+
+ if (!has_symlinks)
+ {
+ return xstrdup (pathspec);
+ }
+
+ tmp_pathspec = realpath (pathspec, buf);
+ if (tmp_pathspec == 0)
+ {
+ lt_fatal ("Could not follow symlinks for %s", pathspec);
+ }
+ return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert (str != NULL);
+ assert (pat != NULL);
+
+ len = strlen (str);
+ patlen = strlen (pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (strcmp (str, pat) == 0)
+ *str = '\0';
+ }
+ return str;
+}
+
+static void
+lt_error_core (int exit_status, const char *mode,
+ const char *message, va_list ap)
+{
+ fprintf (stderr, "%s: %s: ", program_name, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+ va_end (ap);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+ LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n",
+ (name ? name : "<NULL>"),
+ (value ? value : "<NULL>")));
+ {
+#ifdef HAVE_SETENV
+ /* always make a copy, for consistency with !HAVE_SETENV */
+ char *str = xstrdup (value);
+ setenv (name, str, 1);
+#else
+ int len = strlen (name) + 1 + strlen (value) + 1;
+ char *str = XMALLOC (char, len);
+ sprintf (str, "%s=%s", name, value);
+ if (putenv (str) != EXIT_SUCCESS)
+ {
+ XFREE (str);
+ }
+#endif
+ }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+ char *new_value;
+ if (orig_value && *orig_value)
+ {
+ int orig_value_len = strlen (orig_value);
+ int add_len = strlen (add);
+ new_value = XMALLOC (char, add_len + orig_value_len + 1);
+ if (to_end)
+ {
+ strcpy (new_value, orig_value);
+ strcpy (new_value + orig_value_len, add);
+ }
+ else
+ {
+ strcpy (new_value, add);
+ strcpy (new_value + add_len, orig_value);
+ }
+ }
+ else
+ {
+ new_value = xstrdup (add);
+ }
+ return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+ LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+ (name ? name : "<NULL>"),
+ (value ? value : "<NULL>")));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ /* some systems can't cope with a ':'-terminated path #' */
+ int len = strlen (new_value);
+ while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+ {
+ new_value[len-1] = '\0';
+ }
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+ LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+ (name ? name : "<NULL>"),
+ (value ? value : "<NULL>")));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+EOF
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+ Note that spawn() does not by itself call the command interpreter
+ (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+ ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&v);
+ v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+ }) ? "cmd.exe" : "command.com").
+ Instead it simply concatenates the arguments, separated by ' ', and calls
+ CreateProcess(). We must quote the arguments since Win32 CreateProcess()
+ interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+ special way:
+ - Space and tab are interpreted as delimiters. They are not treated as
+ delimiters if they are surrounded by double quotes: "...".
+ - Unescaped double quotes are removed from the input. Their only effect is
+ that within double quotes, space and tab are treated like normal
+ characters.
+ - Backslashes not followed by double quotes are not special.
+ - But 2*n+1 backslashes followed by a double quote become
+ n backslashes followed by a double quote (n >= 0):
+ \" -> "
+ \\\" -> \"
+ \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+ size_t argc;
+ char **new_argv;
+ size_t i;
+
+ /* Count number of arguments. */
+ for (argc = 0; argv[argc] != NULL; argc++)
+ ;
+
+ /* Allocate new argument vector. */
+ new_argv = XMALLOC (char *, argc + 1);
+
+ /* Put quoted arguments into the new argument vector. */
+ for (i = 0; i < argc; i++)
+ {
+ const char *string = argv[i];
+
+ if (string[0] == '\0')
+ new_argv[i] = xstrdup ("\"\"");
+ else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+ {
+ int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+ size_t length;
+ unsigned int backslashes;
+ const char *s;
+ char *quoted_string;
+ char *p;
+
+ length = 0;
+ backslashes = 0;
+ if (quote_around)
+ length++;
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ length += backslashes + 1;
+ length++;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ length += backslashes + 1;
+
+ quoted_string = XMALLOC (char, length + 1);
+
+ p = quoted_string;
+ backslashes = 0;
+ if (quote_around)
+ *p++ = '"';
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ {
+ unsigned int j;
+ for (j = backslashes + 1; j > 0; j--)
+ *p++ = '\\';
+ }
+ *p++ = c;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ {
+ unsigned int j;
+ for (j = backslashes; j > 0; j--)
+ *p++ = '\\';
+ *p++ = '"';
+ }
+ *p = '\0';
+
+ new_argv[i] = quoted_string;
+ }
+ else
+ new_argv[i] = (char *) string;
+ }
+ new_argv[argc] = NULL;
+
+ return new_argv;
+}
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+ func_emit_wrapper yes |
+ $SED -e 's/\([\\"]\)/\\\1/g' \
+ -e 's/^/ fputs ("/' -e 's/$/\\n", f);/'
+
+ cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+ $opt_debug
+ case `eval "$file_magic_cmd \"\$1\" 2>/dev/null" | $SED -e 10q` in
+ *import*) : ;;
+ *) false ;;
+ esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+ $opt_debug
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # which system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll which has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args=$nonopt
+ base_compile="$nonopt $@"
+ compile_command=$nonopt
+ finalize_command=$nonopt
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+ new_inherited_linker_flags=
+
+ avoid_version=no
+ bindir=
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ non_pic_objects=
+ precious_files_regex=
+ prefer_static_libs=no
+ preload=no
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+ weak_libs=
+ single_module="${wl}-single_module"
+ func_infer_tag $base_compile
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -shared)
+ test "$build_libtool_libs" != yes && \
+ func_fatal_configuration "can not build a shared library"
+ build_old_libs=no
+ break
+ ;;
+ -all-static | -static | -static-libtool-libs)
+ case $arg in
+ -all-static)
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ func_warning "complete static linking is impossible in this configuration"
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ -static)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=built
+ ;;
+ -static-libtool-libs)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ esac
+ build_libtool_libs=no
+ build_old_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg="$1"
+ shift
+ func_quote_for_eval "$arg"
+ qarg=$func_quote_for_eval_unquoted_result
+ func_append libtool_args " $func_quote_for_eval_result"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ func_append compile_command " @OUTPUT@"
+ func_append finalize_command " @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ bindir)
+ bindir="$arg"
+ prev=
+ continue
+ ;;
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ func_append compile_command " @SYMFILE@"
+ func_append finalize_command " @SYMFILE@"
+ preload=yes
+ fi
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ else
+ dlprefiles="$dlprefiles $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ test -f "$arg" \
+ || func_fatal_error "symbol file \`$arg' does not exist"
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ framework)
+ case $host in
+ *-*-darwin*)
+ case "$deplibs " in
+ *" $qarg.ltframework "*) ;;
+ *) deplibs="$deplibs $qarg.ltframework" # this is fixed later
+ ;;
+ esac
+ ;;
+ esac
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir="$arg"
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat "$save_arg"`
+ do
+# moreargs="$moreargs $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none &&
+ test "$non_pic_object" = none; then
+ func_fatal_error "cannot find name of object for \`$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "\`$arg' is not a valid libtool object"
+ fi
+ fi
+ done
+ else
+ func_fatal_error "link input file \`$arg' does not exist"
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) rpath="$rpath $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) xrpath="$xrpath $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ shrext)
+ shrext_cmds="$arg"
+ prev=
+ continue
+ ;;
+ weak)
+ weak_libs="$weak_libs $arg"
+ prev=
+ continue
+ ;;
+ xcclinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xcompiler)
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xlinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $wl$qarg"
+ prev=
+ func_append compile_command " $wl$qarg"
+ func_append finalize_command " $wl$qarg"
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg="$arg"
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ # See comment for -static flag below, for more details.
+ func_append compile_command " $link_static_flag"
+ func_append finalize_command " $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -bindir)
+ prev=bindir
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ func_fatal_error "more than one -exported-symbols argument is not allowed"
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -framework)
+ prev=framework
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ func_stripname '-L' '' "$arg"
+ dir=$func_stripname_result
+ if test -z "$dir"; then
+ if test "$#" -gt 0; then
+ func_fatal_error "require no space between \`-L' and \`$1'"
+ else
+ func_fatal_error "need path for \`-L' option"
+ fi
+ fi
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ test -z "$absdir" && \
+ func_fatal_error "cannot determine absolute directory name of \`$dir'"
+ dir="$absdir"
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "*) ;;
+ *)
+ deplibs="$deplibs -L$dir"
+ lib_search_path="$lib_search_path $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ ::) dllsearchpath=$dir;;
+ *) dllsearchpath="$dllsearchpath:$dir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ deplibs="$deplibs System.ltframework"
+ continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-linux*)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ esac
+ elif test "X$arg" = "X-lc_r"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ deplibs="$deplibs $arg"
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # Tru64 UNIX uses -model [arg] to determine the layout of C++
+ # classes, name mangling, and exception handling.
+ # Darwin uses the -arch flag to determine output architecture.
+ -model|-arch|-isysroot)
+ compiler_flags="$compiler_flags $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ prev=xcompiler
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+ compiler_flags="$compiler_flags $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case "$new_inherited_linker_flags " in
+ *" $arg "*) ;;
+ * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;;
+ esac
+ continue
+ ;;
+
+ -multi_module)
+ single_module="${wl}-multi_module"
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # and Darwin in order for the loader to find any dlls it needs.
+ func_warning "\`-no-install' is ignored for $host"
+ func_warning "assuming \`-no-fast-install' instead"
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ func_stripname '-R' '' "$arg"
+ dir=$func_stripname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ continue
+ ;;
+
+ -shared)
+ # The effects of -shared are defined in a previous loop.
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -static | -static-libtool-libs)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -weak)
+ prev=weak
+ continue
+ ;;
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$flag"
+ arg="$arg $func_quote_for_eval_result"
+ compiler_flags="$compiler_flags $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Wl,*)
+ func_stripname '-Wl,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$flag"
+ arg="$arg $wl$func_quote_for_eval_result"
+ compiler_flags="$compiler_flags $wl$func_quote_for_eval_result"
+ linker_flags="$linker_flags $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # -msg_* for osf cc
+ -msg_*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+
+ # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
+ # -r[0-9][0-9]* specifies the processor on the SGI compiler
+ # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
+ # +DA*, +DD* enable 64-bit mode on the HP compiler
+ # -q* pass through compiler args for the IBM compiler
+ # -m*, -t[45]*, -txscale* pass through architecture-specific
+ # compiler args for GCC
+ # -F/path gives path to uninstalled frameworks, gcc on darwin
+ # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ compiler_flags="$compiler_flags $arg"
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+
+ *.$objext)
+ # A standard object.
+ objs="$objs $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none &&
+ test "$non_pic_object" = none; then
+ func_fatal_error "cannot find name of object for \`$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "\`$arg' is not a valid libtool object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ deplibs="$deplibs $arg"
+ old_deplibs="$old_deplibs $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ if test "$prev" = dlfiles; then
+ # This library was specified with -dlopen.
+ dlfiles="$dlfiles $arg"
+ prev=
+ elif test "$prev" = dlprefiles; then
+ # The library was specified with -dlpreopen.
+ dlprefiles="$dlprefiles $arg"
+ prev=
+ else
+ deplibs="$deplibs $arg"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+ done # argument parsing loop
+
+ test -n "$prev" && \
+ func_fatal_help "the \`$prevarg' option requires an argument"
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval "arg=\"$export_dynamic_flag_spec\""
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ func_basename "$output"
+ outputname="$func_basename_result"
+ libobjs_save="$libobjs"
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval "sys_lib_search_path=\"$sys_lib_search_path_spec\""
+ eval "sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\""
+
+ func_dirname "$output" "/" ""
+ output_objdir="$func_dirname_result$objdir"
+ # Create the object directory.
+ func_mkdir_p "$output_objdir"
+
+ # Determine the type of output
+ case $output in
+ "")
+ func_fatal_help "you must specify an output file"
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if $opt_duplicate_deps ; then
+ case "$libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ libs="$libs $deplib"
+ done
+
+ if test "$linkmode" = lib; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if $opt_duplicate_compiler_generated_deps; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+ esac
+ pre_post_deps="$pre_post_deps $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+
+ case $linkmode in
+ lib)
+ passes="conv dlpreopen link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=no
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+
+ for pass in $passes; do
+ # The preopen pass in lib mode reverses $deplibs; put it back here
+ # so that -L comes before libs that need it for instance...
+ if test "$linkmode,$pass" = "lib,link"; then
+ ## FIXME: Find the place where the list is rebuilt in the wrong
+ ## order, and fix it there properly
+ tmp_deplibs=
+ for deplib in $deplibs; do
+ tmp_deplibs="$deplib $tmp_deplibs"
+ done
+ deplibs="$tmp_deplibs"
+ fi
+
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan"; then
+ libs="$deplibs"
+ deplibs=
+ fi
+ if test "$linkmode" = prog; then
+ case $pass in
+ dlopen) libs="$dlfiles" ;;
+ dlpreopen) libs="$dlprefiles" ;;
+ link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+ esac
+ fi
+ if test "$linkmode,$pass" = "lib,dlpreopen"; then
+ # Collect and forward deplibs of preopened libtool libs
+ for lib in $dlprefiles; do
+ # Ignore non-libtool-libs
+ dependency_libs=
+ case $lib in
+ *.la) func_source "$lib" ;;
+ esac
+
+ # Collect preopened libtool deplibs, except any this library
+ # has declared as weak libs
+ for deplib in $dependency_libs; do
+ func_basename "$deplib"
+ deplib_base=$func_basename_result
+ case " $weak_libs " in
+ *" $deplib_base "*) ;;
+ *) deplibs="$deplibs $deplib" ;;
+ esac
+ done
+ done
+ libs="$dlprefiles"
+ fi
+ if test "$pass" = dlopen; then
+ # Collect dlpreopened libraries
+ save_deplibs="$deplibs"
+ deplibs=
+ fi
+
+ for deplib in $libs; do
+ lib=
+ found=no
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags $deplib"
+ if test "$linkmode" = lib ; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -l*)
+ if test "$linkmode" != lib && test "$linkmode" != prog; then
+ func_warning "\`-l' is ignored for archives/objects"
+ continue
+ fi
+ func_stripname '-l' '' "$deplib"
+ name=$func_stripname_result
+ if test "$linkmode" = lib; then
+ searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+ else
+ searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+ fi
+ for searchdir in $searchdirs; do
+ for search_ext in .la $std_shrext .so .a; do
+ # Search the libtool library
+ lib="$searchdir/lib${name}${search_ext}"
+ if test -f "$lib"; then
+ if test "$search_ext" = ".la"; then
+ found=yes
+ else
+ found=no
+ fi
+ break 2
+ fi
+ done
+ done
+ if test "$found" != yes; then
+ # deplib doesn't seem to be a libtool library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ else # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if func_lalib_p "$lib"; then
+ library_names=
+ old_library=
+ func_source "$lib"
+ for l in $old_library $library_names; do
+ ll="$l"
+ done
+ if test "X$ll" = "X$old_library" ; then # only static version available
+ found=no
+ func_dirname "$lib" "" "."
+ ladir="$func_dirname_result"
+ lib=$ladir/$old_library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ fi
+ ;; # -l
+ *.ltframework)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ if test "$linkmode" = lib ; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test "$pass" = conv && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ func_stripname '-L' '' "$deplib"
+ newlib_search_path="$newlib_search_path $func_stripname_result"
+ ;;
+ prog)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test "$pass" = scan; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ func_stripname '-L' '' "$deplib"
+ newlib_search_path="$newlib_search_path $func_stripname_result"
+ ;;
+ *)
+ func_warning "\`-L' is ignored for archives/objects"
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test "$pass" = link; then
+ func_stripname '-R' '' "$deplib"
+ dir=$func_stripname_result
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la) lib="$deplib" ;;
+ *.$libext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ # Linking convenience modules into shared libraries is allowed,
+ # but linking other static libraries is non-portable.
+ case " $dlpreconveniencelibs " in
+ *" $deplib "*) ;;
+ *)
+ valid_a_lib=no
+ case $deplibs_check_method in
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ valid_a_lib=yes
+ fi
+ ;;
+ pass_all)
+ valid_a_lib=yes
+ ;;
+ esac
+ if test "$valid_a_lib" != yes; then
+ echo
+ $ECHO "*** Warning: Trying to link with static lib archive $deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because the file extensions .$libext of this argument makes me believe"
+ echo "*** that it is just a static archive that I should not use here."
+ else
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the"
+ $ECHO "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ fi
+ ;;
+ esac
+ continue
+ ;;
+ prog)
+ if test "$pass" != link; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ elif test "$linkmode" = prog; then
+ if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ newdlprefiles="$newdlprefiles $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ newdlfiles="$newdlfiles $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=yes
+ continue
+ ;;
+ esac # case $deplib
+
+ if test "$found" = yes || test -f "$lib"; then :
+ else
+ func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+ fi
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$lib" \
+ || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+ func_dirname "$lib" "" "."
+ ladir="$func_dirname_result"
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ inherited_linker_flags=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+ avoidtemprpath=
+
+
+ # Read the .la file
+ func_source "$lib"
+
+ # Convert "-framework foo" to "foo.ltframework"
+ if test -n "$inherited_linker_flags"; then
+ tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+ for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+ case " $new_inherited_linker_flags " in
+ *" $tmp_inherited_linker_flag "*) ;;
+ *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";;
+ esac
+ done
+ fi
+ dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan" ||
+ { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+ test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+ test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+ fi
+
+ if test "$pass" = conv; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ func_fatal_error "cannot find name of link library for \`$lib'"
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ convenience="$convenience $ladir/$objdir/$old_library"
+ old_convenience="$old_convenience $ladir/$objdir/$old_library"
+ elif test "$linkmode" != prog && test "$linkmode" != lib; then
+ func_fatal_error "\`$lib' is not a convenience library"
+ fi
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if $opt_duplicate_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+ if test -z "$linklib"; then
+ func_fatal_error "cannot find name of link library for \`$lib'"
+ fi
+
+ # This library was specified with -dlopen.
+ if test "$pass" = dlopen; then
+ if test -z "$libdir"; then
+ func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+ fi
+ if test -z "$dlname" ||
+ test "$dlopen_support" != yes ||
+ test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ dlprefiles="$dlprefiles $lib $dependency_libs"
+ else
+ newdlfiles="$newdlfiles $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ func_warning "cannot determine absolute directory name of \`$ladir'"
+ func_warning "passing it literally to the linker, although it might fail"
+ abs_ladir="$ladir"
+ fi
+ ;;
+ esac
+ func_basename "$lib"
+ laname="$func_basename_result"
+
+ # Find the relevant object directory and library name.
+ if test "X$installed" = Xyes; then
+ if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ func_warning "library \`$lib' was moved."
+ dir="$ladir"
+ absdir="$abs_ladir"
+ libdir="$abs_ladir"
+ else
+ dir="$libdir"
+ absdir="$libdir"
+ fi
+ test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ else
+ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ dir="$ladir"
+ absdir="$abs_ladir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ fi
+ fi # $installed = yes
+ func_stripname 'lib' '.la' "$laname"
+ name=$func_stripname_result
+
+ # This library was specified with -dlpreopen.
+ if test "$pass" = dlpreopen; then
+ if test -z "$libdir" && test "$linkmode" = prog; then
+ func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+ fi
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ newdlprefiles="$newdlprefiles $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ newdlprefiles="$newdlprefiles $dir/$dlname"
+ else
+ newdlprefiles="$newdlprefiles $dir/$linklib"
+ fi
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test "$linkmode" = lib; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test "$linkmode" = prog && test "$pass" != link; then
+ newlib_search_path="$newlib_search_path $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=no
+ if test "$link_all_deplibs" != no || test -z "$library_names" ||
+ test "$build_libtool_libs" = no; then
+ linkalldeplibs=yes
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ newlib_search_path="$newlib_search_path $func_stripname_result"
+ ;;
+ esac
+ # Need to link against all dependency_libs?
+ if test "$linkalldeplibs" = yes; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if $opt_duplicate_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test "$linkmode,$pass" = "prog,link"; then
+ if test -n "$library_names" &&
+ { { test "$prefer_static_libs" = no ||
+ test "$prefer_static_libs,$installed" = "built,yes"; } ||
+ test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath:" in
+ *"$absdir:"*) ;;
+ *) temp_rpath="$temp_rpath$absdir:" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ use_static_libs=$prefer_static_libs
+ if test "$use_static_libs" = built && test "$installed" = yes; then
+ use_static_libs=no
+ fi
+ if test -n "$library_names" &&
+ { test "$use_static_libs" = no || test -z "$old_library"; }; then
+ case $host in
+ *cygwin* | *mingw* | *cegcc*)
+ # No point in relinking DLLs because paths are not encoded
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=no
+ ;;
+ *)
+ if test "$installed" = no; then
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=yes
+ fi
+ ;;
+ esac
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on some
+ # systems (darwin). Don't bleat about dlopened modules though!
+ dlopenmodule=""
+ for dlpremoduletest in $dlprefiles; do
+ if test "X$dlpremoduletest" = "X$lib"; then
+ dlopenmodule="$dlpremoduletest"
+ break
+ fi
+ done
+ if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+ echo
+ if test "$linkmode" = prog; then
+ $ECHO "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $ECHO "*** $linklib is not portable!"
+ fi
+ if test "$linkmode" = lib &&
+ test "$hardcode_into_libs" = yes; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ shift
+ realname="$1"
+ shift
+ eval "libname=\"$libname_spec\""
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname="$dlname"
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw* | *cegcc*)
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix="-$major"
+ ;;
+ esac
+ eval "soname=\"$soname_spec\""
+ else
+ soname="$realname"
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot="$soname"
+ func_basename "$soroot"
+ soname="$func_basename_result"
+ func_stripname 'lib' '.dll' "$soname"
+ newlib=libimp-$func_stripname_result.a
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ func_verbose "extracting exported symbol list from \`$soname'"
+ func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ func_verbose "generating import library for \`$soname'"
+ func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test "$linkmode" = prog || test "$mode" != relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ add="$dir/$linklib"
+ case $host in
+ *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+ *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+ *-*-unixware7*) add_dir="-L$dir" ;;
+ *-*-darwin* )
+ # if the lib is a (non-dlopened) module then we can not
+ # link against it, someone is ignoring the earlier warnings
+ if /usr/bin/file -L $add 2> /dev/null |
+ $GREP ": [^:]* bundle" >/dev/null ; then
+ if test "X$dlopenmodule" != "X$lib"; then
+ $ECHO "*** Warning: lib $linklib is a module, not a shared library"
+ if test -z "$old_library" ; then
+ echo
+ echo "*** And there doesn't seem to be a static archive available"
+ echo "*** The link will probably fail, sorry"
+ else
+ add="$dir/$old_library"
+ fi
+ elif test -n "$old_library"; then
+ add="$dir/$old_library"
+ fi
+ fi
+ esac
+ elif test "$hardcode_minus_L" = no; then
+ case $host in
+ *-*-sunos*) add_shlibpath="$dir" ;;
+ esac
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test "$hardcode_direct" = yes &&
+ test "$hardcode_direct_absolute" = no; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$dir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ func_fatal_configuration "unsupported hardcode properties"
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+ esac
+ fi
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test "$hardcode_direct" != yes &&
+ test "$hardcode_minus_L" != yes &&
+ test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test "$linkmode" = prog || test "$mode" = relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes &&
+ test "$hardcode_direct_absolute" = no; then
+ add="$libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$libdir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ add="-l$name"
+ elif test "$hardcode_automatic" = yes; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib" ; then
+ add="$inst_prefix_dir$libdir/$linklib"
+ else
+ add="$libdir/$linklib"
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir="-L$libdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ fi
+
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test "$linkmode" = prog; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test "$build_libtool_libs" = yes; then
+ # Not a shared library
+ if test "$deplibs_check_method" != pass_all; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ echo
+ $ECHO "*** Warning: This system can not link to static lib archive $lib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ if test "$module" = yes; then
+ echo "*** But as you try to build a module library, libtool will still create "
+ echo "*** a static module, that should work as long as the dlopening application"
+ echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test "$linkmode" = lib; then
+ if test -n "$dependency_libs" &&
+ { test "$hardcode_into_libs" != yes ||
+ test "$build_old_libs" = yes ||
+ test "$link_static" = yes; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) func_stripname '-R' '' "$libdir"
+ temp_xrpath=$func_stripname_result
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) xrpath="$xrpath $temp_xrpath";;
+ esac;;
+ *) temp_deplibs="$temp_deplibs $libdir";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ newlib_search_path="$newlib_search_path $absdir"
+ # Link against this library
+ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ if $opt_duplicate_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+
+ if test "$link_all_deplibs" != no; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ path=
+ case $deplib in
+ -L*) path="$deplib" ;;
+ *.la)
+ func_dirname "$deplib" "" "."
+ dir="$func_dirname_result"
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ func_warning "cannot determine absolute directory name of \`$dir'"
+ absdir="$dir"
+ fi
+ ;;
+ esac
+ if $GREP "^installed=no" $deplib > /dev/null; then
+ case $host in
+ *-*-darwin*)
+ depdepl=
+ deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names" ; then
+ for tmp in $deplibrary_names ; do
+ depdepl=$tmp
+ done
+ if test -f "$absdir/$objdir/$depdepl" ; then
+ depdepl="$absdir/$objdir/$depdepl"
+ darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ if test -z "$darwin_install_name"; then
+ darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ fi
+ compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+ linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}"
+ path=
+ fi
+ fi
+ ;;
+ *)
+ path="-L$absdir/$objdir"
+ ;;
+ esac
+ else
+ libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$deplib' is not a valid libtool archive"
+ test "$absdir" != "$libdir" && \
+ func_warning "\`$deplib' seems to be moved"
+
+ path="-L$absdir"
+ fi
+ ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ if test "$pass" = link; then
+ if test "$linkmode" = "prog"; then
+ compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+ finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ fi
+ fi
+ dependency_libs="$newdependency_libs"
+ if test "$pass" = dlpreopen; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test "$pass" != dlopen; then
+ if test "$pass" != conv; then
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) lib_search_path="$lib_search_path $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ fi
+
+ if test "$linkmode,$pass" != "prog,link"; then
+ vars="deplibs"
+ else
+ vars="compile_deplibs finalize_deplibs"
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\$$var
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ done
+ eval $var=\$tmp_libs
+ done # for var
+ fi
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs ; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=""
+ ;;
+ esac
+ if test -n "$i" ; then
+ tmp_libs="$tmp_libs $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test "$linkmode" = prog; then
+ dlfiles="$newdlfiles"
+ fi
+ if test "$linkmode" = prog || test "$linkmode" = lib; then
+ dlprefiles="$newdlprefiles"
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ func_warning "\`-dlopen' is ignored for archives"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "\`-l' and \`-L' are ignored for archives" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "\`-rpath' is ignored for archives"
+
+ test -n "$xrpath" && \
+ func_warning "\`-R' is ignored for archives"
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info/-version-number' is ignored for archives"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for archives"
+
+ test -n "$export_symbols$export_symbols_regex" && \
+ func_warning "\`-export-symbols' is ignored for archives"
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ objs="$objs$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case $outputname in
+ lib*)
+ func_stripname 'lib' '.la' "$outputname"
+ name=$func_stripname_result
+ eval "shared_ext=\"$shrext_cmds\""
+ eval "libname=\"$libname_spec\""
+ ;;
+ *)
+ test "$module" = no && \
+ func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ func_stripname '' '.la' "$outputname"
+ name=$func_stripname_result
+ eval "shared_ext=\"$shrext_cmds\""
+ eval "libname=\"$libname_spec\""
+ else
+ func_stripname '' '.la' "$outputname"
+ libname=$func_stripname_result
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test "$deplibs_check_method" != pass_all; then
+ func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+ else
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+ $ECHO "*** objects $objs is not portable!"
+ libobjs="$libobjs $objs"
+ fi
+ fi
+
+ test "$dlself" != no && \
+ func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+ set dummy $rpath
+ shift
+ test "$#" -gt 1 && \
+ func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+ install_libdir="$1"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a `.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for convenience libraries"
+ else
+
+ # Parse the version information argument.
+ save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ shift
+ IFS="$save_ifs"
+
+ test -n "$7" && \
+ func_fatal_help "too many parameters to \`-version-info'"
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major="$1"
+ number_minor="$2"
+ number_revision="$3"
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # which has an extra 1 added just for fun
+ #
+ case $version_type in
+ darwin|linux|osf|windows|none)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age="$number_minor"
+ revision="$number_revision"
+ ;;
+ freebsd-aout|freebsd-elf|qnx|sunos)
+ current="$number_major"
+ revision="$number_minor"
+ age="0"
+ ;;
+ irix|nonstopux)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age="$number_minor"
+ revision="$number_minor"
+ lt_irix_increment=no
+ ;;
+ esac
+ ;;
+ no)
+ current="$1"
+ revision="$2"
+ age="$3"
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "CURRENT \`$current' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $revision in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "REVISION \`$revision' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $age in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "AGE \`$age' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ func_error "AGE \`$age' is greater than the current interface number \`$current'"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix="$major.$age.$revision"
+ # Darwin ld doesn't like 0 for these options...
+ func_arith $current + 1
+ minor_current=$func_arith_result
+ xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current"
+ ;;
+
+ irix | nonstopux)
+ if test "X$lt_irix_increment" = "Xno"; then
+ func_arith $current - $age
+ else
+ func_arith $current - $age + 1
+ fi
+ major=$func_arith_result
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring="$verstring_prefix$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test "$loop" -ne 0; do
+ func_arith $revision - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring="$verstring_prefix$major.$iface:$verstring"
+ done
+
+ # Before this point, $major must not contain `.'.
+ major=.$major
+ versuffix="$major.$revision"
+ ;;
+
+ linux)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test "$loop" -ne 0; do
+ func_arith $current - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ verstring="$verstring:${current}.0"
+ ;;
+
+ qnx)
+ major=".$current"
+ versuffix=".$current"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 filesystems.
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix="-$major"
+ ;;
+
+ *)
+ func_fatal_configuration "unknown library version type \`$version_type'"
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring="0.0"
+ ;;
+ esac
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ func_warning "undefined symbols not allowed in $host shared libraries"
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+
+ fi
+
+ func_generate_dlsyms "$libname" "$libname" "yes"
+ libobjs="$libobjs $symfileobj"
+ test "X$libobjs" = "X " && libobjs=
+
+ if test "$mode" != relink; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$ECHO "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext | *.gcno)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+ if test "X$precious_files_regex" != "X"; then
+ if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+ removelist="$removelist $p"
+ ;;
+ *) ;;
+ esac
+ done
+ test -n "$removelist" && \
+ func_show_eval "${RM}r \$removelist"
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ #for path in $notinst_path; do
+ # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+ # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+ # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+ #done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ temp_xrpath="$temp_xrpath -R$libdir"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles="$dlfiles"
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) dlfiles="$dlfiles $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles="$dlprefiles"
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) dlprefiles="$dlprefiles $lib" ;;
+ esac
+ done
+
+ if test "$build_libtool_libs" = yes; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ deplibs="$deplibs System.ltframework"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test "$build_libtool_need_lc" = "yes"; then
+ deplibs="$deplibs -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $opt_dry_run || $RM conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ eval "libname=\"$libname_spec\""
+ eval "deplib_matches=\"$library_names_spec\""
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which I believe you do not have"
+ echo "*** because a test_compile did reveal that the linker did not use it for"
+ echo "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ ;;
+ *)
+ newdeplibs="$newdeplibs $i"
+ ;;
+ esac
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+ ldd_output=`ldd conftest`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ eval "libname=\"$libname_spec\""
+ eval "deplib_matches=\"$library_names_spec\""
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because a test_compile did reveal that the linker did not use this one"
+ echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning! Library $i is needed by this library but I was not able to"
+ echo "*** make it link in! You will probably need to install it or some"
+ echo "*** library that it depends on before this library will be fully"
+ echo "*** functional. Installing it before continuing would be even better."
+ fi
+ ;;
+ *)
+ newdeplibs="$newdeplibs $i"
+ ;;
+ esac
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method; shift
+ file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ eval "libname=\"$libname_spec\""
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null |
+ $GREP " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval "$file_magic_cmd \"\$potlib\"" 2>/dev/null |
+ $SED -e 10q |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ eval "libname=\"$libname_spec\""
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib="$potent_lib" # see symlink-check above in file_magic test
+ if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+ $EGREP "$match_pattern_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ for i in $predeps $postdeps ; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+ done
+ fi
+ case $tmp_deplibs in
+ *[!\ \ ]*)
+ echo
+ if test "X$deplibs_check_method" = "Xnone"; then
+ echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ ;;
+ esac
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library with the System framework
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ echo
+ echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $ECHO "*** dependencies of module $libname. Therefore, libtool will create"
+ echo "*** a static module, that should work as long as the dlopening"
+ echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ echo "*** The inter-library dependencies that have been dropped here will be"
+ echo "*** automatically added whenever a program is linked with this library"
+ echo "*** or is declared to -dlopen it."
+
+ if test "$allow_undefined" = no; then
+ echo
+ echo "*** Since this library must not contain undefined symbols,"
+ echo "*** because either the platform does not support them or"
+ echo "*** it was explicitly requested with -no-undefined,"
+ echo "*** libtool will only create a static version of it."
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ case $host in
+ *-*-darwin*)
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ deplibs="$new_libs"
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ if test "$hardcode_into_libs" = yes; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath="$finalize_rpath"
+ test "$mode" != relink && rpath="$compile_rpath$rpath"
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval "flag=\"$hardcode_libdir_flag_spec\""
+ dep_rpath="$dep_rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ if test -n "$hardcode_libdir_flag_spec_ld"; then
+ eval "dep_rpath=\"$hardcode_libdir_flag_spec_ld\""
+ else
+ eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+ fi
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ eval $runpath_var=\$rpath\$$runpath_var
+ export $runpath_var
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath="$finalize_shlibpath"
+ test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ if test -n "$shlibpath"; then
+ eval $shlibpath_var=\$shlibpath\$$shlibpath_var
+ export $shlibpath_var
+ fi
+
+ # Get the real and link names of the library.
+ eval "shared_ext=\"$shrext_cmds\""
+ eval "library_names=\"$library_names_spec\""
+ set dummy $library_names
+ shift
+ realname="$1"
+ shift
+
+ if test -n "$soname_spec"; then
+ eval "soname=\"$soname_spec\""
+ else
+ soname="$realname"
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib="$output_objdir/$realname"
+ linknames=
+ for link
+ do
+ linknames="$linknames $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ test "X$libobjs" = "X " && libobjs=
+
+ delfiles=
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+ export_symbols="$output_objdir/$libname.uexp"
+ delfiles="$delfiles $export_symbols"
+ fi
+
+ orig_export_symbols=
+ case $host_os in
+ cygwin* | mingw* | cegcc*)
+ if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+ # exporting using user supplied symfile
+ if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+ # and it's NOT already a .def file. Must figure out
+ # which of the given symbols are data symbols and tag
+ # them as such. So, trigger use of export_symbols_cmds.
+ # export_symbols gets reassigned inside the "prepare
+ # the list of exported symbols" if statement, so the
+ # include_expsyms logic still works.
+ orig_export_symbols="$export_symbols"
+ export_symbols=
+ always_export_symbols=yes
+ fi
+ fi
+ ;;
+ esac
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ func_verbose "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $opt_dry_run || $RM $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval "cmd=\"$cmd\""
+ func_len " $cmd"
+ len=$func_len_result
+ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ func_show_eval "$cmd" 'exit $?'
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ func_verbose "using reloadable object file for export list..."
+ skipped_export=:
+ # Break out early, otherwise skipped_export may be
+ # set to false by a later but shorter cmd.
+ break
+ fi
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols="$export_symbols"
+ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ $opt_dry_run || $ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"
+ fi
+
+ if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ tmp_deplibs="$tmp_deplibs $test_deplib"
+ ;;
+ esac
+ done
+ deplibs="$tmp_deplibs"
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec" &&
+ test "$compiler_needs_object" = yes &&
+ test -z "$libobjs"; then
+ # extract the archives, so we have objects to list.
+ # TODO: could optimize this to just extract one archive.
+ whole_archive_flag_spec=
+ fi
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval "libobjs=\"\$libobjs $whole_archive_flag_spec\""
+ test "X$libobjs" = "X " && libobjs=
+ else
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $convenience
+ libobjs="$libobjs $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval "flag=\"$thread_safe_flag_spec\""
+ linker_flags="$linker_flags $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test "$mode" = relink; then
+ $opt_dry_run || (cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U) || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval "test_cmds=\"$module_expsym_cmds\""
+ cmds=$module_expsym_cmds
+ else
+ eval "test_cmds=\"$module_cmds\""
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval "test_cmds=\"$archive_expsym_cmds\""
+ cmds=$archive_expsym_cmds
+ else
+ eval "test_cmds=\"$archive_cmds\""
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test "X$skipped_export" != "X:" &&
+ func_len " $test_cmds" &&
+ len=$func_len_result &&
+ test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise
+ # or, if using GNU ld and skipped_export is not :, use a linker
+ # script.
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+ func_basename "$output"
+ output_la=$func_basename_result
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ last_robj=
+ k=1
+
+ if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+ output=${output_objdir}/${output_la}.lnkscript
+ func_verbose "creating GNU ld script: $output"
+ echo 'INPUT (' > $output
+ for obj in $save_libobjs
+ do
+ $ECHO "$obj" >> $output
+ done
+ echo ')' >> $output
+ delfiles="$delfiles $output"
+ elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+ output=${output_objdir}/${output_la}.lnk
+ func_verbose "creating linker input file list: $output"
+ : > $output
+ set x $save_libobjs
+ shift
+ firstobj=
+ if test "$compiler_needs_object" = yes; then
+ firstobj="$1 "
+ shift
+ fi
+ for obj
+ do
+ $ECHO "$obj" >> $output
+ done
+ delfiles="$delfiles $output"
+ output=$firstobj\"$file_list_spec$output\"
+ else
+ if test -n "$save_libobjs"; then
+ func_verbose "creating reloadable object files..."
+ output=$output_objdir/$output_la-${k}.$objext
+ eval "test_cmds=\"$reload_cmds\""
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ if test "X$objlist" = X ||
+ test "$len" -lt "$max_cmd_len"; then
+ func_append objlist " $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test "$k" -eq 1 ; then
+ # The first file doesn't have a previous command to add.
+ reload_objs=$objlist
+ eval "concat_cmds=\"$reload_cmds\""
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ reload_objs="$objlist $last_robj"
+ eval "concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\""
+ fi
+ last_robj=$output_objdir/$output_la-${k}.$objext
+ func_arith $k + 1
+ k=$func_arith_result
+ output=$output_objdir/$output_la-${k}.$objext
+ objlist=" $obj"
+ func_len " $last_robj"
+ func_arith $len0 + $func_len_result
+ len=$func_arith_result
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ reload_objs="$objlist $last_robj"
+ eval "concat_cmds=\"\${concat_cmds}$reload_cmds\""
+ if test -n "$last_robj"; then
+ eval "concat_cmds=\"\${concat_cmds}~\$RM $last_robj\""
+ fi
+ delfiles="$delfiles $output"
+
+ else
+ output=
+ fi
+
+ if ${skipped_export-false}; then
+ func_verbose "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $opt_dry_run || $RM $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval "concat_cmds=\"\$concat_cmds$export_symbols_cmds\""
+ if test -n "$last_robj"; then
+ eval "concat_cmds=\"\$concat_cmds~\$RM $last_robj\""
+ fi
+ fi
+
+ test -n "$save_libobjs" &&
+ func_verbose "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS="$save_ifs"
+ $opt_silent || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+
+ if ${skipped_export-false}; then
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols="$export_symbols"
+ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ $opt_dry_run || $ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"
+ fi
+
+ if test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+ fi
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval "libobjs=\"\$libobjs $whole_archive_flag_spec\""
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+ fi
+
+ if test -n "$delfiles"; then
+ # Append the command to remove temporary files to $cmds.
+ eval "cmds=\"\$cmds~\$RM $delfiles\""
+ fi
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ libobjs="$libobjs $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval "cmd=\"$cmd\""
+ $opt_silent || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $opt_dry_run || (cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname) || exit $?
+
+ if test -n "$convenience"; then
+ if test -z "$whole_archive_flag_spec"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ func_warning "\`-dlopen' is ignored for objects"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "\`-l' and \`-L' are ignored for objects" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "\`-rpath' is ignored for objects"
+
+ test -n "$xrpath" && \
+ func_warning "\`-R' is ignored for objects"
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info' is ignored for objects"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for objects"
+
+ case $output in
+ *.lo)
+ test -n "$objs$old_deplibs" && \
+ func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+ libobj=$output
+ func_lo2o "$libobj"
+ obj=$func_lo2o_result
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $opt_dry_run || $RM $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec and hope we can get by with
+ # turning comma into space..
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval "tmp_whole_archive_flags=\"$whole_archive_flag_spec\""
+ reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+ else
+ gentop="$output_objdir/${obj}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $convenience
+ reload_conv_objs="$reload_objs $func_extract_archives_result"
+ fi
+ fi
+
+ # Create the old-style object.
+ reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+ output="$obj"
+ func_execute_cmds "$reload_cmds" 'exit $?'
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $opt_dry_run || echo timestamp > $libobj || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ if test -n "$pic_flag" || test "$pic_mode" != default; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ func_execute_cmds "$reload_cmds" 'exit $?'
+ fi
+
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result.exe;;
+ esac
+ test -n "$vinfo" && \
+ func_warning "\`-version-info' is ignored for programs"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for programs"
+
+ test "$preload" = yes \
+ && test "$dlopen_support" = unknown \
+ && test "$dlopen_self" = unknown \
+ && test "$dlopen_self_static" = unknown && \
+ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ case $host in
+ *-*-darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ # But is supposedly fixed on 10.4 or later (yay!).
+ if test "$tagname" = CXX ; then
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+ 10.[0123])
+ compile_command="$compile_command ${wl}-bind_at_load"
+ finalize_command="$finalize_command ${wl}-bind_at_load"
+ ;;
+ esac
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $compile_deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $compile_deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ compile_deplibs="$new_libs"
+
+
+ compile_command="$compile_command $compile_deplibs"
+ finalize_command="$finalize_command $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval "flag=\"$hardcode_libdir_flag_spec\""
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ ::) dllsearchpath=$libdir;;
+ *) dllsearchpath="$dllsearchpath:$libdir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval "rpath=\" $hardcode_libdir_flag_spec\""
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval "flag=\"$hardcode_libdir_flag_spec\""
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval "rpath=\" $hardcode_libdir_flag_spec\""
+ fi
+ finalize_rpath="$rpath"
+
+ if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ fi
+
+ func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+ # template prelinking step
+ if test -n "$prelink_cmds"; then
+ func_execute_cmds "$prelink_cmds" 'exit $?'
+ fi
+
+ wrappers_required=yes
+ case $host in
+ *cegcc* | *mingw32ce*)
+ # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+ wrappers_required=no
+ ;;
+ *cygwin* | *mingw* )
+ if test "$build_libtool_libs" != yes; then
+ wrappers_required=no
+ fi
+ ;;
+ *)
+ if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+ wrappers_required=no
+ fi
+ ;;
+ esac
+ if test "$wrappers_required" = no; then
+ # Replace the output file specification.
+ compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ exit_status=0
+ func_show_eval "$link_command" 'exit_status=$?'
+
+ # Delete the generated files.
+ if test -f "$output_objdir/${outputname}S.${objext}"; then
+ func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+ fi
+
+ exit $exit_status
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$no_install" = yes; then
+ # We don't need to create a wrapper script.
+ link_command="$compile_var$compile_command$compile_rpath"
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $opt_dry_run || $RM $output
+ # Link the executable and exit
+ func_show_eval "$link_command" 'exit $?'
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ func_warning "this platform does not like uninstalled shared libraries"
+ func_warning "\`$output' will be relinked during installation"
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ func_show_eval "$link_command" 'exit $?'
+
+ # Now create the wrapper script.
+ func_verbose "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if not in dry run mode.
+ $opt_dry_run || {
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ func_stripname '' '.exe' "$outputname"
+ outputname=$func_stripname_result ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ func_dirname_and_basename "$output" "" "."
+ output_name=$func_basename_result
+ output_path=$func_dirname_result
+ cwrappersource="$output_path/$objdir/lt-$output_name.c"
+ cwrapper="$output_path/$output_name.exe"
+ $RM $cwrappersource $cwrapper
+ trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_cwrapperexe_src > $cwrappersource
+
+ # The wrapper executable is built using the $host compiler,
+ # because it contains $host paths and files. If cross-
+ # compiling, it, like the target executable, must be
+ # executed on the $host or under an emulation environment.
+ $opt_dry_run || {
+ $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+ $STRIP $cwrapper
+ }
+
+ # Now, create the wrapper script for func_source use:
+ func_ltwrapper_scriptname $cwrapper
+ $RM $func_ltwrapper_scriptname_result
+ trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+ $opt_dry_run || {
+ # note: this script will not be executed, so do not chmod.
+ if test "x$build" = "x$host" ; then
+ $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+ else
+ func_emit_wrapper no > $func_ltwrapper_scriptname_result
+ fi
+ }
+ ;;
+ * )
+ $RM $output
+ trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_wrapper no > $output
+ chmod +x $output
+ ;;
+ esac
+ }
+ exit $EXIT_SUCCESS
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save $symfileobj"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$old_deplibs $non_pic_objects"
+ if test "$preload" = yes && test -f "$symfileobj"; then
+ oldobjs="$oldobjs $symfileobj"
+ fi
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $addlibs
+ oldobjs="$oldobjs $func_extract_archives_result"
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ cmds=$old_archive_from_new_cmds
+ else
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ oldobjs="$oldobjs $func_extract_archives_result"
+ fi
+
+ # POSIX demands no paths to be encoded in archives. We have
+ # to avoid creating archives with duplicate basenames if we
+ # might have to extract them afterwards, e.g., when creating a
+ # static archive out of a convenience library, or when linking
+ # the entirety of a libtool archive into another (currently
+ # not supported by libtool).
+ if (for obj in $oldobjs
+ do
+ func_basename "$obj"
+ $ECHO "$func_basename_result"
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ echo "copying selected object files to avoid basename conflicts..."
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+ func_mkdir_p "$gentop"
+ save_oldobjs=$oldobjs
+ oldobjs=
+ counter=1
+ for obj in $save_oldobjs
+ do
+ func_basename "$obj"
+ objbase="$func_basename_result"
+ case " $oldobjs " in
+ " ") oldobjs=$obj ;;
+ *[\ /]"$objbase "*)
+ while :; do
+ # Make sure we don't pick an alternate name that also
+ # overlaps.
+ newobj=lt$counter-$objbase
+ func_arith $counter + 1
+ counter=$func_arith_result
+ case " $oldobjs " in
+ *[\ /]"$newobj "*) ;;
+ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+ esac
+ done
+ func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+ oldobjs="$oldobjs $gentop/$newobj"
+ ;;
+ *) oldobjs="$oldobjs $obj" ;;
+ esac
+ done
+ fi
+ eval "cmds=\"$old_archive_cmds\""
+
+ func_len " $cmds"
+ len=$func_len_result
+ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ func_verbose "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ oldobjs=
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ eval "test_cmds=\"$old_archive_cmds\""
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+ for obj in $save_oldobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ func_append objlist " $obj"
+ if test "$len" -lt "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj" ; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval "concat_cmds=\"\${concat_cmds}$old_archive_cmds\""
+ objlist=
+ len=$len0
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test "X$oldobjs" = "X" ; then
+ eval "cmds=\"\$concat_cmds\""
+ else
+ eval "cmds=\"\$concat_cmds~\$old_archive_cmds\""
+ fi
+ fi
+ fi
+ func_execute_cmds "$cmds" 'exit $?'
+ done
+
+ test -n "$generated" && \
+ func_show_eval "${RM}r$generated"
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ func_verbose "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ if test "$hardcode_automatic" = yes ; then
+ relink_command=
+ fi
+
+ # Only create the output if not a dry run.
+ $opt_dry_run || {
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ func_basename "$deplib"
+ name="$func_basename_result"
+ libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$deplib' is not a valid libtool archive"
+ newdependency_libs="$newdependency_libs $libdir/$name"
+ ;;
+ *) newdependency_libs="$newdependency_libs $deplib" ;;
+ esac
+ done
+ dependency_libs="$newdependency_libs"
+ newdlfiles=
+
+ for lib in $dlfiles; do
+ case $lib in
+ *.la)
+ func_basename "$lib"
+ name="$func_basename_result"
+ libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$lib' is not a valid libtool archive"
+ newdlfiles="$newdlfiles $libdir/$name"
+ ;;
+ *) newdlfiles="$newdlfiles $lib" ;;
+ esac
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ *.la)
+ # Only pass preopened files to the pseudo-archive (for
+ # eventual linking with the app. that links it) if we
+ # didn't already link the preopened objects directly into
+ # the library:
+ func_basename "$lib"
+ name="$func_basename_result"
+ libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$lib' is not a valid libtool archive"
+ newdlprefiles="$newdlprefiles $libdir/$name"
+ ;;
+ esac
+ done
+ dlprefiles="$newdlprefiles"
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlfiles="$newdlfiles $abs"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlprefiles="$newdlprefiles $abs"
+ done
+ dlprefiles="$newdlprefiles"
+ fi
+ $RM $output
+ # place dlname in correct position for cygwin
+ # In fact, it would be nice if we could use this code for all target
+ # systems that can't hard-code library paths into their executables
+ # and that have no shared library path variable independent of PATH,
+ # but it turns out we can't easily determine that from inspecting
+ # libtool variables, so we have to hard-code the OSs to which it
+ # applies here; at the moment, that means platforms that use the PE
+ # object format with DLL files. See the long comment at the top of
+ # tests/bindir.at for full details.
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+ # If a -bindir argument was supplied, place the dll there.
+ if test "x$bindir" != x ;
+ then
+ func_relative_path "$install_libdir" "$bindir"
+ tdlname=$func_relative_path_result$dlname
+ else
+ # Otherwise fall back on heuristic.
+ tdlname=../bin/$dlname
+ fi
+ ;;
+ esac
+ $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test "$installed" = no && test "$need_relink" = yes; then
+ $ECHO >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ }
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+ ;;
+ esac
+ exit $EXIT_SUCCESS
+}
+
+{ test "$mode" = link || test "$mode" = relink; } &&
+ func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+ $opt_debug
+ RM="$nonopt"
+ files=
+ rmforce=
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ for arg
+ do
+ case $arg in
+ -f) RM="$RM $arg"; rmforce=yes ;;
+ -*) RM="$RM $arg" ;;
+ *) files="$files $arg" ;;
+ esac
+ done
+
+ test -z "$RM" && \
+ func_fatal_help "you must specify an RM program"
+
+ rmdirs=
+
+ origobjdir="$objdir"
+ for file in $files; do
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+ if test "X$dir" = X.; then
+ objdir="$origobjdir"
+ else
+ objdir="$dir/$origobjdir"
+ fi
+ func_basename "$file"
+ name="$func_basename_result"
+ test "$mode" = uninstall && objdir="$dir"
+
+ # Remember objdir for removal later, being careful to avoid duplicates
+ if test "$mode" = clean; then
+ case " $rmdirs " in
+ *" $objdir "*) ;;
+ *) rmdirs="$rmdirs $objdir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if { test -L "$file"; } >/dev/null 2>&1 ||
+ { test -h "$file"; } >/dev/null 2>&1 ||
+ test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif test "$rmforce" = yes; then
+ continue
+ fi
+
+ rmfiles="$file"
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if func_lalib_p "$file"; then
+ func_source $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ rmfiles="$rmfiles $objdir/$n"
+ done
+ test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+
+ case "$mode" in
+ clean)
+ case " $library_names " in
+ # " " in the beginning catches empty $dlname
+ *" $dlname "*) ;;
+ *) rmfiles="$rmfiles $objdir/$dlname" ;;
+ esac
+ test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+ ;;
+ uninstall)
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ ;;
+ esac
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if func_lalib_p "$file"; then
+
+ # Read the .lo file
+ func_source $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" &&
+ test "$pic_object" != none; then
+ rmfiles="$rmfiles $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" &&
+ test "$non_pic_object" != none; then
+ rmfiles="$rmfiles $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test "$mode" = clean ; then
+ noexename=$name
+ case $file in
+ *.exe)
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ func_stripname '' '.exe' "$name"
+ noexename=$func_stripname_result
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ rmfiles="$rmfiles $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if func_ltwrapper_p "$file"; then
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ relink_command=
+ func_source $func_ltwrapper_scriptname_result
+ rmfiles="$rmfiles $func_ltwrapper_scriptname_result"
+ else
+ relink_command=
+ func_source $dir/$noexename
+ fi
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+ if test "$fast_install" = yes && test -n "$relink_command"; then
+ rmfiles="$rmfiles $objdir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name" ; then
+ rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ func_show_eval "$RM $rmfiles" 'exit_status=1'
+ done
+ objdir="$origobjdir"
+
+ # Try to remove the ${objdir}s in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ func_show_eval "rmdir $dir >/dev/null 2>&1"
+ fi
+ done
+
+ exit $exit_status
+}
+
+{ test "$mode" = uninstall || test "$mode" = clean; } &&
+ func_mode_uninstall ${1+"$@"}
+
+test -z "$mode" && {
+ help="$generic_help"
+ func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+ func_fatal_help "invalid operation mode \`$mode'"
+
+if test -n "$exec_cmd"; then
+ eval exec "$exec_cmd"
+ exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
diff --git a/libgo/config/ltoptions.m4 b/libgo/config/ltoptions.m4
new file mode 100644
index 000000000..5ef12ced2
--- /dev/null
+++ b/libgo/config/ltoptions.m4
@@ -0,0 +1,369 @@
+# Helper functions for option handling. -*- Autoconf -*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it. Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+ _LT_MANGLE_DEFUN([$1], [$2]),
+ [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+ [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME. If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+ dnl
+ dnl Simply set some default values (i.e off) if boolean options were not
+ dnl specified:
+ _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+ ])
+ _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+ ])
+ dnl
+ dnl If no reference was made to various pairs of opposing options, then
+ dnl we run the default mode handler for the pair. For example, if neither
+ dnl `shared' nor `disable-shared' was passed, we enable building of shared
+ dnl archives by default:
+ _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+ _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+ [_LT_ENABLE_FAST_INSTALL])
+ ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS], [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+ [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+ _LT_DECL([build_libtool_libs], [enable_shared], [0],
+ [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+ [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+ _LT_DECL([build_old_libs], [enable_static], [0],
+ [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+ [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+ [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+ [AS_HELP_STRING([--with-pic],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [pic_mode="$withval"],
+ [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+ [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+ [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+ [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+ [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+ [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/libgo/config/ltsugar.m4 b/libgo/config/ltsugar.m4
new file mode 100644
index 000000000..9000a057d
--- /dev/null
+++ b/libgo/config/ltsugar.m4
@@ -0,0 +1,123 @@
+# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+ [$#], [2], [[$2]],
+ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+ [$#], 1, [],
+ [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+ [m4_foreach([_Lt_suffix],
+ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+ [lt_append([$1], [$2], [$3])$4],
+ [$5])],
+ [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+ [$5],
+ [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+ [lt_join(m4_quote(m4_default([$4], [[, ]])),
+ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/libgo/config/ltversion.m4 b/libgo/config/ltversion.m4
new file mode 100644
index 000000000..bf87f7713
--- /dev/null
+++ b/libgo/config/ltversion.m4
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers -*- Autoconf -*-
+#
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# Generated from ltversion.in.
+
+# serial 3134 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.2.7a])
+m4_define([LT_PACKAGE_REVISION], [1.3134])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.2.7a'
+macro_revision='1.3134'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/libgo/config/lt~obsolete.m4 b/libgo/config/lt~obsolete.m4
new file mode 100644
index 000000000..bf92b5e07
--- /dev/null
+++ b/libgo/config/lt~obsolete.m4
@@ -0,0 +1,98 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 4 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else. This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/libgo/configure b/libgo/configure
new file mode 100644
index 000000000..ca3544e5f
--- /dev/null
+++ b/libgo/configure
@@ -0,0 +1,17026 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.64 for package-unused version-unused.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software
+# Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1
+
+ test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ # We cannot yet assume a decent shell, so we have to provide a
+ # neutralization value for shells without unset; and this also
+ # works around shells that cannot unset nonexistent variables.
+ BASH_ENV=/dev/null
+ ENV=/dev/null
+ (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with status $?, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$?; test $as_status -eq 0 && as_status=1
+ if test "$3"; then
+ as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+ fi
+ $as_echo "$as_me: error: $1" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='package-unused'
+PACKAGE_TARNAME='libgo'
+PACKAGE_VERSION='version-unused'
+PACKAGE_STRING='package-unused version-unused'
+PACKAGE_BUGREPORT=''
+PACKAGE_URL=''
+
+ac_unique_file="Makefile.am"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+STRINGOPS_FLAG
+HAVE_SYS_MMAN_H_FALSE
+HAVE_SYS_MMAN_H_TRUE
+PTHREAD_LIBS
+PTHREAD_CFLAGS
+NET_LIBS
+MATH_LIBS
+USING_SPLIT_STACK_FALSE
+USING_SPLIT_STACK_TRUE
+SPLIT_STACK
+GO_DEBUG_PROC_REGS_OS_ARCH_FILE
+GO_SYSCALLS_SYSCALL_OS_ARCH_FILE
+GOARCH
+LIBGO_IS_X86_64_FALSE
+LIBGO_IS_X86_64_TRUE
+LIBGO_IS_SPARC64_FALSE
+LIBGO_IS_SPARC64_TRUE
+LIBGO_IS_SPARC_FALSE
+LIBGO_IS_SPARC_TRUE
+LIBGO_IS_PPC64_FALSE
+LIBGO_IS_PPC64_TRUE
+LIBGO_IS_PPC_FALSE
+LIBGO_IS_PPC_TRUE
+LIBGO_IS_MIPS64_FALSE
+LIBGO_IS_MIPS64_TRUE
+LIBGO_IS_MIPS_FALSE
+LIBGO_IS_MIPS_TRUE
+LIBGO_IS_M68K_FALSE
+LIBGO_IS_M68K_TRUE
+LIBGO_IS_ARM_FALSE
+LIBGO_IS_ARM_TRUE
+LIBGO_IS_386_FALSE
+LIBGO_IS_386_TRUE
+GOOS
+LIBGO_IS_SOLARIS_FALSE
+LIBGO_IS_SOLARIS_TRUE
+LIBGO_IS_RTEMS_FALSE
+LIBGO_IS_RTEMS_TRUE
+LIBGO_IS_LINUX_FALSE
+LIBGO_IS_LINUX_TRUE
+LIBGO_IS_FREEBSD_FALSE
+LIBGO_IS_FREEBSD_TRUE
+LIBGO_IS_DARWIN_FALSE
+LIBGO_IS_DARWIN_TRUE
+LIBFFIINCS
+LIBFFI
+glibgo_toolexeclibdir
+glibgo_toolexecdir
+glibgo_prefixdir
+WERROR
+WARN_FLAGS
+enable_static
+enable_shared
+CPP
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+AR
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LIBTOOL
+OBJCOPY
+RANLIB
+LD
+FGREP
+EGREP
+GREP
+SED
+MAINT
+MAINTAINER_MODE_FALSE
+MAINTAINER_MODE_TRUE
+GOCFLAGS
+GOC
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_os
+target_vendor
+target_cpu
+target
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+multi_basedir
+libtool_VERSION
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_multilib
+enable_dependency_tracking
+enable_maintainer_mode
+with_gnu_ld
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+enable_libtool_lock
+enable_version_specific_runtime_libs
+with_libffi
+with_system_libunwind
+enable_sjlj_exceptions
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CPP
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information."
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures package-unused version-unused to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/libgo]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+ --target=TARGET configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of package-unused version-unused:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-multilib build many library versions (default)
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer
+ --enable-shared[=PKGS] build shared libraries [default=yes]
+ --enable-static[=PKGS] build static libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+ --enable-version-specific-runtime-libs
+ Specify that runtime libraries should be installed
+ in a compiler-specific directory
+ --enable-sjlj-exceptions
+ force use of builtin_setjmp for exceptions
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-pic try to use only PIC/non-PIC objects [default=use
+ both]
+ --without-libffi don't use libffi
+ --with-system-libunwind use installed libunwind
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ GOC Go compiler command
+ GOCFLAGS Go compiler flags
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+package-unused configure version-unused
+generated by GNU Autoconf 2.64
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ return $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ return $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ return $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ return $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_type
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by package-unused $as_me version-unused, which was
+generated by GNU Autoconf 2.64. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ ac_site_file1=$CONFIG_SITE
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+libtool_VERSION=1:0:0
+
+
+# Default to --enable-multilib
+# Check whether --enable-multilib was given.
+if test "${enable_multilib+set}" = set; then :
+ enableval=$enable_multilib; case "$enableval" in
+ yes) multilib=yes ;;
+ no) multilib=no ;;
+ *) as_fn_error "bad value $enableval for multilib option" "$LINENO" 5 ;;
+ esac
+else
+ multilib=yes
+fi
+
+
+# We may get other options which we leave undocumented:
+# --with-target-subdir, --with-multisrctop, --with-multisubdir
+# See config-ml.in if you want the gory details.
+
+if test "$srcdir" = "."; then
+ if test "$with_target_subdir" != "."; then
+ multi_basedir="$srcdir/$with_multisrctop../.."
+ else
+ multi_basedir="$srcdir/$with_multisrctop.."
+ fi
+else
+ multi_basedir="$srcdir/.."
+fi
+
+
+# Even if the default multilib is not a cross compilation,
+# it may be that some of the other multilibs are.
+if test $cross_compiling = no && test $multilib = yes \
+ && test "x${with_multisubdir}" != x ; then
+ cross_compiling=maybe
+fi
+
+ac_config_commands="$ac_config_commands default-1"
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ for ac_t in install-sh install.sh shtool; do
+ if test -f "$ac_dir/$ac_t"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/$ac_t -c"
+ break 2
+ fi
+ done
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if test "${ac_cv_build+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if test "${ac_cv_host+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if test "${ac_cv_target+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$target_alias" = x; then
+ ac_cv_target=$ac_cv_host
+else
+ ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+ as_fn_error "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+target_alias=${target_alias-$host_alias}
+
+am__api_version='1.11'
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error "ls -t appears to fail. Make sure there is not a broken
+alias in your environment" "$LINENO" 5
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+ if test "${ac_cv_path_mkdir+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
+ done
+IFS=$as_save_IFS
+
+fi
+
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for MKDIR_P within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ test -d ./--version && rmdir ./--version
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+mkdir_p="$MKDIR_P"
+case $mkdir_p in
+ [\\/$]* | ?:[\\/]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='libgo'
+ VERSION='version-unused'
+
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "no acceptable C compiler found in \$PATH
+See \`config.log' for more details." "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ rm -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+if test -z "$ac_file"; then :
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "C compiler cannot create executables
+See \`config.log' for more details." "$LINENO" 5; }; }
+fi
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." "$LINENO" 5; }
+fi
+rm -f conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+ac_ext=go
+ac_compile='$GOC -c $GOCFLAGS conftest.$ac_ext >&5'
+ac_link='$GOC -o conftest$ac_exeext $GOCFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compile_gnu=yes
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gccgo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gccgo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_GOC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$GOC"; then
+ ac_cv_prog_GOC="$GOC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_GOC="${ac_tool_prefix}gccgo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+GOC=$ac_cv_prog_GOC
+if test -n "$GOC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GOC" >&5
+$as_echo "$GOC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_GOC"; then
+ ac_ct_GOC=$GOC
+ # Extract the first word of "gccgo", so it can be a program name with args.
+set dummy gccgo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_GOC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_GOC"; then
+ ac_cv_prog_ac_ct_GOC="$ac_ct_GOC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_GOC="gccgo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_GOC=$ac_cv_prog_ac_ct_GOC
+if test -n "$ac_ct_GOC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_GOC" >&5
+$as_echo "$ac_ct_GOC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_GOC" = x; then
+ GOC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ GOC=$ac_ct_GOC
+ fi
+else
+ GOC="$ac_cv_prog_GOC"
+fi
+
+if test -z "$GOC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gccgo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gccgo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_GOC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$GOC"; then
+ ac_cv_prog_GOC="$GOC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_GOC="$ac_tool_prefix}gccgo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+GOC=$ac_cv_prog_GOC
+if test -n "$GOC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GOC" >&5
+$as_echo "$GOC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$GOC"; then
+ # Extract the first word of "gccgo", so it can be a program name with args.
+set dummy gccgo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_GOC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$GOC"; then
+ ac_cv_prog_GOC="$GOC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "gccgo"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_GOC="gccgo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_GOC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set GOC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_GOC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+GOC=$ac_cv_prog_GOC
+if test -n "$GOC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GOC" >&5
+$as_echo "$GOC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for Go compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+{ { ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler --version >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ rm -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+GOCFLAGS="-g -O2"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
+$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
+ # Check whether --enable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then :
+ enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
+$as_echo "$USE_MAINTAINER_MODE" >&6; }
+ if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if test "${ac_cv_path_SED+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if test "${ac_cv_path_FGREP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+ then ac_cv_path_FGREP="$GREP -F"
+ else
+ if test -z "$FGREP"; then
+ ac_path_FGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in fgrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+ # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'FGREP' >> "conftest.nl"
+ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_FGREP="$ac_path_FGREP"
+ ac_path_FGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_FGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_FGREP"; then
+ as_fn_error "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_FGREP=$FGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`print -r -- -n 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO ""
+}
+
+case "$ECHO" in
+ printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+ print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if test "${lt_cv_path_LD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if test "${lt_cv_prog_gnu_ld+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objcopy", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objcopy; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OBJCOPY+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJCOPY"; then
+ ac_cv_prog_OBJCOPY="$OBJCOPY" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OBJCOPY="${ac_tool_prefix}objcopy"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJCOPY=$ac_cv_prog_OBJCOPY
+if test -n "$OBJCOPY"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJCOPY" >&5
+$as_echo "$OBJCOPY" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJCOPY"; then
+ ac_ct_OBJCOPY=$OBJCOPY
+ # Extract the first word of "objcopy", so it can be a program name with args.
+set dummy objcopy; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OBJCOPY+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJCOPY"; then
+ ac_cv_prog_ac_ct_OBJCOPY="$ac_ct_OBJCOPY" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OBJCOPY="objcopy"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJCOPY=$ac_cv_prog_ac_ct_OBJCOPY
+if test -n "$ac_ct_OBJCOPY"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJCOPY" >&5
+$as_echo "$ac_ct_OBJCOPY" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJCOPY" = x; then
+ OBJCOPY="missing-objcopy"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJCOPY=$ac_ct_OBJCOPY
+ fi
+else
+ OBJCOPY="$ac_cv_prog_OBJCOPY"
+fi
+
+
+enable_dlopen=yes
+
+
+
+case `pwd` in
+ *\ * | *\ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.2.7a'
+macro_revision='1.3134'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if test "${lt_cv_path_NM+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in dumpbin "link -dump"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DUMPBIN+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DUMPBIN"; then
+ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$DUMPBIN" && break
+ done
+fi
+if test -z "$DUMPBIN"; then
+ ac_ct_DUMPBIN=$DUMPBIN
+ for ac_prog in dumpbin "link -dump"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DUMPBIN"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_DUMPBIN" && break
+done
+
+ if test "x$ac_ct_DUMPBIN" = x; then
+ DUMPBIN=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DUMPBIN=$ac_ct_DUMPBIN
+ fi
+fi
+
+ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if test "${lt_cv_nm_interface+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+ cat conftest.out >&5
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if test "${lt_cv_ld_reload_flag+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OBJDUMP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if test "${lt_cv_deplibs_check_method+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[45]*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[3-9]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AR+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_AR="ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDEGRST]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris*)
+ symcode='[BDRT]'
+ ;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK '"\
+" {last_section=section; section=\$ 3};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+ (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+ enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if test "${lt_cv_cc_needs_belf+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_cc_needs_belf=yes
+else
+ lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD="${LD-ld}_sol2"
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+
+ case $host_os in
+ rhapsody* | darwin*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DSYMUTIL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DSYMUTIL"; then
+ ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+ ac_ct_DSYMUTIL=$DSYMUTIL
+ # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DSYMUTIL"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DSYMUTIL" = x; then
+ DSYMUTIL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DSYMUTIL=$ac_ct_DSYMUTIL
+ fi
+else
+ DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_NMEDIT+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NMEDIT"; then
+ ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+ ac_ct_NMEDIT=$NMEDIT
+ # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_NMEDIT"; then
+ ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_NMEDIT="nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_NMEDIT" = x; then
+ NMEDIT=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ NMEDIT=$ac_ct_NMEDIT
+ fi
+else
+ NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_LIPO+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LIPO"; then
+ ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+ ac_ct_LIPO=$LIPO
+ # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_LIPO"; then
+ ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_LIPO="lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_LIPO" = x; then
+ LIPO=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ LIPO=$ac_ct_LIPO
+ fi
+else
+ LIPO="$ac_cv_prog_LIPO"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OTOOL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL"; then
+ ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+ ac_ct_OTOOL=$OTOOL
+ # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL"; then
+ ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OTOOL="otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL" = x; then
+ OTOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL=$ac_ct_OTOOL
+ fi
+else
+ OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OTOOL64+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL64"; then
+ ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+ ac_ct_OTOOL64=$OTOOL64
+ # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL64"; then
+ ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OTOOL64="otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL64" = x; then
+ OTOOL64=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL64=$ac_ct_OTOOL64
+ fi
+else
+ OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if test "${lt_cv_apple_cc_single_mod+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if test "${lt_cv_ld_exported_symbols_list+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_ld_exported_symbols_list=yes
+else
+ lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if test "${lt_cv_ld_force_load+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+ echo "$AR cru libconftest.a conftest.o" >&5
+ $AR cru libconftest.a conftest.o 2>&5
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[012]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gccgo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gccgo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_GOC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$GOC"; then
+ ac_cv_prog_GOC="$GOC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_GOC="${ac_tool_prefix}gccgo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+GOC=$ac_cv_prog_GOC
+if test -n "$GOC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GOC" >&5
+$as_echo "$GOC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_GOC"; then
+ ac_ct_GOC=$GOC
+ # Extract the first word of "gccgo", so it can be a program name with args.
+set dummy gccgo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_GOC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_GOC"; then
+ ac_cv_prog_ac_ct_GOC="$ac_ct_GOC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_GOC="gccgo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_GOC=$ac_cv_prog_ac_ct_GOC
+if test -n "$ac_ct_GOC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_GOC" >&5
+$as_echo "$ac_ct_GOC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_GOC" = x; then
+ GOC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ GOC=$ac_ct_GOC
+ fi
+else
+ GOC="$ac_cv_prog_GOC"
+fi
+
+
+
+
+
+
+# Set options
+
+
+
+
+ enable_win32_dll=no
+
+
+ # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+ # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+ enableval=$enable_static; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+ withval=$with_pic; pic_mode="$withval"
+else
+ pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+ # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+ enableval=$enable_fast_install; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if test "${lt_cv_objdir+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/${ac_tool_prefix}file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+ *)
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+
+
+
+
+
+ lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ lt_prog_compiler_wl='-Xlinker '
+ lt_prog_compiler_pic='-Xcompiler -fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='--shared'
+ lt_prog_compiler_static='--static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-qpic'
+ lt_prog_compiler_static='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ F* | *Sun*Fortran*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl=''
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5
+$as_echo "$lt_prog_compiler_pic" >&6; }
+
+
+
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if test "${lt_cv_prog_compiler_pic_works+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if test "${lt_cv_prog_compiler_static_works+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ runpath_var=
+ allow_undefined_flag=
+ always_export_symbols=no
+ archive_cmds=
+ archive_expsym_cmds=
+ compiler_needs_object=no
+ enable_shared_with_static_runtimes=no
+ export_dynamic_flag_spec=
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic=no
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld=
+ hardcode_libdir_separator=
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ inherit_rpath=no
+ link_all_deplibs=unknown
+ module_cmds=
+ module_expsym_cmds=
+ old_archive_from_new_cmds=
+ old_archive_from_expsyms_cmds=
+ thread_safe_flag_spec=
+ whole_archive_flag_spec=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+ *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ export_dynamic_flag_spec='${wl}--export-all-symbols'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ haiku*)
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ link_all_deplibs=yes
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ whole_archive_flag_spec=
+ tmp_sharedflag='--shared' ;;
+ xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld='-rpath $libdir'
+ archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ file_list_spec='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ export_dynamic_flag_spec='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bernotok'
+ allow_undefined_flag=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec='$convenience'
+ fi
+ archive_cmds_need_lc=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ else
+ whole_archive_flag_spec=''
+ fi
+ link_all_deplibs=yes
+ allow_undefined_flag="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+ else
+ ld_shlibs=no
+ fi
+
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld='+b $libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if test "${lt_cv_prog_compiler__b+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler__b=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -b"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler__b=yes
+ fi
+ else
+ lt_cv_prog_compiler__b=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ *)
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foo(void) {}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ inherit_rpath=yes
+ link_all_deplibs=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ hardcode_direct_absolute=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_separator=:
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag='${wl}-z,text'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='${wl}-z,text'
+ allow_undefined_flag='${wl}-z,nodefs'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-R,$libdir'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if test "${lt_cv_archive_cmds_need_lc+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc=no
+ else
+ lt_cv_archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+ archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+ *) lt_sed_strip_eq="s,=/,/,g" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[lt_foo]++; }
+ if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[123]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+haiku*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[3-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ if test "${lt_cv_shlibpath_overrides_runpath+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+fi
+
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+ test -n "$runpath_var" ||
+ test "X$hardcode_automatic" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+ test "$inherit_rpath" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+ if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = x""yes; then :
+ lt_cv_dlopen="shl_load"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_shl_load=yes
+else
+ ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = x""yes; then :
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_svld_dlopen=yes
+else
+ ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_dld_link=yes
+else
+ ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = x""yes; then :
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if test "${lt_cv_dlopen_self+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line 10901 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if test "${lt_cv_dlopen_self_static+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line 11007 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+ # Report which library types will actually be built
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+objext_GO=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC="$GCC"
+GCC=yes
+CC=${GOC-"gccgo"}
+compiler=$CC
+compiler_GO=$CC
+LD_GO="$LD"
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+archive_cmds_need_lc_GO=no
+
+old_archive_cmds_GO=$old_archive_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag_GO=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ lt_prog_compiler_no_builtin_flag_GO=' -Xcompiler -fno-builtin' ;;
+ *)
+ lt_prog_compiler_no_builtin_flag_GO=' -fno-builtin' ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag_GO="$lt_prog_compiler_no_builtin_flag_GO -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+
+
+ lt_prog_compiler_wl_GO=
+lt_prog_compiler_pic_GO=
+lt_prog_compiler_static_GO=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl_GO='-Wl,'
+ lt_prog_compiler_static_GO='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_GO='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic_GO='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic_GO='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic_GO='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic_GO='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static_GO=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_GO='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared_GO=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic_GO='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic_GO=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic_GO='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ lt_prog_compiler_wl_GO='-Xlinker '
+ lt_prog_compiler_pic_GO='-Xcompiler -fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl_GO='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_GO='-Bstatic'
+ else
+ lt_prog_compiler_static_GO='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_GO='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl_GO='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_GO='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static_GO='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl_GO='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static_GO='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ lt_prog_compiler_wl_GO='-Wl,'
+ lt_prog_compiler_pic_GO='-KPIC'
+ lt_prog_compiler_static_GO='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ lt_prog_compiler_wl_GO='-Wl,'
+ lt_prog_compiler_pic_GO='-fPIC'
+ lt_prog_compiler_static_GO='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ lt_prog_compiler_wl_GO='-Wl,'
+ lt_prog_compiler_pic_GO='--shared'
+ lt_prog_compiler_static_GO='--static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl_GO='-Wl,'
+ lt_prog_compiler_pic_GO='-fpic'
+ lt_prog_compiler_static_GO='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl_GO='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static_GO='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ lt_prog_compiler_wl_GO='-Wl,'
+ lt_prog_compiler_pic_GO='-qpic'
+ lt_prog_compiler_static_GO='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ F* | *Sun*Fortran*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic_GO='-KPIC'
+ lt_prog_compiler_static_GO='-Bstatic'
+ lt_prog_compiler_wl_GO=''
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic_GO='-KPIC'
+ lt_prog_compiler_static_GO='-Bstatic'
+ lt_prog_compiler_wl_GO='-Wl,'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic_GO='-KPIC'
+ lt_prog_compiler_static_GO='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic_GO='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl_GO='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static_GO='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static_GO='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic_GO='-KPIC'
+ lt_prog_compiler_static_GO='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ lt_prog_compiler_wl_GO='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl_GO='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl_GO='-Qoption ld '
+ lt_prog_compiler_pic_GO='-PIC'
+ lt_prog_compiler_static_GO='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl_GO='-Wl,'
+ lt_prog_compiler_pic_GO='-KPIC'
+ lt_prog_compiler_static_GO='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic_GO='-Kconform_pic'
+ lt_prog_compiler_static_GO='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl_GO='-Wl,'
+ lt_prog_compiler_pic_GO='-KPIC'
+ lt_prog_compiler_static_GO='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl_GO='-Wl,'
+ lt_prog_compiler_can_build_shared_GO=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic_GO='-pic'
+ lt_prog_compiler_static_GO='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared_GO=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic_GO=
+ ;;
+ *)
+ lt_prog_compiler_pic_GO="$lt_prog_compiler_pic_GO"
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_GO" >&5
+$as_echo "$lt_prog_compiler_pic_GO" >&6; }
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_GO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_GO works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_GO works... " >&6; }
+if test "${lt_cv_prog_compiler_pic_works_GO+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works_GO=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic_GO"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works_GO=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_GO" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works_GO" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works_GO" = xyes; then
+ case $lt_prog_compiler_pic_GO in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic_GO=" $lt_prog_compiler_pic_GO" ;;
+ esac
+else
+ lt_prog_compiler_pic_GO=
+ lt_prog_compiler_can_build_shared_GO=no
+fi
+
+fi
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_GO eval lt_tmp_static_flag=\"$lt_prog_compiler_static_GO\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if test "${lt_cv_prog_compiler_static_works_GO+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works_GO=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works_GO=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works_GO=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_GO" >&5
+$as_echo "$lt_cv_prog_compiler_static_works_GO" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works_GO" = xyes; then
+ :
+else
+ lt_prog_compiler_static_GO=
+fi
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o_GO+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o_GO=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o_GO=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_GO" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_GO" >&6; }
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o_GO+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o_GO=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o_GO=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_GO" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_GO" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_GO" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ runpath_var=
+ allow_undefined_flag_GO=
+ always_export_symbols_GO=no
+ archive_cmds_GO=
+ archive_expsym_cmds_GO=
+ compiler_needs_object_GO=no
+ enable_shared_with_static_runtimes_GO=no
+ export_dynamic_flag_spec_GO=
+ export_symbols_cmds_GO='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic_GO=no
+ hardcode_direct_GO=no
+ hardcode_direct_absolute_GO=no
+ hardcode_libdir_flag_spec_GO=
+ hardcode_libdir_flag_spec_ld_GO=
+ hardcode_libdir_separator_GO=
+ hardcode_minus_L_GO=no
+ hardcode_shlibpath_var_GO=unsupported
+ inherit_rpath_GO=no
+ link_all_deplibs_GO=unknown
+ module_cmds_GO=
+ module_expsym_cmds_GO=
+ old_archive_from_new_cmds_GO=
+ old_archive_from_expsyms_cmds_GO=
+ thread_safe_flag_spec_GO=
+ whole_archive_flag_spec_GO=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms_GO=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms_GO='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs_GO=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+ *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_GO='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec_GO='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_GO="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_GO=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs_GO=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GO=''
+ ;;
+ m68k)
+ archive_cmds_GO='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_GO='-L$libdir'
+ hardcode_minus_L_GO=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag_GO=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds_GO='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs_GO=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, GO) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec_GO='-L$libdir'
+ export_dynamic_flag_spec_GO='${wl}--export-all-symbols'
+ allow_undefined_flag_GO=unsupported
+ always_export_symbols_GO=no
+ enable_shared_with_static_runtimes_GO=yes
+ export_symbols_cmds_GO='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds_GO='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs_GO=no
+ fi
+ ;;
+
+ haiku*)
+ archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ link_all_deplibs_GO=yes
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct_GO=no
+ hardcode_shlibpath_var_GO=no
+ hardcode_libdir_flag_spec_GO='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_GO='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds_GO='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds_GO='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec_GO='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec_GO='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ whole_archive_flag_spec_GO=
+ tmp_sharedflag='--shared' ;;
+ xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ whole_archive_flag_spec_GO='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object_GO=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec_GO='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object_GO=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ archive_cmds_GO='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds_GO='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ whole_archive_flag_spec_GO='--whole-archive$convenience --no-whole-archive'
+ hardcode_libdir_flag_spec_GO=
+ hardcode_libdir_flag_spec_ld_GO='-rpath $libdir'
+ archive_cmds_GO='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds_GO='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ ld_shlibs_GO=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds_GO='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs_GO=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_GO=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs_GO=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec_GO='${wl}-rpath ${wl}$libdir'
+ archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_GO=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds_GO='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct_GO=yes
+ hardcode_shlibpath_var_GO=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs_GO=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs_GO" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec_GO=
+ export_dynamic_flag_spec_GO=
+ whole_archive_flag_spec_GO=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag_GO=unsupported
+ always_export_symbols_GO=yes
+ archive_expsym_cmds_GO='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L_GO=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct_GO=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds_GO='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds_GO='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds_GO=''
+ hardcode_direct_GO=yes
+ hardcode_direct_absolute_GO=yes
+ hardcode_libdir_separator_GO=':'
+ link_all_deplibs_GO=yes
+ file_list_spec_GO='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct_GO=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L_GO=yes
+ hardcode_libdir_flag_spec_GO='-L$libdir'
+ hardcode_libdir_separator_GO=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ export_dynamic_flag_spec_GO='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols_GO=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag_GO='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_GO='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds_GO='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec_GO='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag_GO="-z nodefs"
+ archive_expsym_cmds_GO="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_GO='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag_GO=' ${wl}-bernotok'
+ allow_undefined_flag_GO=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec_GO='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec_GO='$convenience'
+ fi
+ archive_cmds_need_lc_GO=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds_GO="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_GO=''
+ ;;
+ m68k)
+ archive_cmds_GO='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec_GO='-L$libdir'
+ hardcode_minus_L_GO=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec_GO=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec_GO=' '
+ allow_undefined_flag_GO=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds_GO='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds_GO='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds_GO='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path_GO='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes_GO=yes
+ ;;
+
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc_GO=no
+ hardcode_direct_GO=no
+ hardcode_automatic_GO=yes
+ hardcode_shlibpath_var_GO=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ whole_archive_flag_spec_GO='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ else
+ whole_archive_flag_spec_GO=''
+ fi
+ link_all_deplibs_GO=yes
+ allow_undefined_flag_GO="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds_GO="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ module_cmds_GO="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ archive_expsym_cmds_GO="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ module_expsym_cmds_GO="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+ else
+ ld_shlibs_GO=no
+ fi
+
+ ;;
+
+ dgux*)
+ archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_GO='-L$libdir'
+ hardcode_shlibpath_var_GO=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds_GO='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec_GO='-R$libdir'
+ hardcode_direct_GO=yes
+ hardcode_shlibpath_var_GO=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds_GO='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GO=yes
+ hardcode_minus_L_GO=yes
+ hardcode_shlibpath_var_GO=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds_GO='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_GO='-R$libdir'
+ hardcode_direct_GO=yes
+ hardcode_shlibpath_var_GO=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds_GO='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds_GO='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec_GO='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_GO=:
+ hardcode_direct_GO=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_GO=yes
+ export_dynamic_flag_spec_GO='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ archive_cmds_GO='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_GO='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec_GO='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld_GO='+b $libdir'
+ hardcode_libdir_separator_GO=:
+ hardcode_direct_GO=yes
+ hardcode_direct_absolute_GO=yes
+ export_dynamic_flag_spec_GO='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_GO=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_GO='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_GO='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_GO='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_GO='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_GO='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_GO='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec_GO='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_GO=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct_GO=no
+ hardcode_shlibpath_var_GO=no
+ ;;
+ *)
+ hardcode_direct_GO=yes
+ hardcode_direct_absolute_GO=yes
+ export_dynamic_flag_spec_GO='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L_GO=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foo(void) {}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ archive_expsym_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+ else
+ archive_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds_GO='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc_GO='no'
+ hardcode_libdir_flag_spec_GO='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_GO=:
+ inherit_rpath_GO=yes
+ link_all_deplibs_GO=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds_GO='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds_GO='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec_GO='-R$libdir'
+ hardcode_direct_GO=yes
+ hardcode_shlibpath_var_GO=no
+ ;;
+
+ newsos6)
+ archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GO=yes
+ hardcode_libdir_flag_spec_GO='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_GO=:
+ hardcode_shlibpath_var_GO=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct_GO=yes
+ hardcode_shlibpath_var_GO=no
+ hardcode_direct_absolute_GO=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds_GO='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GO='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec_GO='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_GO='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds_GO='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_GO='-R$libdir'
+ ;;
+ *)
+ archive_cmds_GO='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec_GO='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ ld_shlibs_GO=no
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec_GO='-L$libdir'
+ hardcode_minus_L_GO=yes
+ allow_undefined_flag_GO=unsupported
+ archive_cmds_GO='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds_GO='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag_GO=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_GO='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag_GO=' -expect_unresolved \*'
+ archive_cmds_GO='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc_GO='no'
+ hardcode_libdir_flag_spec_GO='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_GO=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag_GO=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_GO='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_GO='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag_GO=' -expect_unresolved \*'
+ archive_cmds_GO='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds_GO='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec_GO='-rpath $libdir'
+ fi
+ archive_cmds_need_lc_GO='no'
+ hardcode_libdir_separator_GO=:
+ ;;
+
+ solaris*)
+ no_undefined_flag_GO=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ archive_cmds_GO='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GO='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds_GO='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds_GO='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ archive_cmds_GO='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GO='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec_GO='-R$libdir'
+ hardcode_shlibpath_var_GO=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ whole_archive_flag_spec_GO='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec_GO='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs_GO=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds_GO='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_GO='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec_GO='-L$libdir'
+ hardcode_direct_GO=yes
+ hardcode_minus_L_GO=yes
+ hardcode_shlibpath_var_GO=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GO=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds_GO='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds_GO='$CC -r -o $output$reload_objs'
+ hardcode_direct_GO=no
+ ;;
+ motorola)
+ archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct_GO=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var_GO=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_GO=no
+ export_dynamic_flag_spec_GO='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var_GO=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs_GO=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag_GO='${wl}-z,text'
+ archive_cmds_need_lc_GO=no
+ hardcode_shlibpath_var_GO=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds_GO='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GO='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_GO='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GO='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag_GO='${wl}-z,text'
+ allow_undefined_flag_GO='${wl}-z,nodefs'
+ archive_cmds_need_lc_GO=no
+ hardcode_shlibpath_var_GO=no
+ hardcode_libdir_flag_spec_GO='${wl}-R,$libdir'
+ hardcode_libdir_separator_GO=':'
+ link_all_deplibs_GO=yes
+ export_dynamic_flag_spec_GO='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds_GO='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GO='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds_GO='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_GO='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds_GO='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec_GO='-L$libdir'
+ hardcode_shlibpath_var_GO=no
+ ;;
+
+ *)
+ ld_shlibs_GO=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec_GO='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_GO" >&5
+$as_echo "$ld_shlibs_GO" >&6; }
+test "$ld_shlibs_GO" = no && can_build_shared=no
+
+with_gnu_ld_GO=$with_gnu_ld
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_GO" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc_GO=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds_GO in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if test "${lt_cv_archive_cmds_need_lc_GO+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl_GO
+ pic_flag=$lt_prog_compiler_pic_GO
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag_GO
+ allow_undefined_flag_GO=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_GO 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds_GO 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc_GO=no
+ else
+ lt_cv_archive_cmds_need_lc_GO=yes
+ fi
+ allow_undefined_flag_GO=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_GO" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc_GO" >&6; }
+ archive_cmds_need_lc_GO=$lt_cv_archive_cmds_need_lc_GO
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action_GO=
+if test -n "$hardcode_libdir_flag_spec_GO" ||
+ test -n "$runpath_var_GO" ||
+ test "X$hardcode_automatic_GO" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct_GO" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, GO)" != no &&
+ test "$hardcode_minus_L_GO" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action_GO=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action_GO=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action_GO=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_GO" >&5
+$as_echo "$hardcode_action_GO" >&6; }
+
+if test "$hardcode_action_GO" = relink ||
+ test "$inherit_rpath_GO" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+GCC=$lt_save_GCC
+CC="$lt_save_CC"
+
+
+
+
+ ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+
+
+WARN_FLAGS='-Wall -Wextra -Wwrite-strings -Wcast-qual'
+
+
+WERROR="-Werror"
+
+
+glibgo_toolexecdir=no
+glibgo_toolexeclibdir=no
+glibgo_prefixdir=$prefix
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-version-specific-runtime-libs" >&5
+$as_echo_n "checking for --enable-version-specific-runtime-libs... " >&6; }
+# Check whether --enable-version-specific-runtime-libs was given.
+if test "${enable_version_specific_runtime_libs+set}" = set; then :
+ enableval=$enable_version_specific_runtime_libs; case "$enableval" in
+ yes) version_specific_libs=yes ;;
+ no) version_specific_libs=no ;;
+ *) as_fn_error "Unknown argument to enable/disable version-specific libs" "$LINENO" 5;;
+ esac
+else
+ version_specific_libs=no
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $version_specific_libs" >&5
+$as_echo "$version_specific_libs" >&6; }
+
+# Version-specific runtime libs processing.
+if test $version_specific_libs = yes; then
+ glibgo_toolexecdir='${libdir}/gcc/${host_alias}'
+ glibgo_toolexeclibdir='${toolexecdir}/${gcc_version}$(MULTISUBDIR)'
+fi
+
+# Calculate glibgo_toolexecdir, glibgo_toolexeclibdir
+# Install a library built with a cross compiler in tooldir, not libdir.
+if test x"$glibgo_toolexecdir" = x"no"; then
+ if test -n "$with_cross_host" &&
+ test x"$with_cross_host" != x"no"; then
+ glibgo_toolexecdir='${exec_prefix}/${host_alias}'
+ glibgo_toolexeclibdir='${toolexecdir}/lib'
+ else
+ glibgo_toolexecdir='${libdir}/gcc/${host_alias}'
+ glibgo_toolexeclibdir='${libdir}'
+ fi
+ multi_os_directory=`$CC -print-multi-os-directory`
+ case $multi_os_directory in
+ .) ;; # Avoid trailing /.
+ *) glibgo_toolexeclibdir=$glibgo_toolexeclibdir/$multi_os_directory ;;
+ esac
+fi
+
+
+
+
+
+# See if the user wants to configure without libffi. Some
+# architectures don't support it. FIXME: We should set a default
+# based on the host.
+
+# Check whether --with-libffi was given.
+if test "${with_libffi+set}" = set; then :
+ withval=$with_libffi; :
+else
+ with_libffi=${with_libffi_default-yes}
+fi
+
+
+LIBFFI=
+LIBFFIINCS=
+if test "$with_libffi" != no; then
+
+$as_echo "#define USE_LIBFFI 1" >>confdefs.h
+
+ LIBFFI=../libffi/libffi_convenience.la
+ LIBFFIINCS='-I$(top_srcdir)/../libffi/include -I../libffi/include'
+fi
+
+
+
+is_darwin=no
+is_freebsd=no
+is_linux=no
+is_rtems=no
+is_solaris=no
+GOOS=unknown
+case ${host} in
+ *-*-darwin*) is_darwin=yes; GOOS=darwin ;;
+ *-*-freebsd*) is_freebsd=yes; GOOS=freebsd ;;
+ *-*-linux*) is_linux=yes; GOOS=linux ;;
+ *-*-rtems*) is_rtems=yes; GOOS=rtems ;;
+ *-*-solaris2*) is_solaris=yes; GOOS=solaris ;;
+esac
+ if test $is_darwin = yes; then
+ LIBGO_IS_DARWIN_TRUE=
+ LIBGO_IS_DARWIN_FALSE='#'
+else
+ LIBGO_IS_DARWIN_TRUE='#'
+ LIBGO_IS_DARWIN_FALSE=
+fi
+
+ if test $is_freebsd = yes; then
+ LIBGO_IS_FREEBSD_TRUE=
+ LIBGO_IS_FREEBSD_FALSE='#'
+else
+ LIBGO_IS_FREEBSD_TRUE='#'
+ LIBGO_IS_FREEBSD_FALSE=
+fi
+
+ if test $is_linux = yes; then
+ LIBGO_IS_LINUX_TRUE=
+ LIBGO_IS_LINUX_FALSE='#'
+else
+ LIBGO_IS_LINUX_TRUE='#'
+ LIBGO_IS_LINUX_FALSE=
+fi
+
+ if test $is_rtems = yes; then
+ LIBGO_IS_RTEMS_TRUE=
+ LIBGO_IS_RTEMS_FALSE='#'
+else
+ LIBGO_IS_RTEMS_TRUE='#'
+ LIBGO_IS_RTEMS_FALSE=
+fi
+
+ if test $is_solaris = yes; then
+ LIBGO_IS_SOLARIS_TRUE=
+ LIBGO_IS_SOLARIS_FALSE='#'
+else
+ LIBGO_IS_SOLARIS_TRUE='#'
+ LIBGO_IS_SOLARIS_FALSE=
+fi
+
+
+
+is_386=no
+is_arm=no
+is_m68k=no
+is_mips=no
+is_mips64=no
+is_ppc=no
+is_ppc64=no
+is_sparc=no
+is_sparc64=no
+is_x86_64=no
+GOARCH=unknown
+case ${host} in
+ arm*-*-* | strongarm*-*-* | ep9312*-*-* | xscale-*-*)
+ is_arm=yes
+ GOARCH=arm
+ ;;
+ i[34567]86-*-* | x86_64-*-*)
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef __x86_64__
+#error 64-bit
+#endif
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ is_386=yes
+else
+ is_x86_64=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "$is_386" = "yes"; then
+ GOARCH=386
+ else
+ GOARCH=amd64
+ fi
+ ;;
+ m68k*-*-*)
+ is_m68k=yes
+ GOARCH=m68k
+ ;;
+ mips*-*-*)
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef __mips64
+#error 64-bit
+#endif
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ is_mips=yes
+else
+ is_mips64=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "$is_mips" = "yes"; then
+ GOARCH=mips
+ else
+ GOARCH=mips64
+ fi
+ ;;
+ rs6000*-*-* | powerpc*-*-*)
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef _ARCH_PPC64
+#error 64-bit
+#endif
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ is_ppc=yes
+else
+ is_ppc64=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "$is_ppc" = "yes"; then
+ GOARCH=ppc
+ else
+ GOARCH=ppc64
+ fi
+ ;;
+ sparc*-*-*)
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#if defined(__sparcv9) || defined(__arch64__)
+#error 64-bit
+#endif
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ is_sparc=yes
+else
+ is_sparc64=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "$is_sparc" = "yes"; then
+ GOARCH=sparc
+ else
+ GOARCH=sparc64
+ fi
+ ;;
+esac
+ if test $is_386 = yes; then
+ LIBGO_IS_386_TRUE=
+ LIBGO_IS_386_FALSE='#'
+else
+ LIBGO_IS_386_TRUE='#'
+ LIBGO_IS_386_FALSE=
+fi
+
+ if test $is_arm = yes; then
+ LIBGO_IS_ARM_TRUE=
+ LIBGO_IS_ARM_FALSE='#'
+else
+ LIBGO_IS_ARM_TRUE='#'
+ LIBGO_IS_ARM_FALSE=
+fi
+
+ if test $is_m68k = yes; then
+ LIBGO_IS_M68K_TRUE=
+ LIBGO_IS_M68K_FALSE='#'
+else
+ LIBGO_IS_M68K_TRUE='#'
+ LIBGO_IS_M68K_FALSE=
+fi
+
+ if test $is_mips = yes; then
+ LIBGO_IS_MIPS_TRUE=
+ LIBGO_IS_MIPS_FALSE='#'
+else
+ LIBGO_IS_MIPS_TRUE='#'
+ LIBGO_IS_MIPS_FALSE=
+fi
+
+ if test $is_mips64 = yes; then
+ LIBGO_IS_MIPS64_TRUE=
+ LIBGO_IS_MIPS64_FALSE='#'
+else
+ LIBGO_IS_MIPS64_TRUE='#'
+ LIBGO_IS_MIPS64_FALSE=
+fi
+
+ if test $is_ppc = yes; then
+ LIBGO_IS_PPC_TRUE=
+ LIBGO_IS_PPC_FALSE='#'
+else
+ LIBGO_IS_PPC_TRUE='#'
+ LIBGO_IS_PPC_FALSE=
+fi
+
+ if test $is_ppc64 = yes; then
+ LIBGO_IS_PPC64_TRUE=
+ LIBGO_IS_PPC64_FALSE='#'
+else
+ LIBGO_IS_PPC64_TRUE='#'
+ LIBGO_IS_PPC64_FALSE=
+fi
+
+ if test $is_sparc = yes; then
+ LIBGO_IS_SPARC_TRUE=
+ LIBGO_IS_SPARC_FALSE='#'
+else
+ LIBGO_IS_SPARC_TRUE='#'
+ LIBGO_IS_SPARC_FALSE=
+fi
+
+ if test $is_sparc64 = yes; then
+ LIBGO_IS_SPARC64_TRUE=
+ LIBGO_IS_SPARC64_FALSE='#'
+else
+ LIBGO_IS_SPARC64_TRUE='#'
+ LIBGO_IS_SPARC64_FALSE=
+fi
+
+ if test $is_x86_64 = yes; then
+ LIBGO_IS_X86_64_TRUE=
+ LIBGO_IS_X86_64_FALSE='#'
+else
+ LIBGO_IS_X86_64_TRUE='#'
+ LIBGO_IS_X86_64_FALSE=
+fi
+
+
+
+GO_SYSCALLS_SYSCALL_OS_ARCH_FILE=
+if test -f ${srcdir}/syscalls/syscall_${GOOS}_${GOARCH}.go; then
+ GO_SYSCALLS_SYSCALL_OS_ARCH_FILE=syscalls/syscall_${GOOS}_${GOARCH}.go
+fi
+
+
+GO_DEBUG_PROC_REGS_OS_ARCH_FILE=
+if test -f ${srcdir}/go/debug/proc/regs_${GOOS}_${GOARCH}.go; then
+ GO_DEBUG_PROC_REGS_OS_ARCH_FILE=go/debug/proc/regs_${GOOS}_${GOARCH}.go
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -fsplit-stack is supported" >&5
+$as_echo_n "checking whether -fsplit-stack is supported... " >&6; }
+if test "${libgo_cv_c_split_stack_supported+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -fsplit-stack"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int i;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ libgo_cv_c_split_stack_supported=yes
+else
+ libgo_cv_c_split_stack_supported=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS=$CFLAGS_hold
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_c_split_stack_supported" >&5
+$as_echo "$libgo_cv_c_split_stack_supported" >&6; }
+if test "$libgo_cv_c_split_stack_supported" = yes; then
+ SPLIT_STACK=-fsplit-stack
+
+$as_echo "#define USING_SPLIT_STACK 1" >>confdefs.h
+
+else
+ SPLIT_STACK=
+fi
+
+ if test "$libgo_cv_c_split_stack_supported" = yes; then
+ USING_SPLIT_STACK_TRUE=
+ USING_SPLIT_STACK_FALSE='#'
+else
+ USING_SPLIT_STACK_TRUE='#'
+ USING_SPLIT_STACK_FALSE=
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether linker supports split stack" >&5
+$as_echo_n "checking whether linker supports split stack... " >&6; }
+if test "${libgo_cv_c_linker_supports_split_stack+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ libgo_cv_c_linker_supports_split_stack=no
+if $LD --help 2>/dev/null | grep split-stack-adjust-size >/dev/null 2>&1; then
+ libgo_cv_c_linker_supports_split_stack=yes
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_c_linker_supports_split_stack" >&5
+$as_echo "$libgo_cv_c_linker_supports_split_stack" >&6; }
+if test "$libgo_cv_c_linker_supports_split_stack" = yes; then
+
+$as_echo "#define LINKER_SUPPORTS_SPLIT_STACK 1" >>confdefs.h
+
+fi
+
+MATH_LIBS=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5
+$as_echo_n "checking for sqrt in -lm... " >&6; }
+if test "${ac_cv_lib_m_sqrt+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sqrt ();
+int
+main ()
+{
+return sqrt ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_sqrt=yes
+else
+ ac_cv_lib_m_sqrt=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt" >&5
+$as_echo "$ac_cv_lib_m_sqrt" >&6; }
+if test "x$ac_cv_lib_m_sqrt" = x""yes; then :
+ MATH_LIBS=-lm
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket libraries" >&5
+$as_echo_n "checking for socket libraries... " >&6; }
+if test "${libgo_cv_lib_sockets+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ libgo_cv_lib_sockets=
+ libgo_check_both=no
+ ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect"
+if test "x$ac_cv_func_connect" = x""yes; then :
+ libgo_check_socket=no
+else
+ libgo_check_socket=yes
+fi
+
+ if test "$libgo_check_socket" = "yes"; then
+ unset ac_cv_func_connect
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lsocket" >&5
+$as_echo_n "checking for main in -lsocket... " >&6; }
+if test "${ac_cv_lib_socket_main+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_socket_main=yes
+else
+ ac_cv_lib_socket_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_main" >&5
+$as_echo "$ac_cv_lib_socket_main" >&6; }
+if test "x$ac_cv_lib_socket_main" = x""yes; then :
+ libgo_cv_lib_sockets="-lsocket"
+else
+ libgo_check_both=yes
+fi
+
+ fi
+ if test "$libgo_check_both" = "yes"; then
+ libgo_old_libs=$LIBS
+ LIBS="$LIBS -lsocket -lnsl"
+ unset ac_cv_func_accept
+ ac_fn_c_check_func "$LINENO" "accept" "ac_cv_func_accept"
+if test "x$ac_cv_func_accept" = x""yes; then :
+ libgo_check_nsl=no
+ libgo_cv_lib_sockets="-lsocket -lnsl"
+fi
+
+ unset ac_cv_func_accept
+ LIBS=$libgo_old_libs
+ fi
+ unset ac_cv_func_gethostbyname
+ libgo_old_libs="$LIBS"
+ ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname"
+if test "x$ac_cv_func_gethostbyname" = x""yes; then :
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lnsl" >&5
+$as_echo_n "checking for main in -lnsl... " >&6; }
+if test "${ac_cv_lib_nsl_main+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_nsl_main=yes
+else
+ ac_cv_lib_nsl_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_main" >&5
+$as_echo "$ac_cv_lib_nsl_main" >&6; }
+if test "x$ac_cv_lib_nsl_main" = x""yes; then :
+ libgo_cv_lib_sockets="$libgo_cv_lib_sockets -lnsl"
+fi
+
+fi
+
+ unset ac_cv_func_gethostbyname
+ LIBS=$libgo_old_libs
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_lib_sockets" >&5
+$as_echo "$libgo_cv_lib_sockets" >&6; }
+NET_LIBS="$libgo_cv_lib_sockets"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -pthread is supported" >&5
+$as_echo_n "checking whether -pthread is supported... " >&6; }
+if test "${libgo_cv_lib_pthread+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -pthread"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int i;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ libgo_cv_lib_pthread=yes
+else
+ libgo_cv_lib_pthread=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS=$CFLAGS_hold
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_lib_pthread" >&5
+$as_echo "$libgo_cv_lib_pthread" >&6; }
+PTHREAD_CFLAGS=
+if test "$libgo_cv_lib_pthread" = yes; then
+ PTHREAD_CFLAGS=-pthread
+fi
+
+
+PTHREAD_LIBS=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_create ();
+int
+main ()
+{
+return pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_pthread_pthread_create=yes
+else
+ ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_create" = x""yes; then :
+ PTHREAD_LIBS=-lpthread
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sched_yield" >&5
+$as_echo_n "checking for library containing sched_yield... " >&6; }
+if test "${ac_cv_search_sched_yield+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sched_yield ();
+int
+main ()
+{
+return sched_yield ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' rt; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_sched_yield=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if test "${ac_cv_search_sched_yield+set}" = set; then :
+ break
+fi
+done
+if test "${ac_cv_search_sched_yield+set}" = set; then :
+
+else
+ ac_cv_search_sched_yield=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sched_yield" >&5
+$as_echo "$ac_cv_search_sched_yield" >&6; }
+ac_res=$ac_cv_search_sched_yield
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if test "${ac_cv_c_bigendian+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_bigendian=unknown
+ # See if we're dealing with a universal compiler.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __APPLE_CC__
+ not a universal capable compiler
+ #endif
+ typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ # Check for potential -arch flags. It is not universal unless
+ # there are at least two -arch flags with different values.
+ ac_arch=
+ ac_prev=
+ for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+ if test -n "$ac_prev"; then
+ case $ac_word in
+ i?86 | x86_64 | ppc | ppc64)
+ if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+ ac_arch=$ac_word
+ else
+ ac_cv_c_bigendian=universal
+ break
+ fi
+ ;;
+ esac
+ ac_prev=
+ elif test "x$ac_word" = "x-arch"; then
+ ac_prev=arch
+ fi
+ done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if sys/param.h defines the BYTE_ORDER macro.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+ && LITTLE_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to _BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # Compile a test program.
+ if test "$cross_compiling" = yes; then :
+ # Try to guess by grepping values from an object file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+short int ascii_mm[] =
+ { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+ short int ascii_ii[] =
+ { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+ int use_ascii (int i) {
+ return ascii_mm[i] + ascii_ii[i];
+ }
+ short int ebcdic_ii[] =
+ { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+ short int ebcdic_mm[] =
+ { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+ int use_ebcdic (int i) {
+ return ebcdic_mm[i] + ebcdic_ii[i];
+ }
+ extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+ ac_cv_c_bigendian=yes
+ fi
+ if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long int l;
+ char c[sizeof (long int)];
+ } u;
+ u.l = 1;
+ return u.c[sizeof (long int) - 1] == 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_c_bigendian=no
+else
+ ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+ yes)
+ $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+ no)
+ ;; #(
+ universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+ ;; #(
+ *)
+ as_fn_error "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+
+
+
+# Check whether --with-system-libunwind was given.
+if test "${with_system_libunwind+set}" = set; then :
+ withval=$with_system_libunwind;
+fi
+
+ # If system-libunwind was not specifically set, pick a default setting.
+ if test x$with_system_libunwind = x; then
+ case ${target} in
+ ia64-*-hpux*) with_system_libunwind=yes ;;
+ *) with_system_libunwind=no ;;
+ esac
+ fi
+ # Based on system-libunwind and target, do we have ipinfo?
+ if test x$with_system_libunwind = xyes; then
+ case ${target} in
+ ia64-*-*) have_unwind_getipinfo=no ;;
+ *) have_unwind_getipinfo=yes ;;
+ esac
+ else
+ # Darwin before version 9 does not have _Unwind_GetIPInfo.
+
+ case ${target} in
+ *-*-darwin[3-8]|*-*-darwin[3-8].*) have_unwind_getipinfo=no ;;
+ *) have_unwind_getipinfo=yes ;;
+ esac
+
+ fi
+
+ if test x$have_unwind_getipinfo = xyes; then
+
+$as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h
+
+ fi
+
+
+# Check whether --enable-sjlj-exceptions was given.
+if test "${enable_sjlj_exceptions+set}" = set; then :
+ enableval=$enable_sjlj_exceptions; case "$enableval" in
+ yes|no|auto) ;;
+ *) as_fn_error "unknown argument to --enable-sjlj-exceptions" "$LINENO" 5 ;;
+ esac
+else
+ enable_sjlj_exceptions=auto
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use setjmp/longjmp exceptions" >&5
+$as_echo_n "checking whether to use setjmp/longjmp exceptions... " >&6; }
+if test "${libgo_cv_lib_sjlj_exceptions+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+void bar ();
+void clean (int *);
+void foo ()
+{
+ int i __attribute__ ((cleanup (clean)));
+ bar();
+}
+
+_ACEOF
+CFLAGS_hold=$CFLAGS
+CFLAGS="--save-temps -fexceptions"
+libgo_cv_lib_sjlj_exceptions=unknown
+if ac_fn_c_try_compile; then :
+ if grep _Unwind_SjLj_Resume conftest.s >/dev/null 2>&1; then
+ libgo_cv_lib_sjlj_exceptions=yes
+ elif grep _Unwind_Resume conftest.s >/dev/null 2>&1; then
+ libgo_cv_lib_sjlj_exceptions=no
+ fi
+fi
+CFLAGS=$CFLAGS_hold
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_lib_sjlj_exceptions" >&5
+$as_echo "$libgo_cv_lib_sjlj_exceptions" >&6; }
+
+if test "$enable_sjlj_exceptions" = "auto"; then
+ enable_sjlj_exceptions=$libgo_cv_lib_sjlj_exceptions
+fi
+
+case $enable_sjlj_exceptions in
+yes)
+
+$as_echo "#define LIBGO_SJLJ_EXCEPTIONS 1" >>confdefs.h
+
+ ;;
+no)
+ ;;
+*)
+ as_fn_error "unable to detect exception model" "$LINENO" 5
+ ;;
+esac
+
+for ac_header in sys/mman.h syscall.h sys/epoll.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ if test "$ac_cv_header_sys_mman_h" = yes; then
+ HAVE_SYS_MMAN_H_TRUE=
+ HAVE_SYS_MMAN_H_FALSE='#'
+else
+ HAVE_SYS_MMAN_H_TRUE='#'
+ HAVE_SYS_MMAN_H_FALSE=
+fi
+
+for ac_func in srandom random strsignal
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+eval as_val=\$$as_ac_var
+ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __sync_bool_compare_and_swap_4" >&5
+$as_echo_n "checking for __sync_bool_compare_and_swap_4... " >&6; }
+if test "${libgo_cv_func___sync_bool_compare_and_swap_4+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+typedef unsigned int uint32 __attribute__ ((mode (SI)));
+uint32 i;
+int main() { return __sync_bool_compare_and_swap (&i, 0, 1); }
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ libgo_cv_func___sync_bool_compare_and_swap_4=yes
+else
+ libgo_cv_func___sync_bool_compare_and_swap_4=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_func___sync_bool_compare_and_swap_4" >&5
+$as_echo "$libgo_cv_func___sync_bool_compare_and_swap_4" >&6; }
+if test "$libgo_cv_func___sync_bool_compare_and_swap_4" = "yes"; then
+
+$as_echo "#define HAVE_SYNC_BOOL_COMPARE_AND_SWAP_4 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __sync_fetch_and_add_4" >&5
+$as_echo_n "checking for __sync_fetch_and_add_4... " >&6; }
+if test "${libgo_cv_func___sync_fetch_and_add_4+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+typedef unsigned int uint32 __attribute__ ((mode (SI)));
+uint32 i;
+int main() { return __sync_fetch_and_add (&i, 1); }
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ libgo_cv_func___sync_fetch_and_add_4=yes
+else
+ libgo_cv_func___sync_fetch_and_add_4=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_func___sync_fetch_and_add_4" >&5
+$as_echo "$libgo_cv_func___sync_fetch_and_add_4" >&6; }
+if test "$libgo_cv_func___sync_fetch_and_add_4" = "yes"; then
+
+$as_echo "#define HAVE_SYNC_FETCH_AND_ADD_4 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -minline-all-stringops" >&5
+$as_echo_n "checking whether compiler supports -minline-all-stringops... " >&6; }
+if test "${libgo_cv_c_stringops+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -minline-all-stringops"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int i;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ libgo_cv_c_stringops=yes
+else
+ libgo_cv_c_stringops=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS=$CFLAGS_hold
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_c_stringops" >&5
+$as_echo "$libgo_cv_c_stringops" >&6; }
+STRINGOPS_FLAG=
+if test "$libgo_cv_c_stringops" = yes; then
+ STRINGOPS_FLAG=-minline-all-stringops
+fi
+
+
+CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE"
+ac_fn_c_check_type "$LINENO" "off64_t" "ac_cv_type_off64_t" "$ac_includes_default"
+if test "x$ac_cv_type_off64_t" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_OFF64_T 1
+_ACEOF
+
+
+fi
+
+CFLAGS=$CFLAGS_hold
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ test "x$cache_file" != "x/dev/null" &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ cat confcache >$cache_file
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+if test ${multilib} = yes; then
+ multilib_arg="--enable-multilib"
+else
+ multilib_arg=
+fi
+
+ac_config_files="$ac_config_files Makefile testsuite/Makefile"
+
+
+ac_config_commands="$ac_config_commands default"
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ test "x$cache_file" != "x/dev/null" &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ cat confcache >$cache_file
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+ if test -n "$EXEEXT"; then
+ am__EXEEXT_TRUE=
+ am__EXEEXT_FALSE='#'
+else
+ am__EXEEXT_TRUE='#'
+ am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ as_fn_error "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+ as_fn_error "conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_DARWIN_TRUE}" && test -z "${LIBGO_IS_DARWIN_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_DARWIN\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_FREEBSD_TRUE}" && test -z "${LIBGO_IS_FREEBSD_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_FREEBSD\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_LINUX_TRUE}" && test -z "${LIBGO_IS_LINUX_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_LINUX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_RTEMS_TRUE}" && test -z "${LIBGO_IS_RTEMS_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_RTEMS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_SOLARIS_TRUE}" && test -z "${LIBGO_IS_SOLARIS_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_SOLARIS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_386_TRUE}" && test -z "${LIBGO_IS_386_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_386\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_ARM_TRUE}" && test -z "${LIBGO_IS_ARM_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_ARM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_M68K_TRUE}" && test -z "${LIBGO_IS_M68K_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_M68K\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_MIPS_TRUE}" && test -z "${LIBGO_IS_MIPS_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_MIPS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_MIPS64_TRUE}" && test -z "${LIBGO_IS_MIPS64_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_MIPS64\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_PPC_TRUE}" && test -z "${LIBGO_IS_PPC_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_PPC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_PPC64_TRUE}" && test -z "${LIBGO_IS_PPC64_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_PPC64\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_SPARC_TRUE}" && test -z "${LIBGO_IS_SPARC_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_SPARC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_SPARC64_TRUE}" && test -z "${LIBGO_IS_SPARC64_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_SPARC64\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBGO_IS_X86_64_TRUE}" && test -z "${LIBGO_IS_X86_64_FALSE}"; then
+ as_fn_error "conditional \"LIBGO_IS_X86_64\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${USING_SPLIT_STACK_TRUE}" && test -z "${USING_SPLIT_STACK_FALSE}"; then
+ as_fn_error "conditional \"USING_SPLIT_STACK\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+if test -z "${HAVE_SYS_MMAN_H_TRUE}" && test -z "${HAVE_SYS_MMAN_H_FALSE}"; then
+ as_fn_error "conditional \"HAVE_SYS_MMAN_H\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with status $?, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$?; test $as_status -eq 0 && as_status=1
+ if test "$3"; then
+ as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+ fi
+ $as_echo "$as_me: error: $1" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by package-unused $as_me version-unused, which was
+generated by GNU Autoconf 2.64. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_version="\\
+package-unused config.status version-unused
+configured by $0, generated by GNU Autoconf 2.64,
+ with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+
+srcdir="$srcdir"
+host="$host"
+target="$target"
+with_multisubdir="$with_multisubdir"
+with_multisrctop="$with_multisrctop"
+with_target_subdir="$with_target_subdir"
+ac_configure_args="${multilib_arg} ${ac_configure_args}"
+multi_basedir="$multi_basedir"
+CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+CC="$CC"
+CXX="$CXX"
+GFORTRAN="$GFORTRAN"
+GCJ="$GCJ"
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+LD_GO='`$ECHO "$LD_GO" | $SED "$delay_single_quote_subst"`'
+reload_flag_GO='`$ECHO "$reload_flag_GO" | $SED "$delay_single_quote_subst"`'
+reload_cmds_GO='`$ECHO "$reload_cmds_GO" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds_GO='`$ECHO "$old_archive_cmds_GO" | $SED "$delay_single_quote_subst"`'
+compiler_GO='`$ECHO "$compiler_GO" | $SED "$delay_single_quote_subst"`'
+GCC_GO='`$ECHO "$GCC_GO" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag_GO='`$ECHO "$lt_prog_compiler_no_builtin_flag_GO" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl_GO='`$ECHO "$lt_prog_compiler_wl_GO" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic_GO='`$ECHO "$lt_prog_compiler_pic_GO" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static_GO='`$ECHO "$lt_prog_compiler_static_GO" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o_GO='`$ECHO "$lt_cv_prog_compiler_c_o_GO" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc_GO='`$ECHO "$archive_cmds_need_lc_GO" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes_GO='`$ECHO "$enable_shared_with_static_runtimes_GO" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec_GO='`$ECHO "$export_dynamic_flag_spec_GO" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec_GO='`$ECHO "$whole_archive_flag_spec_GO" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object_GO='`$ECHO "$compiler_needs_object_GO" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds_GO='`$ECHO "$old_archive_from_new_cmds_GO" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds_GO='`$ECHO "$old_archive_from_expsyms_cmds_GO" | $SED "$delay_single_quote_subst"`'
+archive_cmds_GO='`$ECHO "$archive_cmds_GO" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds_GO='`$ECHO "$archive_expsym_cmds_GO" | $SED "$delay_single_quote_subst"`'
+module_cmds_GO='`$ECHO "$module_cmds_GO" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds_GO='`$ECHO "$module_expsym_cmds_GO" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld_GO='`$ECHO "$with_gnu_ld_GO" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag_GO='`$ECHO "$allow_undefined_flag_GO" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag_GO='`$ECHO "$no_undefined_flag_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_GO='`$ECHO "$hardcode_libdir_flag_spec_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld_GO='`$ECHO "$hardcode_libdir_flag_spec_ld_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator_GO='`$ECHO "$hardcode_libdir_separator_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_GO='`$ECHO "$hardcode_direct_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute_GO='`$ECHO "$hardcode_direct_absolute_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L_GO='`$ECHO "$hardcode_minus_L_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var_GO='`$ECHO "$hardcode_shlibpath_var_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic_GO='`$ECHO "$hardcode_automatic_GO" | $SED "$delay_single_quote_subst"`'
+inherit_rpath_GO='`$ECHO "$inherit_rpath_GO" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs_GO='`$ECHO "$link_all_deplibs_GO" | $SED "$delay_single_quote_subst"`'
+fix_srcfile_path_GO='`$ECHO "$fix_srcfile_path_GO" | $SED "$delay_single_quote_subst"`'
+always_export_symbols_GO='`$ECHO "$always_export_symbols_GO" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds_GO='`$ECHO "$export_symbols_cmds_GO" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms_GO='`$ECHO "$exclude_expsyms_GO" | $SED "$delay_single_quote_subst"`'
+include_expsyms_GO='`$ECHO "$include_expsyms_GO" | $SED "$delay_single_quote_subst"`'
+prelink_cmds_GO='`$ECHO "$prelink_cmds_GO" | $SED "$delay_single_quote_subst"`'
+file_list_spec_GO='`$ECHO "$file_list_spec_GO" | $SED "$delay_single_quote_subst"`'
+hardcode_action_GO='`$ECHO "$hardcode_action_GO" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SED \
+GREP \
+EGREP \
+FGREP \
+SHELL \
+ECHO \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+AR \
+AR_FLAGS \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_wl \
+lt_prog_compiler_pic \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_flag_spec_ld \
+hardcode_libdir_separator \
+fix_srcfile_path \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib \
+LD_GO \
+reload_flag_GO \
+compiler_GO \
+lt_prog_compiler_no_builtin_flag_GO \
+lt_prog_compiler_wl_GO \
+lt_prog_compiler_pic_GO \
+lt_prog_compiler_static_GO \
+lt_cv_prog_compiler_c_o_GO \
+export_dynamic_flag_spec_GO \
+whole_archive_flag_spec_GO \
+compiler_needs_object_GO \
+with_gnu_ld_GO \
+allow_undefined_flag_GO \
+no_undefined_flag_GO \
+hardcode_libdir_flag_spec_GO \
+hardcode_libdir_flag_spec_ld_GO \
+hardcode_libdir_separator_GO \
+fix_srcfile_path_GO \
+exclude_expsyms_GO \
+include_expsyms_GO \
+file_list_spec_GO; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec \
+reload_cmds_GO \
+old_archive_cmds_GO \
+old_archive_from_new_cmds_GO \
+old_archive_from_expsyms_cmds_GO \
+archive_cmds_GO \
+archive_expsym_cmds_GO \
+module_cmds_GO \
+module_expsym_cmds_GO \
+export_symbols_cmds_GO \
+prelink_cmds_GO; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'
+
+
+
+
+
+
+# Variables needed in config.status (file generation) which aren't already
+# passed by autoconf.
+SUBDIRS="$SUBDIRS"
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;;
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "testsuite/Makefile") CONFIG_FILES="$CONFIG_FILES testsuite/Makefile" ;;
+ "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
+
+ *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp=
+ trap 'exit_status=$?
+ { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\).*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\).*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+ || as_fn_error "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[ ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_t"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$tmp/stdin" \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined." >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined." >&2;}
+
+ rm -f "$tmp/stdin"
+ case $ac_file in
+ -) cat "$tmp/out" && rm -f "$tmp/out";;
+ *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+ } >"$tmp/config.h" \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$tmp/config.h" "$ac_file" \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "default-1":C)
+# Only add multilib support code if we just rebuilt the top-level
+# Makefile.
+case " $CONFIG_FILES " in
+ *" Makefile "*)
+ ac_file=Makefile . ${multi_basedir}/config-ml.in
+ ;;
+esac ;;
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir=$dirpart/$fdir; as_fn_mkdir_p
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+ ;;
+ "libtool":C)
+
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags="GO "
+
+# ### BEGIN LIBTOOL CONFIG
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking. This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ case $xsi_shell in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+ func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=${1%%=*}
+ func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=$(( $* ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=${#1}
+}
+
+_LT_EOF
+ ;;
+ *) # Bourne compatible functions.
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+}
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[^=]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"`
+ func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=`expr "$@"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$1+=\$2"
+}
+_LT_EOF
+ ;;
+ *)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$1=\$$1\$2"
+}
+
+_LT_EOF
+ ;;
+ esac
+
+
+ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+
+ cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: GO
+
+# The linker used to build libraries.
+LD=$lt_LD_GO
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag_GO
+reload_cmds=$lt_reload_cmds_GO
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_GO
+
+# A language specific compiler.
+CC=$lt_compiler_GO
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_GO
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GO
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_GO
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_GO
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_GO
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GO
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_GO
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GO
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GO
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_GO
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_GO
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GO
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GO
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_GO
+archive_expsym_cmds=$lt_archive_expsym_cmds_GO
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_GO
+module_expsym_cmds=$lt_module_expsym_cmds_GO
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_GO
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_GO
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_GO
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GO
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking. This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GO
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_GO
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_GO
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute_GO
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_GO
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_GO
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic_GO
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_GO
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_GO
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path_GO
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_GO
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_GO
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_GO
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_GO
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_GO
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_GO
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_GO
+
+# ### END LIBTOOL TAG CONFIG: GO
+_LT_EOF
+
+ ;;
+ "default":C) if test -n "$CONFIG_FILES"; then
+ # Multilibs need MULTISUBDIR defined correctly in certain makefiles so
+ # that multilib installs will end up installed in the correct place.
+ # The testsuite needs it for multilib-aware ABI baseline files.
+ # To work around this not being passed down from config-ml.in ->
+ # srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually
+ # append it here. Only modify Makefiles that have just been created.
+ #
+ # Also, get rid of this simulated-VPATH thing that automake does.
+ cat > vpsed << \_EOF
+s!`test -f '$<' || echo '$(srcdir)/'`!!
+_EOF
+ for i in $SUBDIRS; do
+ case $CONFIG_FILES in
+ *${i}/Makefile*)
+ #echo "Adding MULTISUBDIR to $i/Makefile"
+ sed -f vpsed $i/Makefile > tmp
+ grep '^MULTISUBDIR =' Makefile >> tmp
+ mv tmp $i/Makefile
+ ;;
+ esac
+ done
+ rm vpsed
+ fi
+ ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit $?
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/libgo/configure.ac b/libgo/configure.ac
new file mode 100644
index 000000000..56306641e
--- /dev/null
+++ b/libgo/configure.ac
@@ -0,0 +1,476 @@
+# configure.ac -- Go library configure script.
+
+# 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.
+
+# Process this file with autoreconf to produce configure.
+
+AC_PREREQ(2.64)
+AC_INIT(package-unused, version-unused,, libgo)
+AC_CONFIG_SRCDIR(Makefile.am)
+AC_CONFIG_HEADER(config.h)
+
+libtool_VERSION=1:0:0
+AC_SUBST(libtool_VERSION)
+
+AM_ENABLE_MULTILIB(, ..)
+
+AC_CANONICAL_SYSTEM
+target_alias=${target_alias-$host_alias}
+
+AM_INIT_AUTOMAKE([1.9.3 no-define foreign no-dist -Wall])
+AH_TEMPLATE(PACKAGE, [Name of package])
+AH_TEMPLATE(VERSION, [Version number of package])
+
+m4_rename([_AC_ARG_VAR_PRECIOUS],[glibgo_PRECIOUS])
+m4_define([_AC_ARG_VAR_PRECIOUS],[])
+AC_PROG_CC
+AC_PROG_GO
+m4_rename_force([glibgo_PRECIOUS],[_AC_ARG_VAR_PRECIOUS])
+
+AC_SUBST(CFLAGS)
+
+AM_MAINTAINER_MODE
+
+AC_PROG_LD
+AC_PROG_RANLIB
+AC_CHECK_TOOL(OBJCOPY, objcopy, missing-objcopy)
+
+AC_LIBTOOL_DLOPEN
+AM_PROG_LIBTOOL
+AC_SUBST(enable_shared)
+AC_SUBST(enable_static)
+
+WARN_FLAGS='-Wall -Wextra -Wwrite-strings -Wcast-qual'
+AC_SUBST(WARN_FLAGS)
+
+dnl FIXME: This should be controlled by --enable-maintainer-mode.
+WERROR="-Werror"
+AC_SUBST(WERROR)
+
+glibgo_toolexecdir=no
+glibgo_toolexeclibdir=no
+glibgo_prefixdir=$prefix
+
+AC_MSG_CHECKING([for --enable-version-specific-runtime-libs])
+AC_ARG_ENABLE([version-specific-runtime-libs],
+ AC_HELP_STRING([--enable-version-specific-runtime-libs],
+ [Specify that runtime libraries should be installed in a compiler-specific directory]),
+ [case "$enableval" in
+ yes) version_specific_libs=yes ;;
+ no) version_specific_libs=no ;;
+ *) AC_MSG_ERROR([Unknown argument to enable/disable version-specific libs]);;
+ esac],
+ [version_specific_libs=no])
+AC_MSG_RESULT($version_specific_libs)
+
+# Version-specific runtime libs processing.
+if test $version_specific_libs = yes; then
+ glibgo_toolexecdir='${libdir}/gcc/${host_alias}'
+ glibgo_toolexeclibdir='${toolexecdir}/${gcc_version}$(MULTISUBDIR)'
+fi
+
+# Calculate glibgo_toolexecdir, glibgo_toolexeclibdir
+# Install a library built with a cross compiler in tooldir, not libdir.
+if test x"$glibgo_toolexecdir" = x"no"; then
+ if test -n "$with_cross_host" &&
+ test x"$with_cross_host" != x"no"; then
+ glibgo_toolexecdir='${exec_prefix}/${host_alias}'
+ glibgo_toolexeclibdir='${toolexecdir}/lib'
+ else
+ glibgo_toolexecdir='${libdir}/gcc/${host_alias}'
+ glibgo_toolexeclibdir='${libdir}'
+ fi
+ multi_os_directory=`$CC -print-multi-os-directory`
+ case $multi_os_directory in
+ .) ;; # Avoid trailing /.
+ *) glibgo_toolexeclibdir=$glibgo_toolexeclibdir/$multi_os_directory ;;
+ esac
+fi
+
+AC_SUBST(glibgo_prefixdir)
+AC_SUBST(glibgo_toolexecdir)
+AC_SUBST(glibgo_toolexeclibdir)
+
+# See if the user wants to configure without libffi. Some
+# architectures don't support it. FIXME: We should set a default
+# based on the host.
+AC_ARG_WITH(libffi,
+ AS_HELP_STRING([--without-libffi],
+ [don't use libffi]),
+ [:],
+ [with_libffi=${with_libffi_default-yes}])
+
+LIBFFI=
+LIBFFIINCS=
+if test "$with_libffi" != no; then
+ AC_DEFINE(USE_LIBFFI, 1, [Define if we're to use libffi.])
+ LIBFFI=../libffi/libffi_convenience.la
+ LIBFFIINCS='-I$(top_srcdir)/../libffi/include -I../libffi/include'
+fi
+AC_SUBST(LIBFFI)
+AC_SUBST(LIBFFIINCS)
+
+is_darwin=no
+is_freebsd=no
+is_linux=no
+is_rtems=no
+is_solaris=no
+GOOS=unknown
+case ${host} in
+ *-*-darwin*) is_darwin=yes; GOOS=darwin ;;
+ *-*-freebsd*) is_freebsd=yes; GOOS=freebsd ;;
+ *-*-linux*) is_linux=yes; GOOS=linux ;;
+ *-*-rtems*) is_rtems=yes; GOOS=rtems ;;
+ *-*-solaris2*) is_solaris=yes; GOOS=solaris ;;
+esac
+AM_CONDITIONAL(LIBGO_IS_DARWIN, test $is_darwin = yes)
+AM_CONDITIONAL(LIBGO_IS_FREEBSD, test $is_freebsd = yes)
+AM_CONDITIONAL(LIBGO_IS_LINUX, test $is_linux = yes)
+AM_CONDITIONAL(LIBGO_IS_RTEMS, test $is_rtems = yes)
+AM_CONDITIONAL(LIBGO_IS_SOLARIS, test $is_solaris = yes)
+AC_SUBST(GOOS)
+
+dnl N.B. Keep in sync with gcc/testsuite/go.test/go-test.exp (go-set-goarch).
+is_386=no
+is_arm=no
+is_m68k=no
+is_mips=no
+is_mips64=no
+is_ppc=no
+is_ppc64=no
+is_sparc=no
+is_sparc64=no
+is_x86_64=no
+GOARCH=unknown
+case ${host} in
+ arm*-*-* | strongarm*-*-* | ep9312*-*-* | xscale-*-*)
+ is_arm=yes
+ GOARCH=arm
+ ;;
+changequote(,)dnl
+ i[34567]86-*-* | x86_64-*-*)
+changequote([,])dnl
+ AC_COMPILE_IFELSE([
+#ifdef __x86_64__
+#error 64-bit
+#endif],
+[is_386=yes], [is_x86_64=yes])
+ if test "$is_386" = "yes"; then
+ GOARCH=386
+ else
+ GOARCH=amd64
+ fi
+ ;;
+ m68k*-*-*)
+ is_m68k=yes
+ GOARCH=m68k
+ ;;
+ mips*-*-*)
+ AC_COMPILE_IFELSE([
+#ifdef __mips64
+#error 64-bit
+#endif],
+[is_mips=yes], [is_mips64=yes])
+ if test "$is_mips" = "yes"; then
+ GOARCH=mips
+ else
+ GOARCH=mips64
+ fi
+ ;;
+ rs6000*-*-* | powerpc*-*-*)
+ AC_COMPILE_IFELSE([
+#ifdef _ARCH_PPC64
+#error 64-bit
+#endif],
+[is_ppc=yes], [is_ppc64=yes])
+ if test "$is_ppc" = "yes"; then
+ GOARCH=ppc
+ else
+ GOARCH=ppc64
+ fi
+ ;;
+ sparc*-*-*)
+ AC_COMPILE_IFELSE([
+#if defined(__sparcv9) || defined(__arch64__)
+#error 64-bit
+#endif],
+[is_sparc=yes], [is_sparc64=yes])
+ if test "$is_sparc" = "yes"; then
+ GOARCH=sparc
+ else
+ GOARCH=sparc64
+ fi
+ ;;
+esac
+AM_CONDITIONAL(LIBGO_IS_386, test $is_386 = yes)
+AM_CONDITIONAL(LIBGO_IS_ARM, test $is_arm = yes)
+AM_CONDITIONAL(LIBGO_IS_M68K, test $is_m68k = yes)
+AM_CONDITIONAL(LIBGO_IS_MIPS, test $is_mips = yes)
+AM_CONDITIONAL(LIBGO_IS_MIPS64, test $is_mips64 = yes)
+AM_CONDITIONAL(LIBGO_IS_PPC, test $is_ppc = yes)
+AM_CONDITIONAL(LIBGO_IS_PPC64, test $is_ppc64 = yes)
+AM_CONDITIONAL(LIBGO_IS_SPARC, test $is_sparc = yes)
+AM_CONDITIONAL(LIBGO_IS_SPARC64, test $is_sparc64 = yes)
+AM_CONDITIONAL(LIBGO_IS_X86_64, test $is_x86_64 = yes)
+AC_SUBST(GOARCH)
+
+dnl Some files are only present when needed for specific architectures.
+GO_SYSCALLS_SYSCALL_OS_ARCH_FILE=
+if test -f ${srcdir}/syscalls/syscall_${GOOS}_${GOARCH}.go; then
+ GO_SYSCALLS_SYSCALL_OS_ARCH_FILE=syscalls/syscall_${GOOS}_${GOARCH}.go
+fi
+AC_SUBST(GO_SYSCALLS_SYSCALL_OS_ARCH_FILE)
+
+GO_DEBUG_PROC_REGS_OS_ARCH_FILE=
+if test -f ${srcdir}/go/debug/proc/regs_${GOOS}_${GOARCH}.go; then
+ GO_DEBUG_PROC_REGS_OS_ARCH_FILE=go/debug/proc/regs_${GOOS}_${GOARCH}.go
+fi
+AC_SUBST(GO_DEBUG_PROC_REGS_OS_ARCH_FILE)
+
+dnl Use -fsplit-stack when compiling C code if available.
+AC_CACHE_CHECK([whether -fsplit-stack is supported],
+[libgo_cv_c_split_stack_supported],
+[CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -fsplit-stack"
+AC_COMPILE_IFELSE([[int i;]],
+[libgo_cv_c_split_stack_supported=yes],
+[libgo_cv_c_split_stack_supported=no])
+CFLAGS=$CFLAGS_hold])
+if test "$libgo_cv_c_split_stack_supported" = yes; then
+ SPLIT_STACK=-fsplit-stack
+ AC_DEFINE(USING_SPLIT_STACK, 1,
+ [Define if the compiler supports -fsplit-stack])
+else
+ SPLIT_STACK=
+fi
+AC_SUBST(SPLIT_STACK)
+AM_CONDITIONAL(USING_SPLIT_STACK,
+ test "$libgo_cv_c_split_stack_supported" = yes)
+
+dnl Check whether the linker does stack munging when calling from
+dnl split-stack into non-split-stack code. We check this by looking
+dnl at the --help output. FIXME: This is only half right: it's
+dnl possible for the linker to support this for some targets but not
+dnl others.
+AC_CACHE_CHECK([whether linker supports split stack],
+[libgo_cv_c_linker_supports_split_stack],
+libgo_cv_c_linker_supports_split_stack=no
+if $LD --help 2>/dev/null | grep split-stack-adjust-size >/dev/null 2>&1; then
+ libgo_cv_c_linker_supports_split_stack=yes
+fi)
+if test "$libgo_cv_c_linker_supports_split_stack" = yes; then
+ AC_DEFINE(LINKER_SUPPORTS_SPLIT_STACK, 1,
+ [Define if the linker support split stack adjustments])
+fi
+
+dnl Test for the -lm library.
+MATH_LIBS=
+AC_CHECK_LIB([m], [sqrt], MATH_LIBS=-lm)
+AC_SUBST(MATH_LIBS)
+
+dnl Test for -lsocket and -lnsl. Copied from libjava/configure.ac.
+AC_CACHE_CHECK([for socket libraries], libgo_cv_lib_sockets,
+ [libgo_cv_lib_sockets=
+ libgo_check_both=no
+ AC_CHECK_FUNC(connect, libgo_check_socket=no, libgo_check_socket=yes)
+ if test "$libgo_check_socket" = "yes"; then
+ unset ac_cv_func_connect
+ AC_CHECK_LIB(socket, main, libgo_cv_lib_sockets="-lsocket",
+ libgo_check_both=yes)
+ fi
+ if test "$libgo_check_both" = "yes"; then
+ libgo_old_libs=$LIBS
+ LIBS="$LIBS -lsocket -lnsl"
+ unset ac_cv_func_accept
+ AC_CHECK_FUNC(accept,
+ [libgo_check_nsl=no
+ libgo_cv_lib_sockets="-lsocket -lnsl"])
+ unset ac_cv_func_accept
+ LIBS=$libgo_old_libs
+ fi
+ unset ac_cv_func_gethostbyname
+ libgo_old_libs="$LIBS"
+ AC_CHECK_FUNC(gethostbyname, ,
+ [AC_CHECK_LIB(nsl, main,
+ [libgo_cv_lib_sockets="$libgo_cv_lib_sockets -lnsl"])])
+ unset ac_cv_func_gethostbyname
+ LIBS=$libgo_old_libs
+])
+NET_LIBS="$libgo_cv_lib_sockets"
+AC_SUBST(NET_LIBS)
+
+dnl Test whether the compiler supports the -pthread option.
+AC_CACHE_CHECK([whether -pthread is supported],
+[libgo_cv_lib_pthread],
+[CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -pthread"
+AC_COMPILE_IFELSE([[int i;]],
+[libgo_cv_lib_pthread=yes],
+[libgo_cv_lib_pthread=no])
+CFLAGS=$CFLAGS_hold])
+PTHREAD_CFLAGS=
+if test "$libgo_cv_lib_pthread" = yes; then
+ PTHREAD_CFLAGS=-pthread
+fi
+AC_SUBST(PTHREAD_CFLAGS)
+
+dnl Test for the -lpthread library.
+PTHREAD_LIBS=
+AC_CHECK_LIB([pthread], [pthread_create], PTHREAD_LIBS=-lpthread)
+AC_SUBST(PTHREAD_LIBS)
+
+dnl Test if -lrt is required for sched_yield.
+AC_SEARCH_LIBS([sched_yield], [rt])
+
+AC_C_BIGENDIAN
+
+GCC_CHECK_UNWIND_GETIPINFO
+
+AC_ARG_ENABLE(sjlj-exceptions,
+ AC_HELP_STRING([--enable-sjlj-exceptions],
+ [force use of builtin_setjmp for exceptions]),
+ [case "$enableval" in
+ yes|no|auto) ;;
+ *) AC_MSG_ERROR([unknown argument to --enable-sjlj-exceptions]) ;;
+ esac],
+ [enable_sjlj_exceptions=auto])
+
+AC_CACHE_CHECK([whether to use setjmp/longjmp exceptions],
+[libgo_cv_lib_sjlj_exceptions],
+[AC_LANG_CONFTEST(
+ [AC_LANG_SOURCE([
+void bar ();
+void clean (int *);
+void foo ()
+{
+ int i __attribute__ ((cleanup (clean)));
+ bar();
+}
+])])
+CFLAGS_hold=$CFLAGS
+CFLAGS="--save-temps -fexceptions"
+libgo_cv_lib_sjlj_exceptions=unknown
+AS_IF([ac_fn_c_try_compile],
+ [if grep _Unwind_SjLj_Resume conftest.s >/dev/null 2>&1; then
+ libgo_cv_lib_sjlj_exceptions=yes
+ elif grep _Unwind_Resume conftest.s >/dev/null 2>&1; then
+ libgo_cv_lib_sjlj_exceptions=no
+ fi])
+CFLAGS=$CFLAGS_hold
+rm -f conftest*
+])
+
+if test "$enable_sjlj_exceptions" = "auto"; then
+ enable_sjlj_exceptions=$libgo_cv_lib_sjlj_exceptions
+fi
+
+case $enable_sjlj_exceptions in
+yes)
+ AC_DEFINE(LIBGO_SJLJ_EXCEPTIONS, 1,
+ [Define if the C++ compiler is configured for setjmp/longjmp exceptions.])
+ ;;
+no)
+ ;;
+*)
+ AC_MSG_ERROR([unable to detect exception model])
+ ;;
+esac
+
+AC_CHECK_HEADERS(sys/mman.h syscall.h sys/epoll.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h)
+AM_CONDITIONAL(HAVE_SYS_MMAN_H, test "$ac_cv_header_sys_mman_h" = yes)
+AC_CHECK_FUNCS(srandom random strsignal)
+
+AC_CACHE_CHECK([for __sync_bool_compare_and_swap_4],
+[libgo_cv_func___sync_bool_compare_and_swap_4],
+[AC_LINK_IFELSE([
+typedef unsigned int uint32 __attribute__ ((mode (SI)));
+uint32 i;
+int main() { return __sync_bool_compare_and_swap (&i, 0, 1); }
+],
+[libgo_cv_func___sync_bool_compare_and_swap_4=yes],
+[libgo_cv_func___sync_bool_compare_and_swap_4=no])])
+if test "$libgo_cv_func___sync_bool_compare_and_swap_4" = "yes"; then
+ AC_DEFINE(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_4, 1,
+ [Define to 1 if the compiler provides the __sync_bool_compare_and_swap function for uint32])
+fi
+
+AC_CACHE_CHECK([for __sync_fetch_and_add_4],
+[libgo_cv_func___sync_fetch_and_add_4],
+[AC_LINK_IFELSE([
+typedef unsigned int uint32 __attribute__ ((mode (SI)));
+uint32 i;
+int main() { return __sync_fetch_and_add (&i, 1); }
+],
+[libgo_cv_func___sync_fetch_and_add_4=yes],
+[libgo_cv_func___sync_fetch_and_add_4=no])])
+if test "$libgo_cv_func___sync_fetch_and_add_4" = "yes"; then
+ AC_DEFINE(HAVE_SYNC_FETCH_AND_ADD_4, 1,
+ [Define to 1 if the compiler provides the __sync_fetch_and_add function for uint32])
+fi
+
+dnl For x86 we want to use the -minline-all-stringops option to avoid
+dnl forcing a stack split when calling memcpy and friends.
+AC_CACHE_CHECK([whether compiler supports -minline-all-stringops],
+[libgo_cv_c_stringops],
+[CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -minline-all-stringops"
+AC_COMPILE_IFELSE([int i;],
+[libgo_cv_c_stringops=yes],
+[libgo_cv_c_stringops=no])
+CFLAGS=$CFLAGS_hold])
+STRINGOPS_FLAG=
+if test "$libgo_cv_c_stringops" = yes; then
+ STRINGOPS_FLAG=-minline-all-stringops
+fi
+AC_SUBST(STRINGOPS_FLAG)
+
+CFLAGS_hold=$CFLAGS
+CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE"
+AC_CHECK_TYPES(off64_t)
+CFLAGS=$CFLAGS_hold
+
+AC_CACHE_SAVE
+
+if test ${multilib} = yes; then
+ multilib_arg="--enable-multilib"
+else
+ multilib_arg=
+fi
+
+AC_CONFIG_FILES(Makefile testsuite/Makefile)
+
+AC_CONFIG_COMMANDS([default],
+[if test -n "$CONFIG_FILES"; then
+ # Multilibs need MULTISUBDIR defined correctly in certain makefiles so
+ # that multilib installs will end up installed in the correct place.
+ # The testsuite needs it for multilib-aware ABI baseline files.
+ # To work around this not being passed down from config-ml.in ->
+ # srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually
+ # append it here. Only modify Makefiles that have just been created.
+ #
+ # Also, get rid of this simulated-VPATH thing that automake does.
+ cat > vpsed << \_EOF
+s!`test -f '$<' || echo '$(srcdir)/'`!!
+_EOF
+ for i in $SUBDIRS; do
+ case $CONFIG_FILES in
+ *${i}/Makefile*)
+ #echo "Adding MULTISUBDIR to $i/Makefile"
+ sed -f vpsed $i/Makefile > tmp
+ grep '^MULTISUBDIR =' Makefile >> tmp
+ mv tmp $i/Makefile
+ ;;
+ esac
+ done
+ rm vpsed
+ fi
+],
+[
+# Variables needed in config.status (file generation) which aren't already
+# passed by autoconf.
+SUBDIRS="$SUBDIRS"
+])
+
+AC_OUTPUT
diff --git a/libgo/go/archive/tar/common.go b/libgo/go/archive/tar/common.go
new file mode 100644
index 000000000..5b781ff3d
--- /dev/null
+++ b/libgo/go/archive/tar/common.go
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The tar package implements access to tar archives.
+// It aims to cover most of the variations, including those produced
+// by GNU and BSD tars.
+//
+// References:
+// http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
+// http://www.gnu.org/software/tar/manual/html_node/Standard.html
+package tar
+
+const (
+ blockSize = 512
+
+ // Types
+ TypeReg = '0'
+ TypeRegA = '\x00'
+ TypeLink = '1'
+ TypeSymlink = '2'
+ TypeChar = '3'
+ TypeBlock = '4'
+ TypeDir = '5'
+ TypeFifo = '6'
+ TypeCont = '7'
+ TypeXHeader = 'x'
+ TypeXGlobalHeader = 'g'
+)
+
+// A Header represents a single header in a tar archive.
+// Some fields may not be populated.
+type Header struct {
+ Name string
+ Mode int64
+ Uid int
+ Gid int
+ Size int64
+ Mtime int64
+ Typeflag byte
+ Linkname string
+ Uname string
+ Gname string
+ Devmajor int64
+ Devminor int64
+ Atime int64
+ Ctime int64
+}
+
+var zeroBlock = make([]byte, blockSize)
+
+// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values.
+// We compute and return both.
+func checksum(header []byte) (unsigned int64, signed int64) {
+ for i := 0; i < len(header); i++ {
+ if i == 148 {
+ // The chksum field (header[148:156]) is special: it should be treated as space bytes.
+ unsigned += ' ' * 8
+ signed += ' ' * 8
+ i += 7
+ continue
+ }
+ unsigned += int64(header[i])
+ signed += int64(int8(header[i]))
+ }
+ return
+}
+
+type slicer []byte
+
+func (sp *slicer) next(n int) (b []byte) {
+ s := *sp
+ b, *sp = s[0:n], s[n:]
+ return
+}
diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go
new file mode 100644
index 000000000..35a15f74b
--- /dev/null
+++ b/libgo/go/archive/tar/reader.go
@@ -0,0 +1,226 @@
+// 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 tar
+
+// TODO(dsymonds):
+// - pax extensions
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+)
+
+var (
+ HeaderError os.Error = os.ErrorString("invalid tar header")
+)
+
+// A Reader provides sequential access to the contents of a tar archive.
+// A tar archive consists of a sequence of files.
+// The Next method advances to the next file in the archive (including the first),
+// and then it can be treated as an io.Reader to access the file's data.
+//
+// Example:
+// tr := tar.NewReader(r)
+// for {
+// hdr, err := tr.Next()
+// if err != nil {
+// // handle error
+// }
+// if hdr == nil {
+// // end of tar archive
+// break
+// }
+// io.Copy(data, tr)
+// }
+type Reader struct {
+ r io.Reader
+ err os.Error
+ nb int64 // number of unread bytes for current file entry
+ pad int64 // amount of padding (ignored) after current file entry
+}
+
+// NewReader creates a new Reader reading from r.
+func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
+
+// Next advances to the next entry in the tar archive.
+func (tr *Reader) Next() (*Header, os.Error) {
+ var hdr *Header
+ if tr.err == nil {
+ tr.skipUnread()
+ }
+ if tr.err == nil {
+ hdr = tr.readHeader()
+ }
+ return hdr, tr.err
+}
+
+// Parse bytes as a NUL-terminated C-style string.
+// If a NUL byte is not found then the whole slice is returned as a string.
+func cString(b []byte) string {
+ n := 0
+ for n < len(b) && b[n] != 0 {
+ n++
+ }
+ return string(b[0:n])
+}
+
+func (tr *Reader) octal(b []byte) int64 {
+ // Removing leading spaces.
+ for len(b) > 0 && b[0] == ' ' {
+ b = b[1:]
+ }
+ // Removing trailing NULs and spaces.
+ for len(b) > 0 && (b[len(b)-1] == ' ' || b[len(b)-1] == '\x00') {
+ b = b[0 : len(b)-1]
+ }
+ x, err := strconv.Btoui64(cString(b), 8)
+ if err != nil {
+ tr.err = err
+ }
+ return int64(x)
+}
+
+type ignoreWriter struct{}
+
+func (ignoreWriter) Write(b []byte) (n int, err os.Error) {
+ return len(b), nil
+}
+
+// Skip any unread bytes in the existing file entry, as well as any alignment padding.
+func (tr *Reader) skipUnread() {
+ nr := tr.nb + tr.pad // number of bytes to skip
+ tr.nb, tr.pad = 0, 0
+ if sr, ok := tr.r.(io.Seeker); ok {
+ if _, err := sr.Seek(nr, 1); err == nil {
+ return
+ }
+ }
+ _, tr.err = io.Copyn(ignoreWriter{}, tr.r, nr)
+}
+
+func (tr *Reader) verifyChecksum(header []byte) bool {
+ if tr.err != nil {
+ return false
+ }
+
+ given := tr.octal(header[148:156])
+ unsigned, signed := checksum(header)
+ return given == unsigned || given == signed
+}
+
+func (tr *Reader) readHeader() *Header {
+ header := make([]byte, blockSize)
+ if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+ return nil
+ }
+
+ // Two blocks of zero bytes marks the end of the archive.
+ if bytes.Equal(header, zeroBlock[0:blockSize]) {
+ if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+ return nil
+ }
+ if bytes.Equal(header, zeroBlock[0:blockSize]) {
+ tr.err = os.EOF
+ } else {
+ tr.err = HeaderError // zero block and then non-zero block
+ }
+ return nil
+ }
+
+ if !tr.verifyChecksum(header) {
+ tr.err = HeaderError
+ return nil
+ }
+
+ // Unpack
+ hdr := new(Header)
+ s := slicer(header)
+
+ hdr.Name = cString(s.next(100))
+ hdr.Mode = tr.octal(s.next(8))
+ hdr.Uid = int(tr.octal(s.next(8)))
+ hdr.Gid = int(tr.octal(s.next(8)))
+ hdr.Size = tr.octal(s.next(12))
+ hdr.Mtime = tr.octal(s.next(12))
+ s.next(8) // chksum
+ hdr.Typeflag = s.next(1)[0]
+ hdr.Linkname = cString(s.next(100))
+
+ // The remainder of the header depends on the value of magic.
+ // The original (v7) version of tar had no explicit magic field,
+ // so its magic bytes, like the rest of the block, are NULs.
+ magic := string(s.next(8)) // contains version field as well.
+ var format string
+ switch magic {
+ case "ustar\x0000": // POSIX tar (1003.1-1988)
+ if string(header[508:512]) == "tar\x00" {
+ format = "star"
+ } else {
+ format = "posix"
+ }
+ case "ustar \x00": // old GNU tar
+ format = "gnu"
+ }
+
+ switch format {
+ case "posix", "gnu", "star":
+ hdr.Uname = cString(s.next(32))
+ hdr.Gname = cString(s.next(32))
+ devmajor := s.next(8)
+ devminor := s.next(8)
+ if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
+ hdr.Devmajor = tr.octal(devmajor)
+ hdr.Devminor = tr.octal(devminor)
+ }
+ var prefix string
+ switch format {
+ case "posix", "gnu":
+ prefix = cString(s.next(155))
+ case "star":
+ prefix = cString(s.next(131))
+ hdr.Atime = tr.octal(s.next(12))
+ hdr.Ctime = tr.octal(s.next(12))
+ }
+ if len(prefix) > 0 {
+ hdr.Name = prefix + "/" + hdr.Name
+ }
+ }
+
+ if tr.err != nil {
+ tr.err = HeaderError
+ return nil
+ }
+
+ // Maximum value of hdr.Size is 64 GB (12 octal digits),
+ // so there's no risk of int64 overflowing.
+ tr.nb = int64(hdr.Size)
+ tr.pad = -tr.nb & (blockSize - 1) // blockSize is a power of two
+
+ return hdr
+}
+
+// Read reads from the current entry in the tar archive.
+// It returns 0, os.EOF when it reaches the end of that entry,
+// until Next is called to advance to the next entry.
+func (tr *Reader) Read(b []byte) (n int, err os.Error) {
+ if tr.nb == 0 {
+ // file consumed
+ return 0, os.EOF
+ }
+
+ if int64(len(b)) > tr.nb {
+ b = b[0:tr.nb]
+ }
+ n, err = tr.r.Read(b)
+ tr.nb -= int64(n)
+
+ if err == os.EOF && tr.nb > 0 {
+ err = io.ErrUnexpectedEOF
+ }
+ tr.err = err
+ return
+}
diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go
new file mode 100644
index 000000000..aa4c797fb
--- /dev/null
+++ b/libgo/go/archive/tar/reader_test.go
@@ -0,0 +1,274 @@
+// 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 tar
+
+import (
+ "bytes"
+ "crypto/md5"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "testing"
+)
+
+type untarTest struct {
+ file string
+ headers []*Header
+ cksums []string
+}
+
+var gnuTarTest = &untarTest{
+ file: "testdata/gnu.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244428340,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244436044,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ },
+ cksums: []string{
+ "e38b27eaccb4391bdec553a7f3ae6b2f",
+ "c65bd2e50a56a2138bf1716f2fd56fe9",
+ },
+}
+
+var untarTests = []*untarTest{
+ gnuTarTest,
+ &untarTest{
+ file: "testdata/star.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ },
+ },
+ &untarTest{
+ file: "testdata/v7.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ },
+ },
+}
+
+func TestReader(t *testing.T) {
+testLoop:
+ for i, test := range untarTests {
+ f, err := os.Open(test.file, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+ tr := NewReader(f)
+ for j, header := range test.headers {
+ hdr, err := tr.Next()
+ if err != nil || hdr == nil {
+ t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
+ f.Close()
+ continue testLoop
+ }
+ if !reflect.DeepEqual(hdr, header) {
+ t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
+ i, j, *hdr, *header)
+ }
+ }
+ hdr, err := tr.Next()
+ if err == os.EOF {
+ break
+ }
+ if hdr != nil || err != nil {
+ t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, hdr, err)
+ }
+ f.Close()
+ }
+}
+
+func TestPartialRead(t *testing.T) {
+ f, err := os.Open("testdata/gnu.tar", os.O_RDONLY, 0444)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ tr := NewReader(f)
+
+ // Read the first four bytes; Next() should skip the last byte.
+ hdr, err := tr.Next()
+ if err != nil || hdr == nil {
+ t.Fatalf("Didn't get first file: %v", err)
+ }
+ buf := make([]byte, 4)
+ if _, err := io.ReadFull(tr, buf); err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ if expected := []byte("Kilt"); !bytes.Equal(buf, expected) {
+ t.Errorf("Contents = %v, want %v", buf, expected)
+ }
+
+ // Second file
+ hdr, err = tr.Next()
+ if err != nil || hdr == nil {
+ t.Fatalf("Didn't get second file: %v", err)
+ }
+ buf = make([]byte, 6)
+ if _, err := io.ReadFull(tr, buf); err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ if expected := []byte("Google"); !bytes.Equal(buf, expected) {
+ t.Errorf("Contents = %v, want %v", buf, expected)
+ }
+}
+
+
+func TestIncrementalRead(t *testing.T) {
+ test := gnuTarTest
+ f, err := os.Open(test.file, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ tr := NewReader(f)
+
+ headers := test.headers
+ cksums := test.cksums
+ nread := 0
+
+ // loop over all files
+ for ; ; nread++ {
+ hdr, err := tr.Next()
+ if hdr == nil || err == os.EOF {
+ break
+ }
+
+ // check the header
+ if !reflect.DeepEqual(hdr, headers[nread]) {
+ t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
+ *hdr, headers[nread])
+ }
+
+ // read file contents in little chunks EOF,
+ // checksumming all the way
+ h := md5.New()
+ rdbuf := make([]uint8, 8)
+ for {
+ nr, err := tr.Read(rdbuf)
+ if err == os.EOF {
+ break
+ }
+ if err != nil {
+ t.Errorf("Read: unexpected error %v\n", err)
+ break
+ }
+ h.Write(rdbuf[0:nr])
+ }
+ // verify checksum
+ have := fmt.Sprintf("%x", h.Sum())
+ want := cksums[nread]
+ if want != have {
+ t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want)
+ }
+ }
+ if nread != len(headers) {
+ t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(headers), nread)
+ }
+}
+
+func TestNonSeekable(t *testing.T) {
+ test := gnuTarTest
+ f, err := os.Open(test.file, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ // pipe the data in
+ r, w, err := os.Pipe()
+ if err != nil {
+ t.Fatalf("Unexpected error %s", err)
+ }
+ go func() {
+ rdbuf := make([]uint8, 1<<16)
+ for {
+ nr, err := f.Read(rdbuf)
+ w.Write(rdbuf[0:nr])
+ if err == os.EOF {
+ break
+ }
+ }
+ w.Close()
+ }()
+
+ tr := NewReader(r)
+ nread := 0
+
+ for ; ; nread++ {
+ hdr, err := tr.Next()
+ if hdr == nil || err == os.EOF {
+ break
+ }
+ }
+
+ if nread != len(test.headers) {
+ t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(test.headers), nread)
+ }
+}
diff --git a/libgo/go/archive/tar/testdata/gnu.tar b/libgo/go/archive/tar/testdata/gnu.tar
new file mode 100644
index 000000000..fc899dc8d
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/gnu.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/small.txt b/libgo/go/archive/tar/testdata/small.txt
new file mode 100644
index 000000000..b249bfc51
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/small.txt
@@ -0,0 +1 @@
+Kilts \ No newline at end of file
diff --git a/libgo/go/archive/tar/testdata/small2.txt b/libgo/go/archive/tar/testdata/small2.txt
new file mode 100644
index 000000000..394ee3ecd
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/small2.txt
@@ -0,0 +1 @@
+Google.com
diff --git a/libgo/go/archive/tar/testdata/star.tar b/libgo/go/archive/tar/testdata/star.tar
new file mode 100644
index 000000000..59e2d4e60
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/star.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/v7.tar b/libgo/go/archive/tar/testdata/v7.tar
new file mode 100644
index 000000000..eb65fc941
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/v7.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/writer-big.tar b/libgo/go/archive/tar/testdata/writer-big.tar
new file mode 100644
index 000000000..753e883ce
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/writer-big.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/writer.tar b/libgo/go/archive/tar/testdata/writer.tar
new file mode 100644
index 000000000..0358f91b9
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/writer.tar
Binary files differ
diff --git a/libgo/go/archive/tar/writer.go b/libgo/go/archive/tar/writer.go
new file mode 100644
index 000000000..8673bad31
--- /dev/null
+++ b/libgo/go/archive/tar/writer.go
@@ -0,0 +1,205 @@
+// 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 tar
+
+// TODO(dsymonds):
+// - catch more errors (no first header, write after close, etc.)
+
+import (
+ "io"
+ "os"
+ "strconv"
+)
+
+var (
+ ErrWriteTooLong = os.NewError("write too long")
+ ErrFieldTooLong = os.NewError("header field too long")
+ ErrWriteAfterClose = os.NewError("write after close")
+)
+
+// A Writer provides sequential writing of a tar archive in POSIX.1 format.
+// A tar archive consists of a sequence of files.
+// Call WriteHeader to begin a new file, and then call Write to supply that file's data,
+// writing at most hdr.Size bytes in total.
+//
+// Example:
+// tw := tar.NewWriter(w)
+// hdr := new(Header)
+// hdr.Size = length of data in bytes
+// // populate other hdr fields as desired
+// if err := tw.WriteHeader(hdr); err != nil {
+// // handle error
+// }
+// io.Copy(tw, data)
+// tw.Close()
+type Writer struct {
+ w io.Writer
+ err os.Error
+ nb int64 // number of unwritten bytes for current file entry
+ pad int64 // amount of padding to write after current file entry
+ closed bool
+ usedBinary bool // whether the binary numeric field extension was used
+}
+
+// NewWriter creates a new Writer writing to w.
+func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
+
+// Flush finishes writing the current file (optional).
+func (tw *Writer) Flush() os.Error {
+ n := tw.nb + tw.pad
+ for n > 0 && tw.err == nil {
+ nr := n
+ if nr > blockSize {
+ nr = blockSize
+ }
+ var nw int
+ nw, tw.err = tw.w.Write(zeroBlock[0:nr])
+ n -= int64(nw)
+ }
+ tw.nb = 0
+ tw.pad = 0
+ return tw.err
+}
+
+// Write s into b, terminating it with a NUL if there is room.
+func (tw *Writer) cString(b []byte, s string) {
+ if len(s) > len(b) {
+ if tw.err == nil {
+ tw.err = ErrFieldTooLong
+ }
+ return
+ }
+ copy(b, s)
+ if len(s) < len(b) {
+ b[len(s)] = 0
+ }
+}
+
+// Encode x as an octal ASCII string and write it into b with leading zeros.
+func (tw *Writer) octal(b []byte, x int64) {
+ s := strconv.Itob64(x, 8)
+ // leading zeros, but leave room for a NUL.
+ for len(s)+1 < len(b) {
+ s = "0" + s
+ }
+ tw.cString(b, s)
+}
+
+// Write x into b, either as octal or as binary (GNUtar/star extension).
+func (tw *Writer) numeric(b []byte, x int64) {
+ // Try octal first.
+ s := strconv.Itob64(x, 8)
+ if len(s) < len(b) {
+ tw.octal(b, x)
+ return
+ }
+ // Too big: use binary (big-endian).
+ tw.usedBinary = true
+ for i := len(b) - 1; x > 0 && i >= 0; i-- {
+ b[i] = byte(x)
+ x >>= 8
+ }
+ b[0] |= 0x80 // highest bit indicates binary format
+}
+
+// WriteHeader writes hdr and prepares to accept the file's contents.
+// WriteHeader calls Flush if it is not the first header.
+// Calling after a Close will return ErrWriteAfterClose.
+func (tw *Writer) WriteHeader(hdr *Header) os.Error {
+ if tw.closed {
+ return ErrWriteAfterClose
+ }
+ if tw.err == nil {
+ tw.Flush()
+ }
+ if tw.err != nil {
+ return tw.err
+ }
+
+ tw.nb = int64(hdr.Size)
+ tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two
+
+ header := make([]byte, blockSize)
+ s := slicer(header)
+
+ // TODO(dsymonds): handle names longer than 100 chars
+ copy(s.next(100), []byte(hdr.Name))
+
+ tw.octal(s.next(8), hdr.Mode) // 100:108
+ tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
+ tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
+ tw.numeric(s.next(12), hdr.Size) // 124:136
+ tw.numeric(s.next(12), hdr.Mtime) // 136:148
+ s.next(8) // chksum (148:156)
+ s.next(1)[0] = hdr.Typeflag // 156:157
+ s.next(100) // linkname (157:257)
+ copy(s.next(8), []byte("ustar\x0000")) // 257:265
+ tw.cString(s.next(32), hdr.Uname) // 265:297
+ tw.cString(s.next(32), hdr.Gname) // 297:329
+ tw.numeric(s.next(8), hdr.Devmajor) // 329:337
+ tw.numeric(s.next(8), hdr.Devminor) // 337:345
+
+ // Use the GNU magic instead of POSIX magic if we used any GNU extensions.
+ if tw.usedBinary {
+ copy(header[257:265], []byte("ustar \x00"))
+ }
+
+ // The chksum field is terminated by a NUL and a space.
+ // This is different from the other octal fields.
+ chksum, _ := checksum(header)
+ tw.octal(header[148:155], chksum)
+ header[155] = ' '
+
+ if tw.err != nil {
+ // problem with header; probably integer too big for a field.
+ return tw.err
+ }
+
+ _, tw.err = tw.w.Write(header)
+
+ return tw.err
+}
+
+// Write writes to the current entry in the tar archive.
+// Write returns the error ErrWriteTooLong if more than
+// hdr.Size bytes are written after WriteHeader.
+func (tw *Writer) Write(b []byte) (n int, err os.Error) {
+ if tw.closed {
+ err = ErrWriteTooLong
+ return
+ }
+ overwrite := false
+ if int64(len(b)) > tw.nb {
+ b = b[0:tw.nb]
+ overwrite = true
+ }
+ n, err = tw.w.Write(b)
+ tw.nb -= int64(n)
+ if err == nil && overwrite {
+ err = ErrWriteTooLong
+ return
+ }
+ tw.err = err
+ return
+}
+
+// Close closes the tar archive, flushing any unwritten
+// data to the underlying writer.
+func (tw *Writer) Close() os.Error {
+ if tw.err != nil || tw.closed {
+ return tw.err
+ }
+ tw.Flush()
+ tw.closed = true
+
+ // trailer: two zero blocks
+ for i := 0; i < 2; i++ {
+ _, tw.err = tw.w.Write(zeroBlock)
+ if tw.err != nil {
+ break
+ }
+ }
+ return tw.err
+}
diff --git a/libgo/go/archive/tar/writer_test.go b/libgo/go/archive/tar/writer_test.go
new file mode 100644
index 000000000..48b891140
--- /dev/null
+++ b/libgo/go/archive/tar/writer_test.go
@@ -0,0 +1,154 @@
+// 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 tar
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "testing"
+ "testing/iotest"
+)
+
+type writerTestEntry struct {
+ header *Header
+ contents string
+}
+
+type writerTest struct {
+ file string // filename of expected output
+ entries []*writerTestEntry
+}
+
+var writerTests = []*writerTest{
+ &writerTest{
+ file: "testdata/writer.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1246508266,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Kilts",
+ },
+ &writerTestEntry{
+ header: &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1245217492,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Google.com\n",
+ },
+ },
+ },
+ // The truncated test file was produced using these commands:
+ // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+ // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+ &writerTest{
+ file: "testdata/writer-big.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "tmp/16gig.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 16 << 30,
+ Mtime: 1254699560,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ // no contents
+ },
+ },
+ },
+}
+
+// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
+func bytestr(offset int, b []byte) string {
+ const rowLen = 32
+ s := fmt.Sprintf("%04x ", offset)
+ for _, ch := range b {
+ switch {
+ case '0' <= ch && ch <= '9', 'A' <= ch && ch <= 'Z', 'a' <= ch && ch <= 'z':
+ s += fmt.Sprintf(" %c", ch)
+ default:
+ s += fmt.Sprintf(" %02x", ch)
+ }
+ }
+ return s
+}
+
+// Render a pseudo-diff between two blocks of bytes.
+func bytediff(a []byte, b []byte) string {
+ const rowLen = 32
+ s := fmt.Sprintf("(%d bytes vs. %d bytes)\n", len(a), len(b))
+ for offset := 0; len(a)+len(b) > 0; offset += rowLen {
+ na, nb := rowLen, rowLen
+ if na > len(a) {
+ na = len(a)
+ }
+ if nb > len(b) {
+ nb = len(b)
+ }
+ sa := bytestr(offset, a[0:na])
+ sb := bytestr(offset, b[0:nb])
+ if sa != sb {
+ s += fmt.Sprintf("-%v\n+%v\n", sa, sb)
+ }
+ a = a[na:]
+ b = b[nb:]
+ }
+ return s
+}
+
+func TestWriter(t *testing.T) {
+testLoop:
+ for i, test := range writerTests {
+ expected, err := ioutil.ReadFile(test.file)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+
+ buf := new(bytes.Buffer)
+ tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB
+ for j, entry := range test.entries {
+ if err := tw.WriteHeader(entry.header); err != nil {
+ t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
+ continue testLoop
+ }
+ if _, err := io.WriteString(tw, entry.contents); err != nil {
+ t.Errorf("test %d, entry %d: Failed writing contents: %v", i, j, err)
+ continue testLoop
+ }
+ }
+ if err := tw.Close(); err != nil {
+ t.Errorf("test %d: Failed closing archive: %v", i, err)
+ continue testLoop
+ }
+
+ actual := buf.Bytes()
+ if !bytes.Equal(expected, actual) {
+ t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v",
+ i, bytediff(expected, actual))
+ }
+ }
+}
diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go
new file mode 100644
index 000000000..579ba1602
--- /dev/null
+++ b/libgo/go/archive/zip/reader.go
@@ -0,0 +1,278 @@
+// 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.
+
+/*
+The zip package provides support for reading ZIP archives.
+
+See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+
+This package does not support ZIP64 or disk spanning.
+*/
+package zip
+
+import (
+ "bufio"
+ "bytes"
+ "compress/flate"
+ "hash"
+ "hash/crc32"
+ "encoding/binary"
+ "io"
+ "os"
+)
+
+var (
+ FormatError = os.NewError("not a valid zip file")
+ UnsupportedMethod = os.NewError("unsupported compression algorithm")
+ ChecksumError = os.NewError("checksum error")
+)
+
+type Reader struct {
+ r io.ReaderAt
+ File []*File
+ Comment string
+}
+
+type File struct {
+ FileHeader
+ zipr io.ReaderAt
+ zipsize int64
+ headerOffset uint32
+ bodyOffset int64
+}
+
+// OpenReader will open the Zip file specified by name and return a Reader.
+func OpenReader(name string) (*Reader, os.Error) {
+ f, err := os.Open(name, os.O_RDONLY, 0644)
+ if err != nil {
+ return nil, err
+ }
+ fi, err := f.Stat()
+ if err != nil {
+ return nil, err
+ }
+ return NewReader(f, fi.Size)
+}
+
+// NewReader returns a new Reader reading from r, which is assumed to
+// have the given size in bytes.
+func NewReader(r io.ReaderAt, size int64) (*Reader, os.Error) {
+ end, err := readDirectoryEnd(r, size)
+ if err != nil {
+ return nil, err
+ }
+ z := &Reader{
+ r: r,
+ File: make([]*File, end.directoryRecords),
+ Comment: end.comment,
+ }
+ rs := io.NewSectionReader(r, 0, size)
+ if _, err = rs.Seek(int64(end.directoryOffset), 0); err != nil {
+ return nil, err
+ }
+ buf := bufio.NewReader(rs)
+ for i := range z.File {
+ z.File[i] = &File{zipr: r, zipsize: size}
+ if err := readDirectoryHeader(z.File[i], buf); err != nil {
+ return nil, err
+ }
+ }
+ return z, nil
+}
+
+// Open returns a ReadCloser that provides access to the File's contents.
+func (f *File) Open() (rc io.ReadCloser, err os.Error) {
+ off := int64(f.headerOffset)
+ if f.bodyOffset == 0 {
+ r := io.NewSectionReader(f.zipr, off, f.zipsize-off)
+ if err = readFileHeader(f, r); err != nil {
+ return
+ }
+ if f.bodyOffset, err = r.Seek(0, 1); err != nil {
+ return
+ }
+ }
+ r := io.NewSectionReader(f.zipr, off+f.bodyOffset, int64(f.CompressedSize))
+ switch f.Method {
+ case 0: // store (no compression)
+ rc = nopCloser{r}
+ case 8: // DEFLATE
+ rc = flate.NewReader(r)
+ default:
+ err = UnsupportedMethod
+ }
+ if rc != nil {
+ rc = &checksumReader{rc, crc32.NewIEEE(), f.CRC32}
+ }
+ return
+}
+
+type checksumReader struct {
+ rc io.ReadCloser
+ hash hash.Hash32
+ sum uint32
+}
+
+func (r *checksumReader) Read(b []byte) (n int, err os.Error) {
+ n, err = r.rc.Read(b)
+ r.hash.Write(b[:n])
+ if err != os.EOF {
+ return
+ }
+ if r.hash.Sum32() != r.sum {
+ err = ChecksumError
+ }
+ return
+}
+
+func (r *checksumReader) Close() os.Error { return r.rc.Close() }
+
+type nopCloser struct {
+ io.Reader
+}
+
+func (f nopCloser) Close() os.Error { return nil }
+
+func readFileHeader(f *File, r io.Reader) (err os.Error) {
+ defer func() {
+ if rerr, ok := recover().(os.Error); ok {
+ err = rerr
+ }
+ }()
+ var (
+ signature uint32
+ filenameLength uint16
+ extraLength uint16
+ )
+ read(r, &signature)
+ if signature != fileHeaderSignature {
+ return FormatError
+ }
+ read(r, &f.ReaderVersion)
+ read(r, &f.Flags)
+ read(r, &f.Method)
+ read(r, &f.ModifiedTime)
+ read(r, &f.ModifiedDate)
+ read(r, &f.CRC32)
+ read(r, &f.CompressedSize)
+ read(r, &f.UncompressedSize)
+ read(r, &filenameLength)
+ read(r, &extraLength)
+ f.Name = string(readByteSlice(r, filenameLength))
+ f.Extra = readByteSlice(r, extraLength)
+ return
+}
+
+func readDirectoryHeader(f *File, r io.Reader) (err os.Error) {
+ defer func() {
+ if rerr, ok := recover().(os.Error); ok {
+ err = rerr
+ }
+ }()
+ var (
+ signature uint32
+ filenameLength uint16
+ extraLength uint16
+ commentLength uint16
+ startDiskNumber uint16 // unused
+ internalAttributes uint16 // unused
+ externalAttributes uint32 // unused
+ )
+ read(r, &signature)
+ if signature != directoryHeaderSignature {
+ return FormatError
+ }
+ read(r, &f.CreatorVersion)
+ read(r, &f.ReaderVersion)
+ read(r, &f.Flags)
+ read(r, &f.Method)
+ read(r, &f.ModifiedTime)
+ read(r, &f.ModifiedDate)
+ read(r, &f.CRC32)
+ read(r, &f.CompressedSize)
+ read(r, &f.UncompressedSize)
+ read(r, &filenameLength)
+ read(r, &extraLength)
+ read(r, &commentLength)
+ read(r, &startDiskNumber)
+ read(r, &internalAttributes)
+ read(r, &externalAttributes)
+ read(r, &f.headerOffset)
+ f.Name = string(readByteSlice(r, filenameLength))
+ f.Extra = readByteSlice(r, extraLength)
+ f.Comment = string(readByteSlice(r, commentLength))
+ return
+}
+
+func readDirectoryEnd(r io.ReaderAt, size int64) (d *directoryEnd, err os.Error) {
+ // look for directoryEndSignature in the last 1k, then in the last 65k
+ var b []byte
+ for i, bLen := range []int64{1024, 65 * 1024} {
+ if bLen > size {
+ bLen = size
+ }
+ b = make([]byte, int(bLen))
+ if _, err := r.ReadAt(b, size-bLen); err != nil && err != os.EOF {
+ return nil, err
+ }
+ if p := findSignatureInBlock(b); p >= 0 {
+ b = b[p:]
+ break
+ }
+ if i == 1 || bLen == size {
+ return nil, FormatError
+ }
+ }
+
+ // read header into struct
+ defer func() {
+ if rerr, ok := recover().(os.Error); ok {
+ err = rerr
+ d = nil
+ }
+ }()
+ br := bytes.NewBuffer(b[4:]) // skip over signature
+ d = new(directoryEnd)
+ read(br, &d.diskNbr)
+ read(br, &d.dirDiskNbr)
+ read(br, &d.dirRecordsThisDisk)
+ read(br, &d.directoryRecords)
+ read(br, &d.directorySize)
+ read(br, &d.directoryOffset)
+ read(br, &d.commentLen)
+ d.comment = string(readByteSlice(br, d.commentLen))
+ return d, nil
+}
+
+func findSignatureInBlock(b []byte) int {
+ const minSize = 4 + 2 + 2 + 2 + 2 + 4 + 4 + 2 // fixed part of header
+ for i := len(b) - minSize; i >= 0; i-- {
+ // defined from directoryEndSignature in struct.go
+ if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
+ // n is length of comment
+ n := int(b[i+minSize-2]) | int(b[i+minSize-1])<<8
+ if n+minSize+i == len(b) {
+ return i
+ }
+ }
+ }
+ return -1
+}
+
+func read(r io.Reader, data interface{}) {
+ if err := binary.Read(r, binary.LittleEndian, data); err != nil {
+ panic(err)
+ }
+}
+
+func readByteSlice(r io.Reader, l uint16) []byte {
+ b := make([]byte, l)
+ if l == 0 {
+ return b
+ }
+ if _, err := io.ReadFull(r, b); err != nil {
+ panic(err)
+ }
+ return b
+}
diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go
new file mode 100644
index 000000000..3c24f1467
--- /dev/null
+++ b/libgo/go/archive/zip/reader_test.go
@@ -0,0 +1,180 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zip
+
+import (
+ "bytes"
+ "encoding/binary"
+ "io"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type ZipTest struct {
+ Name string
+ Comment string
+ File []ZipTestFile
+ Error os.Error // the error that Opening this file should return
+}
+
+type ZipTestFile struct {
+ Name string
+ Content []byte // if blank, will attempt to compare against File
+ File string // name of file to compare to (relative to testdata/)
+}
+
+var tests = []ZipTest{
+ {
+ Name: "test.zip",
+ Comment: "This is a zipfile comment.",
+ File: []ZipTestFile{
+ {
+ Name: "test.txt",
+ Content: []byte("This is a test text file.\n"),
+ },
+ {
+ Name: "gophercolor16x16.png",
+ File: "gophercolor16x16.png",
+ },
+ },
+ },
+ {
+ Name: "r.zip",
+ File: []ZipTestFile{
+ {
+ Name: "r/r.zip",
+ File: "r.zip",
+ },
+ },
+ },
+ {Name: "readme.zip"},
+ {Name: "readme.notzip", Error: FormatError},
+}
+
+func TestReader(t *testing.T) {
+ for _, zt := range tests {
+ readTestZip(t, zt)
+ }
+}
+
+func readTestZip(t *testing.T, zt ZipTest) {
+ z, err := OpenReader("testdata/" + zt.Name)
+ if err != zt.Error {
+ t.Errorf("error=%v, want %v", err, zt.Error)
+ return
+ }
+
+ // bail here if no Files expected to be tested
+ // (there may actually be files in the zip, but we don't care)
+ if zt.File == nil {
+ return
+ }
+
+ if z.Comment != zt.Comment {
+ t.Errorf("%s: comment=%q, want %q", zt.Name, z.Comment, zt.Comment)
+ }
+ if len(z.File) != len(zt.File) {
+ t.Errorf("%s: file count=%d, want %d", zt.Name, len(z.File), len(zt.File))
+ }
+
+ // test read of each file
+ for i, ft := range zt.File {
+ readTestFile(t, ft, z.File[i])
+ }
+
+ // test simultaneous reads
+ n := 0
+ done := make(chan bool)
+ for i := 0; i < 5; i++ {
+ for j, ft := range zt.File {
+ go func() {
+ readTestFile(t, ft, z.File[j])
+ done <- true
+ }()
+ n++
+ }
+ }
+ for ; n > 0; n-- {
+ <-done
+ }
+
+ // test invalid checksum
+ z.File[0].CRC32++ // invalidate
+ r, err := z.File[0].Open()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ var b bytes.Buffer
+ _, err = io.Copy(&b, r)
+ if err != ChecksumError {
+ t.Errorf("%s: copy error=%v, want %v", z.File[0].Name, err, ChecksumError)
+ }
+}
+
+func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
+ if f.Name != ft.Name {
+ t.Errorf("name=%q, want %q", f.Name, ft.Name)
+ }
+ var b bytes.Buffer
+ r, err := f.Open()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ _, err = io.Copy(&b, r)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ r.Close()
+ var c []byte
+ if len(ft.Content) != 0 {
+ c = ft.Content
+ } else if c, err = ioutil.ReadFile("testdata/" + ft.File); err != nil {
+ t.Error(err)
+ return
+ }
+ if b.Len() != len(c) {
+ t.Errorf("%s: len=%d, want %d", f.Name, b.Len(), len(c))
+ return
+ }
+ for i, b := range b.Bytes() {
+ if b != c[i] {
+ t.Errorf("%s: content[%d]=%q want %q", f.Name, i, b, c[i])
+ return
+ }
+ }
+}
+
+func TestInvalidFiles(t *testing.T) {
+ const size = 1024 * 70 // 70kb
+ b := make([]byte, size)
+
+ // zeroes
+ _, err := NewReader(sliceReaderAt(b), size)
+ if err != FormatError {
+ t.Errorf("zeroes: error=%v, want %v", err, FormatError)
+ }
+
+ // repeated directoryEndSignatures
+ sig := make([]byte, 4)
+ binary.LittleEndian.PutUint32(sig, directoryEndSignature)
+ for i := 0; i < size-4; i += 4 {
+ copy(b[i:i+4], sig)
+ }
+ _, err = NewReader(sliceReaderAt(b), size)
+ if err != FormatError {
+ t.Errorf("sigs: error=%v, want %v", err, FormatError)
+ }
+}
+
+type sliceReaderAt []byte
+
+func (r sliceReaderAt) ReadAt(b []byte, off int64) (int, os.Error) {
+ copy(b, r[int(off):int(off)+len(b)])
+ return len(b), nil
+}
diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go
new file mode 100644
index 000000000..8a8c727d4
--- /dev/null
+++ b/libgo/go/archive/zip/struct.go
@@ -0,0 +1,33 @@
+package zip
+
+const (
+ fileHeaderSignature = 0x04034b50
+ directoryHeaderSignature = 0x02014b50
+ directoryEndSignature = 0x06054b50
+)
+
+type FileHeader struct {
+ Name string
+ CreatorVersion uint16
+ ReaderVersion uint16
+ Flags uint16
+ Method uint16
+ ModifiedTime uint16
+ ModifiedDate uint16
+ CRC32 uint32
+ CompressedSize uint32
+ UncompressedSize uint32
+ Extra []byte
+ Comment string
+}
+
+type directoryEnd struct {
+ diskNbr uint16 // unused
+ dirDiskNbr uint16 // unused
+ dirRecordsThisDisk uint16 // unused
+ directoryRecords uint16
+ directorySize uint32
+ directoryOffset uint32 // relative to file
+ commentLen uint16
+ comment string
+}
diff --git a/libgo/go/archive/zip/testdata/gophercolor16x16.png b/libgo/go/archive/zip/testdata/gophercolor16x16.png
new file mode 100644
index 000000000..48854ff3b
--- /dev/null
+++ b/libgo/go/archive/zip/testdata/gophercolor16x16.png
Binary files differ
diff --git a/libgo/go/archive/zip/testdata/r.zip b/libgo/go/archive/zip/testdata/r.zip
new file mode 100644
index 000000000..ea0fa2ffc
--- /dev/null
+++ b/libgo/go/archive/zip/testdata/r.zip
Binary files differ
diff --git a/libgo/go/archive/zip/testdata/readme.notzip b/libgo/go/archive/zip/testdata/readme.notzip
new file mode 100644
index 000000000..06668c4c1
--- /dev/null
+++ b/libgo/go/archive/zip/testdata/readme.notzip
Binary files differ
diff --git a/libgo/go/archive/zip/testdata/readme.zip b/libgo/go/archive/zip/testdata/readme.zip
new file mode 100644
index 000000000..db3bb900e
--- /dev/null
+++ b/libgo/go/archive/zip/testdata/readme.zip
Binary files differ
diff --git a/libgo/go/archive/zip/testdata/test.zip b/libgo/go/archive/zip/testdata/test.zip
new file mode 100644
index 000000000..03890c05d
--- /dev/null
+++ b/libgo/go/archive/zip/testdata/test.zip
Binary files differ
diff --git a/libgo/go/asn1/asn1.go b/libgo/go/asn1/asn1.go
new file mode 100644
index 000000000..d06b1d4d7
--- /dev/null
+++ b/libgo/go/asn1/asn1.go
@@ -0,0 +1,785 @@
+// 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.
+
+// The asn1 package implements parsing of DER-encoded ASN.1 data structures,
+// as defined in ITU-T Rec X.690.
+//
+// See also ``A Layman's Guide to a Subset of ASN.1, BER, and DER,''
+// http://luca.ntop.org/Teaching/Appunti/asn1.html.
+package asn1
+
+// ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc
+// are different encoding formats for those objects. Here, we'll be dealing
+// with DER, the Distinguished Encoding Rules. DER is used in X.509 because
+// it's fast to parse and, unlike BER, has a unique encoding for every object.
+// When calculating hashes over objects, it's important that the resulting
+// bytes be the same at both ends and DER removes this margin of error.
+//
+// ASN.1 is very complex and this package doesn't attempt to implement
+// everything by any means.
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "time"
+)
+
+// A StructuralError suggests that the ASN.1 data is valid, but the Go type
+// which is receiving it doesn't match.
+type StructuralError struct {
+ Msg string
+}
+
+func (e StructuralError) String() string { return "ASN.1 structure error: " + e.Msg }
+
+// A SyntaxError suggests that the ASN.1 data is invalid.
+type SyntaxError struct {
+ Msg string
+}
+
+func (e SyntaxError) String() string { return "ASN.1 syntax error: " + e.Msg }
+
+// We start by dealing with each of the primitive types in turn.
+
+// BOOLEAN
+
+func parseBool(bytes []byte) (ret bool, err os.Error) {
+ if len(bytes) != 1 {
+ err = SyntaxError{"invalid boolean"}
+ return
+ }
+
+ return bytes[0] != 0, nil
+}
+
+// INTEGER
+
+// parseInt64 treats the given bytes as a big-endian, signed integer and
+// returns the result.
+func parseInt64(bytes []byte) (ret int64, err os.Error) {
+ if len(bytes) > 8 {
+ // We'll overflow an int64 in this case.
+ err = StructuralError{"integer too large"}
+ return
+ }
+ for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
+ ret <<= 8
+ ret |= int64(bytes[bytesRead])
+ }
+
+ // Shift up and down in order to sign extend the result.
+ ret <<= 64 - uint8(len(bytes))*8
+ ret >>= 64 - uint8(len(bytes))*8
+ return
+}
+
+// parseInt treats the given bytes as a big-endian, signed integer and returns
+// the result.
+func parseInt(bytes []byte) (int, os.Error) {
+ ret64, err := parseInt64(bytes)
+ if err != nil {
+ return 0, err
+ }
+ if ret64 != int64(int(ret64)) {
+ return 0, StructuralError{"integer too large"}
+ }
+ return int(ret64), nil
+}
+
+// BIT STRING
+
+// BitString is the structure to use when you want an ASN.1 BIT STRING type. A
+// bit string is padded up to the nearest byte in memory and the number of
+// valid bits is recorded. Padding bits will be zero.
+type BitString struct {
+ Bytes []byte // bits packed into bytes.
+ BitLength int // length in bits.
+}
+
+// At returns the bit at the given index. If the index is out of range it
+// returns false.
+func (b BitString) At(i int) int {
+ if i < 0 || i >= b.BitLength {
+ return 0
+ }
+ x := i / 8
+ y := 7 - uint(i%8)
+ return int(b.Bytes[x]>>y) & 1
+}
+
+// RightAlign returns a slice where the padding bits are at the beginning. The
+// slice may share memory with the BitString.
+func (b BitString) RightAlign() []byte {
+ shift := uint(8 - (b.BitLength % 8))
+ if shift == 8 || len(b.Bytes) == 0 {
+ return b.Bytes
+ }
+
+ a := make([]byte, len(b.Bytes))
+ a[0] = b.Bytes[0] >> shift
+ for i := 1; i < len(b.Bytes); i++ {
+ a[i] = b.Bytes[i-1] << (8 - shift)
+ a[i] |= b.Bytes[i] >> shift
+ }
+
+ return a
+}
+
+// parseBitString parses an ASN.1 bit string from the given byte array and returns it.
+func parseBitString(bytes []byte) (ret BitString, err os.Error) {
+ if len(bytes) == 0 {
+ err = SyntaxError{"zero length BIT STRING"}
+ return
+ }
+ paddingBits := int(bytes[0])
+ if paddingBits > 7 ||
+ len(bytes) == 1 && paddingBits > 0 ||
+ bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {
+ err = SyntaxError{"invalid padding bits in BIT STRING"}
+ return
+ }
+ ret.BitLength = (len(bytes)-1)*8 - paddingBits
+ ret.Bytes = bytes[1:]
+ return
+}
+
+// OBJECT IDENTIFIER
+
+// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
+type ObjectIdentifier []int
+
+// Equal returns true iff oi and other represent the same identifier.
+func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
+ if len(oi) != len(other) {
+ return false
+ }
+ for i := 0; i < len(oi); i++ {
+ if oi[i] != other[i] {
+ return false
+ }
+ }
+
+ return true
+}
+
+// parseObjectIdentifier parses an OBJECT IDENTIFER from the given bytes and
+// returns it. An object identifer is a sequence of variable length integers
+// that are assigned in a hierarachy.
+func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
+ if len(bytes) == 0 {
+ err = SyntaxError{"zero length OBJECT IDENTIFIER"}
+ return
+ }
+
+ // In the worst case, we get two elements from the first byte (which is
+ // encoded differently) and then every varint is a single byte long.
+ s = make([]int, len(bytes)+1)
+
+ // The first byte is 40*value1 + value2:
+ s[0] = int(bytes[0]) / 40
+ s[1] = int(bytes[0]) % 40
+ i := 2
+ for offset := 1; offset < len(bytes); i++ {
+ var v int
+ v, offset, err = parseBase128Int(bytes, offset)
+ if err != nil {
+ return
+ }
+ s[i] = v
+ }
+ s = s[0:i]
+ return
+}
+
+// ENUMERATED
+
+// An Enumerated is represented as a plain int.
+type Enumerated int
+
+
+// FLAG
+
+// A Flag accepts any data and is set to true if present.
+type Flag bool
+
+// parseBase128Int parses a base-128 encoded int from the given offset in the
+// given byte array. It returns the value and the new offset.
+func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Error) {
+ offset = initOffset
+ for shifted := 0; offset < len(bytes); shifted++ {
+ if shifted > 4 {
+ err = StructuralError{"base 128 integer too large"}
+ return
+ }
+ ret <<= 7
+ b := bytes[offset]
+ ret |= int(b & 0x7f)
+ offset++
+ if b&0x80 == 0 {
+ return
+ }
+ }
+ err = SyntaxError{"truncated base 128 integer"}
+ return
+}
+
+// UTCTime
+
+func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) {
+ s := string(bytes)
+ ret, err = time.Parse("0601021504Z0700", s)
+ if err == nil {
+ return
+ }
+ ret, err = time.Parse("060102150405Z0700", s)
+ return
+}
+
+// parseGeneralizedTime parses the GeneralizedTime from the given byte array
+// and returns the resulting time.
+func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
+ return time.Parse("20060102150405Z0700", string(bytes))
+}
+
+// PrintableString
+
+// parsePrintableString parses a ASN.1 PrintableString from the given byte
+// array and returns it.
+func parsePrintableString(bytes []byte) (ret string, err os.Error) {
+ for _, b := range bytes {
+ if !isPrintable(b) {
+ err = SyntaxError{"PrintableString contains invalid character"}
+ return
+ }
+ }
+ ret = string(bytes)
+ return
+}
+
+// isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
+func isPrintable(b byte) bool {
+ return 'a' <= b && b <= 'z' ||
+ 'A' <= b && b <= 'Z' ||
+ '0' <= b && b <= '9' ||
+ '\'' <= b && b <= ')' ||
+ '+' <= b && b <= '/' ||
+ b == ' ' ||
+ b == ':' ||
+ b == '=' ||
+ b == '?' ||
+ // This is techincally not allowed in a PrintableString.
+ // However, x509 certificates with wildcard strings don't
+ // always use the correct string type so we permit it.
+ b == '*'
+}
+
+// IA5String
+
+// parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
+// byte array and returns it.
+func parseIA5String(bytes []byte) (ret string, err os.Error) {
+ for _, b := range bytes {
+ if b >= 0x80 {
+ err = SyntaxError{"IA5String contains invalid character"}
+ return
+ }
+ }
+ ret = string(bytes)
+ return
+}
+
+// T61String
+
+// parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
+// byte array and returns it.
+func parseT61String(bytes []byte) (ret string, err os.Error) {
+ return string(bytes), nil
+}
+
+// A RawValue represents an undecoded ASN.1 object.
+type RawValue struct {
+ Class, Tag int
+ IsCompound bool
+ Bytes []byte
+ FullBytes []byte // includes the tag and length
+}
+
+// RawContent is used to signal that the undecoded, DER data needs to be
+// preserved for a struct. To use it, the first field of the struct must have
+// this type. It's an error for any of the other fields to have this type.
+type RawContent []byte
+
+// Tagging
+
+// parseTagAndLength parses an ASN.1 tag and length pair from the given offset
+// into a byte array. It returns the parsed data and the new offset. SET and
+// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
+// don't distinguish between ordered and unordered objects in this code.
+func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err os.Error) {
+ offset = initOffset
+ b := bytes[offset]
+ offset++
+ ret.class = int(b >> 6)
+ ret.isCompound = b&0x20 == 0x20
+ ret.tag = int(b & 0x1f)
+
+ // If the bottom five bits are set, then the tag number is actually base 128
+ // encoded afterwards
+ if ret.tag == 0x1f {
+ ret.tag, offset, err = parseBase128Int(bytes, offset)
+ if err != nil {
+ return
+ }
+ }
+ if offset >= len(bytes) {
+ err = SyntaxError{"truncated tag or length"}
+ return
+ }
+ b = bytes[offset]
+ offset++
+ if b&0x80 == 0 {
+ // The length is encoded in the bottom 7 bits.
+ ret.length = int(b & 0x7f)
+ } else {
+ // Bottom 7 bits give the number of length bytes to follow.
+ numBytes := int(b & 0x7f)
+ // We risk overflowing a signed 32-bit number if we accept more than 3 bytes.
+ if numBytes > 3 {
+ err = StructuralError{"length too large"}
+ return
+ }
+ if numBytes == 0 {
+ err = SyntaxError{"indefinite length found (not DER)"}
+ return
+ }
+ ret.length = 0
+ for i := 0; i < numBytes; i++ {
+ if offset >= len(bytes) {
+ err = SyntaxError{"truncated tag or length"}
+ return
+ }
+ b = bytes[offset]
+ offset++
+ ret.length <<= 8
+ ret.length |= int(b)
+ }
+ }
+
+ return
+}
+
+// parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
+// a number of ASN.1 values from the given byte array and returns them as a
+// slice of Go values of the given type.
+func parseSequenceOf(bytes []byte, sliceType *reflect.SliceType, elemType reflect.Type) (ret *reflect.SliceValue, err os.Error) {
+ expectedTag, compoundType, ok := getUniversalType(elemType)
+ if !ok {
+ err = StructuralError{"unknown Go type for slice"}
+ return
+ }
+
+ // First we iterate over the input and count the number of elements,
+ // checking that the types are correct in each case.
+ numElements := 0
+ for offset := 0; offset < len(bytes); {
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
+ err = StructuralError{"sequence tag mismatch"}
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"truncated sequence"}
+ return
+ }
+ offset += t.length
+ numElements++
+ }
+ ret = reflect.MakeSlice(sliceType, numElements, numElements)
+ params := fieldParameters{}
+ offset := 0
+ for i := 0; i < numElements; i++ {
+ offset, err = parseField(ret.Elem(i), bytes, offset, params)
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+var (
+ bitStringType = reflect.Typeof(BitString{})
+ objectIdentifierType = reflect.Typeof(ObjectIdentifier{})
+ enumeratedType = reflect.Typeof(Enumerated(0))
+ flagType = reflect.Typeof(Flag(false))
+ timeType = reflect.Typeof(&time.Time{})
+ rawValueType = reflect.Typeof(RawValue{})
+ rawContentsType = reflect.Typeof(RawContent(nil))
+)
+
+// invalidLength returns true iff offset + length > sliceLength, or if the
+// addition would overflow.
+func invalidLength(offset, length, sliceLength int) bool {
+ return offset+length < offset || offset+length > sliceLength
+}
+
+// parseField is the main parsing function. Given a byte array and an offset
+// into the array, it will try to parse a suitable ASN.1 value out and store it
+// in the given Value.
+func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err os.Error) {
+ offset = initOffset
+ fieldType := v.Type()
+
+ // If we have run out of data, it may be that there are optional elements at the end.
+ if offset == len(bytes) {
+ if !setDefaultValue(v, params) {
+ err = SyntaxError{"sequence truncated"}
+ }
+ return
+ }
+
+ // Deal with raw values.
+ if fieldType == rawValueType {
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length], bytes[initOffset : offset+t.length]}
+ offset += t.length
+ v.(*reflect.StructValue).Set(reflect.NewValue(result).(*reflect.StructValue))
+ return
+ }
+
+ // Deal with the ANY type.
+ if ifaceType, ok := fieldType.(*reflect.InterfaceType); ok && ifaceType.NumMethod() == 0 {
+ ifaceValue := v.(*reflect.InterfaceValue)
+ var t tagAndLength
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ var result interface{}
+ if !t.isCompound && t.class == classUniversal {
+ innerBytes := bytes[offset : offset+t.length]
+ switch t.tag {
+ case tagPrintableString:
+ result, err = parsePrintableString(innerBytes)
+ case tagIA5String:
+ result, err = parseIA5String(innerBytes)
+ case tagT61String:
+ result, err = parseT61String(innerBytes)
+ case tagInteger:
+ result, err = parseInt64(innerBytes)
+ case tagBitString:
+ result, err = parseBitString(innerBytes)
+ case tagOID:
+ result, err = parseObjectIdentifier(innerBytes)
+ case tagUTCTime:
+ result, err = parseUTCTime(innerBytes)
+ case tagOctetString:
+ result = innerBytes
+ default:
+ // If we don't know how to handle the type, we just leave Value as nil.
+ }
+ }
+ offset += t.length
+ if err != nil {
+ return
+ }
+ if result != nil {
+ ifaceValue.Set(reflect.NewValue(result))
+ }
+ return
+ }
+ universalTag, compoundType, ok1 := getUniversalType(fieldType)
+ if !ok1 {
+ err = StructuralError{fmt.Sprintf("unknown Go type: %v", fieldType)}
+ return
+ }
+
+ t, offset, err := parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ if params.explicit {
+ if t.class == classContextSpecific && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
+ if t.length > 0 {
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ } else {
+ if fieldType != flagType {
+ err = StructuralError{"Zero length explicit tag was not an asn1.Flag"}
+ return
+ }
+
+ flagValue := v.(*reflect.BoolValue)
+ flagValue.Set(true)
+ return
+ }
+ } else {
+ // The tags didn't match, it might be an optional element.
+ ok := setDefaultValue(v, params)
+ if ok {
+ offset = initOffset
+ } else {
+ err = StructuralError{"explicitly tagged member didn't match"}
+ }
+ return
+ }
+ }
+
+ // Special case for strings: PrintableString and IA5String both map to
+ // the Go type string. getUniversalType returns the tag for
+ // PrintableString when it sees a string so, if we see an IA5String on
+ // the wire, we change the universal type to match.
+ if universalTag == tagPrintableString && t.tag == tagIA5String {
+ universalTag = tagIA5String
+ }
+
+ // Special case for time: UTCTime and GeneralizedTime both map to the
+ // Go type time.Time.
+ if universalTag == tagUTCTime && t.tag == tagGeneralizedTime {
+ universalTag = tagGeneralizedTime
+ }
+
+ expectedClass := classUniversal
+ expectedTag := universalTag
+
+ if !params.explicit && params.tag != nil {
+ expectedClass = classContextSpecific
+ expectedTag = *params.tag
+ }
+
+ // We have unwrapped any explicit tagging at this point.
+ if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType {
+ // Tags don't match. Again, it could be an optional element.
+ ok := setDefaultValue(v, params)
+ if ok {
+ offset = initOffset
+ } else {
+ err = StructuralError{fmt.Sprintf("tags don't match (%d vs %+v) %+v %s @%d", expectedTag, t, params, fieldType.Name(), offset)}
+ }
+ return
+ }
+ if invalidLength(offset, t.length, len(bytes)) {
+ err = SyntaxError{"data truncated"}
+ return
+ }
+ innerBytes := bytes[offset : offset+t.length]
+ offset += t.length
+
+ // We deal with the structures defined in this package first.
+ switch fieldType {
+ case objectIdentifierType:
+ newSlice, err1 := parseObjectIdentifier(innerBytes)
+ sliceValue := v.(*reflect.SliceValue)
+ sliceValue.Set(reflect.MakeSlice(sliceValue.Type().(*reflect.SliceType), len(newSlice), len(newSlice)))
+ if err1 == nil {
+ reflect.Copy(sliceValue, reflect.NewValue(newSlice).(reflect.ArrayOrSliceValue))
+ }
+ err = err1
+ return
+ case bitStringType:
+ structValue := v.(*reflect.StructValue)
+ bs, err1 := parseBitString(innerBytes)
+ if err1 == nil {
+ structValue.Set(reflect.NewValue(bs).(*reflect.StructValue))
+ }
+ err = err1
+ return
+ case timeType:
+ ptrValue := v.(*reflect.PtrValue)
+ var time *time.Time
+ var err1 os.Error
+ if universalTag == tagUTCTime {
+ time, err1 = parseUTCTime(innerBytes)
+ } else {
+ time, err1 = parseGeneralizedTime(innerBytes)
+ }
+ if err1 == nil {
+ ptrValue.Set(reflect.NewValue(time).(*reflect.PtrValue))
+ }
+ err = err1
+ return
+ case enumeratedType:
+ parsedInt, err1 := parseInt(innerBytes)
+ enumValue := v.(*reflect.IntValue)
+ if err1 == nil {
+ enumValue.Set(int64(parsedInt))
+ }
+ err = err1
+ return
+ case flagType:
+ flagValue := v.(*reflect.BoolValue)
+ flagValue.Set(true)
+ return
+ }
+ switch val := v.(type) {
+ case *reflect.BoolValue:
+ parsedBool, err1 := parseBool(innerBytes)
+ if err1 == nil {
+ val.Set(parsedBool)
+ }
+ err = err1
+ return
+ case *reflect.IntValue:
+ switch val.Type().Kind() {
+ case reflect.Int:
+ parsedInt, err1 := parseInt(innerBytes)
+ if err1 == nil {
+ val.Set(int64(parsedInt))
+ }
+ err = err1
+ return
+ case reflect.Int64:
+ parsedInt, err1 := parseInt64(innerBytes)
+ if err1 == nil {
+ val.Set(parsedInt)
+ }
+ err = err1
+ return
+ }
+ case *reflect.StructValue:
+ structType := fieldType.(*reflect.StructType)
+
+ if structType.NumField() > 0 &&
+ structType.Field(0).Type == rawContentsType {
+ bytes := bytes[initOffset:offset]
+ val.Field(0).SetValue(reflect.NewValue(RawContent(bytes)))
+ }
+
+ innerOffset := 0
+ for i := 0; i < structType.NumField(); i++ {
+ field := structType.Field(i)
+ if i == 0 && field.Type == rawContentsType {
+ continue
+ }
+ innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag))
+ if err != nil {
+ return
+ }
+ }
+ // We allow extra bytes at the end of the SEQUENCE because
+ // adding elements to the end has been used in X.509 as the
+ // version numbers have increased.
+ return
+ case *reflect.SliceValue:
+ sliceType := fieldType.(*reflect.SliceType)
+ if sliceType.Elem().Kind() == reflect.Uint8 {
+ val.Set(reflect.MakeSlice(sliceType, len(innerBytes), len(innerBytes)))
+ reflect.Copy(val, reflect.NewValue(innerBytes).(reflect.ArrayOrSliceValue))
+ return
+ }
+ newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
+ if err1 == nil {
+ val.Set(newSlice)
+ }
+ err = err1
+ return
+ case *reflect.StringValue:
+ var v string
+ switch universalTag {
+ case tagPrintableString:
+ v, err = parsePrintableString(innerBytes)
+ case tagIA5String:
+ v, err = parseIA5String(innerBytes)
+ case tagT61String:
+ v, err = parseT61String(innerBytes)
+ default:
+ err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
+ }
+ if err == nil {
+ val.Set(v)
+ }
+ return
+ }
+ err = StructuralError{"unknown Go type"}
+ return
+}
+
+// setDefaultValue is used to install a default value, from a tag string, into
+// a Value. It is successful is the field was optional, even if a default value
+// wasn't provided or it failed to install it into the Value.
+func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
+ if !params.optional {
+ return
+ }
+ ok = true
+ if params.defaultValue == nil {
+ return
+ }
+ switch val := v.(type) {
+ case *reflect.IntValue:
+ val.Set(*params.defaultValue)
+ }
+ return
+}
+
+// Unmarshal parses the DER-encoded ASN.1 data structure b
+// and uses the reflect package to fill in an arbitrary value pointed at by val.
+// Because Unmarshal uses the reflect package, the structs
+// being written to must use upper case field names.
+//
+// An ASN.1 INTEGER can be written to an int or int64.
+// If the encoded value does not fit in the Go type,
+// Unmarshal returns a parse error.
+//
+// An ASN.1 BIT STRING can be written to a BitString.
+//
+// An ASN.1 OCTET STRING can be written to a []byte.
+//
+// An ASN.1 OBJECT IDENTIFIER can be written to an
+// ObjectIdentifier.
+//
+// An ASN.1 ENUMERATED can be written to an Enumerated.
+//
+// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time.
+//
+// An ASN.1 PrintableString or IA5String can be written to a string.
+//
+// Any of the above ASN.1 values can be written to an interface{}.
+// The value stored in the interface has the corresponding Go type.
+// For integers, that type is int64.
+//
+// An ASN.1 SEQUENCE OF x or SET OF x can be written
+// to a slice if an x can be written to the slice's element type.
+//
+// An ASN.1 SEQUENCE or SET can be written to a struct
+// if each of the elements in the sequence can be
+// written to the corresponding element in the struct.
+//
+// The following tags on struct fields have special meaning to Unmarshal:
+//
+// optional marks the field as ASN.1 OPTIONAL
+// [explicit] tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
+// default:x sets the default value for optional integer fields
+//
+// If the type of the first field of a structure is RawContent then the raw
+// ASN1 contents of the struct will be stored in it.
+//
+// Other ASN.1 types are not supported; if it encounters them,
+// Unmarshal returns a parse error.
+func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) {
+ v := reflect.NewValue(val).(*reflect.PtrValue).Elem()
+ offset, err := parseField(v, b, 0, fieldParameters{})
+ if err != nil {
+ return nil, err
+ }
+ return b[offset:], nil
+}
diff --git a/libgo/go/asn1/asn1_test.go b/libgo/go/asn1/asn1_test.go
new file mode 100644
index 000000000..34b5f1ecd
--- /dev/null
+++ b/libgo/go/asn1/asn1_test.go
@@ -0,0 +1,634 @@
+// 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 asn1
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+ "time"
+)
+
+type int64Test struct {
+ in []byte
+ ok bool
+ out int64
+}
+
+var int64TestData = []int64Test{
+ {[]byte{0x00}, true, 0},
+ {[]byte{0x7f}, true, 127},
+ {[]byte{0x00, 0x80}, true, 128},
+ {[]byte{0x01, 0x00}, true, 256},
+ {[]byte{0x80}, true, -128},
+ {[]byte{0xff, 0x7f}, true, -129},
+ {[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, true, -1},
+ {[]byte{0xff}, true, -1},
+ {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, true, -9223372036854775808},
+ {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, false, 0},
+}
+
+func TestParseInt64(t *testing.T) {
+ for i, test := range int64TestData {
+ ret, err := parseInt64(test.in)
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if test.ok && ret != test.out {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ }
+ }
+}
+
+type bitStringTest struct {
+ in []byte
+ ok bool
+ out []byte
+ bitLength int
+}
+
+var bitStringTestData = []bitStringTest{
+ {[]byte{}, false, []byte{}, 0},
+ {[]byte{0x00}, true, []byte{}, 0},
+ {[]byte{0x07, 0x00}, true, []byte{0x00}, 1},
+ {[]byte{0x07, 0x01}, false, []byte{}, 0},
+ {[]byte{0x07, 0x40}, false, []byte{}, 0},
+ {[]byte{0x08, 0x00}, false, []byte{}, 0},
+}
+
+func TestBitString(t *testing.T) {
+ for i, test := range bitStringTestData {
+ ret, err := parseBitString(test.in)
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if err == nil {
+ if test.bitLength != ret.BitLength || bytes.Compare(ret.Bytes, test.out) != 0 {
+ t.Errorf("#%d: Bad result: %v (expected %v %v)", i, ret, test.out, test.bitLength)
+ }
+ }
+ }
+}
+
+func TestBitStringAt(t *testing.T) {
+ bs := BitString{[]byte{0x82, 0x40}, 16}
+ if bs.At(0) != 1 {
+ t.Error("#1: Failed")
+ }
+ if bs.At(1) != 0 {
+ t.Error("#2: Failed")
+ }
+ if bs.At(6) != 1 {
+ t.Error("#3: Failed")
+ }
+ if bs.At(9) != 1 {
+ t.Error("#4: Failed")
+ }
+}
+
+type bitStringRightAlignTest struct {
+ in []byte
+ inlen int
+ out []byte
+}
+
+var bitStringRightAlignTests = []bitStringRightAlignTest{
+ {[]byte{0x80}, 1, []byte{0x01}},
+ {[]byte{0x80, 0x80}, 9, []byte{0x01, 0x01}},
+ {[]byte{}, 0, []byte{}},
+ {[]byte{0xce}, 8, []byte{0xce}},
+ {[]byte{0xce, 0x47}, 16, []byte{0xce, 0x47}},
+ {[]byte{0x34, 0x50}, 12, []byte{0x03, 0x45}},
+}
+
+func TestBitStringRightAlign(t *testing.T) {
+ for i, test := range bitStringRightAlignTests {
+ bs := BitString{test.in, test.inlen}
+ out := bs.RightAlign()
+ if bytes.Compare(out, test.out) != 0 {
+ t.Errorf("#%d got: %x want: %x", i, out, test.out)
+ }
+ }
+}
+
+type objectIdentifierTest struct {
+ in []byte
+ ok bool
+ out []int
+}
+
+var objectIdentifierTestData = []objectIdentifierTest{
+ {[]byte{}, false, []int{}},
+ {[]byte{85}, true, []int{2, 5}},
+ {[]byte{85, 0x02}, true, []int{2, 5, 2}},
+ {[]byte{85, 0x02, 0xc0, 0x00}, true, []int{2, 5, 2, 0x2000}},
+ {[]byte{85, 0x02, 0xc0, 0x80, 0x80, 0x80, 0x80}, false, []int{}},
+}
+
+func TestObjectIdentifier(t *testing.T) {
+ for i, test := range objectIdentifierTestData {
+ ret, err := parseObjectIdentifier(test.in)
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if err == nil {
+ if !reflect.DeepEqual(test.out, ret) {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ }
+ }
+ }
+}
+
+type timeTest struct {
+ in string
+ ok bool
+ out *time.Time
+}
+
+var utcTestData = []timeTest{
+ {"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, -7 * 60 * 60, ""}},
+ {"910506164540+0730", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 7*60*60 + 30*60, ""}},
+ {"910506234540Z", true, &time.Time{1991, 05, 06, 23, 45, 40, 0, 0, "UTC"}},
+ {"9105062345Z", true, &time.Time{1991, 05, 06, 23, 45, 0, 0, 0, "UTC"}},
+ {"a10506234540Z", false, nil},
+ {"91a506234540Z", false, nil},
+ {"9105a6234540Z", false, nil},
+ {"910506a34540Z", false, nil},
+ {"910506334a40Z", false, nil},
+ {"91050633444aZ", false, nil},
+ {"910506334461Z", false, nil},
+ {"910506334400Za", false, nil},
+}
+
+func TestUTCTime(t *testing.T) {
+ for i, test := range utcTestData {
+ ret, err := parseUTCTime([]byte(test.in))
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if err == nil {
+ if !reflect.DeepEqual(test.out, ret) {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ }
+ }
+ }
+}
+
+var generalizedTimeTestData = []timeTest{
+ {"20100102030405Z", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, "UTC"}},
+ {"20100102030405", false, nil},
+ {"20100102030405+0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 6*60*60 + 7*60, ""}},
+ {"20100102030405-0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, -6*60*60 - 7*60, ""}},
+}
+
+func TestGeneralizedTime(t *testing.T) {
+ for i, test := range generalizedTimeTestData {
+ ret, err := parseGeneralizedTime([]byte(test.in))
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if err == nil {
+ if !reflect.DeepEqual(test.out, ret) {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ }
+ }
+ }
+}
+
+type tagAndLengthTest struct {
+ in []byte
+ ok bool
+ out tagAndLength
+}
+
+var tagAndLengthData = []tagAndLengthTest{
+ {[]byte{0x80, 0x01}, true, tagAndLength{2, 0, 1, false}},
+ {[]byte{0xa0, 0x01}, true, tagAndLength{2, 0, 1, true}},
+ {[]byte{0x02, 0x00}, true, tagAndLength{0, 2, 0, false}},
+ {[]byte{0xfe, 0x00}, true, tagAndLength{3, 30, 0, true}},
+ {[]byte{0x1f, 0x01, 0x00}, true, tagAndLength{0, 1, 0, false}},
+ {[]byte{0x1f, 0x81, 0x00, 0x00}, true, tagAndLength{0, 128, 0, false}},
+ {[]byte{0x1f, 0x81, 0x80, 0x01, 0x00}, true, tagAndLength{0, 0x4001, 0, false}},
+ {[]byte{0x00, 0x81, 0x01}, true, tagAndLength{0, 0, 1, false}},
+ {[]byte{0x00, 0x82, 0x01, 0x00}, true, tagAndLength{0, 0, 256, false}},
+ {[]byte{0x00, 0x83, 0x01, 0x00}, false, tagAndLength{}},
+ {[]byte{0x1f, 0x85}, false, tagAndLength{}},
+ {[]byte{0x30, 0x80}, false, tagAndLength{}},
+}
+
+func TestParseTagAndLength(t *testing.T) {
+ for i, test := range tagAndLengthData {
+ tagAndLength, _, err := parseTagAndLength(test.in, 0)
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did pass? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if err == nil && !reflect.DeepEqual(test.out, tagAndLength) {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, tagAndLength, test.out)
+ }
+ }
+}
+
+type parseFieldParametersTest struct {
+ in string
+ out fieldParameters
+}
+
+func newInt(n int) *int { return &n }
+
+func newInt64(n int64) *int64 { return &n }
+
+func newString(s string) *string { return &s }
+
+func newBool(b bool) *bool { return &b }
+
+var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParametersTest{
+ {"", fieldParameters{}},
+ {"ia5", fieldParameters{stringType: tagIA5String}},
+ {"printable", fieldParameters{stringType: tagPrintableString}},
+ {"optional", fieldParameters{optional: true}},
+ {"explicit", fieldParameters{explicit: true, tag: new(int)}},
+ {"optional,explicit", fieldParameters{optional: true, explicit: true, tag: new(int)}},
+ {"default:42", fieldParameters{defaultValue: newInt64(42)}},
+ {"tag:17", fieldParameters{tag: newInt(17)}},
+ {"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}},
+ {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, newInt64(42), newInt(17), 0, false}},
+ {"set", fieldParameters{set: true}},
+}
+
+func TestParseFieldParameters(t *testing.T) {
+ for i, test := range parseFieldParametersTestData {
+ f := parseFieldParameters(test.in)
+ if !reflect.DeepEqual(f, test.out) {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, f, test.out)
+ }
+ }
+}
+
+type unmarshalTest struct {
+ in []byte
+ out interface{}
+}
+
+type TestObjectIdentifierStruct struct {
+ OID ObjectIdentifier
+}
+
+type TestContextSpecificTags struct {
+ A int "tag:1"
+}
+
+type TestContextSpecificTags2 struct {
+ A int "explicit,tag:1"
+ B int
+}
+
+type TestElementsAfterString struct {
+ S string
+ A, B int
+}
+
+var unmarshalTestData []unmarshalTest = []unmarshalTest{
+ {[]byte{0x02, 0x01, 0x42}, newInt(0x42)},
+ {[]byte{0x30, 0x08, 0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d}, &TestObjectIdentifierStruct{[]int{1, 2, 840, 113549}}},
+ {[]byte{0x03, 0x04, 0x06, 0x6e, 0x5d, 0xc0}, &BitString{[]byte{110, 93, 192}, 18}},
+ {[]byte{0x30, 0x09, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03}, &[]int{1, 2, 3}},
+ {[]byte{0x02, 0x01, 0x10}, newInt(16)},
+ {[]byte{0x13, 0x04, 't', 'e', 's', 't'}, newString("test")},
+ {[]byte{0x16, 0x04, 't', 'e', 's', 't'}, newString("test")},
+ {[]byte{0x16, 0x04, 't', 'e', 's', 't'}, &RawValue{0, 22, false, []byte("test"), []byte("\x16\x04test")}},
+ {[]byte{0x04, 0x04, 1, 2, 3, 4}, &RawValue{0, 4, false, []byte{1, 2, 3, 4}, []byte{4, 4, 1, 2, 3, 4}}},
+ {[]byte{0x30, 0x03, 0x81, 0x01, 0x01}, &TestContextSpecificTags{1}},
+ {[]byte{0x30, 0x08, 0xa1, 0x03, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02}, &TestContextSpecificTags2{1, 2}},
+ {[]byte{0x01, 0x01, 0x00}, newBool(false)},
+ {[]byte{0x01, 0x01, 0x01}, newBool(true)},
+ {[]byte{0x30, 0x0b, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x01, 0x22, 0x02, 0x01, 0x33}, &TestElementsAfterString{"foo", 0x22, 0x33}},
+}
+
+func TestUnmarshal(t *testing.T) {
+ for i, test := range unmarshalTestData {
+ pv := reflect.MakeZero(reflect.NewValue(test.out).Type())
+ zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem())
+ pv.(*reflect.PtrValue).PointTo(zv)
+ val := pv.Interface()
+ _, err := Unmarshal(test.in, val)
+ if err != nil {
+ t.Errorf("Unmarshal failed at index %d %v", i, err)
+ }
+ if !reflect.DeepEqual(val, test.out) {
+ t.Errorf("#%d:\nhave %#v\nwant %#v", i, val, test.out)
+ }
+ }
+}
+
+type Certificate struct {
+ TBSCertificate TBSCertificate
+ SignatureAlgorithm AlgorithmIdentifier
+ SignatureValue BitString
+}
+
+type TBSCertificate struct {
+ Version int "optional,explicit,default:0,tag:0"
+ SerialNumber RawValue
+ SignatureAlgorithm AlgorithmIdentifier
+ Issuer RDNSequence
+ Validity Validity
+ Subject RDNSequence
+ PublicKey PublicKeyInfo
+}
+
+type AlgorithmIdentifier struct {
+ Algorithm ObjectIdentifier
+}
+
+type RDNSequence []RelativeDistinguishedNameSET
+
+type RelativeDistinguishedNameSET []AttributeTypeAndValue
+
+type AttributeTypeAndValue struct {
+ Type ObjectIdentifier
+ Value interface{}
+}
+
+type Validity struct {
+ NotBefore, NotAfter *time.Time
+}
+
+type PublicKeyInfo struct {
+ Algorithm AlgorithmIdentifier
+ PublicKey BitString
+}
+
+func TestCertificate(t *testing.T) {
+ // This is a minimal, self-signed certificate that should parse correctly.
+ var cert Certificate
+ if _, err := Unmarshal(derEncodedSelfSignedCertBytes, &cert); err != nil {
+ t.Errorf("Unmarshal failed: %v", err)
+ }
+ if !reflect.DeepEqual(cert, derEncodedSelfSignedCert) {
+ t.Errorf("Bad result:\ngot: %+v\nwant: %+v", cert, derEncodedSelfSignedCert)
+ }
+}
+
+func TestCertificateWithNUL(t *testing.T) {
+ // This is the paypal NUL-hack certificate. It should fail to parse because
+ // NUL isn't a permitted character in a PrintableString.
+
+ var cert Certificate
+ if _, err := Unmarshal(derEncodedPaypalNULCertBytes, &cert); err == nil {
+ t.Error("Unmarshal succeeded, should not have")
+ }
+}
+
+type rawStructTest struct {
+ Raw RawContent
+ A int
+}
+
+func TestRawStructs(t *testing.T) {
+ var s rawStructTest
+ input := []byte{0x30, 0x03, 0x02, 0x01, 0x50}
+
+ rest, err := Unmarshal(input, &s)
+ if len(rest) != 0 {
+ t.Errorf("incomplete parse: %x", rest)
+ return
+ }
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if s.A != 0x50 {
+ t.Errorf("bad value for A: got %d want %d", s.A, 0x50)
+ }
+ if bytes.Compare([]byte(s.Raw), input) != 0 {
+ t.Errorf("bad value for Raw: got %x want %x", s.Raw, input)
+ }
+}
+
+var derEncodedSelfSignedCert = Certificate{
+ TBSCertificate: TBSCertificate{
+ Version: 0,
+ SerialNumber: RawValue{Class: 0, Tag: 2, IsCompound: false, Bytes: []uint8{0x0, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c, 0x98}, FullBytes: []byte{2, 9, 0x0, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c, 0x98}},
+ SignatureAlgorithm: AlgorithmIdentifier{Algorithm: ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}},
+ Issuer: RDNSequence{
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 7}, Value: "City"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 10}, Value: "Internet Widgits Pty Ltd"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 3}, Value: "false.example.com"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "false@example.com"}},
+ },
+ Validity: Validity{NotBefore: &time.Time{Year: 2009, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}, NotAfter: &time.Time{Year: 2010, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}},
+ Subject: RDNSequence{
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 7}, Value: "City"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 10}, Value: "Internet Widgits Pty Ltd"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 3}, Value: "false.example.com"}},
+ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "false@example.com"}},
+ },
+ PublicKey: PublicKeyInfo{
+ Algorithm: AlgorithmIdentifier{Algorithm: ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}},
+ PublicKey: BitString{
+ Bytes: []uint8{
+ 0x30, 0x48, 0x2, 0x41, 0x0, 0xcd, 0xb7,
+ 0x63, 0x9c, 0x32, 0x78, 0xf0, 0x6, 0xaa, 0x27, 0x7f, 0x6e, 0xaf, 0x42,
+ 0x90, 0x2b, 0x59, 0x2d, 0x8c, 0xbc, 0xbe, 0x38, 0xa1, 0xc9, 0x2b, 0xa4,
+ 0x69, 0x5a, 0x33, 0x1b, 0x1d, 0xea, 0xde, 0xad, 0xd8, 0xe9, 0xa5, 0xc2,
+ 0x7e, 0x8c, 0x4c, 0x2f, 0xd0, 0xa8, 0x88, 0x96, 0x57, 0x72, 0x2a, 0x4f,
+ 0x2a, 0xf7, 0x58, 0x9c, 0xf2, 0xc7, 0x70, 0x45, 0xdc, 0x8f, 0xde, 0xec,
+ 0x35, 0x7d, 0x2, 0x3, 0x1, 0x0, 0x1,
+ },
+ BitLength: 592,
+ },
+ },
+ },
+ SignatureAlgorithm: AlgorithmIdentifier{Algorithm: ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}},
+ SignatureValue: BitString{
+ Bytes: []uint8{
+ 0xa6, 0x7b, 0x6, 0xec, 0x5e, 0xce,
+ 0x92, 0x77, 0x2c, 0xa4, 0x13, 0xcb, 0xa3, 0xca, 0x12, 0x56, 0x8f, 0xdc, 0x6c,
+ 0x7b, 0x45, 0x11, 0xcd, 0x40, 0xa7, 0xf6, 0x59, 0x98, 0x4, 0x2, 0xdf, 0x2b,
+ 0x99, 0x8b, 0xb9, 0xa4, 0xa8, 0xcb, 0xeb, 0x34, 0xc0, 0xf0, 0xa7, 0x8c, 0xf8,
+ 0xd9, 0x1e, 0xde, 0x14, 0xa5, 0xed, 0x76, 0xbf, 0x11, 0x6f, 0xe3, 0x60, 0xaa,
+ 0xfa, 0x88, 0x21, 0x49, 0x4, 0x35,
+ },
+ BitLength: 512,
+ },
+}
+
+var derEncodedSelfSignedCertBytes = []byte{
+ 0x30, 0x82, 0x02, 0x18, 0x30,
+ 0x82, 0x01, 0xc2, 0x02, 0x09, 0x00, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c,
+ 0x98, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x05, 0x05, 0x00, 0x30, 0x81, 0x92, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x58, 0x58, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
+ 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x04, 0x43,
+ 0x69, 0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+ 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31,
+ 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x66, 0x61, 0x6c,
+ 0x73, 0x65, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+ 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x09, 0x01, 0x16, 0x11, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x40, 0x65, 0x78,
+ 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d,
+ 0x30, 0x39, 0x31, 0x30, 0x30, 0x38, 0x30, 0x30, 0x32, 0x35, 0x35, 0x33, 0x5a,
+ 0x17, 0x0d, 0x31, 0x30, 0x31, 0x30, 0x30, 0x38, 0x30, 0x30, 0x32, 0x35, 0x35,
+ 0x33, 0x5a, 0x30, 0x81, 0x92, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+ 0x06, 0x13, 0x02, 0x58, 0x58, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+ 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x04, 0x43, 0x69,
+ 0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18,
+ 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x1a,
+ 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x66, 0x61, 0x6c, 0x73,
+ 0x65, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x09, 0x01, 0x16, 0x11, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x40, 0x65, 0x78, 0x61,
+ 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x5c, 0x30, 0x0d, 0x06,
+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+ 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xcd, 0xb7, 0x63, 0x9c, 0x32, 0x78,
+ 0xf0, 0x06, 0xaa, 0x27, 0x7f, 0x6e, 0xaf, 0x42, 0x90, 0x2b, 0x59, 0x2d, 0x8c,
+ 0xbc, 0xbe, 0x38, 0xa1, 0xc9, 0x2b, 0xa4, 0x69, 0x5a, 0x33, 0x1b, 0x1d, 0xea,
+ 0xde, 0xad, 0xd8, 0xe9, 0xa5, 0xc2, 0x7e, 0x8c, 0x4c, 0x2f, 0xd0, 0xa8, 0x88,
+ 0x96, 0x57, 0x72, 0x2a, 0x4f, 0x2a, 0xf7, 0x58, 0x9c, 0xf2, 0xc7, 0x70, 0x45,
+ 0xdc, 0x8f, 0xde, 0xec, 0x35, 0x7d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+ 0x03, 0x41, 0x00, 0xa6, 0x7b, 0x06, 0xec, 0x5e, 0xce, 0x92, 0x77, 0x2c, 0xa4,
+ 0x13, 0xcb, 0xa3, 0xca, 0x12, 0x56, 0x8f, 0xdc, 0x6c, 0x7b, 0x45, 0x11, 0xcd,
+ 0x40, 0xa7, 0xf6, 0x59, 0x98, 0x04, 0x02, 0xdf, 0x2b, 0x99, 0x8b, 0xb9, 0xa4,
+ 0xa8, 0xcb, 0xeb, 0x34, 0xc0, 0xf0, 0xa7, 0x8c, 0xf8, 0xd9, 0x1e, 0xde, 0x14,
+ 0xa5, 0xed, 0x76, 0xbf, 0x11, 0x6f, 0xe3, 0x60, 0xaa, 0xfa, 0x88, 0x21, 0x49,
+ 0x04, 0x35,
+}
+
+var derEncodedPaypalNULCertBytes = []byte{
+ 0x30, 0x82, 0x06, 0x44, 0x30,
+ 0x82, 0x05, 0xad, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x00, 0xf0, 0x9b,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+ 0x05, 0x00, 0x30, 0x82, 0x01, 0x12, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
+ 0x04, 0x08, 0x13, 0x09, 0x42, 0x61, 0x72, 0x63, 0x65, 0x6c, 0x6f, 0x6e, 0x61,
+ 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x42, 0x61,
+ 0x72, 0x63, 0x65, 0x6c, 0x6f, 0x6e, 0x61, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x13, 0x20, 0x49, 0x50, 0x53, 0x20, 0x43, 0x65, 0x72, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74,
+ 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x73, 0x2e, 0x6c, 0x2e, 0x31, 0x2e,
+ 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x14, 0x25, 0x67, 0x65, 0x6e, 0x65,
+ 0x72, 0x61, 0x6c, 0x40, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x20, 0x43, 0x2e, 0x49, 0x2e, 0x46, 0x2e, 0x20, 0x20, 0x42, 0x2d, 0x42, 0x36,
+ 0x32, 0x32, 0x31, 0x30, 0x36, 0x39, 0x35, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03,
+ 0x55, 0x04, 0x0b, 0x13, 0x25, 0x69, 0x70, 0x73, 0x43, 0x41, 0x20, 0x43, 0x4c,
+ 0x41, 0x53, 0x45, 0x41, 0x31, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+ 0x69, 0x74, 0x79, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x25, 0x69, 0x70, 0x73, 0x43, 0x41, 0x20, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41,
+ 0x31, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
+ 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
+ 0x01, 0x16, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x40, 0x69, 0x70,
+ 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39,
+ 0x30, 0x32, 0x32, 0x34, 0x32, 0x33, 0x30, 0x34, 0x31, 0x37, 0x5a, 0x17, 0x0d,
+ 0x31, 0x31, 0x30, 0x32, 0x32, 0x34, 0x32, 0x33, 0x30, 0x34, 0x31, 0x37, 0x5a,
+ 0x30, 0x81, 0x94, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16,
+ 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0d, 0x53, 0x61, 0x6e, 0x20,
+ 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x31, 0x11, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69,
+ 0x74, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0b,
+ 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x55, 0x6e, 0x69, 0x74, 0x31, 0x2f,
+ 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x26, 0x77, 0x77, 0x77, 0x2e,
+ 0x70, 0x61, 0x79, 0x70, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x73, 0x73,
+ 0x6c, 0x2e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x63, 0x63, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+ 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xd2, 0x69,
+ 0xfa, 0x6f, 0x3a, 0x00, 0xb4, 0x21, 0x1b, 0xc8, 0xb1, 0x02, 0xd7, 0x3f, 0x19,
+ 0xb2, 0xc4, 0x6d, 0xb4, 0x54, 0xf8, 0x8b, 0x8a, 0xcc, 0xdb, 0x72, 0xc2, 0x9e,
+ 0x3c, 0x60, 0xb9, 0xc6, 0x91, 0x3d, 0x82, 0xb7, 0x7d, 0x99, 0xff, 0xd1, 0x29,
+ 0x84, 0xc1, 0x73, 0x53, 0x9c, 0x82, 0xdd, 0xfc, 0x24, 0x8c, 0x77, 0xd5, 0x41,
+ 0xf3, 0xe8, 0x1e, 0x42, 0xa1, 0xad, 0x2d, 0x9e, 0xff, 0x5b, 0x10, 0x26, 0xce,
+ 0x9d, 0x57, 0x17, 0x73, 0x16, 0x23, 0x38, 0xc8, 0xd6, 0xf1, 0xba, 0xa3, 0x96,
+ 0x5b, 0x16, 0x67, 0x4a, 0x4f, 0x73, 0x97, 0x3a, 0x4d, 0x14, 0xa4, 0xf4, 0xe2,
+ 0x3f, 0x8b, 0x05, 0x83, 0x42, 0xd1, 0xd0, 0xdc, 0x2f, 0x7a, 0xe5, 0xb6, 0x10,
+ 0xb2, 0x11, 0xc0, 0xdc, 0x21, 0x2a, 0x90, 0xff, 0xae, 0x97, 0x71, 0x5a, 0x49,
+ 0x81, 0xac, 0x40, 0xf3, 0x3b, 0xb8, 0x59, 0xb2, 0x4f, 0x02, 0x03, 0x01, 0x00,
+ 0x01, 0xa3, 0x82, 0x03, 0x21, 0x30, 0x82, 0x03, 0x1d, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x11, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x06, 0x40,
+ 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x03, 0xf8,
+ 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x61, 0x8f, 0x61, 0x34, 0x43, 0x55, 0x14,
+ 0x7f, 0x27, 0x09, 0xce, 0x4c, 0x8b, 0xea, 0x9b, 0x7b, 0x19, 0x25, 0xbc, 0x6e,
+ 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+ 0x0e, 0x07, 0x60, 0xd4, 0x39, 0xc9, 0x1b, 0x5b, 0x5d, 0x90, 0x7b, 0x23, 0xc8,
+ 0xd2, 0x34, 0x9d, 0x4a, 0x9a, 0x46, 0x39, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d,
+ 0x11, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x1d, 0x12, 0x04,
+ 0x15, 0x30, 0x13, 0x81, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x40,
+ 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x72, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x0d, 0x04, 0x65, 0x16, 0x63,
+ 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+ 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4e,
+ 0x4f, 0x54, 0x20, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x45, 0x44, 0x2e,
+ 0x20, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x20, 0x53, 0x65, 0x72, 0x76,
+ 0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x65, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x68,
+ 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70,
+ 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x2f, 0x06, 0x09, 0x60,
+ 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x02, 0x04, 0x22, 0x16, 0x20, 0x68,
+ 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70,
+ 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61,
+ 0x32, 0x30, 0x30, 0x32, 0x2f, 0x30, 0x43, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+ 0x86, 0xf8, 0x42, 0x01, 0x04, 0x04, 0x36, 0x16, 0x34, 0x68, 0x74, 0x74, 0x70,
+ 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30,
+ 0x32, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x43, 0x4c,
+ 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x46, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x03, 0x04, 0x39, 0x16, 0x37,
+ 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69,
+ 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63,
+ 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x72, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x68, 0x74,
+ 0x6d, 0x6c, 0x3f, 0x30, 0x43, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8,
+ 0x42, 0x01, 0x07, 0x04, 0x36, 0x16, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
+ 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f,
+ 0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x6c, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41,
+ 0x31, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x3f, 0x30, 0x41, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x08, 0x04, 0x34, 0x16, 0x32, 0x68, 0x74,
+ 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x70, 0x73,
+ 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32,
+ 0x30, 0x30, 0x32, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x43, 0x4c, 0x41,
+ 0x53, 0x45, 0x41, 0x31, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x30, 0x81, 0x83, 0x06,
+ 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x7c, 0x30, 0x7a, 0x30, 0x39, 0xa0, 0x37, 0xa0,
+ 0x35, 0x86, 0x33, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+ 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70,
+ 0x73, 0x63, 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61,
+ 0x32, 0x30, 0x30, 0x32, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x63,
+ 0x72, 0x6c, 0x30, 0x3d, 0xa0, 0x3b, 0xa0, 0x39, 0x86, 0x37, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x62, 0x61, 0x63, 0x6b, 0x2e, 0x69,
+ 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x70, 0x73, 0x63,
+ 0x61, 0x32, 0x30, 0x30, 0x32, 0x2f, 0x69, 0x70, 0x73, 0x63, 0x61, 0x32, 0x30,
+ 0x30, 0x32, 0x43, 0x4c, 0x41, 0x53, 0x45, 0x41, 0x31, 0x2e, 0x63, 0x72, 0x6c,
+ 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
+ 0x26, 0x30, 0x24, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+ 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63,
+ 0x73, 0x70, 0x2e, 0x69, 0x70, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+ 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x68, 0xee, 0x79, 0x97, 0x97, 0xdd, 0x3b,
+ 0xef, 0x16, 0x6a, 0x06, 0xf2, 0x14, 0x9a, 0x6e, 0xcd, 0x9e, 0x12, 0xf7, 0xaa,
+ 0x83, 0x10, 0xbd, 0xd1, 0x7c, 0x98, 0xfa, 0xc7, 0xae, 0xd4, 0x0e, 0x2c, 0x9e,
+ 0x38, 0x05, 0x9d, 0x52, 0x60, 0xa9, 0x99, 0x0a, 0x81, 0xb4, 0x98, 0x90, 0x1d,
+ 0xae, 0xbb, 0x4a, 0xd7, 0xb9, 0xdc, 0x88, 0x9e, 0x37, 0x78, 0x41, 0x5b, 0xf7,
+ 0x82, 0xa5, 0xf2, 0xba, 0x41, 0x25, 0x5a, 0x90, 0x1a, 0x1e, 0x45, 0x38, 0xa1,
+ 0x52, 0x58, 0x75, 0x94, 0x26, 0x44, 0xfb, 0x20, 0x07, 0xba, 0x44, 0xcc, 0xe5,
+ 0x4a, 0x2d, 0x72, 0x3f, 0x98, 0x47, 0xf6, 0x26, 0xdc, 0x05, 0x46, 0x05, 0x07,
+ 0x63, 0x21, 0xab, 0x46, 0x9b, 0x9c, 0x78, 0xd5, 0x54, 0x5b, 0x3d, 0x0c, 0x1e,
+ 0xc8, 0x64, 0x8c, 0xb5, 0x50, 0x23, 0x82, 0x6f, 0xdb, 0xb8, 0x22, 0x1c, 0x43,
+ 0x96, 0x07, 0xa8, 0xbb,
+}
diff --git a/libgo/go/asn1/common.go b/libgo/go/asn1/common.go
new file mode 100644
index 000000000..4a5eca145
--- /dev/null
+++ b/libgo/go/asn1/common.go
@@ -0,0 +1,149 @@
+// 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 asn1
+
+import (
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+// ASN.1 objects have metadata preceeding them:
+// the tag: the type of the object
+// a flag denoting if this object is compound or not
+// the class type: the namespace of the tag
+// the length of the object, in bytes
+
+// Here are some standard tags and classes
+
+const (
+ tagBoolean = 1
+ tagInteger = 2
+ tagBitString = 3
+ tagOctetString = 4
+ tagOID = 6
+ tagEnum = 10
+ tagSequence = 16
+ tagSet = 17
+ tagPrintableString = 19
+ tagT61String = 20
+ tagIA5String = 22
+ tagUTCTime = 23
+ tagGeneralizedTime = 24
+)
+
+const (
+ classUniversal = 0
+ classApplication = 1
+ classContextSpecific = 2
+ classPrivate = 3
+)
+
+type tagAndLength struct {
+ class, tag, length int
+ isCompound bool
+}
+
+// ASN.1 has IMPLICIT and EXPLICIT tags, which can be translated as "instead
+// of" and "in addition to". When not specified, every primitive type has a
+// default tag in the UNIVERSAL class.
+//
+// For example: a BIT STRING is tagged [UNIVERSAL 3] by default (although ASN.1
+// doesn't actually have a UNIVERSAL keyword). However, by saying [IMPLICIT
+// CONTEXT-SPECIFIC 42], that means that the tag is replaced by another.
+//
+// On the other hand, if it said [EXPLICIT CONTEXT-SPECIFIC 10], then an
+// /additional/ tag would wrap the default tag. This explicit tag will have the
+// compound flag set.
+//
+// (This is used in order to remove ambiguity with optional elements.)
+//
+// You can layer EXPLICIT and IMPLICIT tags to an arbitrary depth, however we
+// don't support that here. We support a single layer of EXPLICIT or IMPLICIT
+// tagging with tag strings on the fields of a structure.
+
+// fieldParameters is the parsed representation of tag string from a structure field.
+type fieldParameters struct {
+ optional bool // true iff the field is OPTIONAL
+ explicit bool // true iff and EXPLICIT tag is in use.
+ defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
+ tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
+ stringType int // the string tag to use when marshaling.
+ set bool // true iff this should be encoded as a SET
+
+ // Invariants:
+ // if explicit is set, tag is non-nil.
+}
+
+// Given a tag string with the format specified in the package comment,
+// parseFieldParameters will parse it into a fieldParameters structure,
+// ignoring unknown parts of the string.
+func parseFieldParameters(str string) (ret fieldParameters) {
+ for _, part := range strings.Split(str, ",", -1) {
+ switch {
+ case part == "optional":
+ ret.optional = true
+ case part == "explicit":
+ ret.explicit = true
+ if ret.tag == nil {
+ ret.tag = new(int)
+ *ret.tag = 0
+ }
+ case part == "ia5":
+ ret.stringType = tagIA5String
+ case part == "printable":
+ ret.stringType = tagPrintableString
+ case strings.HasPrefix(part, "default:"):
+ i, err := strconv.Atoi64(part[8:])
+ if err == nil {
+ ret.defaultValue = new(int64)
+ *ret.defaultValue = i
+ }
+ case strings.HasPrefix(part, "tag:"):
+ i, err := strconv.Atoi(part[4:])
+ if err == nil {
+ ret.tag = new(int)
+ *ret.tag = i
+ }
+ case part == "set":
+ ret.set = true
+ }
+ }
+ return
+}
+
+// Given a reflected Go type, getUniversalType returns the default tag number
+// and expected compound flag.
+func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
+ switch t {
+ case objectIdentifierType:
+ return tagOID, false, true
+ case bitStringType:
+ return tagBitString, false, true
+ case timeType:
+ return tagUTCTime, false, true
+ case enumeratedType:
+ return tagEnum, false, true
+ }
+ switch t := t.(type) {
+ case *reflect.BoolType:
+ return tagBoolean, false, true
+ case *reflect.IntType:
+ return tagInteger, false, true
+ case *reflect.StructType:
+ return tagSequence, true, true
+ case *reflect.SliceType:
+ if t.Elem().Kind() == reflect.Uint8 {
+ return tagOctetString, false, true
+ }
+ if strings.HasSuffix(t.Name(), "SET") {
+ return tagSet, true, true
+ }
+ return tagSequence, true, true
+ case *reflect.StringType:
+ return tagPrintableString, false, true
+ }
+ return 0, false, false
+}
diff --git a/libgo/go/asn1/marshal.go b/libgo/go/asn1/marshal.go
new file mode 100644
index 000000000..24548714b
--- /dev/null
+++ b/libgo/go/asn1/marshal.go
@@ -0,0 +1,482 @@
+// 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 asn1
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "time"
+)
+
+// A forkableWriter is an in-memory buffer that can be
+// 'forked' to create new forkableWriters that bracket the
+// original. After
+// pre, post := w.fork();
+// the overall sequence of bytes represented is logically w+pre+post.
+type forkableWriter struct {
+ *bytes.Buffer
+ pre, post *forkableWriter
+}
+
+func newForkableWriter() *forkableWriter {
+ return &forkableWriter{bytes.NewBuffer(nil), nil, nil}
+}
+
+func (f *forkableWriter) fork() (pre, post *forkableWriter) {
+ if f.pre != nil || f.post != nil {
+ panic("have already forked")
+ }
+ f.pre = newForkableWriter()
+ f.post = newForkableWriter()
+ return f.pre, f.post
+}
+
+func (f *forkableWriter) Len() (l int) {
+ l += f.Buffer.Len()
+ if f.pre != nil {
+ l += f.pre.Len()
+ }
+ if f.post != nil {
+ l += f.post.Len()
+ }
+ return
+}
+
+func (f *forkableWriter) writeTo(out io.Writer) (n int, err os.Error) {
+ n, err = out.Write(f.Bytes())
+ if err != nil {
+ return
+ }
+
+ var nn int
+
+ if f.pre != nil {
+ nn, err = f.pre.writeTo(out)
+ n += nn
+ if err != nil {
+ return
+ }
+ }
+
+ if f.post != nil {
+ nn, err = f.post.writeTo(out)
+ n += nn
+ }
+ return
+}
+
+func marshalBase128Int(out *forkableWriter, n int64) (err os.Error) {
+ if n == 0 {
+ err = out.WriteByte(0)
+ return
+ }
+
+ l := 0
+ for i := n; i > 0; i >>= 7 {
+ l++
+ }
+
+ for i := l - 1; i >= 0; i-- {
+ o := byte(n >> uint(i*7))
+ o &= 0x7f
+ if i != 0 {
+ o |= 0x80
+ }
+ err = out.WriteByte(o)
+ if err != nil {
+ return
+ }
+ }
+
+ return nil
+}
+
+func marshalInt64(out *forkableWriter, i int64) (err os.Error) {
+ n := int64Length(i)
+
+ for ; n > 0; n-- {
+ err = out.WriteByte(byte(i >> uint((n-1)*8)))
+ if err != nil {
+ return
+ }
+ }
+
+ return nil
+}
+
+func int64Length(i int64) (numBytes int) {
+ numBytes = 1
+
+ for i > 127 {
+ numBytes++
+ i >>= 8
+ }
+
+ for i < -128 {
+ numBytes++
+ i >>= 8
+ }
+
+ return
+}
+
+func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err os.Error) {
+ b := uint8(t.class) << 6
+ if t.isCompound {
+ b |= 0x20
+ }
+ if t.tag >= 31 {
+ b |= 0x1f
+ err = out.WriteByte(b)
+ if err != nil {
+ return
+ }
+ err = marshalBase128Int(out, int64(t.tag))
+ if err != nil {
+ return
+ }
+ } else {
+ b |= uint8(t.tag)
+ err = out.WriteByte(b)
+ if err != nil {
+ return
+ }
+ }
+
+ if t.length >= 128 {
+ l := int64Length(int64(t.length))
+ err = out.WriteByte(0x80 | byte(l))
+ if err != nil {
+ return
+ }
+ err = marshalInt64(out, int64(t.length))
+ if err != nil {
+ return
+ }
+ } else {
+ err = out.WriteByte(byte(t.length))
+ if err != nil {
+ return
+ }
+ }
+
+ return nil
+}
+
+func marshalBitString(out *forkableWriter, b BitString) (err os.Error) {
+ paddingBits := byte((8 - b.BitLength%8) % 8)
+ err = out.WriteByte(paddingBits)
+ if err != nil {
+ return
+ }
+ _, err = out.Write(b.Bytes)
+ return
+}
+
+func marshalObjectIdentifier(out *forkableWriter, oid []int) (err os.Error) {
+ if len(oid) < 2 || oid[0] > 6 || oid[1] >= 40 {
+ return StructuralError{"invalid object identifier"}
+ }
+
+ err = out.WriteByte(byte(oid[0]*40 + oid[1]))
+ if err != nil {
+ return
+ }
+ for i := 2; i < len(oid); i++ {
+ err = marshalBase128Int(out, int64(oid[i]))
+ if err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+func marshalPrintableString(out *forkableWriter, s string) (err os.Error) {
+ b := []byte(s)
+ for _, c := range b {
+ if !isPrintable(c) {
+ return StructuralError{"PrintableString contains invalid character"}
+ }
+ }
+
+ _, err = out.Write(b)
+ return
+}
+
+func marshalIA5String(out *forkableWriter, s string) (err os.Error) {
+ b := []byte(s)
+ for _, c := range b {
+ if c > 127 {
+ return StructuralError{"IA5String contains invalid character"}
+ }
+ }
+
+ _, err = out.Write(b)
+ return
+}
+
+func marshalTwoDigits(out *forkableWriter, v int) (err os.Error) {
+ err = out.WriteByte(byte('0' + (v/10)%10))
+ if err != nil {
+ return
+ }
+ return out.WriteByte(byte('0' + v%10))
+}
+
+func marshalUTCTime(out *forkableWriter, t *time.Time) (err os.Error) {
+ switch {
+ case 1950 <= t.Year && t.Year < 2000:
+ err = marshalTwoDigits(out, int(t.Year-1900))
+ case 2000 <= t.Year && t.Year < 2050:
+ err = marshalTwoDigits(out, int(t.Year-2000))
+ default:
+ return StructuralError{"Cannot represent time as UTCTime"}
+ }
+
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, t.Month)
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, t.Day)
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, t.Hour)
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, t.Minute)
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, t.Second)
+ if err != nil {
+ return
+ }
+
+ switch {
+ case t.ZoneOffset/60 == 0:
+ err = out.WriteByte('Z')
+ return
+ case t.ZoneOffset > 0:
+ err = out.WriteByte('+')
+ case t.ZoneOffset < 0:
+ err = out.WriteByte('-')
+ }
+
+ if err != nil {
+ return
+ }
+
+ offsetMinutes := t.ZoneOffset / 60
+ if offsetMinutes < 0 {
+ offsetMinutes = -offsetMinutes
+ }
+
+ err = marshalTwoDigits(out, offsetMinutes/60)
+ if err != nil {
+ return
+ }
+
+ err = marshalTwoDigits(out, offsetMinutes%60)
+ return
+}
+
+func stripTagAndLength(in []byte) []byte {
+ _, offset, err := parseTagAndLength(in, 0)
+ if err != nil {
+ return in
+ }
+ return in[offset:]
+}
+
+func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err os.Error) {
+ switch value.Type() {
+ case timeType:
+ return marshalUTCTime(out, value.Interface().(*time.Time))
+ case bitStringType:
+ return marshalBitString(out, value.Interface().(BitString))
+ case objectIdentifierType:
+ return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier))
+ }
+
+ switch v := value.(type) {
+ case *reflect.BoolValue:
+ if v.Get() {
+ return out.WriteByte(1)
+ } else {
+ return out.WriteByte(0)
+ }
+ case *reflect.IntValue:
+ return marshalInt64(out, int64(v.Get()))
+ case *reflect.StructValue:
+ t := v.Type().(*reflect.StructType)
+
+ startingField := 0
+
+ // If the first element of the structure is a non-empty
+ // RawContents, then we don't bother serialising the rest.
+ if t.NumField() > 0 && t.Field(0).Type == rawContentsType {
+ s := v.Field(0).(*reflect.SliceValue)
+ if s.Len() > 0 {
+ bytes := make([]byte, s.Len())
+ for i := 0; i < s.Len(); i++ {
+ bytes[i] = uint8(s.Elem(i).(*reflect.UintValue).Get())
+ }
+ /* The RawContents will contain the tag and
+ * length fields but we'll also be writing
+ * those outselves, so we strip them out of
+ * bytes */
+ _, err = out.Write(stripTagAndLength(bytes))
+ return
+ } else {
+ startingField = 1
+ }
+ }
+
+ for i := startingField; i < t.NumField(); i++ {
+ var pre *forkableWriter
+ pre, out = out.fork()
+ err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag))
+ if err != nil {
+ return
+ }
+ }
+ return
+ case *reflect.SliceValue:
+ sliceType := v.Type().(*reflect.SliceType)
+ if sliceType.Elem().Kind() == reflect.Uint8 {
+ bytes := make([]byte, v.Len())
+ for i := 0; i < v.Len(); i++ {
+ bytes[i] = uint8(v.Elem(i).(*reflect.UintValue).Get())
+ }
+ _, err = out.Write(bytes)
+ return
+ }
+
+ var params fieldParameters
+ for i := 0; i < v.Len(); i++ {
+ var pre *forkableWriter
+ pre, out = out.fork()
+ err = marshalField(pre, v.Elem(i), params)
+ if err != nil {
+ return
+ }
+ }
+ return
+ case *reflect.StringValue:
+ if params.stringType == tagIA5String {
+ return marshalIA5String(out, v.Get())
+ } else {
+ return marshalPrintableString(out, v.Get())
+ }
+ return
+ }
+
+ return StructuralError{"unknown Go type"}
+}
+
+func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err os.Error) {
+ // If the field is an interface{} then recurse into it.
+ if v, ok := v.(*reflect.InterfaceValue); ok && v.Type().(*reflect.InterfaceType).NumMethod() == 0 {
+ return marshalField(out, v.Elem(), params)
+ }
+
+ if v.Type() == rawValueType {
+ rv := v.Interface().(RawValue)
+ err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
+ if err != nil {
+ return
+ }
+ _, err = out.Write(rv.Bytes)
+ return
+ }
+
+ if params.optional && reflect.DeepEqual(v.Interface(), reflect.MakeZero(v.Type()).Interface()) {
+ return
+ }
+
+ tag, isCompound, ok := getUniversalType(v.Type())
+ if !ok {
+ err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
+ return
+ }
+ class := classUniversal
+
+ if params.stringType != 0 {
+ if tag != tagPrintableString {
+ return StructuralError{"Explicit string type given to non-string member"}
+ }
+ tag = params.stringType
+ }
+
+ if params.set {
+ if tag != tagSequence {
+ return StructuralError{"Non sequence tagged as set"}
+ }
+ tag = tagSet
+ }
+
+ tags, body := out.fork()
+
+ err = marshalBody(body, v, params)
+ if err != nil {
+ return
+ }
+
+ bodyLen := body.Len()
+
+ var explicitTag *forkableWriter
+ if params.explicit {
+ explicitTag, tags = tags.fork()
+ }
+
+ if !params.explicit && params.tag != nil {
+ // implicit tag.
+ tag = *params.tag
+ class = classContextSpecific
+ }
+
+ err = marshalTagAndLength(tags, tagAndLength{class, tag, bodyLen, isCompound})
+ if err != nil {
+ return
+ }
+
+ if params.explicit {
+ err = marshalTagAndLength(explicitTag, tagAndLength{
+ class: classContextSpecific,
+ tag: *params.tag,
+ length: bodyLen + tags.Len(),
+ isCompound: true,
+ })
+ }
+
+ return nil
+}
+
+// Marshal returns the ASN.1 encoding of val.
+func Marshal(val interface{}) ([]byte, os.Error) {
+ var out bytes.Buffer
+ v := reflect.NewValue(val)
+ f := newForkableWriter()
+ err := marshalField(f, v, fieldParameters{})
+ if err != nil {
+ return nil, err
+ }
+ _, err = f.writeTo(&out)
+ return out.Bytes(), nil
+}
diff --git a/libgo/go/asn1/marshal_test.go b/libgo/go/asn1/marshal_test.go
new file mode 100644
index 000000000..85eafc9e4
--- /dev/null
+++ b/libgo/go/asn1/marshal_test.go
@@ -0,0 +1,100 @@
+// 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 asn1
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+ "time"
+)
+
+type intStruct struct {
+ A int
+}
+
+type twoIntStruct struct {
+ A int
+ B int
+}
+
+type nestedStruct struct {
+ A intStruct
+}
+
+type rawContentsStruct struct {
+ Raw RawContent
+ A int
+}
+
+type implicitTagTest struct {
+ A int "implicit,tag:5"
+}
+
+type explicitTagTest struct {
+ A int "explicit,tag:5"
+}
+
+type ia5StringTest struct {
+ A string "ia5"
+}
+
+type printableStringTest struct {
+ A string "printable"
+}
+
+type testSET []int
+
+func setPST(t *time.Time) *time.Time {
+ t.ZoneOffset = -28800
+ return t
+}
+
+type marshalTest struct {
+ in interface{}
+ out string // hex encoded
+}
+
+var marshalTests = []marshalTest{
+ {10, "02010a"},
+ {127, "02017f"},
+ {128, "02020080"},
+ {-128, "020180"},
+ {-129, "0202ff7f"},
+ {intStruct{64}, "3003020140"},
+ {twoIntStruct{64, 65}, "3006020140020141"},
+ {nestedStruct{intStruct{127}}, "3005300302017f"},
+ {[]byte{1, 2, 3}, "0403010203"},
+ {implicitTagTest{64}, "3003850140"},
+ {explicitTagTest{64}, "3005a503020140"},
+ {time.SecondsToUTC(0), "170d3730303130313030303030305a"},
+ {time.SecondsToUTC(1258325776), "170d3039313131353232353631365a"},
+ {setPST(time.SecondsToUTC(1258325776)), "17113039313131353232353631362d30383030"},
+ {BitString{[]byte{0x80}, 1}, "03020780"},
+ {BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
+ {ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
+ {ObjectIdentifier([]int{1, 2, 840, 133549, 1, 1, 5}), "06092a864888932d010105"},
+ {"test", "130474657374"},
+ {ia5StringTest{"test"}, "3006160474657374"},
+ {printableStringTest{"test"}, "3006130474657374"},
+ {printableStringTest{"test*"}, "30071305746573742a"},
+ {rawContentsStruct{nil, 64}, "3003020140"},
+ {rawContentsStruct{[]byte{0x30, 3, 1, 2, 3}, 64}, "3003010203"},
+ {RawValue{Tag: 1, Class: 2, IsCompound: false, Bytes: []byte{1, 2, 3}}, "8103010203"},
+ {testSET([]int{10}), "310302010a"},
+}
+
+func TestMarshal(t *testing.T) {
+ for i, test := range marshalTests {
+ data, err := Marshal(test.in)
+ if err != nil {
+ t.Errorf("#%d failed: %s", i, err)
+ }
+ out, _ := hex.DecodeString(test.out)
+ if bytes.Compare(out, data) != 0 {
+ t.Errorf("#%d got: %x want %x", i, data, out)
+ }
+ }
+}
diff --git a/libgo/go/big/arith.go b/libgo/go/big/arith.go
new file mode 100644
index 000000000..a4048d6d7
--- /dev/null
+++ b/libgo/go/big/arith.go
@@ -0,0 +1,259 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file provides Go implementations of elementary multi-precision
+// arithmetic operations on word vectors. Needed for platforms without
+// assembly implementations of these routines.
+
+package big
+
+// TODO(gri) Decide if Word needs to remain exported.
+
+type Word uintptr
+
+const (
+ // Compute the size _S of a Word in bytes.
+ _m = ^Word(0)
+ _logS = _m>>8&1 + _m>>16&1 + _m>>32&1
+ _S = 1 << _logS
+
+ _W = _S << 3 // word size in bits
+ _B = 1 << _W // digit base
+ _M = _B - 1 // digit mask
+
+ _W2 = _W / 2 // half word size in bits
+ _B2 = 1 << _W2 // half digit base
+ _M2 = _B2 - 1 // half digit mask
+)
+
+
+// ----------------------------------------------------------------------------
+// Elementary operations on words
+//
+// These operations are used by the vector operations below.
+
+// z1<<_W + z0 = x+y+c, with c == 0 or 1
+func addWW_g(x, y, c Word) (z1, z0 Word) {
+ yc := y + c
+ z0 = x + yc
+ if z0 < x || yc < y {
+ z1 = 1
+ }
+ return
+}
+
+
+// z1<<_W + z0 = x-y-c, with c == 0 or 1
+func subWW_g(x, y, c Word) (z1, z0 Word) {
+ yc := y + c
+ z0 = x - yc
+ if z0 > x || yc < y {
+ z1 = 1
+ }
+ return
+}
+
+
+// z1<<_W + z0 = x*y
+func mulWW(x, y Word) (z1, z0 Word) { return mulWW_g(x, y) }
+// Adapted from Warren, Hacker's Delight, p. 132.
+func mulWW_g(x, y Word) (z1, z0 Word) {
+ x0 := x & _M2
+ x1 := x >> _W2
+ y0 := y & _M2
+ y1 := y >> _W2
+ w0 := x0 * y0
+ t := x1*y0 + w0>>_W2
+ w1 := t & _M2
+ w2 := t >> _W2
+ w1 += x0 * y1
+ z1 = x1*y1 + w2 + w1>>_W2
+ z0 = x * y
+ return
+}
+
+
+// z1<<_W + z0 = x*y + c
+func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
+ z1, zz0 := mulWW(x, y)
+ if z0 = zz0 + c; z0 < zz0 {
+ z1++
+ }
+ return
+}
+
+
+// Length of x in bits.
+func bitLen(x Word) (n int) {
+ for ; x >= 0x100; x >>= 8 {
+ n += 8
+ }
+ for ; x > 0; x >>= 1 {
+ n++
+ }
+ return
+}
+
+
+// log2 computes the integer binary logarithm of x.
+// The result is the integer n for which 2^n <= x < 2^(n+1).
+// If x == 0, the result is -1.
+func log2(x Word) int {
+ return bitLen(x) - 1
+}
+
+
+// Number of leading zeros in x.
+func leadingZeros(x Word) uint {
+ return uint(_W - bitLen(x))
+}
+
+
+// q = (u1<<_W + u0 - r)/y
+func divWW(x1, x0, y Word) (q, r Word) { return divWW_g(x1, x0, y) }
+// Adapted from Warren, Hacker's Delight, p. 152.
+func divWW_g(u1, u0, v Word) (q, r Word) {
+ if u1 >= v {
+ return 1<<_W - 1, 1<<_W - 1
+ }
+
+ s := leadingZeros(v)
+ v <<= s
+
+ vn1 := v >> _W2
+ vn0 := v & _M2
+ un32 := u1<<s | u0>>(_W-s)
+ un10 := u0 << s
+ un1 := un10 >> _W2
+ un0 := un10 & _M2
+ q1 := un32 / vn1
+ rhat := un32 - q1*vn1
+
+again1:
+ if q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
+ q1--
+ rhat += vn1
+ if rhat < _B2 {
+ goto again1
+ }
+ }
+
+ un21 := un32*_B2 + un1 - q1*v
+ q0 := un21 / vn1
+ rhat = un21 - q0*vn1
+
+again2:
+ if q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
+ q0--
+ rhat += vn1
+ if rhat < _B2 {
+ goto again2
+ }
+ }
+
+ return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
+}
+
+
+func addVV(z, x, y []Word) (c Word) { return addVV_g(z, x, y) }
+func addVV_g(z, x, y []Word) (c Word) {
+ for i := range z {
+ c, z[i] = addWW_g(x[i], y[i], c)
+ }
+ return
+}
+
+
+func subVV(z, x, y []Word) (c Word) { return subVV_g(z, x, y) }
+func subVV_g(z, x, y []Word) (c Word) {
+ for i := range z {
+ c, z[i] = subWW_g(x[i], y[i], c)
+ }
+ return
+}
+
+
+func addVW(z, x []Word, y Word) (c Word) { return addVW_g(z, x, y) }
+func addVW_g(z, x []Word, y Word) (c Word) {
+ c = y
+ for i := range z {
+ c, z[i] = addWW_g(x[i], c, 0)
+ }
+ return
+}
+
+
+func subVW(z, x []Word, y Word) (c Word) { return subVW_g(z, x, y) }
+func subVW_g(z, x []Word, y Word) (c Word) {
+ c = y
+ for i := range z {
+ c, z[i] = subWW_g(x[i], c, 0)
+ }
+ return
+}
+
+
+func shlVW(z, x []Word, s Word) (c Word) { return shlVW_g(z, x, s) }
+func shlVW_g(z, x []Word, s Word) (c Word) {
+ if n := len(z); n > 0 {
+ ŝ := _W - s
+ w1 := x[n-1]
+ c = w1 >> ŝ
+ for i := n - 1; i > 0; i-- {
+ w := w1
+ w1 = x[i-1]
+ z[i] = w<<s | w1>>ŝ
+ }
+ z[0] = w1 << s
+ }
+ return
+}
+
+
+func shrVW(z, x []Word, s Word) (c Word) { return shrVW_g(z, x, s) }
+func shrVW_g(z, x []Word, s Word) (c Word) {
+ if n := len(z); n > 0 {
+ ŝ := _W - s
+ w1 := x[0]
+ c = w1 << ŝ
+ for i := 0; i < n-1; i++ {
+ w := w1
+ w1 = x[i+1]
+ z[i] = w>>s | w1<<ŝ
+ }
+ z[n-1] = w1 >> s
+ }
+ return
+}
+
+
+func mulAddVWW(z, x []Word, y, r Word) (c Word) { return mulAddVWW_g(z, x, y, r) }
+func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
+ c = r
+ for i := range z {
+ c, z[i] = mulAddWWW_g(x[i], y, c)
+ }
+ return
+}
+
+
+func addMulVVW(z, x []Word, y Word) (c Word) { return addMulVVW_g(z, x, y) }
+func addMulVVW_g(z, x []Word, y Word) (c Word) {
+ for i := range z {
+ z1, z0 := mulAddWWW_g(x[i], y, z[i])
+ c, z[i] = addWW_g(z0, c, 0)
+ c += z1
+ }
+ return
+}
+
+
+func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) { return divWVW_g(z, xn, x, y) }
+func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
+ r = xn
+ for i := len(z) - 1; i >= 0; i-- {
+ z[i], r = divWW_g(r, x[i], y)
+ }
+ return
+}
diff --git a/libgo/go/big/arith_decl.go b/libgo/go/big/arith_decl.go
new file mode 100644
index 000000000..c456d5f67
--- /dev/null
+++ b/libgo/go/big/arith_decl.go
@@ -0,0 +1,18 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+// implemented in arith_$GOARCH.s
+func mulWW(x, y Word) (z1, z0 Word)
+func divWW(x1, x0, y Word) (q, r Word)
+func addVV(z, x, y []Word) (c Word)
+func subVV(z, x, y []Word) (c Word)
+func addVW(z, x []Word, y Word) (c Word)
+func subVW(z, x []Word, y Word) (c Word)
+func shlVW(z, x []Word, s Word) (c Word)
+func shrVW(z, x []Word, s Word) (c Word)
+func mulAddVWW(z, x []Word, y, r Word) (c Word)
+func addMulVVW(z, x []Word, y Word) (c Word)
+func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
diff --git a/libgo/go/big/arith_test.go b/libgo/go/big/arith_test.go
new file mode 100644
index 000000000..934b302df
--- /dev/null
+++ b/libgo/go/big/arith_test.go
@@ -0,0 +1,342 @@
+// 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 big
+
+import "testing"
+
+
+type funWW func(x, y, c Word) (z1, z0 Word)
+type argWW struct {
+ x, y, c, z1, z0 Word
+}
+
+var sumWW = []argWW{
+ {0, 0, 0, 0, 0},
+ {0, 1, 0, 0, 1},
+ {0, 0, 1, 0, 1},
+ {0, 1, 1, 0, 2},
+ {12345, 67890, 0, 0, 80235},
+ {12345, 67890, 1, 0, 80236},
+ {_M, 1, 0, 1, 0},
+ {_M, 0, 1, 1, 0},
+ {_M, 1, 1, 1, 1},
+ {_M, _M, 0, 1, _M - 1},
+ {_M, _M, 1, 1, _M},
+}
+
+
+func testFunWW(t *testing.T, msg string, f funWW, a argWW) {
+ z1, z0 := f(a.x, a.y, a.c)
+ if z1 != a.z1 || z0 != a.z0 {
+ t.Errorf("%s%+v\n\tgot z1:z0 = %#x:%#x; want %#x:%#x", msg, a, z1, z0, a.z1, a.z0)
+ }
+}
+
+
+func TestFunWW(t *testing.T) {
+ for _, a := range sumWW {
+ arg := a
+ testFunWW(t, "addWW_g", addWW_g, arg)
+
+ arg = argWW{a.y, a.x, a.c, a.z1, a.z0}
+ testFunWW(t, "addWW_g symmetric", addWW_g, arg)
+
+ arg = argWW{a.z0, a.x, a.c, a.z1, a.y}
+ testFunWW(t, "subWW_g", subWW_g, arg)
+
+ arg = argWW{a.z0, a.y, a.c, a.z1, a.x}
+ testFunWW(t, "subWW_g symmetric", subWW_g, arg)
+ }
+}
+
+
+type funVV func(z, x, y []Word) (c Word)
+type argVV struct {
+ z, x, y nat
+ c Word
+}
+
+var sumVV = []argVV{
+ {},
+ {nat{0}, nat{0}, nat{0}, 0},
+ {nat{1}, nat{1}, nat{0}, 0},
+ {nat{0}, nat{_M}, nat{1}, 1},
+ {nat{80235}, nat{12345}, nat{67890}, 0},
+ {nat{_M - 1}, nat{_M}, nat{_M}, 1},
+ {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1},
+ {nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0},
+ {nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
+}
+
+
+func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
+ z := make(nat, len(a.z))
+ c := f(z, a.x, a.y)
+ for i, zi := range z {
+ if zi != a.z[i] {
+ t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+ break
+ }
+ }
+ if c != a.c {
+ t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+ }
+}
+
+
+func TestFunVV(t *testing.T) {
+ for _, a := range sumVV {
+ arg := a
+ testFunVV(t, "addVV_g", addVV_g, arg)
+ testFunVV(t, "addVV", addVV, arg)
+
+ arg = argVV{a.z, a.y, a.x, a.c}
+ testFunVV(t, "addVV_g symmetric", addVV_g, arg)
+ testFunVV(t, "addVV symmetric", addVV, arg)
+
+ arg = argVV{a.x, a.z, a.y, a.c}
+ testFunVV(t, "subVV_g", subVV_g, arg)
+ testFunVV(t, "subVV", subVV, arg)
+
+ arg = argVV{a.y, a.z, a.x, a.c}
+ testFunVV(t, "subVV_g symmetric", subVV_g, arg)
+ testFunVV(t, "subVV symmetric", subVV, arg)
+ }
+}
+
+
+type funVW func(z, x []Word, y Word) (c Word)
+type argVW struct {
+ z, x nat
+ y Word
+ c Word
+}
+
+var sumVW = []argVW{
+ {},
+ {nil, nil, 2, 2},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{1}, nat{0}, 1, 0},
+ {nat{1}, nat{1}, 0, 0},
+ {nat{0}, nat{_M}, 1, 1},
+ {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
+}
+
+var prodVW = []argVW{
+ {},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{0}, nat{_M}, 0, 0},
+ {nat{0}, nat{0}, _M, 0},
+ {nat{1}, nat{1}, 1, 0},
+ {nat{22793}, nat{991}, 23, 0},
+ {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0},
+ {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0},
+ {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0},
+ {nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)},
+ {nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)},
+ {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)},
+}
+
+var lshVW = []argVW{
+ {},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{0}, nat{0}, 1, 0},
+ {nat{0}, nat{0}, 20, 0},
+
+ {nat{_M}, nat{_M}, 0, 0},
+ {nat{_M << 1 & _M}, nat{_M}, 1, 1},
+ {nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)},
+
+ {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+ {nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1},
+ {nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)},
+}
+
+var rshVW = []argVW{
+ {},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{0}, nat{0}, 1, 0},
+ {nat{0}, nat{0}, 20, 0},
+
+ {nat{_M}, nat{_M}, 0, 0},
+ {nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M},
+ {nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M},
+
+ {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+ {nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M},
+ {nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M},
+}
+
+
+func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
+ z := make(nat, len(a.z))
+ c := f(z, a.x, a.y)
+ for i, zi := range z {
+ if zi != a.z[i] {
+ t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+ break
+ }
+ }
+ if c != a.c {
+ t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+ }
+}
+
+
+func TestFunVW(t *testing.T) {
+ for _, a := range sumVW {
+ arg := a
+ testFunVW(t, "addVW_g", addVW_g, arg)
+ testFunVW(t, "addVW", addVW, arg)
+
+ arg = argVW{a.x, a.z, a.y, a.c}
+ testFunVW(t, "subVW_g", subVW_g, arg)
+ testFunVW(t, "subVW", subVW, arg)
+ }
+
+ for _, a := range lshVW {
+ arg := a
+ testFunVW(t, "shlVW_g", shlVW_g, arg)
+ testFunVW(t, "shlVW", shlVW, arg)
+ }
+
+ for _, a := range rshVW {
+ arg := a
+ testFunVW(t, "shrVW_g", shrVW_g, arg)
+ testFunVW(t, "shrVW", shrVW, arg)
+ }
+}
+
+
+type funVWW func(z, x []Word, y, r Word) (c Word)
+type argVWW struct {
+ z, x nat
+ y, r Word
+ c Word
+}
+
+var prodVWW = []argVWW{
+ {},
+ {nat{0}, nat{0}, 0, 0, 0},
+ {nat{991}, nat{0}, 0, 991, 0},
+ {nat{0}, nat{_M}, 0, 0, 0},
+ {nat{991}, nat{_M}, 0, 991, 0},
+ {nat{0}, nat{0}, _M, 0, 0},
+ {nat{991}, nat{0}, _M, 991, 0},
+ {nat{1}, nat{1}, 1, 0, 0},
+ {nat{992}, nat{1}, 1, 991, 0},
+ {nat{22793}, nat{991}, 23, 0, 0},
+ {nat{22800}, nat{991}, 23, 7, 0},
+ {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0},
+ {nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0},
+ {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
+ {nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
+ {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0},
+ {nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0},
+ {nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)},
+ {nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)},
+ {nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)},
+ {nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+ {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)},
+ {nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+}
+
+
+func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
+ z := make(nat, len(a.z))
+ c := f(z, a.x, a.y, a.r)
+ for i, zi := range z {
+ if zi != a.z[i] {
+ t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+ break
+ }
+ }
+ if c != a.c {
+ t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+ }
+}
+
+
+// TODO(gri) mulAddVWW and divWVW are symmetric operations but
+// their signature is not symmetric. Try to unify.
+
+type funWVW func(z []Word, xn Word, x []Word, y Word) (r Word)
+type argWVW struct {
+ z nat
+ xn Word
+ x nat
+ y Word
+ r Word
+}
+
+func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
+ z := make(nat, len(a.z))
+ r := f(z, a.xn, a.x, a.y)
+ for i, zi := range z {
+ if zi != a.z[i] {
+ t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+ break
+ }
+ }
+ if r != a.r {
+ t.Errorf("%s%+v\n\tgot r = %#x; want %#x", msg, a, r, a.r)
+ }
+}
+
+
+func TestFunVWW(t *testing.T) {
+ for _, a := range prodVWW {
+ arg := a
+ testFunVWW(t, "mulAddVWW_g", mulAddVWW_g, arg)
+ testFunVWW(t, "mulAddVWW", mulAddVWW, arg)
+
+ if a.y != 0 && a.r < a.y {
+ arg := argWVW{a.x, a.c, a.z, a.y, a.r}
+ testFunWVW(t, "divWVW_g", divWVW_g, arg)
+ testFunWVW(t, "divWVW", divWVW, arg)
+ }
+ }
+}
+
+
+var mulWWTests = []struct {
+ x, y Word
+ q, r Word
+}{
+ {_M, _M, _M - 1, 1},
+ // 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4},
+}
+
+
+func TestMulWW(t *testing.T) {
+ for i, test := range mulWWTests {
+ q, r := mulWW_g(test.x, test.y)
+ if q != test.q || r != test.r {
+ t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
+ }
+ }
+}
+
+
+var mulAddWWWTests = []struct {
+ x, y, c Word
+ q, r Word
+}{
+ // TODO(agl): These will only work on 64-bit platforms.
+ // {15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781},
+ // {15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382},
+ {_M, _M, 0, _M - 1, 1},
+ {_M, _M, _M, _M, 0},
+}
+
+
+func TestMulAddWWW(t *testing.T) {
+ for i, test := range mulAddWWWTests {
+ q, r := mulAddWWW_g(test.x, test.y, test.c)
+ if q != test.q || r != test.r {
+ t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
+ }
+ }
+}
diff --git a/libgo/go/big/calibrate_test.go b/libgo/go/big/calibrate_test.go
new file mode 100644
index 000000000..c6cd2e693
--- /dev/null
+++ b/libgo/go/big/calibrate_test.go
@@ -0,0 +1,92 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file prints execution times for the Mul benchmark
+// given different Karatsuba thresholds. The result may be
+// used to manually fine-tune the threshold constant. The
+// results are somewhat fragile; use repeated runs to get
+// a clear picture.
+
+// Usage: gotest -calibrate
+
+package big
+
+import (
+ "flag"
+ "fmt"
+ "testing"
+ "time"
+)
+
+
+var calibrate = flag.Bool("calibrate", false, "run calibration test")
+
+
+// measure returns the time to run f
+func measure(f func()) int64 {
+ const N = 100
+ start := time.Nanoseconds()
+ for i := N; i > 0; i-- {
+ f()
+ }
+ stop := time.Nanoseconds()
+ return (stop - start) / N
+}
+
+
+func computeThresholds() {
+ fmt.Printf("Multiplication times for varying Karatsuba thresholds\n")
+ fmt.Printf("(run repeatedly for good results)\n")
+
+ // determine Tk, the work load execution time using basic multiplication
+ karatsubaThreshold = 1e9 // disable karatsuba
+ Tb := measure(benchmarkMulLoad)
+ fmt.Printf("Tb = %dns\n", Tb)
+
+ // thresholds
+ n := 8 // any lower values for the threshold lead to very slow multiplies
+ th1 := -1
+ th2 := -1
+
+ var deltaOld int64
+ for count := -1; count != 0; count-- {
+ // determine Tk, the work load execution time using Karatsuba multiplication
+ karatsubaThreshold = n // enable karatsuba
+ Tk := measure(benchmarkMulLoad)
+
+ // improvement over Tb
+ delta := (Tb - Tk) * 100 / Tb
+
+ fmt.Printf("n = %3d Tk = %8dns %4d%%", n, Tk, delta)
+
+ // determine break-even point
+ if Tk < Tb && th1 < 0 {
+ th1 = n
+ fmt.Print(" break-even point")
+ }
+
+ // determine diminishing return
+ if 0 < delta && delta < deltaOld && th2 < 0 {
+ th2 = n
+ fmt.Print(" diminishing return")
+ }
+ deltaOld = delta
+
+ fmt.Println()
+
+ // trigger counter
+ if th1 >= 0 && th2 >= 0 && count < 0 {
+ count = 20 // this many extra measurements after we got both thresholds
+ }
+
+ n++
+ }
+}
+
+
+func TestCalibrate(t *testing.T) {
+ if *calibrate {
+ computeThresholds()
+ }
+}
diff --git a/libgo/go/big/hilbert_test.go b/libgo/go/big/hilbert_test.go
new file mode 100644
index 000000000..66a21214d
--- /dev/null
+++ b/libgo/go/big/hilbert_test.go
@@ -0,0 +1,173 @@
+// 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 little test program and benchmark for rational arithmetics.
+// Computes a Hilbert matrix, its inverse, multiplies them
+// and verifies that the product is the identity matrix.
+
+package big
+
+import (
+ "fmt"
+ "testing"
+)
+
+
+type matrix struct {
+ n, m int
+ a []*Rat
+}
+
+
+func (a *matrix) at(i, j int) *Rat {
+ if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
+ panic("index out of range")
+ }
+ return a.a[i*a.m+j]
+}
+
+
+func (a *matrix) set(i, j int, x *Rat) {
+ if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
+ panic("index out of range")
+ }
+ a.a[i*a.m+j] = x
+}
+
+
+func newMatrix(n, m int) *matrix {
+ if !(0 <= n && 0 <= m) {
+ panic("illegal matrix")
+ }
+ a := new(matrix)
+ a.n = n
+ a.m = m
+ a.a = make([]*Rat, n*m)
+ return a
+}
+
+
+func newUnit(n int) *matrix {
+ a := newMatrix(n, n)
+ for i := 0; i < n; i++ {
+ for j := 0; j < n; j++ {
+ x := NewRat(0, 1)
+ if i == j {
+ x.SetInt64(1)
+ }
+ a.set(i, j, x)
+ }
+ }
+ return a
+}
+
+
+func newHilbert(n int) *matrix {
+ a := newMatrix(n, n)
+ for i := 0; i < n; i++ {
+ for j := 0; j < n; j++ {
+ a.set(i, j, NewRat(1, int64(i+j+1)))
+ }
+ }
+ return a
+}
+
+
+func newInverseHilbert(n int) *matrix {
+ a := newMatrix(n, n)
+ for i := 0; i < n; i++ {
+ for j := 0; j < n; j++ {
+ x1 := new(Rat).SetInt64(int64(i + j + 1))
+ x2 := new(Rat).SetInt(new(Int).Binomial(int64(n+i), int64(n-j-1)))
+ x3 := new(Rat).SetInt(new(Int).Binomial(int64(n+j), int64(n-i-1)))
+ x4 := new(Rat).SetInt(new(Int).Binomial(int64(i+j), int64(i)))
+
+ x1.Mul(x1, x2)
+ x1.Mul(x1, x3)
+ x1.Mul(x1, x4)
+ x1.Mul(x1, x4)
+
+ if (i+j)&1 != 0 {
+ x1.Neg(x1)
+ }
+
+ a.set(i, j, x1)
+ }
+ }
+ return a
+}
+
+
+func (a *matrix) mul(b *matrix) *matrix {
+ if a.m != b.n {
+ panic("illegal matrix multiply")
+ }
+ c := newMatrix(a.n, b.m)
+ for i := 0; i < c.n; i++ {
+ for j := 0; j < c.m; j++ {
+ x := NewRat(0, 1)
+ for k := 0; k < a.m; k++ {
+ x.Add(x, new(Rat).Mul(a.at(i, k), b.at(k, j)))
+ }
+ c.set(i, j, x)
+ }
+ }
+ return c
+}
+
+
+func (a *matrix) eql(b *matrix) bool {
+ if a.n != b.n || a.m != b.m {
+ return false
+ }
+ for i := 0; i < a.n; i++ {
+ for j := 0; j < a.m; j++ {
+ if a.at(i, j).Cmp(b.at(i, j)) != 0 {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+
+func (a *matrix) String() string {
+ s := ""
+ for i := 0; i < a.n; i++ {
+ for j := 0; j < a.m; j++ {
+ s += fmt.Sprintf("\t%s", a.at(i, j))
+ }
+ s += "\n"
+ }
+ return s
+}
+
+
+func doHilbert(t *testing.T, n int) {
+ a := newHilbert(n)
+ b := newInverseHilbert(n)
+ I := newUnit(n)
+ ab := a.mul(b)
+ if !ab.eql(I) {
+ if t == nil {
+ panic("Hilbert failed")
+ }
+ t.Errorf("a = %s\n", a)
+ t.Errorf("b = %s\n", b)
+ t.Errorf("a*b = %s\n", ab)
+ t.Errorf("I = %s\n", I)
+ }
+}
+
+
+func TestHilbert(t *testing.T) {
+ doHilbert(t, 10)
+}
+
+
+func BenchmarkHilbert(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ doHilbert(nil, 10)
+ }
+}
diff --git a/libgo/go/big/int.go b/libgo/go/big/int.go
new file mode 100644
index 000000000..46e008734
--- /dev/null
+++ b/libgo/go/big/int.go
@@ -0,0 +1,741 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements signed multi-precision integers.
+
+package big
+
+import (
+ "fmt"
+ "rand"
+)
+
+// An Int represents a signed multi-precision integer.
+// The zero value for an Int represents the value 0.
+type Int struct {
+ neg bool // sign
+ abs nat // absolute value of the integer
+}
+
+
+var intOne = &Int{false, natOne}
+
+
+// Sign returns:
+//
+// -1 if x < 0
+// 0 if x == 0
+// +1 if x > 0
+//
+func (x *Int) Sign() int {
+ if len(x.abs) == 0 {
+ return 0
+ }
+ if x.neg {
+ return -1
+ }
+ return 1
+}
+
+
+// SetInt64 sets z to x and returns z.
+func (z *Int) SetInt64(x int64) *Int {
+ neg := false
+ if x < 0 {
+ neg = true
+ x = -x
+ }
+ z.abs = z.abs.setUint64(uint64(x))
+ z.neg = neg
+ return z
+}
+
+
+// NewInt allocates and returns a new Int set to x.
+func NewInt(x int64) *Int {
+ return new(Int).SetInt64(x)
+}
+
+
+// Set sets z to x and returns z.
+func (z *Int) Set(x *Int) *Int {
+ z.abs = z.abs.set(x.abs)
+ z.neg = x.neg
+ return z
+}
+
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Int) Abs(x *Int) *Int {
+ z.abs = z.abs.set(x.abs)
+ z.neg = false
+ return z
+}
+
+
+// Neg sets z to -x and returns z.
+func (z *Int) Neg(x *Int) *Int {
+ z.abs = z.abs.set(x.abs)
+ z.neg = len(z.abs) > 0 && !x.neg // 0 has no sign
+ return z
+}
+
+
+// Add sets z to the sum x+y and returns z.
+func (z *Int) Add(x, y *Int) *Int {
+ neg := x.neg
+ if x.neg == y.neg {
+ // x + y == x + y
+ // (-x) + (-y) == -(x + y)
+ z.abs = z.abs.add(x.abs, y.abs)
+ } else {
+ // x + (-y) == x - y == -(y - x)
+ // (-x) + y == y - x == -(x - y)
+ if x.abs.cmp(y.abs) >= 0 {
+ z.abs = z.abs.sub(x.abs, y.abs)
+ } else {
+ neg = !neg
+ z.abs = z.abs.sub(y.abs, x.abs)
+ }
+ }
+ z.neg = len(z.abs) > 0 && neg // 0 has no sign
+ return z
+}
+
+
+// Sub sets z to the difference x-y and returns z.
+func (z *Int) Sub(x, y *Int) *Int {
+ neg := x.neg
+ if x.neg != y.neg {
+ // x - (-y) == x + y
+ // (-x) - y == -(x + y)
+ z.abs = z.abs.add(x.abs, y.abs)
+ } else {
+ // x - y == x - y == -(y - x)
+ // (-x) - (-y) == y - x == -(x - y)
+ if x.abs.cmp(y.abs) >= 0 {
+ z.abs = z.abs.sub(x.abs, y.abs)
+ } else {
+ neg = !neg
+ z.abs = z.abs.sub(y.abs, x.abs)
+ }
+ }
+ z.neg = len(z.abs) > 0 && neg // 0 has no sign
+ return z
+}
+
+
+// Mul sets z to the product x*y and returns z.
+func (z *Int) Mul(x, y *Int) *Int {
+ // x * y == x * y
+ // x * (-y) == -(x * y)
+ // (-x) * y == -(x * y)
+ // (-x) * (-y) == x * y
+ z.abs = z.abs.mul(x.abs, y.abs)
+ z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
+ return z
+}
+
+
+// MulRange sets z to the product of all integers
+// in the range [a, b] inclusively and returns z.
+// If a > b (empty range), the result is 1.
+func (z *Int) MulRange(a, b int64) *Int {
+ switch {
+ case a > b:
+ return z.SetInt64(1) // empty range
+ case a <= 0 && b >= 0:
+ return z.SetInt64(0) // range includes 0
+ }
+ // a <= b && (b < 0 || a > 0)
+
+ neg := false
+ if a < 0 {
+ neg = (b-a)&1 == 0
+ a, b = -b, -a
+ }
+
+ z.abs = z.abs.mulRange(uint64(a), uint64(b))
+ z.neg = neg
+ return z
+}
+
+
+// Binomial sets z to the binomial coefficient of (n, k) and returns z.
+func (z *Int) Binomial(n, k int64) *Int {
+ var a, b Int
+ a.MulRange(n-k+1, n)
+ b.MulRange(1, k)
+ return z.Quo(&a, &b)
+}
+
+
+// Quo sets z to the quotient x/y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See QuoRem for more details.
+func (z *Int) Quo(x, y *Int) *Int {
+ z.abs, _ = z.abs.div(nil, x.abs, y.abs)
+ z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
+ return z
+}
+
+
+// Rem sets z to the remainder x%y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See QuoRem for more details.
+func (z *Int) Rem(x, y *Int) *Int {
+ _, z.abs = nat(nil).div(z.abs, x.abs, y.abs)
+ z.neg = len(z.abs) > 0 && x.neg // 0 has no sign
+ return z
+}
+
+
+// QuoRem sets z to the quotient x/y and r to the remainder x%y
+// and returns the pair (z, r) for y != 0.
+// If y == 0, a division-by-zero run-time panic occurs.
+//
+// QuoRem implements T-division and modulus (like Go):
+//
+// q = x/y with the result truncated to zero
+// r = x - y*q
+//
+// (See Daan Leijen, ``Division and Modulus for Computer Scientists''.)
+//
+func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
+ z.abs, r.abs = z.abs.div(r.abs, x.abs, y.abs)
+ z.neg, r.neg = len(z.abs) > 0 && x.neg != y.neg, len(r.abs) > 0 && x.neg // 0 has no sign
+ return z, r
+}
+
+
+// Div sets z to the quotient x/y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See DivMod for more details.
+func (z *Int) Div(x, y *Int) *Int {
+ y_neg := y.neg // z may be an alias for y
+ var r Int
+ z.QuoRem(x, y, &r)
+ if r.neg {
+ if y_neg {
+ z.Add(z, intOne)
+ } else {
+ z.Sub(z, intOne)
+ }
+ }
+ return z
+}
+
+
+// Mod sets z to the modulus x%y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// See DivMod for more details.
+func (z *Int) Mod(x, y *Int) *Int {
+ y0 := y // save y
+ if z == y || alias(z.abs, y.abs) {
+ y0 = new(Int).Set(y)
+ }
+ var q Int
+ q.QuoRem(x, y, z)
+ if z.neg {
+ if y0.neg {
+ z.Sub(z, y0)
+ } else {
+ z.Add(z, y0)
+ }
+ }
+ return z
+}
+
+
+// DivMod sets z to the quotient x div y and m to the modulus x mod y
+// and returns the pair (z, m) for y != 0.
+// If y == 0, a division-by-zero run-time panic occurs.
+//
+// DivMod implements Euclidean division and modulus (unlike Go):
+//
+// q = x div y such that
+// m = x - y*q with 0 <= m < |q|
+//
+// (See Raymond T. Boute, ``The Euclidean definition of the functions
+// div and mod''. ACM Transactions on Programming Languages and
+// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
+// ACM press.)
+//
+func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
+ y0 := y // save y
+ if z == y || alias(z.abs, y.abs) {
+ y0 = new(Int).Set(y)
+ }
+ z.QuoRem(x, y, m)
+ if m.neg {
+ if y0.neg {
+ z.Add(z, intOne)
+ m.Sub(m, y0)
+ } else {
+ z.Sub(z, intOne)
+ m.Add(m, y0)
+ }
+ }
+ return z, m
+}
+
+
+// Cmp compares x and y and returns:
+//
+// -1 if x < y
+// 0 if x == y
+// +1 if x > y
+//
+func (x *Int) Cmp(y *Int) (r int) {
+ // x cmp y == x cmp y
+ // x cmp (-y) == x
+ // (-x) cmp y == y
+ // (-x) cmp (-y) == -(x cmp y)
+ switch {
+ case x.neg == y.neg:
+ r = x.abs.cmp(y.abs)
+ if x.neg {
+ r = -r
+ }
+ case x.neg:
+ r = -1
+ default:
+ r = 1
+ }
+ return
+}
+
+
+func (x *Int) String() string {
+ s := ""
+ if x.neg {
+ s = "-"
+ }
+ return s + x.abs.string(10)
+}
+
+
+func fmtbase(ch int) int {
+ switch ch {
+ case 'b':
+ return 2
+ case 'o':
+ return 8
+ case 'd':
+ return 10
+ case 'x':
+ return 16
+ }
+ return 10
+}
+
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), 'd' (decimal) and
+// 'x' (hexadecimal).
+//
+func (x *Int) Format(s fmt.State, ch int) {
+ if x.neg {
+ fmt.Fprint(s, "-")
+ }
+ fmt.Fprint(s, x.abs.string(fmtbase(ch)))
+}
+
+
+// Int64 returns the int64 representation of z.
+// If z cannot be represented in an int64, the result is undefined.
+func (x *Int) Int64() int64 {
+ if len(x.abs) == 0 {
+ return 0
+ }
+ v := int64(x.abs[0])
+ if _W == 32 && len(x.abs) > 1 {
+ v |= int64(x.abs[1]) << 32
+ }
+ if x.neg {
+ v = -v
+ }
+ return v
+}
+
+
+// SetString sets z to the value of s, interpreted in the given base,
+// and returns z and a boolean indicating success. If SetString fails,
+// the value of z is undefined.
+//
+// If the base argument is 0, the string prefix determines the actual
+// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
+// ``0'' prefix selects base 8, and a ``0b'' or ``0B'' prefix selects
+// base 2. Otherwise the selected base is 10.
+//
+func (z *Int) SetString(s string, base int) (*Int, bool) {
+ if len(s) == 0 || base < 0 || base == 1 || 16 < base {
+ return z, false
+ }
+
+ neg := s[0] == '-'
+ if neg || s[0] == '+' {
+ s = s[1:]
+ if len(s) == 0 {
+ return z, false
+ }
+ }
+
+ var scanned int
+ z.abs, _, scanned = z.abs.scan(s, base)
+ if scanned != len(s) {
+ return z, false
+ }
+ z.neg = len(z.abs) > 0 && neg // 0 has no sign
+
+ return z, true
+}
+
+
+// SetBytes interprets b as the bytes of a big-endian, unsigned integer and
+// sets z to that value.
+func (z *Int) SetBytes(b []byte) *Int {
+ const s = _S
+ z.abs = z.abs.make((len(b) + s - 1) / s)
+
+ j := 0
+ for len(b) >= s {
+ var w Word
+
+ for i := s; i > 0; i-- {
+ w <<= 8
+ w |= Word(b[len(b)-i])
+ }
+
+ z.abs[j] = w
+ j++
+ b = b[0 : len(b)-s]
+ }
+
+ if len(b) > 0 {
+ var w Word
+
+ for i := len(b); i > 0; i-- {
+ w <<= 8
+ w |= Word(b[len(b)-i])
+ }
+
+ z.abs[j] = w
+ }
+
+ z.abs = z.abs.norm()
+ z.neg = false
+ return z
+}
+
+
+// Bytes returns the absolute value of x as a big-endian byte array.
+func (z *Int) Bytes() []byte {
+ const s = _S
+ b := make([]byte, len(z.abs)*s)
+
+ for i, w := range z.abs {
+ wordBytes := b[(len(z.abs)-i-1)*s : (len(z.abs)-i)*s]
+ for j := s - 1; j >= 0; j-- {
+ wordBytes[j] = byte(w)
+ w >>= 8
+ }
+ }
+
+ i := 0
+ for i < len(b) && b[i] == 0 {
+ i++
+ }
+
+ return b[i:]
+}
+
+
+// BitLen returns the length of the absolute value of z in bits.
+// The bit length of 0 is 0.
+func (z *Int) BitLen() int {
+ return z.abs.bitLen()
+}
+
+
+// Exp sets z = x**y mod m. If m is nil, z = x**y.
+// See Knuth, volume 2, section 4.6.3.
+func (z *Int) Exp(x, y, m *Int) *Int {
+ if y.neg || len(y.abs) == 0 {
+ neg := x.neg
+ z.SetInt64(1)
+ z.neg = neg
+ return z
+ }
+
+ var mWords nat
+ if m != nil {
+ mWords = m.abs
+ }
+
+ z.abs = z.abs.expNN(x.abs, y.abs, mWords)
+ z.neg = len(z.abs) > 0 && x.neg && y.abs[0]&1 == 1 // 0 has no sign
+ return z
+}
+
+
+// GcdInt sets d to the greatest common divisor of a and b, which must be
+// positive numbers.
+// If x and y are not nil, GcdInt sets x and y such that d = a*x + b*y.
+// If either a or b is not positive, GcdInt sets d = x = y = 0.
+func GcdInt(d, x, y, a, b *Int) {
+ if a.neg || b.neg {
+ d.SetInt64(0)
+ if x != nil {
+ x.SetInt64(0)
+ }
+ if y != nil {
+ y.SetInt64(0)
+ }
+ return
+ }
+
+ A := new(Int).Set(a)
+ B := new(Int).Set(b)
+
+ X := new(Int)
+ Y := new(Int).SetInt64(1)
+
+ lastX := new(Int).SetInt64(1)
+ lastY := new(Int)
+
+ q := new(Int)
+ temp := new(Int)
+
+ for len(B.abs) > 0 {
+ r := new(Int)
+ q, r = q.QuoRem(A, B, r)
+
+ A, B = B, r
+
+ temp.Set(X)
+ X.Mul(X, q)
+ X.neg = !X.neg
+ X.Add(X, lastX)
+ lastX.Set(temp)
+
+ temp.Set(Y)
+ Y.Mul(Y, q)
+ Y.neg = !Y.neg
+ Y.Add(Y, lastY)
+ lastY.Set(temp)
+ }
+
+ if x != nil {
+ *x = *lastX
+ }
+
+ if y != nil {
+ *y = *lastY
+ }
+
+ *d = *A
+}
+
+
+// ProbablyPrime performs n Miller-Rabin tests to check whether z is prime.
+// If it returns true, z is prime with probability 1 - 1/4^n.
+// If it returns false, z is not prime.
+func ProbablyPrime(z *Int, n int) bool {
+ return !z.neg && z.abs.probablyPrime(n)
+}
+
+
+// Rand sets z to a pseudo-random number in [0, n) and returns z.
+func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
+ z.neg = false
+ if n.neg == true || len(n.abs) == 0 {
+ z.abs = nil
+ return z
+ }
+ z.abs = z.abs.random(rnd, n.abs, n.abs.bitLen())
+ return z
+}
+
+
+// ModInverse sets z to the multiplicative inverse of g in the group ℤ/pℤ (where
+// p is a prime) and returns z.
+func (z *Int) ModInverse(g, p *Int) *Int {
+ var d Int
+ GcdInt(&d, z, nil, g, p)
+ // x and y are such that g*x + p*y = d. Since p is prime, d = 1. Taking
+ // that modulo p results in g*x = 1, therefore x is the inverse element.
+ if z.neg {
+ z.Add(z, p)
+ }
+ return z
+}
+
+
+// Lsh sets z = x << n and returns z.
+func (z *Int) Lsh(x *Int, n uint) *Int {
+ z.abs = z.abs.shl(x.abs, n)
+ z.neg = x.neg
+ return z
+}
+
+
+// Rsh sets z = x >> n and returns z.
+func (z *Int) Rsh(x *Int, n uint) *Int {
+ if x.neg {
+ // (-x) >> s == ^(x-1) >> s == ^((x-1) >> s) == -(((x-1) >> s) + 1)
+ t := z.abs.sub(x.abs, natOne) // no underflow because |x| > 0
+ t = t.shr(t, n)
+ z.abs = t.add(t, natOne)
+ z.neg = true // z cannot be zero if x is negative
+ return z
+ }
+
+ z.abs = z.abs.shr(x.abs, n)
+ z.neg = false
+ return z
+}
+
+
+// And sets z = x & y and returns z.
+func (z *Int) And(x, y *Int) *Int {
+ if x.neg == y.neg {
+ if x.neg {
+ // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
+ x1 := nat{}.sub(x.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.add(z.abs.or(x1, y1), natOne)
+ z.neg = true // z cannot be zero if x and y are negative
+ return z
+ }
+
+ // x & y == x & y
+ z.abs = z.abs.and(x.abs, y.abs)
+ z.neg = false
+ return z
+ }
+
+ // x.neg != y.neg
+ if x.neg {
+ x, y = y, x // & is symmetric
+ }
+
+ // x & (-y) == x & ^(y-1) == x &^ (y-1)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.andNot(x.abs, y1)
+ z.neg = false
+ return z
+}
+
+
+// AndNot sets z = x &^ y and returns z.
+func (z *Int) AndNot(x, y *Int) *Int {
+ if x.neg == y.neg {
+ if x.neg {
+ // (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
+ x1 := nat{}.sub(x.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.andNot(y1, x1)
+ z.neg = false
+ return z
+ }
+
+ // x &^ y == x &^ y
+ z.abs = z.abs.andNot(x.abs, y.abs)
+ z.neg = false
+ return z
+ }
+
+ if x.neg {
+ // (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
+ x1 := nat{}.sub(x.abs, natOne)
+ z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne)
+ z.neg = true // z cannot be zero if x is negative and y is positive
+ return z
+ }
+
+ // x &^ (-y) == x &^ ^(y-1) == x & (y-1)
+ y1 := nat{}.add(y.abs, natOne)
+ z.abs = z.abs.and(x.abs, y1)
+ z.neg = false
+ return z
+}
+
+
+// Or sets z = x | y and returns z.
+func (z *Int) Or(x, y *Int) *Int {
+ if x.neg == y.neg {
+ if x.neg {
+ // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
+ x1 := nat{}.sub(x.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.add(z.abs.and(x1, y1), natOne)
+ z.neg = true // z cannot be zero if x and y are negative
+ return z
+ }
+
+ // x | y == x | y
+ z.abs = z.abs.or(x.abs, y.abs)
+ z.neg = false
+ return z
+ }
+
+ // x.neg != y.neg
+ if x.neg {
+ x, y = y, x // | is symmetric
+ }
+
+ // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne)
+ z.neg = true // z cannot be zero if one of x or y is negative
+ return z
+}
+
+
+// Xor sets z = x ^ y and returns z.
+func (z *Int) Xor(x, y *Int) *Int {
+ if x.neg == y.neg {
+ if x.neg {
+ // (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
+ x1 := nat{}.sub(x.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.xor(x1, y1)
+ z.neg = false
+ return z
+ }
+
+ // x ^ y == x ^ y
+ z.abs = z.abs.xor(x.abs, y.abs)
+ z.neg = false
+ return z
+ }
+
+ // x.neg != y.neg
+ if x.neg {
+ x, y = y, x // ^ is symmetric
+ }
+
+ // x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
+ y1 := nat{}.sub(y.abs, natOne)
+ z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne)
+ z.neg = true // z cannot be zero if only one of x or y is negative
+ return z
+}
+
+
+// Not sets z = ^x and returns z.
+func (z *Int) Not(x *Int) *Int {
+ if x.neg {
+ // ^(-x) == ^(^(x-1)) == x-1
+ z.abs = z.abs.sub(x.abs, natOne)
+ z.neg = false
+ return z
+ }
+
+ // ^x == -x-1 == -(x+1)
+ z.abs = z.abs.add(x.abs, natOne)
+ z.neg = true // z cannot be zero if x is positive
+ return z
+}
diff --git a/libgo/go/big/int_test.go b/libgo/go/big/int_test.go
new file mode 100644
index 000000000..fc981e1da
--- /dev/null
+++ b/libgo/go/big/int_test.go
@@ -0,0 +1,1055 @@
+// 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 big
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "testing"
+ "testing/quick"
+)
+
+
+func isNormalized(x *Int) bool {
+ if len(x.abs) == 0 {
+ return !x.neg
+ }
+ // len(x.abs) > 0
+ return x.abs[len(x.abs)-1] != 0
+}
+
+
+type funZZ func(z, x, y *Int) *Int
+type argZZ struct {
+ z, x, y *Int
+}
+
+
+var sumZZ = []argZZ{
+ {NewInt(0), NewInt(0), NewInt(0)},
+ {NewInt(1), NewInt(1), NewInt(0)},
+ {NewInt(1111111110), NewInt(123456789), NewInt(987654321)},
+ {NewInt(-1), NewInt(-1), NewInt(0)},
+ {NewInt(864197532), NewInt(-123456789), NewInt(987654321)},
+ {NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)},
+}
+
+
+var prodZZ = []argZZ{
+ {NewInt(0), NewInt(0), NewInt(0)},
+ {NewInt(0), NewInt(1), NewInt(0)},
+ {NewInt(1), NewInt(1), NewInt(1)},
+ {NewInt(-991 * 991), NewInt(991), NewInt(-991)},
+ // TODO(gri) add larger products
+}
+
+
+func TestSignZ(t *testing.T) {
+ var zero Int
+ for _, a := range sumZZ {
+ s := a.z.Sign()
+ e := a.z.Cmp(&zero)
+ if s != e {
+ t.Errorf("got %d; want %d for z = %v", s, e, a.z)
+ }
+ }
+}
+
+
+func TestSetZ(t *testing.T) {
+ for _, a := range sumZZ {
+ var z Int
+ z.Set(a.z)
+ if !isNormalized(&z) {
+ t.Errorf("%v is not normalized", z)
+ }
+ if (&z).Cmp(a.z) != 0 {
+ t.Errorf("got z = %v; want %v", z, a.z)
+ }
+ }
+}
+
+
+func TestAbsZ(t *testing.T) {
+ var zero Int
+ for _, a := range sumZZ {
+ var z Int
+ z.Abs(a.z)
+ var e Int
+ e.Set(a.z)
+ if e.Cmp(&zero) < 0 {
+ e.Sub(&zero, &e)
+ }
+ if z.Cmp(&e) != 0 {
+ t.Errorf("got z = %v; want %v", z, e)
+ }
+ }
+}
+
+
+func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
+ var z Int
+ f(&z, a.x, a.y)
+ if !isNormalized(&z) {
+ t.Errorf("%s%v is not normalized", z, msg)
+ }
+ if (&z).Cmp(a.z) != 0 {
+ t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z)
+ }
+}
+
+
+func TestSumZZ(t *testing.T) {
+ AddZZ := func(z, x, y *Int) *Int { return z.Add(x, y) }
+ SubZZ := func(z, x, y *Int) *Int { return z.Sub(x, y) }
+ for _, a := range sumZZ {
+ arg := a
+ testFunZZ(t, "AddZZ", AddZZ, arg)
+
+ arg = argZZ{a.z, a.y, a.x}
+ testFunZZ(t, "AddZZ symmetric", AddZZ, arg)
+
+ arg = argZZ{a.x, a.z, a.y}
+ testFunZZ(t, "SubZZ", SubZZ, arg)
+
+ arg = argZZ{a.y, a.z, a.x}
+ testFunZZ(t, "SubZZ symmetric", SubZZ, arg)
+ }
+}
+
+
+func TestProdZZ(t *testing.T) {
+ MulZZ := func(z, x, y *Int) *Int { return z.Mul(x, y) }
+ for _, a := range prodZZ {
+ arg := a
+ testFunZZ(t, "MulZZ", MulZZ, arg)
+
+ arg = argZZ{a.z, a.y, a.x}
+ testFunZZ(t, "MulZZ symmetric", MulZZ, arg)
+ }
+}
+
+
+// mulBytes returns x*y via grade school multiplication. Both inputs
+// and the result are assumed to be in big-endian representation (to
+// match the semantics of Int.Bytes and Int.SetBytes).
+func mulBytes(x, y []byte) []byte {
+ z := make([]byte, len(x)+len(y))
+
+ // multiply
+ k0 := len(z) - 1
+ for j := len(y) - 1; j >= 0; j-- {
+ d := int(y[j])
+ if d != 0 {
+ k := k0
+ carry := 0
+ for i := len(x) - 1; i >= 0; i-- {
+ t := int(z[k]) + int(x[i])*d + carry
+ z[k], carry = byte(t), t>>8
+ k--
+ }
+ z[k] = byte(carry)
+ }
+ k0--
+ }
+
+ // normalize (remove leading 0's)
+ i := 0
+ for i < len(z) && z[i] == 0 {
+ i++
+ }
+
+ return z[i:]
+}
+
+
+func checkMul(a, b []byte) bool {
+ var x, y, z1 Int
+ x.SetBytes(a)
+ y.SetBytes(b)
+ z1.Mul(&x, &y)
+
+ var z2 Int
+ z2.SetBytes(mulBytes(a, b))
+
+ return z1.Cmp(&z2) == 0
+}
+
+
+func TestMul(t *testing.T) {
+ if err := quick.Check(checkMul, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+
+var mulRangesZ = []struct {
+ a, b int64
+ prod string
+}{
+ // entirely positive ranges are covered by mulRangesN
+ {-1, 1, "0"},
+ {-2, -1, "2"},
+ {-3, -2, "6"},
+ {-3, -1, "-6"},
+ {1, 3, "6"},
+ {-10, -10, "-10"},
+ {0, -1, "1"}, // empty range
+ {-1, -100, "1"}, // empty range
+ {-1, 1, "0"}, // range includes 0
+ {-1e9, 0, "0"}, // range includes 0
+ {-1e9, 1e9, "0"}, // range includes 0
+ {-10, -1, "3628800"}, // 10!
+ {-20, -2, "-2432902008176640000"}, // -20!
+ {-99, -1,
+ "-933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "511852109168640000000000000000000000", // -99!
+ },
+}
+
+
+func TestMulRangeZ(t *testing.T) {
+ var tmp Int
+ // test entirely positive ranges
+ for i, r := range mulRangesN {
+ prod := tmp.MulRange(int64(r.a), int64(r.b)).String()
+ if prod != r.prod {
+ t.Errorf("#%da: got %s; want %s", i, prod, r.prod)
+ }
+ }
+ // test other ranges
+ for i, r := range mulRangesZ {
+ prod := tmp.MulRange(r.a, r.b).String()
+ if prod != r.prod {
+ t.Errorf("#%db: got %s; want %s", i, prod, r.prod)
+ }
+ }
+}
+
+
+var stringTests = []struct {
+ in string
+ out string
+ base int
+ val int64
+ ok bool
+}{
+ {in: "", ok: false},
+ {in: "a", ok: false},
+ {in: "z", ok: false},
+ {in: "+", ok: false},
+ {in: "-", ok: false},
+ {in: "0b", ok: false},
+ {in: "0x", ok: false},
+ {in: "2", base: 2, ok: false},
+ {in: "0b2", base: 0, ok: false},
+ {in: "08", ok: false},
+ {in: "8", base: 8, ok: false},
+ {in: "0xg", base: 0, ok: false},
+ {in: "g", base: 16, ok: false},
+ {"0", "0", 0, 0, true},
+ {"0", "0", 10, 0, true},
+ {"0", "0", 16, 0, true},
+ {"+0", "0", 0, 0, true},
+ {"-0", "0", 0, 0, true},
+ {"10", "10", 0, 10, true},
+ {"10", "10", 10, 10, true},
+ {"10", "10", 16, 16, true},
+ {"-10", "-10", 16, -16, true},
+ {"+10", "10", 16, 16, true},
+ {"0x10", "16", 0, 16, true},
+ {in: "0x10", base: 16, ok: false},
+ {"-0x10", "-16", 0, -16, true},
+ {"+0x10", "16", 0, 16, true},
+ {"00", "0", 0, 0, true},
+ {"0", "0", 8, 0, true},
+ {"07", "7", 0, 7, true},
+ {"7", "7", 8, 7, true},
+ {"023", "19", 0, 19, true},
+ {"23", "23", 8, 19, true},
+ {"cafebabe", "cafebabe", 16, 0xcafebabe, true},
+ {"0b0", "0", 0, 0, true},
+ {"-111", "-111", 2, -7, true},
+ {"-0b111", "-7", 0, -7, true},
+ {"0b1001010111", "599", 0, 0x257, true},
+ {"1001010111", "1001010111", 2, 0x257, true},
+}
+
+
+func format(base int) string {
+ switch base {
+ case 2:
+ return "%b"
+ case 8:
+ return "%o"
+ case 16:
+ return "%x"
+ }
+ return "%d"
+}
+
+
+func TestGetString(t *testing.T) {
+ z := new(Int)
+ for i, test := range stringTests {
+ if !test.ok {
+ continue
+ }
+ z.SetInt64(test.val)
+
+ if test.base == 10 {
+ s := z.String()
+ if s != test.out {
+ t.Errorf("#%da got %s; want %s", i, s, test.out)
+ }
+ }
+
+ s := fmt.Sprintf(format(test.base), z)
+ if s != test.out {
+ t.Errorf("#%db got %s; want %s", i, s, test.out)
+ }
+ }
+}
+
+
+func TestSetString(t *testing.T) {
+ tmp := new(Int)
+ for i, test := range stringTests {
+ n1, ok1 := new(Int).SetString(test.in, test.base)
+ n2, ok2 := tmp.SetString(test.in, test.base)
+ expected := NewInt(test.val)
+ if ok1 != test.ok || ok2 != test.ok {
+ t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
+ continue
+ }
+ if !ok1 || !ok2 {
+ continue
+ }
+
+ if ok1 && !isNormalized(n1) {
+ t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
+ }
+ if ok2 && !isNormalized(n2) {
+ t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
+ }
+
+ if n1.Cmp(expected) != 0 {
+ t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
+ }
+ if n2.Cmp(expected) != 0 {
+ t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
+ }
+ }
+}
+
+
+// Examples from the Go Language Spec, section "Arithmetic operators"
+var divisionSignsTests = []struct {
+ x, y int64
+ q, r int64 // T-division
+ d, m int64 // Euclidian division
+}{
+ {5, 3, 1, 2, 1, 2},
+ {-5, 3, -1, -2, -2, 1},
+ {5, -3, -1, 2, -1, 2},
+ {-5, -3, 1, -2, 2, 1},
+ {1, 2, 0, 1, 0, 1},
+ {8, 4, 2, 0, 2, 0},
+}
+
+
+func TestDivisionSigns(t *testing.T) {
+ for i, test := range divisionSignsTests {
+ x := NewInt(test.x)
+ y := NewInt(test.y)
+ q := NewInt(test.q)
+ r := NewInt(test.r)
+ d := NewInt(test.d)
+ m := NewInt(test.m)
+
+ q1 := new(Int).Quo(x, y)
+ r1 := new(Int).Rem(x, y)
+ if !isNormalized(q1) {
+ t.Errorf("#%d Quo: %v is not normalized", i, *q1)
+ }
+ if !isNormalized(r1) {
+ t.Errorf("#%d Rem: %v is not normalized", i, *r1)
+ }
+ if q1.Cmp(q) != 0 || r1.Cmp(r) != 0 {
+ t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q1, r1, q, r)
+ }
+
+ q2, r2 := new(Int).QuoRem(x, y, new(Int))
+ if !isNormalized(q2) {
+ t.Errorf("#%d Quo: %v is not normalized", i, *q2)
+ }
+ if !isNormalized(r2) {
+ t.Errorf("#%d Rem: %v is not normalized", i, *r2)
+ }
+ if q2.Cmp(q) != 0 || r2.Cmp(r) != 0 {
+ t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q2, r2, q, r)
+ }
+
+ d1 := new(Int).Div(x, y)
+ m1 := new(Int).Mod(x, y)
+ if !isNormalized(d1) {
+ t.Errorf("#%d Div: %v is not normalized", i, *d1)
+ }
+ if !isNormalized(m1) {
+ t.Errorf("#%d Mod: %v is not normalized", i, *m1)
+ }
+ if d1.Cmp(d) != 0 || m1.Cmp(m) != 0 {
+ t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d1, m1, d, m)
+ }
+
+ d2, m2 := new(Int).DivMod(x, y, new(Int))
+ if !isNormalized(d2) {
+ t.Errorf("#%d Div: %v is not normalized", i, *d2)
+ }
+ if !isNormalized(m2) {
+ t.Errorf("#%d Mod: %v is not normalized", i, *m2)
+ }
+ if d2.Cmp(d) != 0 || m2.Cmp(m) != 0 {
+ t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d2, m2, d, m)
+ }
+ }
+}
+
+
+func checkSetBytes(b []byte) bool {
+ hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
+ hex2 := hex.EncodeToString(b)
+
+ for len(hex1) < len(hex2) {
+ hex1 = "0" + hex1
+ }
+
+ for len(hex1) > len(hex2) {
+ hex2 = "0" + hex2
+ }
+
+ return hex1 == hex2
+}
+
+
+func TestSetBytes(t *testing.T) {
+ if err := quick.Check(checkSetBytes, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+
+func checkBytes(b []byte) bool {
+ b2 := new(Int).SetBytes(b).Bytes()
+ return bytes.Compare(b, b2) == 0
+}
+
+
+func TestBytes(t *testing.T) {
+ if err := quick.Check(checkSetBytes, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+
+func checkQuo(x, y []byte) bool {
+ u := new(Int).SetBytes(x)
+ v := new(Int).SetBytes(y)
+
+ if len(v.abs) == 0 {
+ return true
+ }
+
+ r := new(Int)
+ q, r := new(Int).QuoRem(u, v, r)
+
+ if r.Cmp(v) >= 0 {
+ return false
+ }
+
+ uprime := new(Int).Set(q)
+ uprime.Mul(uprime, v)
+ uprime.Add(uprime, r)
+
+ return uprime.Cmp(u) == 0
+}
+
+
+var quoTests = []struct {
+ x, y string
+ q, r string
+}{
+ {
+ "476217953993950760840509444250624797097991362735329973741718102894495832294430498335824897858659711275234906400899559094370964723884706254265559534144986498357",
+ "9353930466774385905609975137998169297361893554149986716853295022578535724979483772383667534691121982974895531435241089241440253066816724367338287092081996",
+ "50911",
+ "1",
+ },
+ {
+ "11510768301994997771168",
+ "1328165573307167369775",
+ "8",
+ "885443715537658812968",
+ },
+}
+
+
+func TestQuo(t *testing.T) {
+ if err := quick.Check(checkQuo, nil); err != nil {
+ t.Error(err)
+ }
+
+ for i, test := range quoTests {
+ x, _ := new(Int).SetString(test.x, 10)
+ y, _ := new(Int).SetString(test.y, 10)
+ expectedQ, _ := new(Int).SetString(test.q, 10)
+ expectedR, _ := new(Int).SetString(test.r, 10)
+
+ r := new(Int)
+ q, r := new(Int).QuoRem(x, y, r)
+
+ if q.Cmp(expectedQ) != 0 || r.Cmp(expectedR) != 0 {
+ t.Errorf("#%d got (%s, %s) want (%s, %s)", i, q, r, expectedQ, expectedR)
+ }
+ }
+}
+
+
+func TestQuoStepD6(t *testing.T) {
+ // See Knuth, Volume 2, section 4.3.1, exercise 21. This code exercises
+ // a code path which only triggers 1 in 10^{-19} cases.
+
+ u := &Int{false, nat{0, 0, 1 + 1<<(_W-1), _M ^ (1 << (_W - 1))}}
+ v := &Int{false, nat{5, 2 + 1<<(_W-1), 1 << (_W - 1)}}
+
+ r := new(Int)
+ q, r := new(Int).QuoRem(u, v, r)
+ const expectedQ64 = "18446744073709551613"
+ const expectedR64 = "3138550867693340382088035895064302439801311770021610913807"
+ const expectedQ32 = "4294967293"
+ const expectedR32 = "39614081266355540837921718287"
+ if q.String() != expectedQ64 && q.String() != expectedQ32 ||
+ r.String() != expectedR64 && r.String() != expectedR32 {
+ t.Errorf("got (%s, %s) want (%s, %s) or (%s, %s)", q, r, expectedQ64, expectedR64, expectedQ32, expectedR32)
+ }
+}
+
+
+var bitLenTests = []struct {
+ in string
+ out int
+}{
+ {"-1", 1},
+ {"0", 0},
+ {"1", 1},
+ {"2", 2},
+ {"4", 3},
+ {"0xabc", 12},
+ {"0x8000", 16},
+ {"0x80000000", 32},
+ {"0x800000000000", 48},
+ {"0x8000000000000000", 64},
+ {"0x80000000000000000000", 80},
+ {"-0x4000000000000000000000", 87},
+}
+
+
+func TestBitLen(t *testing.T) {
+ for i, test := range bitLenTests {
+ x, ok := new(Int).SetString(test.in, 0)
+ if !ok {
+ t.Errorf("#%d test input invalid: %s", i, test.in)
+ continue
+ }
+
+ if n := x.BitLen(); n != test.out {
+ t.Errorf("#%d got %d want %d", i, n, test.out)
+ }
+ }
+}
+
+
+var expTests = []struct {
+ x, y, m string
+ out string
+}{
+ {"5", "0", "", "1"},
+ {"-5", "0", "", "-1"},
+ {"5", "1", "", "5"},
+ {"-5", "1", "", "-5"},
+ {"-2", "3", "2", "0"},
+ {"5", "2", "", "25"},
+ {"1", "65537", "2", "1"},
+ {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+ {"0x8000000000000000", "2", "6719", "4944"},
+ {"0x8000000000000000", "3", "6719", "5447"},
+ {"0x8000000000000000", "1000", "6719", "1603"},
+ {"0x8000000000000000", "1000000", "6719", "3199"},
+ {
+ "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
+ "298472983472983471903246121093472394872319615612417471234712061",
+ "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
+ "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
+ },
+}
+
+
+func TestExp(t *testing.T) {
+ for i, test := range expTests {
+ x, ok1 := new(Int).SetString(test.x, 0)
+ y, ok2 := new(Int).SetString(test.y, 0)
+ out, ok3 := new(Int).SetString(test.out, 0)
+
+ var ok4 bool
+ var m *Int
+
+ if len(test.m) == 0 {
+ m, ok4 = nil, true
+ } else {
+ m, ok4 = new(Int).SetString(test.m, 0)
+ }
+
+ if !ok1 || !ok2 || !ok3 || !ok4 {
+ t.Errorf("#%d: error in input", i)
+ continue
+ }
+
+ z := y.Exp(x, y, m)
+ if !isNormalized(z) {
+ t.Errorf("#%d: %v is not normalized", i, *z)
+ }
+ if z.Cmp(out) != 0 {
+ t.Errorf("#%d: got %s want %s", i, z, out)
+ }
+ }
+}
+
+
+func checkGcd(aBytes, bBytes []byte) bool {
+ a := new(Int).SetBytes(aBytes)
+ b := new(Int).SetBytes(bBytes)
+
+ x := new(Int)
+ y := new(Int)
+ d := new(Int)
+
+ GcdInt(d, x, y, a, b)
+ x.Mul(x, a)
+ y.Mul(y, b)
+ x.Add(x, y)
+
+ return x.Cmp(d) == 0
+}
+
+
+var gcdTests = []struct {
+ a, b int64
+ d, x, y int64
+}{
+ {120, 23, 1, -9, 47},
+}
+
+
+func TestGcd(t *testing.T) {
+ for i, test := range gcdTests {
+ a := NewInt(test.a)
+ b := NewInt(test.b)
+
+ x := new(Int)
+ y := new(Int)
+ d := new(Int)
+
+ expectedX := NewInt(test.x)
+ expectedY := NewInt(test.y)
+ expectedD := NewInt(test.d)
+
+ GcdInt(d, x, y, a, b)
+
+ if expectedX.Cmp(x) != 0 ||
+ expectedY.Cmp(y) != 0 ||
+ expectedD.Cmp(d) != 0 {
+ t.Errorf("#%d got (%s %s %s) want (%s %s %s)", i, x, y, d, expectedX, expectedY, expectedD)
+ }
+ }
+
+ quick.Check(checkGcd, nil)
+}
+
+
+var primes = []string{
+ "2",
+ "3",
+ "5",
+ "7",
+ "11",
+
+ "13756265695458089029",
+ "13496181268022124907",
+ "10953742525620032441",
+ "17908251027575790097",
+
+ // http://code.google.com/p/go/issues/detail?id=638
+ "18699199384836356663",
+
+ "98920366548084643601728869055592650835572950932266967461790948584315647051443",
+ "94560208308847015747498523884063394671606671904944666360068158221458669711639",
+
+ // http://primes.utm.edu/lists/small/small3.html
+ "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
+ "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
+ "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
+ "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
+}
+
+
+var composites = []string{
+ "21284175091214687912771199898307297748211672914763848041968395774954376176754",
+ "6084766654921918907427900243509372380954290099172559290432744450051395395951",
+ "84594350493221918389213352992032324280367711247940675652888030554255915464401",
+ "82793403787388584738507275144194252681",
+}
+
+
+func TestProbablyPrime(t *testing.T) {
+ for i, s := range primes {
+ p, _ := new(Int).SetString(s, 10)
+ if !ProbablyPrime(p, 20) {
+ t.Errorf("#%d prime found to be non-prime (%s)", i, s)
+ }
+ }
+
+ for i, s := range composites {
+ c, _ := new(Int).SetString(s, 10)
+ if ProbablyPrime(c, 20) {
+ t.Errorf("#%d composite found to be prime (%s)", i, s)
+ }
+ }
+}
+
+
+type intShiftTest struct {
+ in string
+ shift uint
+ out string
+}
+
+
+var rshTests = []intShiftTest{
+ {"0", 0, "0"},
+ {"-0", 0, "0"},
+ {"0", 1, "0"},
+ {"0", 2, "0"},
+ {"1", 0, "1"},
+ {"1", 1, "0"},
+ {"1", 2, "0"},
+ {"2", 0, "2"},
+ {"2", 1, "1"},
+ {"-1", 0, "-1"},
+ {"-1", 1, "-1"},
+ {"-1", 10, "-1"},
+ {"-100", 2, "-25"},
+ {"-100", 3, "-13"},
+ {"-100", 100, "-1"},
+ {"4294967296", 0, "4294967296"},
+ {"4294967296", 1, "2147483648"},
+ {"4294967296", 2, "1073741824"},
+ {"18446744073709551616", 0, "18446744073709551616"},
+ {"18446744073709551616", 1, "9223372036854775808"},
+ {"18446744073709551616", 2, "4611686018427387904"},
+ {"18446744073709551616", 64, "1"},
+ {"340282366920938463463374607431768211456", 64, "18446744073709551616"},
+ {"340282366920938463463374607431768211456", 128, "1"},
+}
+
+
+func TestRsh(t *testing.T) {
+ for i, test := range rshTests {
+ in, _ := new(Int).SetString(test.in, 10)
+ expected, _ := new(Int).SetString(test.out, 10)
+ out := new(Int).Rsh(in, test.shift)
+
+ if !isNormalized(out) {
+ t.Errorf("#%d: %v is not normalized", i, *out)
+ }
+ if out.Cmp(expected) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, expected)
+ }
+ }
+}
+
+
+func TestRshSelf(t *testing.T) {
+ for i, test := range rshTests {
+ z, _ := new(Int).SetString(test.in, 10)
+ expected, _ := new(Int).SetString(test.out, 10)
+ z.Rsh(z, test.shift)
+
+ if !isNormalized(z) {
+ t.Errorf("#%d: %v is not normalized", i, *z)
+ }
+ if z.Cmp(expected) != 0 {
+ t.Errorf("#%d: got %s want %s", i, z, expected)
+ }
+ }
+}
+
+
+var lshTests = []intShiftTest{
+ {"0", 0, "0"},
+ {"0", 1, "0"},
+ {"0", 2, "0"},
+ {"1", 0, "1"},
+ {"1", 1, "2"},
+ {"1", 2, "4"},
+ {"2", 0, "2"},
+ {"2", 1, "4"},
+ {"2", 2, "8"},
+ {"-87", 1, "-174"},
+ {"4294967296", 0, "4294967296"},
+ {"4294967296", 1, "8589934592"},
+ {"4294967296", 2, "17179869184"},
+ {"18446744073709551616", 0, "18446744073709551616"},
+ {"9223372036854775808", 1, "18446744073709551616"},
+ {"4611686018427387904", 2, "18446744073709551616"},
+ {"1", 64, "18446744073709551616"},
+ {"18446744073709551616", 64, "340282366920938463463374607431768211456"},
+ {"1", 128, "340282366920938463463374607431768211456"},
+}
+
+
+func TestLsh(t *testing.T) {
+ for i, test := range lshTests {
+ in, _ := new(Int).SetString(test.in, 10)
+ expected, _ := new(Int).SetString(test.out, 10)
+ out := new(Int).Lsh(in, test.shift)
+
+ if !isNormalized(out) {
+ t.Errorf("#%d: %v is not normalized", i, *out)
+ }
+ if out.Cmp(expected) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, expected)
+ }
+ }
+}
+
+
+func TestLshSelf(t *testing.T) {
+ for i, test := range lshTests {
+ z, _ := new(Int).SetString(test.in, 10)
+ expected, _ := new(Int).SetString(test.out, 10)
+ z.Lsh(z, test.shift)
+
+ if !isNormalized(z) {
+ t.Errorf("#%d: %v is not normalized", i, *z)
+ }
+ if z.Cmp(expected) != 0 {
+ t.Errorf("#%d: got %s want %s", i, z, expected)
+ }
+ }
+}
+
+
+func TestLshRsh(t *testing.T) {
+ for i, test := range rshTests {
+ in, _ := new(Int).SetString(test.in, 10)
+ out := new(Int).Lsh(in, test.shift)
+ out = out.Rsh(out, test.shift)
+
+ if !isNormalized(out) {
+ t.Errorf("#%d: %v is not normalized", i, *out)
+ }
+ if in.Cmp(out) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, in)
+ }
+ }
+ for i, test := range lshTests {
+ in, _ := new(Int).SetString(test.in, 10)
+ out := new(Int).Lsh(in, test.shift)
+ out.Rsh(out, test.shift)
+
+ if !isNormalized(out) {
+ t.Errorf("#%d: %v is not normalized", i, *out)
+ }
+ if in.Cmp(out) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, in)
+ }
+ }
+}
+
+
+var int64Tests = []int64{
+ 0,
+ 1,
+ -1,
+ 4294967295,
+ -4294967295,
+ 4294967296,
+ -4294967296,
+ 9223372036854775807,
+ -9223372036854775807,
+ -9223372036854775808,
+}
+
+
+func TestInt64(t *testing.T) {
+ for i, testVal := range int64Tests {
+ in := NewInt(testVal)
+ out := in.Int64()
+
+ if out != testVal {
+ t.Errorf("#%d got %d want %d", i, out, testVal)
+ }
+ }
+}
+
+
+var bitwiseTests = []struct {
+ x, y string
+ and, or, xor, andNot string
+}{
+ {"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"},
+ {"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"},
+ {"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"},
+ {"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"},
+ {"-0xaf", "-0x50", "-0xf0", "-0x0f", "0xe1", "0x41"},
+ {"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"},
+ {"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"},
+ {"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"},
+ {"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"},
+ {"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"},
+ {"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"},
+ {"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"},
+ {"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"},
+ {
+ "0x1000009dc6e3d9822cba04129bcbe3401",
+ "0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+ "0x1000001186210100001000009048c2001",
+ "0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
+ "0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
+ "0x8c40c2d8822caa04120b8321400",
+ },
+ {
+ "0x1000009dc6e3d9822cba04129bcbe3401",
+ "-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+ "0x8c40c2d8822caa04120b8321401",
+ "-0xb9bd7d543685789d57ca918e82229142459020483cd2014001fd",
+ "-0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fe",
+ "0x1000001186210100001000009048c2000",
+ },
+ {
+ "-0x1000009dc6e3d9822cba04129bcbe3401",
+ "-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+ "-0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
+ "-0x1000001186210100001000009048c2001",
+ "0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
+ "0xb9bd7d543685789d57ca918e82229142459020483cd2014001fc",
+ },
+}
+
+
+type bitFun func(z, x, y *Int) *Int
+
+func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
+ expected := new(Int)
+ expected.SetString(exp, 0)
+
+ out := f(new(Int), x, y)
+ if out.Cmp(expected) != 0 {
+ t.Errorf("%s: got %s want %s", msg, out, expected)
+ }
+}
+
+
+func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
+ self := new(Int)
+ self.Set(x)
+ expected := new(Int)
+ expected.SetString(exp, 0)
+
+ self = f(self, self, y)
+ if self.Cmp(expected) != 0 {
+ t.Errorf("%s: got %s want %s", msg, self, expected)
+ }
+}
+
+
+func TestBitwise(t *testing.T) {
+ x := new(Int)
+ y := new(Int)
+ for _, test := range bitwiseTests {
+ x.SetString(test.x, 0)
+ y.SetString(test.y, 0)
+
+ testBitFun(t, "and", (*Int).And, x, y, test.and)
+ testBitFunSelf(t, "and", (*Int).And, x, y, test.and)
+ testBitFun(t, "andNot", (*Int).AndNot, x, y, test.andNot)
+ testBitFunSelf(t, "andNot", (*Int).AndNot, x, y, test.andNot)
+ testBitFun(t, "or", (*Int).Or, x, y, test.or)
+ testBitFunSelf(t, "or", (*Int).Or, x, y, test.or)
+ testBitFun(t, "xor", (*Int).Xor, x, y, test.xor)
+ testBitFunSelf(t, "xor", (*Int).Xor, x, y, test.xor)
+ }
+}
+
+
+var notTests = []struct {
+ in string
+ out string
+}{
+ {"0", "-1"},
+ {"1", "-2"},
+ {"7", "-8"},
+ {"0", "-1"},
+ {"-81910", "81909"},
+ {
+ "298472983472983471903246121093472394872319615612417471234712061",
+ "-298472983472983471903246121093472394872319615612417471234712062",
+ },
+}
+
+func TestNot(t *testing.T) {
+ in := new(Int)
+ out := new(Int)
+ expected := new(Int)
+ for i, test := range notTests {
+ in.SetString(test.in, 10)
+ expected.SetString(test.out, 10)
+ out = out.Not(in)
+ if out.Cmp(expected) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, expected)
+ }
+ out = out.Not(out)
+ if out.Cmp(in) != 0 {
+ t.Errorf("#%d: got %s want %s", i, out, in)
+ }
+ }
+}
+
+
+var modInverseTests = []struct {
+ element string
+ prime string
+}{
+ {"1", "7"},
+ {"1", "13"},
+ {"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
+}
+
+func TestModInverse(t *testing.T) {
+ var element, prime Int
+ one := NewInt(1)
+ for i, test := range modInverseTests {
+ (&element).SetString(test.element, 10)
+ (&prime).SetString(test.prime, 10)
+ inverse := new(Int).ModInverse(&element, &prime)
+ inverse.Mul(inverse, &element)
+ inverse.Mod(inverse, &prime)
+ if inverse.Cmp(one) != 0 {
+ t.Errorf("#%d: failed (e·e^(-1)=%s)", i, inverse)
+ }
+ }
+}
diff --git a/libgo/go/big/nat.go b/libgo/go/big/nat.go
new file mode 100644
index 000000000..a308f69e8
--- /dev/null
+++ b/libgo/go/big/nat.go
@@ -0,0 +1,1067 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains operations on unsigned multi-precision integers.
+// These are the building blocks for the operations on signed integers
+// and rationals.
+
+// This package implements multi-precision arithmetic (big numbers).
+// The following numeric types are supported:
+//
+// - Int signed integers
+// - Rat rational numbers
+//
+// All methods on Int take the result as the receiver; if it is one
+// of the operands it may be overwritten (and its memory reused).
+// To enable chaining of operations, the result is also returned.
+//
+package big
+
+import "rand"
+
+// An unsigned integer x of the form
+//
+// x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
+//
+// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n,
+// with the digits x[i] as the slice elements.
+//
+// A number is normalized if the slice contains no leading 0 digits.
+// During arithmetic operations, denormalized values may occur but are
+// always normalized before returning the final result. The normalized
+// representation of 0 is the empty or nil slice (length = 0).
+
+type nat []Word
+
+var (
+ natOne = nat{1}
+ natTwo = nat{2}
+ natTen = nat{10}
+)
+
+
+func (z nat) clear() {
+ for i := range z {
+ z[i] = 0
+ }
+}
+
+
+func (z nat) norm() nat {
+ i := len(z)
+ for i > 0 && z[i-1] == 0 {
+ i--
+ }
+ return z[0:i]
+}
+
+
+func (z nat) make(n int) nat {
+ if n <= cap(z) {
+ return z[0:n] // reuse z
+ }
+ // Choosing a good value for e has significant performance impact
+ // because it increases the chance that a value can be reused.
+ const e = 4 // extra capacity
+ return make(nat, n, n+e)
+}
+
+
+func (z nat) setWord(x Word) nat {
+ if x == 0 {
+ return z.make(0)
+ }
+ z = z.make(1)
+ z[0] = x
+ return z
+}
+
+
+func (z nat) setUint64(x uint64) nat {
+ // single-digit values
+ if w := Word(x); uint64(w) == x {
+ return z.setWord(w)
+ }
+
+ // compute number of words n required to represent x
+ n := 0
+ for t := x; t > 0; t >>= _W {
+ n++
+ }
+
+ // split x into n words
+ z = z.make(n)
+ for i := range z {
+ z[i] = Word(x & _M)
+ x >>= _W
+ }
+
+ return z
+}
+
+
+func (z nat) set(x nat) nat {
+ z = z.make(len(x))
+ copy(z, x)
+ return z
+}
+
+
+func (z nat) add(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+
+ switch {
+ case m < n:
+ return z.add(y, x)
+ case m == 0:
+ // n == 0 because m >= n; result is 0
+ return z.make(0)
+ case n == 0:
+ // result is x
+ return z.set(x)
+ }
+ // m > 0
+
+ z = z.make(m + 1)
+ c := addVV(z[0:n], x, y)
+ if m > n {
+ c = addVW(z[n:m], x[n:], c)
+ }
+ z[m] = c
+
+ return z.norm()
+}
+
+
+func (z nat) sub(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+
+ switch {
+ case m < n:
+ panic("underflow")
+ case m == 0:
+ // n == 0 because m >= n; result is 0
+ return z.make(0)
+ case n == 0:
+ // result is x
+ return z.set(x)
+ }
+ // m > 0
+
+ z = z.make(m)
+ c := subVV(z[0:n], x, y)
+ if m > n {
+ c = subVW(z[n:], x[n:], c)
+ }
+ if c != 0 {
+ panic("underflow")
+ }
+
+ return z.norm()
+}
+
+
+func (x nat) cmp(y nat) (r int) {
+ m := len(x)
+ n := len(y)
+ if m != n || m == 0 {
+ switch {
+ case m < n:
+ r = -1
+ case m > n:
+ r = 1
+ }
+ return
+ }
+
+ i := m - 1
+ for i > 0 && x[i] == y[i] {
+ i--
+ }
+
+ switch {
+ case x[i] < y[i]:
+ r = -1
+ case x[i] > y[i]:
+ r = 1
+ }
+ return
+}
+
+
+func (z nat) mulAddWW(x nat, y, r Word) nat {
+ m := len(x)
+ if m == 0 || y == 0 {
+ return z.setWord(r) // result is r
+ }
+ // m > 0
+
+ z = z.make(m + 1)
+ z[m] = mulAddVWW(z[0:m], x, y, r)
+
+ return z.norm()
+}
+
+
+// basicMul multiplies x and y and leaves the result in z.
+// The (non-normalized) result is placed in z[0 : len(x) + len(y)].
+func basicMul(z, x, y nat) {
+ z[0 : len(x)+len(y)].clear() // initialize z
+ for i, d := range y {
+ if d != 0 {
+ z[len(x)+i] = addMulVVW(z[i:i+len(x)], x, d)
+ }
+ }
+}
+
+
+// Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks.
+// Factored out for readability - do not use outside karatsuba.
+func karatsubaAdd(z, x nat, n int) {
+ if c := addVV(z[0:n], z, x); c != 0 {
+ addVW(z[n:n+n>>1], z[n:], c)
+ }
+}
+
+
+// Like karatsubaAdd, but does subtract.
+func karatsubaSub(z, x nat, n int) {
+ if c := subVV(z[0:n], z, x); c != 0 {
+ subVW(z[n:n+n>>1], z[n:], c)
+ }
+}
+
+
+// Operands that are shorter than karatsubaThreshold are multiplied using
+// "grade school" multiplication; for longer operands the Karatsuba algorithm
+// is used.
+var karatsubaThreshold int = 32 // computed by calibrate.go
+
+// karatsuba multiplies x and y and leaves the result in z.
+// Both x and y must have the same length n and n must be a
+// power of 2. The result vector z must have len(z) >= 6*n.
+// The (non-normalized) result is placed in z[0 : 2*n].
+func karatsuba(z, x, y nat) {
+ n := len(y)
+
+ // Switch to basic multiplication if numbers are odd or small.
+ // (n is always even if karatsubaThreshold is even, but be
+ // conservative)
+ if n&1 != 0 || n < karatsubaThreshold || n < 2 {
+ basicMul(z, x, y)
+ return
+ }
+ // n&1 == 0 && n >= karatsubaThreshold && n >= 2
+
+ // Karatsuba multiplication is based on the observation that
+ // for two numbers x and y with:
+ //
+ // x = x1*b + x0
+ // y = y1*b + y0
+ //
+ // the product x*y can be obtained with 3 products z2, z1, z0
+ // instead of 4:
+ //
+ // x*y = x1*y1*b*b + (x1*y0 + x0*y1)*b + x0*y0
+ // = z2*b*b + z1*b + z0
+ //
+ // with:
+ //
+ // xd = x1 - x0
+ // yd = y0 - y1
+ //
+ // z1 = xd*yd + z1 + z0
+ // = (x1-x0)*(y0 - y1) + z1 + z0
+ // = x1*y0 - x1*y1 - x0*y0 + x0*y1 + z1 + z0
+ // = x1*y0 - z1 - z0 + x0*y1 + z1 + z0
+ // = x1*y0 + x0*y1
+
+ // split x, y into "digits"
+ n2 := n >> 1 // n2 >= 1
+ x1, x0 := x[n2:], x[0:n2] // x = x1*b + y0
+ y1, y0 := y[n2:], y[0:n2] // y = y1*b + y0
+
+ // z is used for the result and temporary storage:
+ //
+ // 6*n 5*n 4*n 3*n 2*n 1*n 0*n
+ // z = [z2 copy|z0 copy| xd*yd | yd:xd | x1*y1 | x0*y0 ]
+ //
+ // For each recursive call of karatsuba, an unused slice of
+ // z is passed in that has (at least) half the length of the
+ // caller's z.
+
+ // compute z0 and z2 with the result "in place" in z
+ karatsuba(z, x0, y0) // z0 = x0*y0
+ karatsuba(z[n:], x1, y1) // z2 = x1*y1
+
+ // compute xd (or the negative value if underflow occurs)
+ s := 1 // sign of product xd*yd
+ xd := z[2*n : 2*n+n2]
+ if subVV(xd, x1, x0) != 0 { // x1-x0
+ s = -s
+ subVV(xd, x0, x1) // x0-x1
+ }
+
+ // compute yd (or the negative value if underflow occurs)
+ yd := z[2*n+n2 : 3*n]
+ if subVV(yd, y0, y1) != 0 { // y0-y1
+ s = -s
+ subVV(yd, y1, y0) // y1-y0
+ }
+
+ // p = (x1-x0)*(y0-y1) == x1*y0 - x1*y1 - x0*y0 + x0*y1 for s > 0
+ // p = (x0-x1)*(y0-y1) == x0*y0 - x0*y1 - x1*y0 + x1*y1 for s < 0
+ p := z[n*3:]
+ karatsuba(p, xd, yd)
+
+ // save original z2:z0
+ // (ok to use upper half of z since we're done recursing)
+ r := z[n*4:]
+ copy(r, z)
+
+ // add up all partial products
+ //
+ // 2*n n 0
+ // z = [ z2 | z0 ]
+ // + [ z0 ]
+ // + [ z2 ]
+ // + [ p ]
+ //
+ karatsubaAdd(z[n2:], r, n)
+ karatsubaAdd(z[n2:], r[n:], n)
+ if s > 0 {
+ karatsubaAdd(z[n2:], p, n)
+ } else {
+ karatsubaSub(z[n2:], p, n)
+ }
+}
+
+
+// alias returns true if x and y share the same base array.
+func alias(x, y nat) bool {
+ return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1]
+}
+
+
+// addAt implements z += x*(1<<(_W*i)); z must be long enough.
+// (we don't use nat.add because we need z to stay the same
+// slice, and we don't need to normalize z after each addition)
+func addAt(z, x nat, i int) {
+ if n := len(x); n > 0 {
+ if c := addVV(z[i:i+n], z[i:], x); c != 0 {
+ j := i + n
+ if j < len(z) {
+ addVW(z[j:], z[j:], c)
+ }
+ }
+ }
+}
+
+
+func max(x, y int) int {
+ if x > y {
+ return x
+ }
+ return y
+}
+
+
+// karatsubaLen computes an approximation to the maximum k <= n such that
+// k = p<<i for a number p <= karatsubaThreshold and an i >= 0. Thus, the
+// result is the largest number that can be divided repeatedly by 2 before
+// becoming about the value of karatsubaThreshold.
+func karatsubaLen(n int) int {
+ i := uint(0)
+ for n > karatsubaThreshold {
+ n >>= 1
+ i++
+ }
+ return n << i
+}
+
+
+func (z nat) mul(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+
+ switch {
+ case m < n:
+ return z.mul(y, x)
+ case m == 0 || n == 0:
+ return z.make(0)
+ case n == 1:
+ return z.mulAddWW(x, y[0], 0)
+ }
+ // m >= n > 1
+
+ // determine if z can be reused
+ if alias(z, x) || alias(z, y) {
+ z = nil // z is an alias for x or y - cannot reuse
+ }
+
+ // use basic multiplication if the numbers are small
+ if n < karatsubaThreshold || n < 2 {
+ z = z.make(m + n)
+ basicMul(z, x, y)
+ return z.norm()
+ }
+ // m >= n && n >= karatsubaThreshold && n >= 2
+
+ // determine Karatsuba length k such that
+ //
+ // x = x1*b + x0
+ // y = y1*b + y0 (and k <= len(y), which implies k <= len(x))
+ // b = 1<<(_W*k) ("base" of digits xi, yi)
+ //
+ k := karatsubaLen(n)
+ // k <= n
+
+ // multiply x0 and y0 via Karatsuba
+ x0 := x[0:k] // x0 is not normalized
+ y0 := y[0:k] // y0 is not normalized
+ z = z.make(max(6*k, m+n)) // enough space for karatsuba of x0*y0 and full result of x*y
+ karatsuba(z, x0, y0)
+ z = z[0 : m+n] // z has final length but may be incomplete, upper portion is garbage
+
+ // If x1 and/or y1 are not 0, add missing terms to z explicitly:
+ //
+ // m+n 2*k 0
+ // z = [ ... | x0*y0 ]
+ // + [ x1*y1 ]
+ // + [ x1*y0 ]
+ // + [ x0*y1 ]
+ //
+ if k < n || m != n {
+ x1 := x[k:] // x1 is normalized because x is
+ y1 := y[k:] // y1 is normalized because y is
+ var t nat
+ t = t.mul(x1, y1)
+ copy(z[2*k:], t)
+ z[2*k+len(t):].clear() // upper portion of z is garbage
+ t = t.mul(x1, y0.norm())
+ addAt(z, t, k)
+ t = t.mul(x0.norm(), y1)
+ addAt(z, t, k)
+ }
+
+ return z.norm()
+}
+
+
+// mulRange computes the product of all the unsigned integers in the
+// range [a, b] inclusively. If a > b (empty range), the result is 1.
+func (z nat) mulRange(a, b uint64) nat {
+ switch {
+ case a == 0:
+ // cut long ranges short (optimization)
+ return z.setUint64(0)
+ case a > b:
+ return z.setUint64(1)
+ case a == b:
+ return z.setUint64(a)
+ case a+1 == b:
+ return z.mul(nat(nil).setUint64(a), nat(nil).setUint64(b))
+ }
+ m := (a + b) / 2
+ return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b))
+}
+
+
+// q = (x-r)/y, with 0 <= r < y
+func (z nat) divW(x nat, y Word) (q nat, r Word) {
+ m := len(x)
+ switch {
+ case y == 0:
+ panic("division by zero")
+ case y == 1:
+ q = z.set(x) // result is x
+ return
+ case m == 0:
+ q = z.make(0) // result is 0
+ return
+ }
+ // m > 0
+ z = z.make(m)
+ r = divWVW(z, 0, x, y)
+ q = z.norm()
+ return
+}
+
+
+func (z nat) div(z2, u, v nat) (q, r nat) {
+ if len(v) == 0 {
+ panic("division by zero")
+ }
+
+ if u.cmp(v) < 0 {
+ q = z.make(0)
+ r = z2.set(u)
+ return
+ }
+
+ if len(v) == 1 {
+ var rprime Word
+ q, rprime = z.divW(u, v[0])
+ if rprime > 0 {
+ r = z2.make(1)
+ r[0] = rprime
+ } else {
+ r = z2.make(0)
+ }
+ return
+ }
+
+ q, r = z.divLarge(z2, u, v)
+ return
+}
+
+
+// q = (uIn-r)/v, with 0 <= r < y
+// Uses z as storage for q, and u as storage for r if possible.
+// See Knuth, Volume 2, section 4.3.1, Algorithm D.
+// Preconditions:
+// len(v) >= 2
+// len(uIn) >= len(v)
+func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
+ n := len(v)
+ m := len(uIn) - n
+
+ // determine if z can be reused
+ // TODO(gri) should find a better solution - this if statement
+ // is very costly (see e.g. time pidigits -s -n 10000)
+ if alias(z, uIn) || alias(z, v) {
+ z = nil // z is an alias for uIn or v - cannot reuse
+ }
+ q = z.make(m + 1)
+
+ qhatv := make(nat, n+1)
+ if alias(u, uIn) || alias(u, v) {
+ u = nil // u is an alias for uIn or v - cannot reuse
+ }
+ u = u.make(len(uIn) + 1)
+ u.clear()
+
+ // D1.
+ shift := Word(leadingZeros(v[n-1]))
+ shlVW(v, v, shift)
+ u[len(uIn)] = shlVW(u[0:len(uIn)], uIn, shift)
+
+ // D2.
+ for j := m; j >= 0; j-- {
+ // D3.
+ qhat := Word(_M)
+ if u[j+n] != v[n-1] {
+ var rhat Word
+ qhat, rhat = divWW(u[j+n], u[j+n-1], v[n-1])
+
+ // x1 | x2 = q̂v_{n-2}
+ x1, x2 := mulWW(qhat, v[n-2])
+ // test if q̂v_{n-2} > br̂ + u_{j+n-2}
+ for greaterThan(x1, x2, rhat, u[j+n-2]) {
+ qhat--
+ prevRhat := rhat
+ rhat += v[n-1]
+ // v[n-1] >= 0, so this tests for overflow.
+ if rhat < prevRhat {
+ break
+ }
+ x1, x2 = mulWW(qhat, v[n-2])
+ }
+ }
+
+ // D4.
+ qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0)
+
+ c := subVV(u[j:j+len(qhatv)], u[j:], qhatv)
+ if c != 0 {
+ c := addVV(u[j:j+n], u[j:], v)
+ u[j+n] += c
+ qhat--
+ }
+
+ q[j] = qhat
+ }
+
+ q = q.norm()
+ shrVW(u, u, shift)
+ shrVW(v, v, shift)
+ r = u.norm()
+
+ return q, r
+}
+
+
+// Length of x in bits. x must be normalized.
+func (x nat) bitLen() int {
+ if i := len(x) - 1; i >= 0 {
+ return i*_W + bitLen(x[i])
+ }
+ return 0
+}
+
+
+func hexValue(ch byte) int {
+ var d byte
+ switch {
+ case '0' <= ch && ch <= '9':
+ d = ch - '0'
+ case 'a' <= ch && ch <= 'f':
+ d = ch - 'a' + 10
+ case 'A' <= ch && ch <= 'F':
+ d = ch - 'A' + 10
+ default:
+ return -1
+ }
+ return int(d)
+}
+
+
+// scan returns the natural number corresponding to the
+// longest possible prefix of s representing a natural number in a
+// given conversion base, the actual conversion base used, and the
+// prefix length. The syntax of natural numbers follows the syntax
+// of unsigned integer literals in Go.
+//
+// If the base argument is 0, the string prefix determines the actual
+// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
+// ``0'' prefix selects base 8, and a ``0b'' or ``0B'' prefix selects
+// base 2. Otherwise the selected base is 10.
+//
+func (z nat) scan(s string, base int) (nat, int, int) {
+ // determine base if necessary
+ i, n := 0, len(s)
+ if base == 0 {
+ base = 10
+ if n > 0 && s[0] == '0' {
+ base, i = 8, 1
+ if n > 1 {
+ switch s[1] {
+ case 'x', 'X':
+ base, i = 16, 2
+ case 'b', 'B':
+ base, i = 2, 2
+ }
+ }
+ }
+ }
+
+ // reject illegal bases or strings consisting only of prefix
+ if base < 2 || 16 < base || (base != 8 && i >= n) {
+ return z, 0, 0
+ }
+
+ // convert string
+ z = z.make(0)
+ for ; i < n; i++ {
+ d := hexValue(s[i])
+ if 0 <= d && d < base {
+ z = z.mulAddWW(z, Word(base), Word(d))
+ } else {
+ break
+ }
+ }
+
+ return z.norm(), base, i
+}
+
+
+// string converts x to a string for a given base, with 2 <= base <= 16.
+// TODO(gri) in the style of the other routines, perhaps this should take
+// a []byte buffer and return it
+func (x nat) string(base int) string {
+ if base < 2 || 16 < base {
+ panic("illegal base")
+ }
+
+ if len(x) == 0 {
+ return "0"
+ }
+
+ // allocate buffer for conversion
+ i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
+ s := make([]byte, i)
+
+ // don't destroy x
+ q := nat(nil).set(x)
+
+ // convert
+ for len(q) > 0 {
+ i--
+ var r Word
+ q, r = q.divW(q, Word(base))
+ s[i] = "0123456789abcdef"[r]
+ }
+
+ return string(s[i:])
+}
+
+
+const deBruijn32 = 0x077CB531
+
+var deBruijn32Lookup = []byte{
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
+}
+
+const deBruijn64 = 0x03f79d71b4ca8b09
+
+var deBruijn64Lookup = []byte{
+ 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
+ 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
+ 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
+ 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
+}
+
+// trailingZeroBits returns the number of consecutive zero bits on the right
+// side of the given Word.
+// See Knuth, volume 4, section 7.3.1
+func trailingZeroBits(x Word) int {
+ // x & -x leaves only the right-most bit set in the word. Let k be the
+ // index of that bit. Since only a single bit is set, the value is two
+ // to the power of k. Multipling by a power of two is equivalent to
+ // left shifting, in this case by k bits. The de Bruijn constant is
+ // such that all six bit, consecutive substrings are distinct.
+ // Therefore, if we have a left shifted version of this constant we can
+ // find by how many bits it was shifted by looking at which six bit
+ // substring ended up at the top of the word.
+ switch _W {
+ case 32:
+ return int(deBruijn32Lookup[((x&-x)*deBruijn32)>>27])
+ case 64:
+ return int(deBruijn64Lookup[((x&-x)*(deBruijn64&_M))>>58])
+ default:
+ panic("Unknown word size")
+ }
+
+ return 0
+}
+
+
+// z = x << s
+func (z nat) shl(x nat, s uint) nat {
+ m := len(x)
+ if m == 0 {
+ return z.make(0)
+ }
+ // m > 0
+
+ n := m + int(s/_W)
+ z = z.make(n + 1)
+ z[n] = shlVW(z[n-m:n], x, Word(s%_W))
+ z[0 : n-m].clear()
+
+ return z.norm()
+}
+
+
+// z = x >> s
+func (z nat) shr(x nat, s uint) nat {
+ m := len(x)
+ n := m - int(s/_W)
+ if n <= 0 {
+ return z.make(0)
+ }
+ // n > 0
+
+ z = z.make(n)
+ shrVW(z, x[m-n:], Word(s%_W))
+
+ return z.norm()
+}
+
+
+func (z nat) and(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+ if m > n {
+ m = n
+ }
+ // m <= n
+
+ z = z.make(m)
+ for i := 0; i < m; i++ {
+ z[i] = x[i] & y[i]
+ }
+
+ return z.norm()
+}
+
+
+func (z nat) andNot(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+ if n > m {
+ n = m
+ }
+ // m >= n
+
+ z = z.make(m)
+ for i := 0; i < n; i++ {
+ z[i] = x[i] &^ y[i]
+ }
+ copy(z[n:m], x[n:m])
+
+ return z.norm()
+}
+
+
+func (z nat) or(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+ s := x
+ if m < n {
+ n, m = m, n
+ s = y
+ }
+ // m >= n
+
+ z = z.make(m)
+ for i := 0; i < n; i++ {
+ z[i] = x[i] | y[i]
+ }
+ copy(z[n:m], s[n:m])
+
+ return z.norm()
+}
+
+
+func (z nat) xor(x, y nat) nat {
+ m := len(x)
+ n := len(y)
+ s := x
+ if m < n {
+ n, m = m, n
+ s = y
+ }
+ // m >= n
+
+ z = z.make(m)
+ for i := 0; i < n; i++ {
+ z[i] = x[i] ^ y[i]
+ }
+ copy(z[n:m], s[n:m])
+
+ return z.norm()
+}
+
+
+// greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2)
+func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 }
+
+
+// modW returns x % d.
+func (x nat) modW(d Word) (r Word) {
+ // TODO(agl): we don't actually need to store the q value.
+ var q nat
+ q = q.make(len(x))
+ return divWVW(q, 0, x, d)
+}
+
+
+// powersOfTwoDecompose finds q and k such that q * 1<<k = n and q is odd.
+func (n nat) powersOfTwoDecompose() (q nat, k Word) {
+ if len(n) == 0 {
+ return n, 0
+ }
+
+ zeroWords := 0
+ for n[zeroWords] == 0 {
+ zeroWords++
+ }
+ // One of the words must be non-zero by invariant, therefore
+ // zeroWords < len(n).
+ x := trailingZeroBits(n[zeroWords])
+
+ q = q.make(len(n) - zeroWords)
+ shrVW(q, n[zeroWords:], Word(x))
+ q = q.norm()
+
+ k = Word(_W*zeroWords + x)
+ return
+}
+
+
+// random creates a random integer in [0..limit), using the space in z if
+// possible. n is the bit length of limit.
+func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
+ bitLengthOfMSW := uint(n % _W)
+ if bitLengthOfMSW == 0 {
+ bitLengthOfMSW = _W
+ }
+ mask := Word((1 << bitLengthOfMSW) - 1)
+ z = z.make(len(limit))
+
+ for {
+ for i := range z {
+ switch _W {
+ case 32:
+ z[i] = Word(rand.Uint32())
+ case 64:
+ z[i] = Word(rand.Uint32()) | Word(rand.Uint32())<<32
+ }
+ }
+
+ z[len(limit)-1] &= mask
+
+ if z.cmp(limit) < 0 {
+ break
+ }
+ }
+
+ return z.norm()
+}
+
+
+// If m != nil, expNN calculates x**y mod m. Otherwise it calculates x**y. It
+// reuses the storage of z if possible.
+func (z nat) expNN(x, y, m nat) nat {
+ if alias(z, x) || alias(z, y) {
+ // We cannot allow in place modification of x or y.
+ z = nil
+ }
+
+ if len(y) == 0 {
+ z = z.make(1)
+ z[0] = 1
+ return z
+ }
+
+ if m != nil {
+ // We likely end up being as long as the modulus.
+ z = z.make(len(m))
+ }
+ z = z.set(x)
+ v := y[len(y)-1]
+ // It's invalid for the most significant word to be zero, therefore we
+ // will find a one bit.
+ shift := leadingZeros(v) + 1
+ v <<= shift
+ var q nat
+
+ const mask = 1 << (_W - 1)
+
+ // We walk through the bits of the exponent one by one. Each time we
+ // see a bit, we square, thus doubling the power. If the bit is a one,
+ // we also multiply by x, thus adding one to the power.
+
+ w := _W - int(shift)
+ for j := 0; j < w; j++ {
+ z = z.mul(z, z)
+
+ if v&mask != 0 {
+ z = z.mul(z, x)
+ }
+
+ if m != nil {
+ q, z = q.div(z, z, m)
+ }
+
+ v <<= 1
+ }
+
+ for i := len(y) - 2; i >= 0; i-- {
+ v = y[i]
+
+ for j := 0; j < _W; j++ {
+ z = z.mul(z, z)
+
+ if v&mask != 0 {
+ z = z.mul(z, x)
+ }
+
+ if m != nil {
+ q, z = q.div(z, z, m)
+ }
+
+ v <<= 1
+ }
+ }
+
+ return z
+}
+
+
+// probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
+// If it returns true, n is prime with probability 1 - 1/4^reps.
+// If it returns false, n is not prime.
+func (n nat) probablyPrime(reps int) bool {
+ if len(n) == 0 {
+ return false
+ }
+
+ if len(n) == 1 {
+ if n[0] < 2 {
+ return false
+ }
+
+ if n[0]%2 == 0 {
+ return n[0] == 2
+ }
+
+ // We have to exclude these cases because we reject all
+ // multiples of these numbers below.
+ switch n[0] {
+ case 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53:
+ return true
+ }
+ }
+
+ const primesProduct32 = 0xC0CFD797 // Π {p ∈ primes, 2 < p <= 29}
+ const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
+
+ var r Word
+ switch _W {
+ case 32:
+ r = n.modW(primesProduct32)
+ case 64:
+ r = n.modW(primesProduct64 & _M)
+ default:
+ panic("Unknown word size")
+ }
+
+ if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
+ r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
+ return false
+ }
+
+ if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
+ r%43 == 0 || r%47 == 0 || r%53 == 0) {
+ return false
+ }
+
+ nm1 := nat(nil).sub(n, natOne)
+ // 1<<k * q = nm1;
+ q, k := nm1.powersOfTwoDecompose()
+
+ nm3 := nat(nil).sub(nm1, natTwo)
+ rand := rand.New(rand.NewSource(int64(n[0])))
+
+ var x, y, quotient nat
+ nm3Len := nm3.bitLen()
+
+NextRandom:
+ for i := 0; i < reps; i++ {
+ x = x.random(rand, nm3, nm3Len)
+ x = x.add(x, natTwo)
+ y = y.expNN(x, q, n)
+ if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
+ continue
+ }
+ for j := Word(1); j < k; j++ {
+ y = y.mul(y, y)
+ quotient, y = quotient.div(y, y, n)
+ if y.cmp(nm1) == 0 {
+ continue NextRandom
+ }
+ if y.cmp(natOne) == 0 {
+ return false
+ }
+ }
+ return false
+ }
+
+ return true
+}
diff --git a/libgo/go/big/nat_test.go b/libgo/go/big/nat_test.go
new file mode 100644
index 000000000..0bcb94554
--- /dev/null
+++ b/libgo/go/big/nat_test.go
@@ -0,0 +1,358 @@
+// 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 big
+
+import "testing"
+
+var cmpTests = []struct {
+ x, y nat
+ r int
+}{
+ {nil, nil, 0},
+ {nil, nat{}, 0},
+ {nat{}, nil, 0},
+ {nat{}, nat{}, 0},
+ {nat{0}, nat{0}, 0},
+ {nat{0}, nat{1}, -1},
+ {nat{1}, nat{0}, 1},
+ {nat{1}, nat{1}, 0},
+ {nat{0, _M}, nat{1}, 1},
+ {nat{1}, nat{0, _M}, -1},
+ {nat{1, _M}, nat{0, _M}, 1},
+ {nat{0, _M}, nat{1, _M}, -1},
+ {nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1},
+ {nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1},
+}
+
+
+func TestCmp(t *testing.T) {
+ for i, a := range cmpTests {
+ r := a.x.cmp(a.y)
+ if r != a.r {
+ t.Errorf("#%d got r = %v; want %v", i, r, a.r)
+ }
+ }
+}
+
+
+type funNN func(z, x, y nat) nat
+type argNN struct {
+ z, x, y nat
+}
+
+
+var sumNN = []argNN{
+ {},
+ {nat{1}, nil, nat{1}},
+ {nat{1111111110}, nat{123456789}, nat{987654321}},
+ {nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}},
+ {nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}},
+ {nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
+}
+
+
+var prodNN = []argNN{
+ {},
+ {nil, nil, nil},
+ {nil, nat{991}, nil},
+ {nat{991}, nat{991}, nat{1}},
+ {nat{991 * 991}, nat{991}, nat{991}},
+ {nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}},
+ {nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}},
+ {nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}},
+}
+
+
+func TestSet(t *testing.T) {
+ for _, a := range sumNN {
+ z := nat(nil).set(a.z)
+ if z.cmp(a.z) != 0 {
+ t.Errorf("got z = %v; want %v", z, a.z)
+ }
+ }
+}
+
+
+func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
+ z := f(nil, a.x, a.y)
+ if z.cmp(a.z) != 0 {
+ t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, z, a.z)
+ }
+}
+
+
+func TestFunNN(t *testing.T) {
+ for _, a := range sumNN {
+ arg := a
+ testFunNN(t, "add", nat.add, arg)
+
+ arg = argNN{a.z, a.y, a.x}
+ testFunNN(t, "add symmetric", nat.add, arg)
+
+ arg = argNN{a.x, a.z, a.y}
+ testFunNN(t, "sub", nat.sub, arg)
+
+ arg = argNN{a.y, a.z, a.x}
+ testFunNN(t, "sub symmetric", nat.sub, arg)
+ }
+
+ for _, a := range prodNN {
+ arg := a
+ testFunNN(t, "mul", nat.mul, arg)
+
+ arg = argNN{a.z, a.y, a.x}
+ testFunNN(t, "mul symmetric", nat.mul, arg)
+ }
+}
+
+
+var mulRangesN = []struct {
+ a, b uint64
+ prod string
+}{
+ {0, 0, "0"},
+ {1, 1, "1"},
+ {1, 2, "2"},
+ {1, 3, "6"},
+ {10, 10, "10"},
+ {0, 100, "0"},
+ {0, 1e9, "0"},
+ {1, 0, "1"}, // empty range
+ {100, 1, "1"}, // empty range
+ {1, 10, "3628800"}, // 10!
+ {1, 20, "2432902008176640000"}, // 20!
+ {1, 100,
+ "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000", // 100!
+ },
+}
+
+
+func TestMulRangeN(t *testing.T) {
+ for i, r := range mulRangesN {
+ prod := nat(nil).mulRange(r.a, r.b).string(10)
+ if prod != r.prod {
+ t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
+ }
+ }
+}
+
+
+var mulArg, mulTmp nat
+
+func init() {
+ const n = 1000
+ mulArg = make(nat, n)
+ for i := 0; i < n; i++ {
+ mulArg[i] = _M
+ }
+}
+
+
+func benchmarkMulLoad() {
+ for j := 1; j <= 10; j++ {
+ x := mulArg[0 : j*100]
+ mulTmp.mul(x, x)
+ }
+}
+
+
+func BenchmarkMul(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ benchmarkMulLoad()
+ }
+}
+
+
+var tab = []struct {
+ x nat
+ b int
+ s string
+}{
+ {nil, 10, "0"},
+ {nat{1}, 10, "1"},
+ {nat{10}, 10, "10"},
+ {nat{1234567890}, 10, "1234567890"},
+}
+
+
+func TestString(t *testing.T) {
+ for _, a := range tab {
+ s := a.x.string(a.b)
+ if s != a.s {
+ t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
+ }
+
+ x, b, n := nat(nil).scan(a.s, a.b)
+ if x.cmp(a.x) != 0 {
+ t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+ }
+ if b != a.b {
+ t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.b)
+ }
+ if n != len(a.s) {
+ t.Errorf("scan%+v\n\tgot n = %d; want %d", a, n, len(a.s))
+ }
+ }
+}
+
+
+func TestLeadingZeros(t *testing.T) {
+ var x Word = _B >> 1
+ for i := 0; i <= _W; i++ {
+ if int(leadingZeros(x)) != i {
+ t.Errorf("failed at %x: got %d want %d", x, leadingZeros(x), i)
+ }
+ x >>= 1
+ }
+}
+
+
+type shiftTest struct {
+ in nat
+ shift uint
+ out nat
+}
+
+
+var leftShiftTests = []shiftTest{
+ {nil, 0, nil},
+ {nil, 1, nil},
+ {natOne, 0, natOne},
+ {natOne, 1, natTwo},
+ {nat{1 << (_W - 1)}, 1, nat{0}},
+ {nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
+}
+
+
+func TestShiftLeft(t *testing.T) {
+ for i, test := range leftShiftTests {
+ var z nat
+ z = z.shl(test.in, test.shift)
+ for j, d := range test.out {
+ if j >= len(z) || z[j] != d {
+ t.Errorf("#%d: got: %v want: %v", i, z, test.out)
+ break
+ }
+ }
+ }
+}
+
+
+var rightShiftTests = []shiftTest{
+ {nil, 0, nil},
+ {nil, 1, nil},
+ {natOne, 0, natOne},
+ {natOne, 1, nil},
+ {natTwo, 1, natOne},
+ {nat{0, 1}, 1, nat{1 << (_W - 1)}},
+ {nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}},
+}
+
+
+func TestShiftRight(t *testing.T) {
+ for i, test := range rightShiftTests {
+ var z nat
+ z = z.shr(test.in, test.shift)
+ for j, d := range test.out {
+ if j >= len(z) || z[j] != d {
+ t.Errorf("#%d: got: %v want: %v", i, z, test.out)
+ break
+ }
+ }
+ }
+}
+
+
+type modWTest struct {
+ in string
+ dividend string
+ out string
+}
+
+
+var modWTests32 = []modWTest{
+ {"23492635982634928349238759823742", "252341", "220170"},
+}
+
+
+var modWTests64 = []modWTest{
+ {"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"},
+}
+
+
+func runModWTests(t *testing.T, tests []modWTest) {
+ for i, test := range tests {
+ in, _ := new(Int).SetString(test.in, 10)
+ d, _ := new(Int).SetString(test.dividend, 10)
+ out, _ := new(Int).SetString(test.out, 10)
+
+ r := in.abs.modW(d.abs[0])
+ if r != out.abs[0] {
+ t.Errorf("#%d failed: got %s want %s", i, r, out)
+ }
+ }
+}
+
+
+func TestModW(t *testing.T) {
+ if _W >= 32 {
+ runModWTests(t, modWTests32)
+ }
+ if _W >= 64 {
+ runModWTests(t, modWTests64)
+ }
+}
+
+
+func TestTrailingZeroBits(t *testing.T) {
+ var x Word
+ x--
+ for i := 0; i < _W; i++ {
+ if trailingZeroBits(x) != i {
+ t.Errorf("Failed at step %d: x: %x got: %d", i, x, trailingZeroBits(x))
+ }
+ x <<= 1
+ }
+}
+
+
+var expNNTests = []struct {
+ x, y, m string
+ out string
+}{
+ {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+ {"0x8000000000000000", "2", "6719", "4944"},
+ {"0x8000000000000000", "3", "6719", "5447"},
+ {"0x8000000000000000", "1000", "6719", "1603"},
+ {"0x8000000000000000", "1000000", "6719", "3199"},
+ {
+ "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
+ "298472983472983471903246121093472394872319615612417471234712061",
+ "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
+ "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
+ },
+}
+
+
+func TestExpNN(t *testing.T) {
+ for i, test := range expNNTests {
+ x, _, _ := nat(nil).scan(test.x, 0)
+ y, _, _ := nat(nil).scan(test.y, 0)
+ out, _, _ := nat(nil).scan(test.out, 0)
+
+ var m nat
+
+ if len(test.m) > 0 {
+ m, _, _ = nat(nil).scan(test.m, 0)
+ }
+
+ z := nat(nil).expNN(x, y, m)
+ if z.cmp(out) != 0 {
+ t.Errorf("#%d got %v want %v", i, z, out)
+ }
+ }
+}
diff --git a/libgo/go/big/rat.go b/libgo/go/big/rat.go
new file mode 100644
index 000000000..e70673a1c
--- /dev/null
+++ b/libgo/go/big/rat.go
@@ -0,0 +1,326 @@
+// 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.
+
+// This file implements multi-precision rational numbers.
+
+package big
+
+import "strings"
+
+// A Rat represents a quotient a/b of arbitrary precision. The zero value for
+// a Rat, 0/0, is not a legal Rat.
+type Rat struct {
+ a Int
+ b nat
+}
+
+
+// NewRat creates a new Rat with numerator a and denominator b.
+func NewRat(a, b int64) *Rat {
+ return new(Rat).SetFrac64(a, b)
+}
+
+
+// SetFrac sets z to a/b and returns z.
+func (z *Rat) SetFrac(a, b *Int) *Rat {
+ z.a.Set(a)
+ z.a.neg = a.neg != b.neg
+ z.b = z.b.set(b.abs)
+ return z.norm()
+}
+
+
+// SetFrac64 sets z to a/b and returns z.
+func (z *Rat) SetFrac64(a, b int64) *Rat {
+ z.a.SetInt64(a)
+ if b < 0 {
+ b = -b
+ z.a.neg = !z.a.neg
+ }
+ z.b = z.b.setUint64(uint64(b))
+ return z.norm()
+}
+
+
+// SetInt sets z to x (by making a copy of x) and returns z.
+func (z *Rat) SetInt(x *Int) *Rat {
+ z.a.Set(x)
+ z.b = z.b.setWord(1)
+ return z
+}
+
+
+// SetInt64 sets z to x and returns z.
+func (z *Rat) SetInt64(x int64) *Rat {
+ z.a.SetInt64(x)
+ z.b = z.b.setWord(1)
+ return z
+}
+
+
+// Sign returns:
+//
+// -1 if x < 0
+// 0 if x == 0
+// +1 if x > 0
+//
+func (x *Rat) Sign() int {
+ return x.a.Sign()
+}
+
+
+// IsInt returns true if the denominator of x is 1.
+func (x *Rat) IsInt() bool {
+ return len(x.b) == 1 && x.b[0] == 1
+}
+
+
+// Num returns the numerator of z; it may be <= 0.
+// The result is a reference to z's numerator; it
+// may change if a new value is assigned to z.
+func (z *Rat) Num() *Int {
+ return &z.a
+}
+
+
+// Demom returns the denominator of z; it is always > 0.
+// The result is a reference to z's denominator; it
+// may change if a new value is assigned to z.
+func (z *Rat) Denom() *Int {
+ return &Int{false, z.b}
+}
+
+
+func gcd(x, y nat) nat {
+ // Euclidean algorithm.
+ var a, b nat
+ a = a.set(x)
+ b = b.set(y)
+ for len(b) != 0 {
+ var q, r nat
+ _, r = q.div(r, a, b)
+ a = b
+ b = r
+ }
+ return a
+}
+
+
+func (z *Rat) norm() *Rat {
+ f := gcd(z.a.abs, z.b)
+ if len(z.a.abs) == 0 {
+ // z == 0
+ z.a.neg = false // normalize sign
+ z.b = z.b.setWord(1)
+ return z
+ }
+ if f.cmp(natOne) != 0 {
+ z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f)
+ z.b, _ = z.b.div(nil, z.b, f)
+ }
+ return z
+}
+
+
+func mulNat(x *Int, y nat) *Int {
+ var z Int
+ z.abs = z.abs.mul(x.abs, y)
+ z.neg = len(z.abs) > 0 && x.neg
+ return &z
+}
+
+
+// Cmp compares x and y and returns:
+//
+// -1 if x < y
+// 0 if x == y
+// +1 if x > y
+//
+func (x *Rat) Cmp(y *Rat) (r int) {
+ return mulNat(&x.a, y.b).Cmp(mulNat(&y.a, x.b))
+}
+
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Rat) Abs(x *Rat) *Rat {
+ z.a.Abs(&x.a)
+ z.b = z.b.set(x.b)
+ return z
+}
+
+
+// Add sets z to the sum x+y and returns z.
+func (z *Rat) Add(x, y *Rat) *Rat {
+ a1 := mulNat(&x.a, y.b)
+ a2 := mulNat(&y.a, x.b)
+ z.a.Add(a1, a2)
+ z.b = z.b.mul(x.b, y.b)
+ return z.norm()
+}
+
+
+// Sub sets z to the difference x-y and returns z.
+func (z *Rat) Sub(x, y *Rat) *Rat {
+ a1 := mulNat(&x.a, y.b)
+ a2 := mulNat(&y.a, x.b)
+ z.a.Sub(a1, a2)
+ z.b = z.b.mul(x.b, y.b)
+ return z.norm()
+}
+
+
+// Mul sets z to the product x*y and returns z.
+func (z *Rat) Mul(x, y *Rat) *Rat {
+ z.a.Mul(&x.a, &y.a)
+ z.b = z.b.mul(x.b, y.b)
+ return z.norm()
+}
+
+
+// Quo sets z to the quotient x/y and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+func (z *Rat) Quo(x, y *Rat) *Rat {
+ if len(y.a.abs) == 0 {
+ panic("division by zero")
+ }
+ a := mulNat(&x.a, y.b)
+ b := mulNat(&y.a, x.b)
+ z.a.abs = a.abs
+ z.b = b.abs
+ z.a.neg = a.neg != b.neg
+ return z.norm()
+}
+
+
+// Neg sets z to -x (by making a copy of x if necessary) and returns z.
+func (z *Rat) Neg(x *Rat) *Rat {
+ z.a.Neg(&x.a)
+ z.b = z.b.set(x.b)
+ return z
+}
+
+
+// Set sets z to x (by making a copy of x if necessary) and returns z.
+func (z *Rat) Set(x *Rat) *Rat {
+ z.a.Set(&x.a)
+ z.b = z.b.set(x.b)
+ return z
+}
+
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s can be given as a fraction "a/b" or as a floating-point number
+// optionally followed by an exponent. If the operation failed, the value of z
+// is undefined.
+func (z *Rat) SetString(s string) (*Rat, bool) {
+ if len(s) == 0 {
+ return z, false
+ }
+
+ // check for a quotient
+ sep := strings.Index(s, "/")
+ if sep >= 0 {
+ if _, ok := z.a.SetString(s[0:sep], 10); !ok {
+ return z, false
+ }
+ s = s[sep+1:]
+ var n int
+ if z.b, _, n = z.b.scan(s, 10); n != len(s) {
+ return z, false
+ }
+ return z.norm(), true
+ }
+
+ // check for a decimal point
+ sep = strings.Index(s, ".")
+ // check for an exponent
+ e := strings.IndexAny(s, "eE")
+ var exp Int
+ if e >= 0 {
+ if e < sep {
+ // The E must come after the decimal point.
+ return z, false
+ }
+ if _, ok := exp.SetString(s[e+1:], 10); !ok {
+ return z, false
+ }
+ s = s[0:e]
+ }
+ if sep >= 0 {
+ s = s[0:sep] + s[sep+1:]
+ exp.Sub(&exp, NewInt(int64(len(s)-sep)))
+ }
+
+ if _, ok := z.a.SetString(s, 10); !ok {
+ return z, false
+ }
+ powTen := nat{}.expNN(natTen, exp.abs, nil)
+ if exp.neg {
+ z.b = powTen
+ z.norm()
+ } else {
+ z.a.abs = z.a.abs.mul(z.a.abs, powTen)
+ z.b = z.b.setWord(1)
+ }
+
+ return z, true
+}
+
+
+// String returns a string representation of z in the form "a/b" (even if b == 1).
+func (z *Rat) String() string {
+ return z.a.String() + "/" + z.b.string(10)
+}
+
+
+// RatString returns a string representation of z in the form "a/b" if b != 1,
+// and in the form "a" if b == 1.
+func (z *Rat) RatString() string {
+ if z.IsInt() {
+ return z.a.String()
+ }
+ return z.String()
+}
+
+
+// FloatString returns a string representation of z in decimal form with prec
+// digits of precision after the decimal point and the last digit rounded.
+func (z *Rat) FloatString(prec int) string {
+ if z.IsInt() {
+ return z.a.String()
+ }
+
+ q, r := nat{}.div(nat{}, z.a.abs, z.b)
+
+ p := natOne
+ if prec > 0 {
+ p = nat{}.expNN(natTen, nat{}.setUint64(uint64(prec)), nil)
+ }
+
+ r = r.mul(r, p)
+ r, r2 := r.div(nat{}, r, z.b)
+
+ // see if we need to round up
+ r2 = r2.add(r2, r2)
+ if z.b.cmp(r2) <= 0 {
+ r = r.add(r, natOne)
+ if r.cmp(p) >= 0 {
+ q = nat{}.add(q, natOne)
+ r = nat{}.sub(r, p)
+ }
+ }
+
+ s := q.string(10)
+ if z.a.neg {
+ s = "-" + s
+ }
+
+ if prec > 0 {
+ rs := r.string(10)
+ leadingZeros := prec - len(rs)
+ s += "." + strings.Repeat("0", leadingZeros) + rs
+ }
+
+ return s
+}
diff --git a/libgo/go/big/rat_test.go b/libgo/go/big/rat_test.go
new file mode 100644
index 000000000..8f42949b0
--- /dev/null
+++ b/libgo/go/big/rat_test.go
@@ -0,0 +1,282 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import "testing"
+
+
+var setStringTests = []struct {
+ in, out string
+ ok bool
+}{
+ {"0", "0", true},
+ {"-0", "0", true},
+ {"1", "1", true},
+ {"-1", "-1", true},
+ {"1.", "1", true},
+ {"1e0", "1", true},
+ {"1.e1", "10", true},
+ {in: "1e", ok: false},
+ {in: "1.e", ok: false},
+ {in: "1e+14e-5", ok: false},
+ {in: "1e4.5", ok: false},
+ {in: "r", ok: false},
+ {in: "a/b", ok: false},
+ {in: "a.b", ok: false},
+ {"-0.1", "-1/10", true},
+ {"-.1", "-1/10", true},
+ {"2/4", "1/2", true},
+ {".25", "1/4", true},
+ {"-1/5", "-1/5", true},
+ {"8129567.7690E14", "812956776900000000000", true},
+ {"78189e+4", "781890000", true},
+ {"553019.8935e+8", "55301989350000", true},
+ {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
+ {"9877861857500000E-7", "3951144743/4", true},
+ {"2169378.417e-3", "2169378417/1000000", true},
+ {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
+ {"53/70893980658822810696", "53/70893980658822810696", true},
+ {"106/141787961317645621392", "53/70893980658822810696", true},
+ {"204211327800791583.81095", "4084226556015831676219/20000", true},
+}
+
+func TestRatSetString(t *testing.T) {
+ for i, test := range setStringTests {
+ x, ok := new(Rat).SetString(test.in)
+
+ if ok != test.ok || ok && x.RatString() != test.out {
+ t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+ }
+ }
+}
+
+
+var floatStringTests = []struct {
+ in string
+ prec int
+ out string
+}{
+ {"0", 0, "0"},
+ {"0", 4, "0"},
+ {"1", 0, "1"},
+ {"1", 2, "1"},
+ {"-1", 0, "-1"},
+ {".25", 2, "0.25"},
+ {".25", 1, "0.3"},
+ {"-1/3", 3, "-0.333"},
+ {"-2/3", 4, "-0.6667"},
+ {"0.96", 1, "1.0"},
+ {"0.999", 2, "1.00"},
+ {"0.9", 0, "1"},
+ {".25", -1, "0"},
+ {".55", -1, "1"},
+}
+
+func TestFloatString(t *testing.T) {
+ for i, test := range floatStringTests {
+ x, _ := new(Rat).SetString(test.in)
+
+ if x.FloatString(test.prec) != test.out {
+ t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
+ }
+ }
+}
+
+
+func TestRatSign(t *testing.T) {
+ zero := NewRat(0, 1)
+ for _, a := range setStringTests {
+ var x Rat
+ x.SetString(a.in)
+ s := x.Sign()
+ e := x.Cmp(zero)
+ if s != e {
+ t.Errorf("got %d; want %d for z = %v", s, e, &x)
+ }
+ }
+}
+
+
+var ratCmpTests = []struct {
+ rat1, rat2 string
+ out int
+}{
+ {"0", "0/1", 0},
+ {"1/1", "1", 0},
+ {"-1", "-2/2", 0},
+ {"1", "0", 1},
+ {"0/1", "1/1", -1},
+ {"-5/1434770811533343057144", "-5/1434770811533343057145", -1},
+ {"49832350382626108453/8964749413", "49832350382626108454/8964749413", -1},
+ {"-37414950961700930/7204075375675961", "37414950961700930/7204075375675961", -1},
+ {"37414950961700930/7204075375675961", "74829901923401860/14408150751351922", 0},
+}
+
+func TestRatCmp(t *testing.T) {
+ for i, test := range ratCmpTests {
+ x, _ := new(Rat).SetString(test.rat1)
+ y, _ := new(Rat).SetString(test.rat2)
+
+ out := x.Cmp(y)
+ if out != test.out {
+ t.Errorf("#%d got out = %v; want %v", i, out, test.out)
+ }
+ }
+}
+
+
+func TestIsInt(t *testing.T) {
+ one := NewInt(1)
+ for _, a := range setStringTests {
+ var x Rat
+ x.SetString(a.in)
+ i := x.IsInt()
+ e := x.Denom().Cmp(one) == 0
+ if i != e {
+ t.Errorf("got %v; want %v for z = %v", i, e, &x)
+ }
+ }
+}
+
+
+func TestRatAbs(t *testing.T) {
+ zero := NewRat(0, 1)
+ for _, a := range setStringTests {
+ var z Rat
+ z.SetString(a.in)
+ var e Rat
+ e.Set(&z)
+ if e.Cmp(zero) < 0 {
+ e.Sub(zero, &e)
+ }
+ z.Abs(&z)
+ if z.Cmp(&e) != 0 {
+ t.Errorf("got z = %v; want %v", &z, &e)
+ }
+ }
+}
+
+
+type ratBinFun func(z, x, y *Rat) *Rat
+type ratBinArg struct {
+ x, y, z string
+}
+
+func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
+ x, _ := NewRat(0, 1).SetString(a.x)
+ y, _ := NewRat(0, 1).SetString(a.y)
+ z, _ := NewRat(0, 1).SetString(a.z)
+ out := f(NewRat(0, 1), x, y)
+
+ if out.Cmp(z) != 0 {
+ t.Errorf("%s #%d got %s want %s", name, i, out, z)
+ }
+}
+
+
+var ratBinTests = []struct {
+ x, y string
+ sum, prod string
+}{
+ {"0", "0", "0", "0"},
+ {"0", "1", "1", "0"},
+ {"-1", "0", "-1", "0"},
+ {"-1", "1", "0", "-1"},
+ {"1", "1", "2", "1"},
+ {"1/2", "1/2", "1", "1/4"},
+ {"1/4", "1/3", "7/12", "1/12"},
+ {"2/5", "-14/3", "-64/15", "-28/15"},
+ {"4707/49292519774798173060", "-3367/70976135186689855734", "84058377121001851123459/1749296273614329067191168098769082663020", "-1760941/388732505247628681598037355282018369560"},
+ {"-61204110018146728334/3", "-31052192278051565633/2", "-215564796870448153567/6", "950260896245257153059642991192710872711/3"},
+ {"-854857841473707320655/4237645934602118692642972629634714039", "-18/31750379913563777419", "-27/133467566250814981", "15387441146526731771790/134546868362786310073779084329032722548987800600710485341"},
+ {"618575745270541348005638912139/19198433543745179392300736", "-19948846211000086/637313996471", "27674141753240653/30123979153216", "-6169936206128396568797607742807090270137721977/6117715203873571641674006593837351328"},
+ {"-3/26206484091896184128", "5/2848423294177090248", "15310893822118706237/9330894968229805033368778458685147968", "-5/24882386581946146755650075889827061248"},
+ {"26946729/330400702820", "41563965/225583428284", "1238218672302860271/4658307703098666660055", "224002580204097/14906584649915733312176"},
+ {"-8259900599013409474/7", "-84829337473700364773/56707961321161574960", "-468402123685491748914621885145127724451/396955729248131024720", "350340947706464153265156004876107029701/198477864624065512360"},
+ {"575775209696864/1320203974639986246357", "29/712593081308", "410331716733912717985762465/940768218243776489278275419794956", "808/45524274987585732633"},
+ {"1786597389946320496771/2066653520653241", "6269770/1992362624741777", "3559549865190272133656109052308126637/4117523232840525481453983149257", "8967230/3296219033"},
+ {"-36459180403360509753/32150500941194292113930", "9381566963714/9633539", "301622077145533298008420642898530153/309723104686531919656937098270", "-3784609207827/3426986245"},
+}
+
+func TestRatBin(t *testing.T) {
+ for i, test := range ratBinTests {
+ arg := ratBinArg{test.x, test.y, test.sum}
+ testRatBin(t, i, "Add", (*Rat).Add, arg)
+
+ arg = ratBinArg{test.y, test.x, test.sum}
+ testRatBin(t, i, "Add symmetric", (*Rat).Add, arg)
+
+ arg = ratBinArg{test.sum, test.x, test.y}
+ testRatBin(t, i, "Sub", (*Rat).Sub, arg)
+
+ arg = ratBinArg{test.sum, test.y, test.x}
+ testRatBin(t, i, "Sub symmetric", (*Rat).Sub, arg)
+
+ arg = ratBinArg{test.x, test.y, test.prod}
+ testRatBin(t, i, "Mul", (*Rat).Mul, arg)
+
+ arg = ratBinArg{test.y, test.x, test.prod}
+ testRatBin(t, i, "Mul symmetric", (*Rat).Mul, arg)
+
+ if test.x != "0" {
+ arg = ratBinArg{test.prod, test.x, test.y}
+ testRatBin(t, i, "Quo", (*Rat).Quo, arg)
+ }
+
+ if test.y != "0" {
+ arg = ratBinArg{test.prod, test.y, test.x}
+ testRatBin(t, i, "Quo symmetric", (*Rat).Quo, arg)
+ }
+ }
+}
+
+
+func TestIssue820(t *testing.T) {
+ x := NewRat(3, 1)
+ y := NewRat(2, 1)
+ z := y.Quo(x, y)
+ q := NewRat(3, 2)
+ if z.Cmp(q) != 0 {
+ t.Errorf("got %s want %s", z, q)
+ }
+
+ y = NewRat(3, 1)
+ x = NewRat(2, 1)
+ z = y.Quo(x, y)
+ q = NewRat(2, 3)
+ if z.Cmp(q) != 0 {
+ t.Errorf("got %s want %s", z, q)
+ }
+
+ x = NewRat(3, 1)
+ z = x.Quo(x, x)
+ q = NewRat(3, 3)
+ if z.Cmp(q) != 0 {
+ t.Errorf("got %s want %s", z, q)
+ }
+}
+
+
+var setFrac64Tests = []struct {
+ a, b int64
+ out string
+}{
+ {0, 1, "0"},
+ {0, -1, "0"},
+ {1, 1, "1"},
+ {-1, 1, "-1"},
+ {1, -1, "-1"},
+ {-1, -1, "1"},
+ {-9223372036854775808, -9223372036854775808, "1"},
+}
+
+func TestRatSetFrac64Rat(t *testing.T) {
+ for i, test := range setFrac64Tests {
+ x := new(Rat).SetFrac64(test.a, test.b)
+ if x.RatString() != test.out {
+ t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+ }
+ }
+}
diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go
new file mode 100644
index 000000000..c13456a63
--- /dev/null
+++ b/libgo/go/bufio/bufio.go
@@ -0,0 +1,526 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements buffered I/O. It wraps an io.Reader or io.Writer
+// object, creating another object (Reader or Writer) that also implements
+// the interface but provides buffering and some help for textual I/O.
+package bufio
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+ "utf8"
+)
+
+
+const (
+ defaultBufSize = 4096
+)
+
+// Errors introduced by this package.
+type Error struct {
+ os.ErrorString
+}
+
+var (
+ ErrInvalidUnreadByte os.Error = &Error{"bufio: invalid use of UnreadByte"}
+ ErrInvalidUnreadRune os.Error = &Error{"bufio: invalid use of UnreadRune"}
+ ErrBufferFull os.Error = &Error{"bufio: buffer full"}
+ ErrNegativeCount os.Error = &Error{"bufio: negative count"}
+ errInternal os.Error = &Error{"bufio: internal error"}
+)
+
+// BufSizeError is the error representing an invalid buffer size.
+type BufSizeError int
+
+func (b BufSizeError) String() string {
+ return "bufio: bad buffer size " + strconv.Itoa(int(b))
+}
+
+
+// Buffered input.
+
+// Reader implements buffering for an io.Reader object.
+type Reader struct {
+ buf []byte
+ rd io.Reader
+ r, w int
+ err os.Error
+ lastByte int
+ lastRuneSize int
+}
+
+// NewReaderSize creates a new Reader whose buffer has the specified size,
+// which must be greater than zero. If the argument io.Reader is already a
+// Reader with large enough size, it returns the underlying Reader.
+// It returns the Reader and any error.
+func NewReaderSize(rd io.Reader, size int) (*Reader, os.Error) {
+ if size <= 0 {
+ return nil, BufSizeError(size)
+ }
+ // Is it already a Reader?
+ b, ok := rd.(*Reader)
+ if ok && len(b.buf) >= size {
+ return b, nil
+ }
+ b = new(Reader)
+ b.buf = make([]byte, size)
+ b.rd = rd
+ b.lastByte = -1
+ b.lastRuneSize = -1
+ return b, nil
+}
+
+// NewReader returns a new Reader whose buffer has the default size.
+func NewReader(rd io.Reader) *Reader {
+ b, err := NewReaderSize(rd, defaultBufSize)
+ if err != nil {
+ // cannot happen - defaultBufSize is a valid size
+ panic(err)
+ }
+ return b
+}
+
+// fill reads a new chunk into the buffer.
+func (b *Reader) fill() {
+ // Slide existing data to beginning.
+ if b.r > 0 {
+ copy(b.buf, b.buf[b.r:b.w])
+ b.w -= b.r
+ b.r = 0
+ }
+
+ // Read new data.
+ n, e := b.rd.Read(b.buf[b.w:])
+ b.w += n
+ if e != nil {
+ b.err = e
+ }
+}
+
+// Peek returns the next n bytes without advancing the reader. The bytes stop
+// being valid at the next read call. If Peek returns fewer than n bytes, it
+// also returns an error explaining why the read is short. The error is
+// ErrBufferFull if n is larger than b's buffer size.
+func (b *Reader) Peek(n int) ([]byte, os.Error) {
+ if n < 0 {
+ return nil, ErrNegativeCount
+ }
+ if n > len(b.buf) {
+ return nil, ErrBufferFull
+ }
+ for b.w-b.r < n && b.err == nil {
+ b.fill()
+ }
+ m := b.w - b.r
+ if m > n {
+ m = n
+ }
+ err := b.err
+ if m < n && err == nil {
+ err = ErrBufferFull
+ }
+ return b.buf[b.r : b.r+m], err
+}
+
+// Read reads data into p.
+// It returns the number of bytes read into p.
+// It calls Read at most once on the underlying Reader,
+// hence n may be less than len(p).
+// At EOF, the count will be zero and err will be os.EOF.
+func (b *Reader) Read(p []byte) (n int, err os.Error) {
+ n = len(p)
+ if n == 0 {
+ return 0, b.err
+ }
+ if b.w == b.r {
+ if b.err != nil {
+ return 0, b.err
+ }
+ if len(p) >= len(b.buf) {
+ // Large read, empty buffer.
+ // Read directly into p to avoid copy.
+ n, b.err = b.rd.Read(p)
+ if n > 0 {
+ b.lastByte = int(p[n-1])
+ b.lastRuneSize = -1
+ }
+ return n, b.err
+ }
+ b.fill()
+ if b.w == b.r {
+ return 0, b.err
+ }
+ }
+
+ if n > b.w-b.r {
+ n = b.w - b.r
+ }
+ copy(p[0:n], b.buf[b.r:])
+ b.r += n
+ b.lastByte = int(b.buf[b.r-1])
+ b.lastRuneSize = -1
+ return n, nil
+}
+
+// ReadByte reads and returns a single byte.
+// If no byte is available, returns an error.
+func (b *Reader) ReadByte() (c byte, err os.Error) {
+ b.lastRuneSize = -1
+ for b.w == b.r {
+ if b.err != nil {
+ return 0, b.err
+ }
+ b.fill()
+ }
+ c = b.buf[b.r]
+ b.r++
+ b.lastByte = int(c)
+ return c, nil
+}
+
+// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
+func (b *Reader) UnreadByte() os.Error {
+ b.lastRuneSize = -1
+ if b.r == b.w && b.lastByte >= 0 {
+ b.w = 1
+ b.r = 0
+ b.buf[0] = byte(b.lastByte)
+ b.lastByte = -1
+ return nil
+ }
+ if b.r <= 0 {
+ return ErrInvalidUnreadByte
+ }
+ b.r--
+ b.lastByte = -1
+ return nil
+}
+
+// ReadRune reads a single UTF-8 encoded Unicode character and returns the
+// rune and its size in bytes.
+func (b *Reader) ReadRune() (rune int, size int, err os.Error) {
+ for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil {
+ b.fill()
+ }
+ b.lastRuneSize = -1
+ if b.r == b.w {
+ return 0, 0, b.err
+ }
+ rune, size = int(b.buf[b.r]), 1
+ if rune >= 0x80 {
+ rune, size = utf8.DecodeRune(b.buf[b.r:b.w])
+ }
+ b.r += size
+ b.lastByte = int(b.buf[b.r-1])
+ b.lastRuneSize = size
+ return rune, size, nil
+}
+
+// UnreadRune unreads the last rune. If the most recent read operation on
+// the buffer was not a ReadRune, UnreadRune returns an error. (In this
+// regard it is stricter than UnreadByte, which will unread the last byte
+// from any read operation.)
+func (b *Reader) UnreadRune() os.Error {
+ if b.lastRuneSize < 0 || b.r == 0 {
+ return ErrInvalidUnreadRune
+ }
+ b.r -= b.lastRuneSize
+ b.lastByte = -1
+ b.lastRuneSize = -1
+ return nil
+}
+
+// Buffered returns the number of bytes that can be read from the current buffer.
+func (b *Reader) Buffered() int { return b.w - b.r }
+
+// ReadSlice reads until the first occurrence of delim in the input,
+// returning a slice pointing at the bytes in the buffer.
+// The bytes stop being valid at the next read call.
+// If ReadSlice encounters an error before finding a delimiter,
+// it returns all the data in the buffer and the error itself (often os.EOF).
+// ReadSlice fails with error ErrBufferFull if the buffer fills without a delim.
+// Because the data returned from ReadSlice will be overwritten
+// by the next I/O operation, most clients should use
+// ReadBytes or ReadString instead.
+// ReadSlice returns err != nil if and only if line does not end in delim.
+func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) {
+ // Look in buffer.
+ if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
+ line1 := b.buf[b.r : b.r+i+1]
+ b.r += i + 1
+ return line1, nil
+ }
+
+ // Read more into buffer, until buffer fills or we find delim.
+ for {
+ if b.err != nil {
+ line := b.buf[b.r:b.w]
+ b.r = b.w
+ return line, b.err
+ }
+
+ n := b.Buffered()
+ b.fill()
+
+ // Search new part of buffer
+ if i := bytes.IndexByte(b.buf[n:b.w], delim); i >= 0 {
+ line := b.buf[0 : n+i+1]
+ b.r = n + i + 1
+ return line, nil
+ }
+
+ // Buffer is full?
+ if b.Buffered() >= len(b.buf) {
+ b.r = b.w
+ return b.buf, ErrBufferFull
+ }
+ }
+ panic("not reached")
+}
+
+// ReadBytes reads until the first occurrence of delim in the input,
+// returning a slice containing the data up to and including the delimiter.
+// If ReadBytes encounters an error before finding a delimiter,
+// it returns the data read before the error and the error itself (often os.EOF).
+// ReadBytes returns err != nil if and only if line does not end in delim.
+func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) {
+ // Use ReadSlice to look for array,
+ // accumulating full buffers.
+ var frag []byte
+ var full [][]byte
+ err = nil
+
+ for {
+ var e os.Error
+ frag, e = b.ReadSlice(delim)
+ if e == nil { // got final fragment
+ break
+ }
+ if e != ErrBufferFull { // unexpected error
+ err = e
+ break
+ }
+
+ // Make a copy of the buffer.
+ buf := make([]byte, len(frag))
+ copy(buf, frag)
+ full = append(full, buf)
+ }
+
+ // Allocate new buffer to hold the full pieces and the fragment.
+ n := 0
+ for i := range full {
+ n += len(full[i])
+ }
+ n += len(frag)
+
+ // Copy full pieces and fragment in.
+ buf := make([]byte, n)
+ n = 0
+ for i := range full {
+ n += copy(buf[n:], full[i])
+ }
+ copy(buf[n:], frag)
+ return buf, err
+}
+
+// ReadString reads until the first occurrence of delim in the input,
+// returning a string containing the data up to and including the delimiter.
+// If ReadString encounters an error before finding a delimiter,
+// it returns the data read before the error and the error itself (often os.EOF).
+// ReadString returns err != nil if and only if line does not end in delim.
+func (b *Reader) ReadString(delim byte) (line string, err os.Error) {
+ bytes, e := b.ReadBytes(delim)
+ return string(bytes), e
+}
+
+
+// buffered output
+
+// Writer implements buffering for an io.Writer object.
+type Writer struct {
+ err os.Error
+ buf []byte
+ n int
+ wr io.Writer
+}
+
+// NewWriterSize creates a new Writer whose buffer has the specified size,
+// which must be greater than zero. If the argument io.Writer is already a
+// Writer with large enough size, it returns the underlying Writer.
+// It returns the Writer and any error.
+func NewWriterSize(wr io.Writer, size int) (*Writer, os.Error) {
+ if size <= 0 {
+ return nil, BufSizeError(size)
+ }
+ // Is it already a Writer?
+ b, ok := wr.(*Writer)
+ if ok && len(b.buf) >= size {
+ return b, nil
+ }
+ b = new(Writer)
+ b.buf = make([]byte, size)
+ b.wr = wr
+ return b, nil
+}
+
+// NewWriter returns a new Writer whose buffer has the default size.
+func NewWriter(wr io.Writer) *Writer {
+ b, err := NewWriterSize(wr, defaultBufSize)
+ if err != nil {
+ // cannot happen - defaultBufSize is valid size
+ panic(err)
+ }
+ return b
+}
+
+// Flush writes any buffered data to the underlying io.Writer.
+func (b *Writer) Flush() os.Error {
+ if b.err != nil {
+ return b.err
+ }
+ n, e := b.wr.Write(b.buf[0:b.n])
+ if n < b.n && e == nil {
+ e = io.ErrShortWrite
+ }
+ if e != nil {
+ if n > 0 && n < b.n {
+ copy(b.buf[0:b.n-n], b.buf[n:b.n])
+ }
+ b.n -= n
+ b.err = e
+ return e
+ }
+ b.n = 0
+ return nil
+}
+
+// Available returns how many bytes are unused in the buffer.
+func (b *Writer) Available() int { return len(b.buf) - b.n }
+
+// Buffered returns the number of bytes that have been written into the current buffer.
+func (b *Writer) Buffered() int { return b.n }
+
+// Write writes the contents of p into the buffer.
+// It returns the number of bytes written.
+// If nn < len(p), it also returns an error explaining
+// why the write is short.
+func (b *Writer) Write(p []byte) (nn int, err os.Error) {
+ if b.err != nil {
+ return 0, b.err
+ }
+ nn = 0
+ for len(p) > 0 {
+ n := b.Available()
+ if n <= 0 {
+ if b.Flush(); b.err != nil {
+ break
+ }
+ n = b.Available()
+ }
+ if b.Buffered() == 0 && len(p) >= len(b.buf) {
+ // Large write, empty buffer.
+ // Write directly from p to avoid copy.
+ n, b.err = b.wr.Write(p)
+ nn += n
+ p = p[n:]
+ if b.err != nil {
+ break
+ }
+ continue
+ }
+ if n > len(p) {
+ n = len(p)
+ }
+ copy(b.buf[b.n:b.n+n], p[0:n])
+ b.n += n
+ nn += n
+ p = p[n:]
+ }
+ return nn, b.err
+}
+
+// WriteByte writes a single byte.
+func (b *Writer) WriteByte(c byte) os.Error {
+ if b.err != nil {
+ return b.err
+ }
+ if b.Available() <= 0 && b.Flush() != nil {
+ return b.err
+ }
+ b.buf[b.n] = c
+ b.n++
+ return nil
+}
+
+// WriteRune writes a single Unicode code point, returning
+// the number of bytes written and any error.
+func (b *Writer) WriteRune(rune int) (size int, err os.Error) {
+ if rune < utf8.RuneSelf {
+ err = b.WriteByte(byte(rune))
+ if err != nil {
+ return 0, err
+ }
+ return 1, nil
+ }
+ if b.err != nil {
+ return 0, b.err
+ }
+ n := b.Available()
+ if n < utf8.UTFMax {
+ if b.Flush(); b.err != nil {
+ return 0, b.err
+ }
+ n = b.Available()
+ if n < utf8.UTFMax {
+ // Can only happen if buffer is silly small.
+ return b.WriteString(string(rune))
+ }
+ }
+ size = utf8.EncodeRune(b.buf[b.n:], rune)
+ b.n += size
+ return size, nil
+}
+
+// WriteString writes a string.
+// It returns the number of bytes written.
+// If the count is less than len(s), it also returns an error explaining
+// why the write is short.
+func (b *Writer) WriteString(s string) (int, os.Error) {
+ if b.err != nil {
+ return 0, b.err
+ }
+ // Common case, worth making fast.
+ if b.Available() >= len(s) || len(b.buf) >= len(s) && b.Flush() == nil {
+ for i := 0; i < len(s); i++ { // loop over bytes, not runes.
+ b.buf[b.n] = s[i]
+ b.n++
+ }
+ return len(s), nil
+ }
+ for i := 0; i < len(s); i++ { // loop over bytes, not runes.
+ b.WriteByte(s[i])
+ if b.err != nil {
+ return i, b.err
+ }
+ }
+ return len(s), nil
+}
+
+// buffered input and output
+
+// ReadWriter stores pointers to a Reader and a Writer.
+// It implements io.ReadWriter.
+type ReadWriter struct {
+ *Reader
+ *Writer
+}
+
+// NewReadWriter allocates a new ReadWriter that dispatches to r and w.
+func NewReadWriter(r *Reader, w *Writer) *ReadWriter {
+ return &ReadWriter{r, w}
+}
diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go
new file mode 100644
index 000000000..059ca6dd2
--- /dev/null
+++ b/libgo/go/bufio/bufio_test.go
@@ -0,0 +1,572 @@
+// 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 bufio
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "testing"
+ "testing/iotest"
+ "utf8"
+)
+
+// Reads from a reader and rot13s the result.
+type rot13Reader struct {
+ r io.Reader
+}
+
+func newRot13Reader(r io.Reader) *rot13Reader {
+ r13 := new(rot13Reader)
+ r13.r = r
+ return r13
+}
+
+func (r13 *rot13Reader) Read(p []byte) (int, os.Error) {
+ n, e := r13.r.Read(p)
+ if e != nil {
+ return n, e
+ }
+ for i := 0; i < n; i++ {
+ c := p[i] | 0x20 // lowercase byte
+ if 'a' <= c && c <= 'm' {
+ p[i] += 13
+ } else if 'n' <= c && c <= 'z' {
+ p[i] -= 13
+ }
+ }
+ return n, nil
+}
+
+// Call ReadByte to accumulate the text of a file
+func readBytes(buf *Reader) string {
+ var b [1000]byte
+ nb := 0
+ for {
+ c, e := buf.ReadByte()
+ if e == os.EOF {
+ break
+ }
+ if e != nil {
+ panic("Data: " + e.String())
+ }
+ b[nb] = c
+ nb++
+ }
+ return string(b[0:nb])
+}
+
+func TestReaderSimple(t *testing.T) {
+ data := "hello world"
+ b := NewReader(bytes.NewBufferString(data))
+ if s := readBytes(b); s != "hello world" {
+ t.Errorf("simple hello world test failed: got %q", s)
+ }
+
+ b = NewReader(newRot13Reader(bytes.NewBufferString(data)))
+ if s := readBytes(b); s != "uryyb jbeyq" {
+ t.Errorf("rot13 hello world test failed: got %q", s)
+ }
+}
+
+
+type readMaker struct {
+ name string
+ fn func(io.Reader) io.Reader
+}
+
+var readMakers = []readMaker{
+ {"full", func(r io.Reader) io.Reader { return r }},
+ {"byte", iotest.OneByteReader},
+ {"half", iotest.HalfReader},
+ {"data+err", iotest.DataErrReader},
+}
+
+// Call ReadString (which ends up calling everything else)
+// to accumulate the text of a file.
+func readLines(b *Reader) string {
+ s := ""
+ for {
+ s1, e := b.ReadString('\n')
+ if e == os.EOF {
+ break
+ }
+ if e != nil {
+ panic("GetLines: " + e.String())
+ }
+ s += s1
+ }
+ return s
+}
+
+// Call Read to accumulate the text of a file
+func reads(buf *Reader, m int) string {
+ var b [1000]byte
+ nb := 0
+ for {
+ n, e := buf.Read(b[nb : nb+m])
+ nb += n
+ if e == os.EOF {
+ break
+ }
+ }
+ return string(b[0:nb])
+}
+
+type bufReader struct {
+ name string
+ fn func(*Reader) string
+}
+
+var bufreaders = []bufReader{
+ {"1", func(b *Reader) string { return reads(b, 1) }},
+ {"2", func(b *Reader) string { return reads(b, 2) }},
+ {"3", func(b *Reader) string { return reads(b, 3) }},
+ {"4", func(b *Reader) string { return reads(b, 4) }},
+ {"5", func(b *Reader) string { return reads(b, 5) }},
+ {"7", func(b *Reader) string { return reads(b, 7) }},
+ {"bytes", readBytes},
+ {"lines", readLines},
+}
+
+var bufsizes = []int{
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 23, 32, 46, 64, 93, 128, 1024, 4096,
+}
+
+func TestReader(t *testing.T) {
+ var texts [31]string
+ str := ""
+ all := ""
+ for i := 0; i < len(texts)-1; i++ {
+ texts[i] = str + "\n"
+ all += texts[i]
+ str += string(i%26 + 'a')
+ }
+ texts[len(texts)-1] = all
+
+ for h := 0; h < len(texts); h++ {
+ text := texts[h]
+ for i := 0; i < len(readMakers); i++ {
+ for j := 0; j < len(bufreaders); j++ {
+ for k := 0; k < len(bufsizes); k++ {
+ readmaker := readMakers[i]
+ bufreader := bufreaders[j]
+ bufsize := bufsizes[k]
+ read := readmaker.fn(bytes.NewBufferString(text))
+ buf, _ := NewReaderSize(read, bufsize)
+ s := bufreader.fn(buf)
+ if s != text {
+ t.Errorf("reader=%s fn=%s bufsize=%d want=%q got=%q",
+ readmaker.name, bufreader.name, bufsize, text, s)
+ }
+ }
+ }
+ }
+ }
+}
+
+// A StringReader delivers its data one string segment at a time via Read.
+type StringReader struct {
+ data []string
+ step int
+}
+
+func (r *StringReader) Read(p []byte) (n int, err os.Error) {
+ if r.step < len(r.data) {
+ s := r.data[r.step]
+ n = copy(p, s)
+ r.step++
+ } else {
+ err = os.EOF
+ }
+ return
+}
+
+func readRuneSegments(t *testing.T, segments []string) {
+ got := ""
+ want := strings.Join(segments, "")
+ r := NewReader(&StringReader{data: segments})
+ for {
+ rune, _, err := r.ReadRune()
+ if err != nil {
+ if err != os.EOF {
+ return
+ }
+ break
+ }
+ got += string(rune)
+ }
+ if got != want {
+ t.Errorf("segments=%v got=%s want=%s", segments, got, want)
+ }
+}
+
+var segmentList = [][]string{
+ {},
+ {""},
+ {"日", "本語"},
+ {"\u65e5", "\u672c", "\u8a9e"},
+ {"\U000065e5", "\U0000672c", "\U00008a9e"},
+ {"\xe6", "\x97\xa5\xe6", "\x9c\xac\xe8\xaa\x9e"},
+ {"Hello", ", ", "World", "!"},
+ {"Hello", ", ", "", "World", "!"},
+}
+
+func TestReadRune(t *testing.T) {
+ for _, s := range segmentList {
+ readRuneSegments(t, s)
+ }
+}
+
+func TestUnreadRune(t *testing.T) {
+ got := ""
+ segments := []string{"Hello, world:", "日本語"}
+ data := strings.Join(segments, "")
+ r := NewReader(&StringReader{data: segments})
+ // Normal execution.
+ for {
+ rune, _, err := r.ReadRune()
+ if err != nil {
+ if err != os.EOF {
+ t.Error("unexpected EOF")
+ }
+ break
+ }
+ got += string(rune)
+ // Put it back and read it again
+ if err = r.UnreadRune(); err != nil {
+ t.Error("unexpected error on UnreadRune:", err)
+ }
+ rune1, _, err := r.ReadRune()
+ if err != nil {
+ t.Error("unexpected error reading after unreading:", err)
+ }
+ if rune != rune1 {
+ t.Errorf("incorrect rune after unread: got %c wanted %c", rune1, rune)
+ }
+ }
+ if got != data {
+ t.Errorf("want=%q got=%q", data, got)
+ }
+}
+
+// Test that UnreadRune fails if the preceding operation was not a ReadRune.
+func TestUnreadRuneError(t *testing.T) {
+ buf := make([]byte, 3) // All runes in this test are 3 bytes long
+ r := NewReader(&StringReader{data: []string{"日本語日本語日本語"}})
+ if r.UnreadRune() == nil {
+ t.Error("expected error on UnreadRune from fresh buffer")
+ }
+ _, _, err := r.ReadRune()
+ if err != nil {
+ t.Error("unexpected error on ReadRune (1):", err)
+ }
+ if err = r.UnreadRune(); err != nil {
+ t.Error("unexpected error on UnreadRune (1):", err)
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after UnreadRune (1)")
+ }
+ // Test error after Read.
+ _, _, err = r.ReadRune() // reset state
+ if err != nil {
+ t.Error("unexpected error on ReadRune (2):", err)
+ }
+ _, err = r.Read(buf)
+ if err != nil {
+ t.Error("unexpected error on Read (2):", err)
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after Read (2)")
+ }
+ // Test error after ReadByte.
+ _, _, err = r.ReadRune() // reset state
+ if err != nil {
+ t.Error("unexpected error on ReadRune (2):", err)
+ }
+ for _ = range buf {
+ _, err = r.ReadByte()
+ if err != nil {
+ t.Error("unexpected error on ReadByte (2):", err)
+ }
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after ReadByte")
+ }
+ // Test error after UnreadByte.
+ _, _, err = r.ReadRune() // reset state
+ if err != nil {
+ t.Error("unexpected error on ReadRune (3):", err)
+ }
+ _, err = r.ReadByte()
+ if err != nil {
+ t.Error("unexpected error on ReadByte (3):", err)
+ }
+ err = r.UnreadByte()
+ if err != nil {
+ t.Error("unexpected error on UnreadByte (3):", err)
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after UnreadByte (3)")
+ }
+}
+
+func TestUnreadRuneAtEOF(t *testing.T) {
+ // UnreadRune/ReadRune should error at EOF (was a bug; used to panic)
+ r := NewReader(strings.NewReader("x"))
+ r.ReadRune()
+ r.ReadRune()
+ r.UnreadRune()
+ _, _, err := r.ReadRune()
+ if err == nil {
+ t.Error("expected error at EOF")
+ } else if err != os.EOF {
+ t.Error("expected EOF; got", err)
+ }
+}
+
+func TestReadWriteRune(t *testing.T) {
+ const NRune = 1000
+ byteBuf := new(bytes.Buffer)
+ w := NewWriter(byteBuf)
+ // Write the runes out using WriteRune
+ buf := make([]byte, utf8.UTFMax)
+ for rune := 0; rune < NRune; rune++ {
+ size := utf8.EncodeRune(buf, rune)
+ nbytes, err := w.WriteRune(rune)
+ if err != nil {
+ t.Fatalf("WriteRune(0x%x) error: %s", rune, err)
+ }
+ if nbytes != size {
+ t.Fatalf("WriteRune(0x%x) expected %d, got %d", rune, size, nbytes)
+ }
+ }
+ w.Flush()
+
+ r := NewReader(byteBuf)
+ // Read them back with ReadRune
+ for rune := 0; rune < NRune; rune++ {
+ size := utf8.EncodeRune(buf, rune)
+ nr, nbytes, err := r.ReadRune()
+ if nr != rune || nbytes != size || err != nil {
+ t.Fatalf("ReadRune(0x%x) got 0x%x,%d not 0x%x,%d (err=%s)", r, nr, nbytes, r, size, err)
+ }
+ }
+}
+
+func TestWriter(t *testing.T) {
+ var data [8192]byte
+
+ for i := 0; i < len(data); i++ {
+ data[i] = byte(' ' + i%('~'-' '))
+ }
+ w := new(bytes.Buffer)
+ for i := 0; i < len(bufsizes); i++ {
+ for j := 0; j < len(bufsizes); j++ {
+ nwrite := bufsizes[i]
+ bs := bufsizes[j]
+
+ // Write nwrite bytes using buffer size bs.
+ // Check that the right amount makes it out
+ // and that the data is correct.
+
+ w.Reset()
+ buf, e := NewWriterSize(w, bs)
+ context := fmt.Sprintf("nwrite=%d bufsize=%d", nwrite, bs)
+ if e != nil {
+ t.Errorf("%s: NewWriterSize %d: %v", context, bs, e)
+ continue
+ }
+ n, e1 := buf.Write(data[0:nwrite])
+ if e1 != nil || n != nwrite {
+ t.Errorf("%s: buf.Write %d = %d, %v", context, nwrite, n, e1)
+ continue
+ }
+ if e = buf.Flush(); e != nil {
+ t.Errorf("%s: buf.Flush = %v", context, e)
+ }
+
+ written := w.Bytes()
+ if len(written) != nwrite {
+ t.Errorf("%s: %d bytes written", context, len(written))
+ }
+ for l := 0; l < len(written); l++ {
+ if written[i] != data[i] {
+ t.Errorf("wrong bytes written")
+ t.Errorf("want=%q", data[0:len(written)])
+ t.Errorf("have=%q", written)
+ }
+ }
+ }
+ }
+}
+
+// Check that write errors are returned properly.
+
+type errorWriterTest struct {
+ n, m int
+ err os.Error
+ expect os.Error
+}
+
+func (w errorWriterTest) Write(p []byte) (int, os.Error) {
+ return len(p) * w.n / w.m, w.err
+}
+
+var errorWriterTests = []errorWriterTest{
+ {0, 1, nil, io.ErrShortWrite},
+ {1, 2, nil, io.ErrShortWrite},
+ {1, 1, nil, nil},
+ {0, 1, os.EPIPE, os.EPIPE},
+ {1, 2, os.EPIPE, os.EPIPE},
+ {1, 1, os.EPIPE, os.EPIPE},
+}
+
+func TestWriteErrors(t *testing.T) {
+ for _, w := range errorWriterTests {
+ buf := NewWriter(w)
+ _, e := buf.Write([]byte("hello world"))
+ if e != nil {
+ t.Errorf("Write hello to %v: %v", w, e)
+ continue
+ }
+ e = buf.Flush()
+ if e != w.expect {
+ t.Errorf("Flush %v: got %v, wanted %v", w, e, w.expect)
+ }
+ }
+}
+
+func TestNewReaderSizeIdempotent(t *testing.T) {
+ const BufSize = 1000
+ b, err := NewReaderSize(bytes.NewBufferString("hello world"), BufSize)
+ if err != nil {
+ t.Error("NewReaderSize create fail", err)
+ }
+ // Does it recognize itself?
+ b1, err2 := NewReaderSize(b, BufSize)
+ if err2 != nil {
+ t.Error("NewReaderSize #2 create fail", err2)
+ }
+ if b1 != b {
+ t.Error("NewReaderSize did not detect underlying Reader")
+ }
+ // Does it wrap if existing buffer is too small?
+ b2, err3 := NewReaderSize(b, 2*BufSize)
+ if err3 != nil {
+ t.Error("NewReaderSize #3 create fail", err3)
+ }
+ if b2 == b {
+ t.Error("NewReaderSize did not enlarge buffer")
+ }
+}
+
+func TestNewWriterSizeIdempotent(t *testing.T) {
+ const BufSize = 1000
+ b, err := NewWriterSize(new(bytes.Buffer), BufSize)
+ if err != nil {
+ t.Error("NewWriterSize create fail", err)
+ }
+ // Does it recognize itself?
+ b1, err2 := NewWriterSize(b, BufSize)
+ if err2 != nil {
+ t.Error("NewWriterSize #2 create fail", err2)
+ }
+ if b1 != b {
+ t.Error("NewWriterSize did not detect underlying Writer")
+ }
+ // Does it wrap if existing buffer is too small?
+ b2, err3 := NewWriterSize(b, 2*BufSize)
+ if err3 != nil {
+ t.Error("NewWriterSize #3 create fail", err3)
+ }
+ if b2 == b {
+ t.Error("NewWriterSize did not enlarge buffer")
+ }
+}
+
+func TestWriteString(t *testing.T) {
+ const BufSize = 8
+ buf := new(bytes.Buffer)
+ b, err := NewWriterSize(buf, BufSize)
+ if err != nil {
+ t.Error("NewWriterSize create fail", err)
+ }
+ b.WriteString("0") // easy
+ b.WriteString("123456") // still easy
+ b.WriteString("7890") // easy after flush
+ b.WriteString("abcdefghijklmnopqrstuvwxy") // hard
+ b.WriteString("z")
+ b.Flush()
+ if b.err != nil {
+ t.Error("WriteString", b.err)
+ }
+ s := "01234567890abcdefghijklmnopqrstuvwxyz"
+ if string(buf.Bytes()) != s {
+ t.Errorf("WriteString wants %q gets %q", s, string(buf.Bytes()))
+ }
+}
+
+func TestBufferFull(t *testing.T) {
+ buf, _ := NewReaderSize(strings.NewReader("hello, world"), 5)
+ line, err := buf.ReadSlice(',')
+ if string(line) != "hello" || err != ErrBufferFull {
+ t.Errorf("first ReadSlice(,) = %q, %v", line, err)
+ }
+ line, err = buf.ReadSlice(',')
+ if string(line) != "," || err != nil {
+ t.Errorf("second ReadSlice(,) = %q, %v", line, err)
+ }
+}
+
+func TestPeek(t *testing.T) {
+ p := make([]byte, 10)
+ buf, _ := NewReaderSize(strings.NewReader("abcdefghij"), 4)
+ if s, err := buf.Peek(1); string(s) != "a" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "a", string(s), err)
+ }
+ if s, err := buf.Peek(4); string(s) != "abcd" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "abcd", string(s), err)
+ }
+ if _, err := buf.Peek(5); err != ErrBufferFull {
+ t.Fatalf("want ErrBufFull got %v", err)
+ }
+ if _, err := buf.Read(p[0:3]); string(p[0:3]) != "abc" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "abc", string(p[0:3]), err)
+ }
+ if s, err := buf.Peek(1); string(s) != "d" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "d", string(s), err)
+ }
+ if s, err := buf.Peek(2); string(s) != "de" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "de", string(s), err)
+ }
+ if _, err := buf.Read(p[0:3]); string(p[0:3]) != "def" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "def", string(p[0:3]), err)
+ }
+ if s, err := buf.Peek(4); string(s) != "ghij" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "ghij", string(s), err)
+ }
+ if _, err := buf.Read(p[0:4]); string(p[0:4]) != "ghij" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "ghij", string(p[0:3]), err)
+ }
+ if s, err := buf.Peek(0); string(s) != "" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "", string(s), err)
+ }
+ if _, err := buf.Peek(1); err != os.EOF {
+ t.Fatalf("want EOF got %v", err)
+ }
+}
+
+func TestPeekThenUnreadRune(t *testing.T) {
+ // This sequence used to cause a crash.
+ r := NewReader(strings.NewReader("x"))
+ r.ReadRune()
+ r.Peek(1)
+ r.UnreadRune()
+ r.ReadRune() // Used to panic here
+}
diff --git a/libgo/go/bytes/buffer.go b/libgo/go/bytes/buffer.go
new file mode 100644
index 000000000..62cf82810
--- /dev/null
+++ b/libgo/go/bytes/buffer.go
@@ -0,0 +1,315 @@
+// 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 bytes
+
+// Simple byte buffer for marshaling data.
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+
+// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
+// The zero value for Buffer is an empty buffer ready to use.
+type Buffer struct {
+ buf []byte // contents are the bytes buf[off : len(buf)]
+ off int // read at &buf[off], write at &buf[len(buf)]
+ runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
+ bootstrap [64]byte // memory to hold first slice; helps small buffers (Printf) avoid allocation.
+ lastRead readOp // last read operation, so that Unread* can work correctly.
+}
+
+// The readOp constants describe the last action performed on
+// the buffer, so that UnreadRune and UnreadByte can
+// check for invalid usage.
+type readOp int
+
+const (
+ opInvalid readOp = iota // Non-read operation.
+ opReadRune // Read rune.
+ opRead // Any other read operation.
+)
+
+// Bytes returns a slice of the contents of the unread portion of the buffer;
+// len(b.Bytes()) == b.Len(). If the caller changes the contents of the
+// returned slice, the contents of the buffer will change provided there
+// are no intervening method calls on the Buffer.
+func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
+
+// String returns the contents of the unread portion of the buffer
+// as a string. If the Buffer is a nil pointer, it returns "<nil>".
+func (b *Buffer) String() string {
+ if b == nil {
+ // Special case, useful in debugging.
+ return "<nil>"
+ }
+ return string(b.buf[b.off:])
+}
+
+// Len returns the number of bytes of the unread portion of the buffer;
+// b.Len() == len(b.Bytes()).
+func (b *Buffer) Len() int { return len(b.buf) - b.off }
+
+// Truncate discards all but the first n unread bytes from the buffer.
+// It is an error to call b.Truncate(n) with n > b.Len().
+func (b *Buffer) Truncate(n int) {
+ b.lastRead = opInvalid
+ if n == 0 {
+ // Reuse buffer space.
+ b.off = 0
+ }
+ b.buf = b.buf[0 : b.off+n]
+}
+
+// Reset resets the buffer so it has no content.
+// b.Reset() is the same as b.Truncate(0).
+func (b *Buffer) Reset() { b.Truncate(0) }
+
+// Grow buffer to guarantee space for n more bytes.
+// Return index where bytes should be written.
+func (b *Buffer) grow(n int) int {
+ m := b.Len()
+ // If buffer is empty, reset to recover space.
+ if m == 0 && b.off != 0 {
+ b.Truncate(0)
+ }
+ if len(b.buf)+n > cap(b.buf) {
+ var buf []byte
+ if b.buf == nil && n <= len(b.bootstrap) {
+ buf = b.bootstrap[0:]
+ } else {
+ // not enough space anywhere
+ buf = make([]byte, 2*cap(b.buf)+n)
+ copy(buf, b.buf[b.off:])
+ }
+ b.buf = buf
+ b.off = 0
+ }
+ b.buf = b.buf[0 : b.off+m+n]
+ return b.off + m
+}
+
+// Write appends the contents of p to the buffer. The return
+// value n is the length of p; err is always nil.
+func (b *Buffer) Write(p []byte) (n int, err os.Error) {
+ b.lastRead = opInvalid
+ m := b.grow(len(p))
+ copy(b.buf[m:], p)
+ return len(p), nil
+}
+
+// WriteString appends the contents of s to the buffer. The return
+// value n is the length of s; err is always nil.
+func (b *Buffer) WriteString(s string) (n int, err os.Error) {
+ b.lastRead = opInvalid
+ m := b.grow(len(s))
+ return copy(b.buf[m:], s), nil
+}
+
+// MinRead is the minimum slice size passed to a Read call by
+// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond
+// what is required to hold the contents of r, ReadFrom will not grow the
+// underlying buffer.
+const MinRead = 512
+
+// ReadFrom reads data from r until EOF and appends it to the buffer.
+// The return value n is the number of bytes read.
+// Any error except os.EOF encountered during the read
+// is also returned.
+func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) {
+ b.lastRead = opInvalid
+ // If buffer is empty, reset to recover space.
+ if b.off >= len(b.buf) {
+ b.Truncate(0)
+ }
+ for {
+ if cap(b.buf)-len(b.buf) < MinRead {
+ var newBuf []byte
+ // can we get space without allocation?
+ if b.off+cap(b.buf)-len(b.buf) >= MinRead {
+ // reuse beginning of buffer
+ newBuf = b.buf[0 : len(b.buf)-b.off]
+ } else {
+ // not enough space at end; put space on end
+ newBuf = make([]byte, len(b.buf)-b.off, 2*(cap(b.buf)-b.off)+MinRead)
+ }
+ copy(newBuf, b.buf[b.off:])
+ b.buf = newBuf
+ b.off = 0
+ }
+ m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
+ b.buf = b.buf[0 : len(b.buf)+m]
+ n += int64(m)
+ if e == os.EOF {
+ break
+ }
+ if e != nil {
+ return n, e
+ }
+ }
+ return n, nil // err is EOF, so return nil explicitly
+}
+
+// WriteTo writes data to w until the buffer is drained or an error
+// occurs. The return value n is the number of bytes written.
+// Any error encountered during the write is also returned.
+func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
+ b.lastRead = opInvalid
+ for b.off < len(b.buf) {
+ m, e := w.Write(b.buf[b.off:])
+ n += int64(m)
+ b.off += m
+ if e != nil {
+ return n, e
+ }
+ }
+ // Buffer is now empty; reset.
+ b.Truncate(0)
+ return
+}
+
+// WriteByte appends the byte c to the buffer.
+// The returned error is always nil, but is included
+// to match bufio.Writer's WriteByte.
+func (b *Buffer) WriteByte(c byte) os.Error {
+ b.lastRead = opInvalid
+ m := b.grow(1)
+ b.buf[m] = c
+ return nil
+}
+
+// WriteRune appends the UTF-8 encoding of Unicode
+// code point r to the buffer, returning its length and
+// an error, which is always nil but is included
+// to match bufio.Writer's WriteRune.
+func (b *Buffer) WriteRune(r int) (n int, err os.Error) {
+ if r < utf8.RuneSelf {
+ b.WriteByte(byte(r))
+ return 1, nil
+ }
+ n = utf8.EncodeRune(b.runeBytes[0:], r)
+ b.Write(b.runeBytes[0:n])
+ return n, nil
+}
+
+// Read reads the next len(p) bytes from the buffer or until the buffer
+// is drained. The return value n is the number of bytes read. If the
+// buffer has no data to return, err is os.EOF even if len(p) is zero;
+// otherwise it is nil.
+func (b *Buffer) Read(p []byte) (n int, err os.Error) {
+ b.lastRead = opInvalid
+ if b.off >= len(b.buf) {
+ // Buffer is empty, reset to recover space.
+ b.Truncate(0)
+ return 0, os.EOF
+ }
+ n = copy(p, b.buf[b.off:])
+ b.off += n
+ if n > 0 {
+ b.lastRead = opRead
+ }
+ return
+}
+
+// Next returns a slice containing the next n bytes from the buffer,
+// advancing the buffer as if the bytes had been returned by Read.
+// If there are fewer than n bytes in the buffer, Next returns the entire buffer.
+// The slice is only valid until the next call to a read or write method.
+func (b *Buffer) Next(n int) []byte {
+ b.lastRead = opInvalid
+ m := b.Len()
+ if n > m {
+ n = m
+ }
+ data := b.buf[b.off : b.off+n]
+ b.off += n
+ if n > 0 {
+ b.lastRead = opRead
+ }
+ return data
+}
+
+// ReadByte reads and returns the next byte from the buffer.
+// If no byte is available, it returns error os.EOF.
+func (b *Buffer) ReadByte() (c byte, err os.Error) {
+ b.lastRead = opInvalid
+ if b.off >= len(b.buf) {
+ // Buffer is empty, reset to recover space.
+ b.Truncate(0)
+ return 0, os.EOF
+ }
+ c = b.buf[b.off]
+ b.off++
+ b.lastRead = opRead
+ return c, nil
+}
+
+// ReadRune reads and returns the next UTF-8-encoded
+// Unicode code point from the buffer.
+// If no bytes are available, the error returned is os.EOF.
+// If the bytes are an erroneous UTF-8 encoding, it
+// consumes one byte and returns U+FFFD, 1.
+func (b *Buffer) ReadRune() (r int, size int, err os.Error) {
+ b.lastRead = opInvalid
+ if b.off >= len(b.buf) {
+ // Buffer is empty, reset to recover space.
+ b.Truncate(0)
+ return 0, 0, os.EOF
+ }
+ b.lastRead = opReadRune
+ c := b.buf[b.off]
+ if c < utf8.RuneSelf {
+ b.off++
+ return int(c), 1, nil
+ }
+ r, n := utf8.DecodeRune(b.buf[b.off:])
+ b.off += n
+ return r, n, nil
+}
+
+// UnreadRune unreads the last rune returned by ReadRune.
+// If the most recent read or write operation on the buffer was
+// not a ReadRune, UnreadRune returns an error. (In this regard
+// it is stricter than UnreadByte, which will unread the last byte
+// 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")
+ }
+ b.lastRead = opInvalid
+ if b.off > 0 {
+ _, n := utf8.DecodeLastRune(b.buf[0:b.off])
+ b.off -= n
+ }
+ return nil
+}
+
+// UnreadByte unreads the last byte returned by the most recent
+// read operation. If write has happened since the last read, UnreadByte
+// 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")
+ }
+ b.lastRead = opInvalid
+ if b.off > 0 {
+ b.off--
+ }
+ return nil
+}
+
+// NewBuffer creates and initializes a new Buffer using buf as its initial
+// contents. It is intended to prepare a Buffer to read existing data. It
+// can also be used to size the internal buffer for writing. To do that,
+// buf should have the desired capacity but a length of zero.
+func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
+
+// NewBufferString creates and initializes a new Buffer using string s as its
+// initial contents. It is intended to prepare a buffer to read an existing
+// string.
+func NewBufferString(s string) *Buffer {
+ return &Buffer{buf: []byte(s)}
+}
diff --git a/libgo/go/bytes/buffer_test.go b/libgo/go/bytes/buffer_test.go
new file mode 100644
index 000000000..509793d24
--- /dev/null
+++ b/libgo/go/bytes/buffer_test.go
@@ -0,0 +1,349 @@
+// 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 bytes_test
+
+import (
+ . "bytes"
+ "rand"
+ "testing"
+ "utf8"
+)
+
+
+const N = 10000 // make this bigger for a larger (and slower) test
+var data string // test data for write tests
+var bytes []byte // test data; same as data but as a slice.
+
+
+func init() {
+ bytes = make([]byte, N)
+ for i := 0; i < N; i++ {
+ bytes[i] = 'a' + byte(i%26)
+ }
+ data = string(bytes)
+}
+
+// Verify that contents of buf match the string s.
+func check(t *testing.T, testname string, buf *Buffer, s string) {
+ bytes := buf.Bytes()
+ str := buf.String()
+ if buf.Len() != len(bytes) {
+ t.Errorf("%s: buf.Len() == %d, len(buf.Bytes()) == %d", testname, buf.Len(), len(bytes))
+ }
+
+ if buf.Len() != len(str) {
+ t.Errorf("%s: buf.Len() == %d, len(buf.String()) == %d", testname, buf.Len(), len(str))
+ }
+
+ if buf.Len() != len(s) {
+ t.Errorf("%s: buf.Len() == %d, len(s) == %d", testname, buf.Len(), len(s))
+ }
+
+ if string(bytes) != s {
+ t.Errorf("%s: string(buf.Bytes()) == %q, s == %q", testname, string(bytes), s)
+ }
+}
+
+
+// Fill buf through n writes of string fus.
+// The initial contents of buf corresponds to the string s;
+// the result is the final contents of buf returned as a string.
+func fillString(t *testing.T, testname string, buf *Buffer, s string, n int, fus string) string {
+ check(t, testname+" (fill 1)", buf, s)
+ for ; n > 0; n-- {
+ m, err := buf.WriteString(fus)
+ if m != len(fus) {
+ t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fus))
+ }
+ if err != nil {
+ t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err)
+ }
+ s += fus
+ check(t, testname+" (fill 4)", buf, s)
+ }
+ return s
+}
+
+
+// Fill buf through n writes of byte slice fub.
+// The initial contents of buf corresponds to the string s;
+// the result is the final contents of buf returned as a string.
+func fillBytes(t *testing.T, testname string, buf *Buffer, s string, n int, fub []byte) string {
+ check(t, testname+" (fill 1)", buf, s)
+ for ; n > 0; n-- {
+ m, err := buf.Write(fub)
+ if m != len(fub) {
+ t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fub))
+ }
+ if err != nil {
+ t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err)
+ }
+ s += string(fub)
+ check(t, testname+" (fill 4)", buf, s)
+ }
+ return s
+}
+
+
+func TestNewBuffer(t *testing.T) {
+ buf := NewBuffer(bytes)
+ check(t, "NewBuffer", buf, data)
+}
+
+
+func TestNewBufferString(t *testing.T) {
+ buf := NewBufferString(data)
+ check(t, "NewBufferString", buf, data)
+}
+
+
+// Empty buf through repeated reads into fub.
+// The initial contents of buf corresponds to the string s.
+func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) {
+ check(t, testname+" (empty 1)", buf, s)
+
+ for {
+ n, err := buf.Read(fub)
+ if n == 0 {
+ break
+ }
+ if err != nil {
+ t.Errorf(testname+" (empty 2): err should always be nil, found err == %s", err)
+ }
+ s = s[n:]
+ check(t, testname+" (empty 3)", buf, s)
+ }
+
+ check(t, testname+" (empty 4)", buf, "")
+}
+
+
+func TestBasicOperations(t *testing.T) {
+ var buf Buffer
+
+ for i := 0; i < 5; i++ {
+ check(t, "TestBasicOperations (1)", &buf, "")
+
+ buf.Reset()
+ check(t, "TestBasicOperations (2)", &buf, "")
+
+ buf.Truncate(0)
+ check(t, "TestBasicOperations (3)", &buf, "")
+
+ n, err := buf.Write([]byte(data[0:1]))
+ if n != 1 {
+ t.Errorf("wrote 1 byte, but n == %d", n)
+ }
+ if err != nil {
+ t.Errorf("err should always be nil, but err == %s", err)
+ }
+ check(t, "TestBasicOperations (4)", &buf, "a")
+
+ buf.WriteByte(data[1])
+ check(t, "TestBasicOperations (5)", &buf, "ab")
+
+ n, err = buf.Write([]byte(data[2:26]))
+ if n != 24 {
+ t.Errorf("wrote 25 bytes, but n == %d", n)
+ }
+ check(t, "TestBasicOperations (6)", &buf, string(data[0:26]))
+
+ buf.Truncate(26)
+ check(t, "TestBasicOperations (7)", &buf, string(data[0:26]))
+
+ buf.Truncate(20)
+ check(t, "TestBasicOperations (8)", &buf, string(data[0:20]))
+
+ empty(t, "TestBasicOperations (9)", &buf, string(data[0:20]), make([]byte, 5))
+ empty(t, "TestBasicOperations (10)", &buf, "", make([]byte, 100))
+
+ buf.WriteByte(data[1])
+ c, err := buf.ReadByte()
+ if err != nil {
+ t.Error("ReadByte unexpected eof")
+ }
+ if c != data[1] {
+ t.Errorf("ReadByte wrong value c=%v", c)
+ }
+ c, err = buf.ReadByte()
+ if err == nil {
+ t.Error("ReadByte unexpected not eof")
+ }
+ }
+}
+
+
+func TestLargeStringWrites(t *testing.T) {
+ var buf Buffer
+ for i := 3; i < 30; i += 3 {
+ s := fillString(t, "TestLargeWrites (1)", &buf, "", 5, data)
+ empty(t, "TestLargeStringWrites (2)", &buf, s, make([]byte, len(data)/i))
+ }
+ check(t, "TestLargeStringWrites (3)", &buf, "")
+}
+
+
+func TestLargeByteWrites(t *testing.T) {
+ var buf Buffer
+ for i := 3; i < 30; i += 3 {
+ s := fillBytes(t, "TestLargeWrites (1)", &buf, "", 5, bytes)
+ empty(t, "TestLargeByteWrites (2)", &buf, s, make([]byte, len(data)/i))
+ }
+ check(t, "TestLargeByteWrites (3)", &buf, "")
+}
+
+
+func TestLargeStringReads(t *testing.T) {
+ var buf Buffer
+ for i := 3; i < 30; i += 3 {
+ s := fillString(t, "TestLargeReads (1)", &buf, "", 5, data[0:len(data)/i])
+ empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data)))
+ }
+ check(t, "TestLargeStringReads (3)", &buf, "")
+}
+
+
+func TestLargeByteReads(t *testing.T) {
+ var buf Buffer
+ for i := 3; i < 30; i += 3 {
+ s := fillBytes(t, "TestLargeReads (1)", &buf, "", 5, bytes[0:len(bytes)/i])
+ empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data)))
+ }
+ check(t, "TestLargeByteReads (3)", &buf, "")
+}
+
+
+func TestMixedReadsAndWrites(t *testing.T) {
+ var buf Buffer
+ s := ""
+ for i := 0; i < 50; i++ {
+ wlen := rand.Intn(len(data))
+ if i%2 == 0 {
+ s = fillString(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, data[0:wlen])
+ } else {
+ s = fillBytes(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, bytes[0:wlen])
+ }
+
+ rlen := rand.Intn(len(data))
+ fub := make([]byte, rlen)
+ n, _ := buf.Read(fub)
+ s = s[n:]
+ }
+ empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len()))
+}
+
+
+func TestNil(t *testing.T) {
+ var b *Buffer
+ if b.String() != "<nil>" {
+ t.Errorf("expcted <nil>; got %q", b.String())
+ }
+}
+
+
+func TestReadFrom(t *testing.T) {
+ var buf Buffer
+ for i := 3; i < 30; i += 3 {
+ s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, bytes[0:len(bytes)/i])
+ var b Buffer
+ b.ReadFrom(&buf)
+ empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(data)))
+ }
+}
+
+
+func TestWriteTo(t *testing.T) {
+ var buf Buffer
+ for i := 3; i < 30; i += 3 {
+ s := fillBytes(t, "TestReadFrom (1)", &buf, "", 5, bytes[0:len(bytes)/i])
+ var b Buffer
+ buf.WriteTo(&b)
+ empty(t, "TestReadFrom (2)", &b, s, make([]byte, len(data)))
+ }
+}
+
+
+func TestRuneIO(t *testing.T) {
+ const NRune = 1000
+ // Built a test array while we write the data
+ b := make([]byte, utf8.UTFMax*NRune)
+ var buf Buffer
+ n := 0
+ for r := 0; r < NRune; r++ {
+ size := utf8.EncodeRune(b[n:], r)
+ nbytes, err := buf.WriteRune(r)
+ if err != nil {
+ t.Fatalf("WriteRune(%U) error: %s", r, err)
+ }
+ if nbytes != size {
+ t.Fatalf("WriteRune(%U) expected %d, got %d", r, size, nbytes)
+ }
+ n += size
+ }
+ b = b[0:n]
+
+ // Check the resulting bytes
+ if !Equal(buf.Bytes(), b) {
+ t.Fatalf("incorrect result from WriteRune: %q not %q", buf.Bytes(), b)
+ }
+
+ p := make([]byte, utf8.UTFMax)
+ // Read it back with ReadRune
+ for r := 0; r < NRune; r++ {
+ size := utf8.EncodeRune(p, r)
+ nr, nbytes, err := buf.ReadRune()
+ if nr != r || nbytes != size || err != nil {
+ t.Fatalf("ReadRune(%U) got %U,%d not %U,%d (err=%s)", r, nr, nbytes, r, size, err)
+ }
+ }
+
+ // Check that UnreadRune works
+ buf.Reset()
+ buf.Write(b)
+ for r := 0; r < NRune; r++ {
+ r1, size, _ := buf.ReadRune()
+ if err := buf.UnreadRune(); err != nil {
+ t.Fatalf("UnreadRune(%U) got error %q", r, err)
+ }
+ r2, nbytes, err := buf.ReadRune()
+ if r1 != r2 || r1 != r || nbytes != size || err != nil {
+ t.Fatalf("ReadRune(%U) after UnreadRune got %U,%d not %U,%d (err=%s)", r, r2, nbytes, r, size, err)
+ }
+ }
+}
+
+
+func TestNext(t *testing.T) {
+ b := []byte{0, 1, 2, 3, 4}
+ tmp := make([]byte, 5)
+ for i := 0; i <= 5; i++ {
+ for j := i; j <= 5; j++ {
+ for k := 0; k <= 6; k++ {
+ // 0 <= i <= j <= 5; 0 <= k <= 6
+ // Check that if we start with a buffer
+ // of length j at offset i and ask for
+ // Next(k), we get the right bytes.
+ buf := NewBuffer(b[0:j])
+ n, _ := buf.Read(tmp[0:i])
+ if n != i {
+ t.Fatalf("Read %d returned %d", i, n)
+ }
+ bb := buf.Next(k)
+ want := k
+ if want > j-i {
+ want = j - i
+ }
+ if len(bb) != want {
+ t.Fatalf("in %d,%d: len(Next(%d)) == %d", i, j, k, len(bb))
+ }
+ for l, v := range bb {
+ if v != byte(l+i) {
+ t.Fatalf("in %d,%d: Next(%d)[%d] = %d, want %d", i, j, k, l, v, l+i)
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go
new file mode 100644
index 000000000..bfe2ef39d
--- /dev/null
+++ b/libgo/go/bytes/bytes.go
@@ -0,0 +1,602 @@
+// 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.
+
+// The bytes package implements functions for the manipulation of byte slices.
+// Analogous to the facilities of the strings package.
+package bytes
+
+import (
+ "unicode"
+ "utf8"
+)
+
+// Compare returns an integer comparing the two byte arrays lexicographically.
+// The result will be 0 if a==b, -1 if a < b, and +1 if a > b
+func Compare(a, b []byte) int {
+ m := len(a)
+ if m > len(b) {
+ m = len(b)
+ }
+ for i, ac := range a[0:m] {
+ bc := b[i]
+ switch {
+ case ac > bc:
+ return 1
+ case ac < bc:
+ return -1
+ }
+ }
+ switch {
+ case len(a) < len(b):
+ return -1
+ case len(a) > len(b):
+ return 1
+ }
+ return 0
+}
+
+// Equal returns a boolean reporting whether a == b.
+func Equal(a, b []byte) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, c := range a {
+ if c != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// explode splits s into an array of UTF-8 sequences, one per Unicode character (still arrays of bytes),
+// up to a maximum of n byte arrays. Invalid UTF-8 sequences are chopped into individual bytes.
+func explode(s []byte, n int) [][]byte {
+ if n <= 0 {
+ n = len(s)
+ }
+ a := make([][]byte, n)
+ var size int
+ na := 0
+ for len(s) > 0 {
+ if na+1 >= n {
+ a[na] = s
+ na++
+ break
+ }
+ _, size = utf8.DecodeRune(s)
+ a[na] = s[0:size]
+ s = s[size:]
+ na++
+ }
+ return a[0:na]
+}
+
+// Count counts the number of non-overlapping instances of sep in s.
+func Count(s, sep []byte) int {
+ if len(sep) == 0 {
+ return utf8.RuneCount(s) + 1
+ }
+ c := sep[0]
+ n := 0
+ for i := 0; i+len(sep) <= len(s); i++ {
+ if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) {
+ n++
+ i += len(sep) - 1
+ }
+ }
+ return n
+}
+
+// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
+func Index(s, sep []byte) int {
+ n := len(sep)
+ if n == 0 {
+ return 0
+ }
+ c := sep[0]
+ for i := 0; i+n <= len(s); i++ {
+ if s[i] == c && (n == 1 || Equal(s[i:i+n], sep)) {
+ return i
+ }
+ }
+ return -1
+}
+
+func indexBytePortable(s []byte, c byte) int {
+ for i, b := range s {
+ if b == c {
+ return i
+ }
+ }
+ return -1
+}
+
+// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
+func LastIndex(s, sep []byte) int {
+ n := len(sep)
+ if n == 0 {
+ return len(s)
+ }
+ c := sep[0]
+ for i := len(s) - n; i >= 0; i-- {
+ if s[i] == c && (n == 1 || Equal(s[i:i+n], sep)) {
+ return i
+ }
+ }
+ return -1
+}
+
+// IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index of the first occurrence in s of the given rune.
+// It returns -1 if rune is not present in s.
+func IndexRune(s []byte, rune int) int {
+ for i := 0; i < len(s); {
+ r, size := utf8.DecodeRune(s[i:])
+ if r == rune {
+ return i
+ }
+ i += size
+ }
+ return -1
+}
+
+// IndexAny interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index of the first occurrence in s of any of the Unicode
+// code points in chars. It returns -1 if chars is empty or if there is no code
+// point in common.
+func IndexAny(s []byte, chars string) int {
+ if len(chars) > 0 {
+ var rune, width int
+ for i := 0; i < len(s); i += width {
+ rune = int(s[i])
+ if rune < utf8.RuneSelf {
+ width = 1
+ } else {
+ rune, width = utf8.DecodeRune(s[i:])
+ }
+ for _, r := range chars {
+ if rune == r {
+ return i
+ }
+ }
+ }
+ }
+ return -1
+}
+
+// LastIndexAny interprets s as a sequence of UTF-8-encoded Unicode code
+// points. It returns the byte index of the last occurrence in s of any of
+// the Unicode code points in chars. It returns -1 if chars is empty or if
+// there is no code point in common.
+func LastIndexAny(s []byte, chars string) int {
+ if len(chars) > 0 {
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRune(s[0:i])
+ i -= size
+ for _, m := range chars {
+ if rune == m {
+ return i
+ }
+ }
+ }
+ }
+ return -1
+}
+
+// Generic split: splits after each instance of sep,
+// including sepSave bytes of sep in the subarrays.
+func genSplit(s, sep []byte, sepSave, n int) [][]byte {
+ if n == 0 {
+ return nil
+ }
+ if len(sep) == 0 {
+ return explode(s, n)
+ }
+ if n < 0 {
+ n = Count(s, sep) + 1
+ }
+ c := sep[0]
+ start := 0
+ a := make([][]byte, n)
+ na := 0
+ for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
+ if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) {
+ a[na] = s[start : i+sepSave]
+ na++
+ start = i + len(sep)
+ i += len(sep) - 1
+ }
+ }
+ a[na] = s[start:]
+ return a[0 : na+1]
+}
+
+// Split slices s into subslices separated by sep and returns a slice of
+// the subslices between those separators.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of subslices to return:
+// n > 0: at most n subslices; the last subslice will be the unsplit remainder.
+// n == 0: the result is nil (zero subslices)
+// n < 0: all subslices
+func Split(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }
+
+// SplitAfter slices s into subslices after each instance of sep and
+// returns a slice of those subslices.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of subslices to return:
+// n > 0: at most n subslices; the last subslice will be the unsplit remainder.
+// n == 0: the result is nil (zero subslices)
+// n < 0: all subslices
+func SplitAfter(s, sep []byte, n int) [][]byte {
+ return genSplit(s, sep, len(sep), n)
+}
+
+// Fields splits the array s around each instance of one or more consecutive white space
+// characters, returning a slice of subarrays of s or an empty list if s contains only white space.
+func Fields(s []byte) [][]byte {
+ return FieldsFunc(s, unicode.IsSpace)
+}
+
+// FieldsFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It splits the array s at each run of code points c satisfying f(c) and
+// returns a slice of subarrays of s. If no code points in s satisfy f(c), an
+// empty slice is returned.
+func FieldsFunc(s []byte, f func(int) bool) [][]byte {
+ n := 0
+ inField := false
+ for i := 0; i < len(s); {
+ rune, size := utf8.DecodeRune(s[i:])
+ wasInField := inField
+ inField = !f(rune)
+ if inField && !wasInField {
+ n++
+ }
+ i += size
+ }
+
+ a := make([][]byte, n)
+ na := 0
+ fieldStart := -1
+ for i := 0; i <= len(s) && na < n; {
+ rune, size := utf8.DecodeRune(s[i:])
+ if fieldStart < 0 && size > 0 && !f(rune) {
+ fieldStart = i
+ i += size
+ continue
+ }
+ if fieldStart >= 0 && (size == 0 || f(rune)) {
+ a[na] = s[fieldStart:i]
+ na++
+ fieldStart = -1
+ }
+ if size == 0 {
+ break
+ }
+ i += size
+ }
+ return a[0:na]
+}
+
+// Join concatenates the elements of a to create a single byte array. The separator
+// sep is placed between elements in the resulting array.
+func Join(a [][]byte, sep []byte) []byte {
+ if len(a) == 0 {
+ return []byte{}
+ }
+ if len(a) == 1 {
+ return a[0]
+ }
+ n := len(sep) * (len(a) - 1)
+ for i := 0; i < len(a); i++ {
+ n += len(a[i])
+ }
+
+ b := make([]byte, n)
+ bp := 0
+ for i := 0; i < len(a); i++ {
+ s := a[i]
+ for j := 0; j < len(s); j++ {
+ b[bp] = s[j]
+ bp++
+ }
+ if i+1 < len(a) {
+ s = sep
+ for j := 0; j < len(s); j++ {
+ b[bp] = s[j]
+ bp++
+ }
+ }
+ }
+ return b
+}
+
+// HasPrefix tests whether the byte array s begins with prefix.
+func HasPrefix(s, prefix []byte) bool {
+ return len(s) >= len(prefix) && Equal(s[0:len(prefix)], prefix)
+}
+
+// HasSuffix tests whether the byte array s ends with suffix.
+func HasSuffix(s, suffix []byte) bool {
+ return len(s) >= len(suffix) && Equal(s[len(s)-len(suffix):], suffix)
+}
+
+// Map returns a copy of the byte array s with all its characters modified
+// according to the mapping function. If mapping returns a negative value, the character is
+// dropped from the string with no replacement. The characters in s and the
+// output are interpreted as UTF-8-encoded Unicode code points.
+func Map(mapping func(rune int) int, s []byte) []byte {
+ // In the worst case, the array can grow when mapped, making
+ // things unpleasant. But it's so rare we barge in assuming it's
+ // fine. It could also shrink but that falls out naturally.
+ maxbytes := len(s) // length of b
+ nbytes := 0 // number of bytes encoded in b
+ b := make([]byte, maxbytes)
+ for i := 0; i < len(s); {
+ wid := 1
+ rune := int(s[i])
+ if rune >= utf8.RuneSelf {
+ rune, wid = utf8.DecodeRune(s[i:])
+ }
+ rune = mapping(rune)
+ if rune >= 0 {
+ if nbytes+utf8.RuneLen(rune) > maxbytes {
+ // Grow the buffer.
+ maxbytes = maxbytes*2 + utf8.UTFMax
+ nb := make([]byte, maxbytes)
+ copy(nb, b[0:nbytes])
+ b = nb
+ }
+ nbytes += utf8.EncodeRune(b[nbytes:maxbytes], rune)
+ }
+ i += wid
+ }
+ return b[0:nbytes]
+}
+
+// Repeat returns a new byte slice consisting of count copies of b.
+func Repeat(b []byte, count int) []byte {
+ nb := make([]byte, len(b)*count)
+ bp := 0
+ for i := 0; i < count; i++ {
+ for j := 0; j < len(b); j++ {
+ nb[bp] = b[j]
+ bp++
+ }
+ }
+ return nb
+}
+
+// ToUpper returns a copy of the byte array s with all Unicode letters mapped to their upper case.
+func ToUpper(s []byte) []byte { return Map(unicode.ToUpper, s) }
+
+// ToUpper returns a copy of the byte array s with all Unicode letters mapped to their lower case.
+func ToLower(s []byte) []byte { return Map(unicode.ToLower, s) }
+
+// ToTitle returns a copy of the byte array s with all Unicode letters mapped to their title case.
+func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) }
+
+// ToUpperSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// upper case, giving priority to the special casing rules.
+func ToUpperSpecial(_case unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r int) int { return _case.ToUpper(r) }, s)
+}
+
+// ToLowerSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// lower case, giving priority to the special casing rules.
+func ToLowerSpecial(_case unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r int) int { return _case.ToLower(r) }, s)
+}
+
+// ToTitleSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// title case, giving priority to the special casing rules.
+func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r int) int { return _case.ToTitle(r) }, s)
+}
+
+
+// isSeparator reports whether the rune could mark a word boundary.
+// TODO: update when package unicode captures more of the properties.
+func isSeparator(rune int) bool {
+ // ASCII alphanumerics and underscore are not separators
+ if rune <= 0x7F {
+ switch {
+ case '0' <= rune && rune <= '9':
+ return false
+ case 'a' <= rune && rune <= 'z':
+ return false
+ case 'A' <= rune && rune <= 'Z':
+ return false
+ case rune == '_':
+ return false
+ }
+ return true
+ }
+ // Letters and digits are not separators
+ if unicode.IsLetter(rune) || unicode.IsDigit(rune) {
+ return false
+ }
+ // Otherwise, all we can do for now is treat spaces as separators.
+ return unicode.IsSpace(rune)
+}
+
+// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+
+// Title returns a copy of s with all Unicode letters that begin words
+// mapped to their title case.
+func Title(s []byte) []byte {
+ // Use a closure here to remember state.
+ // Hackish but effective. Depends on Map scanning in order and calling
+ // the closure once per rune.
+ prev := ' '
+ return Map(
+ func(r int) int {
+ if isSeparator(prev) {
+ prev = r
+ return unicode.ToTitle(r)
+ }
+ prev = r
+ return r
+ },
+ s)
+}
+
+// TrimLeftFunc returns a subslice of s by slicing off all leading UTF-8-encoded
+// Unicode code points c that satisfy f(c).
+func TrimLeftFunc(s []byte, f func(r int) bool) []byte {
+ i := indexFunc(s, f, false)
+ if i == -1 {
+ return nil
+ }
+ return s[i:]
+}
+
+// TrimRightFunc returns a subslice of s by slicing off all trailing UTF-8
+// encoded Unicode code points c that satisfy f(c).
+func TrimRightFunc(s []byte, f func(r int) bool) []byte {
+ i := lastIndexFunc(s, f, false)
+ if i >= 0 && s[i] >= utf8.RuneSelf {
+ _, wid := utf8.DecodeRune(s[i:])
+ i += wid
+ } else {
+ i++
+ }
+ return s[0:i]
+}
+
+// TrimFunc returns a subslice of s by slicing off all leading and trailing
+// UTF-8-encoded Unicode code points c that satisfy f(c).
+func TrimFunc(s []byte, f func(r int) bool) []byte {
+ return TrimRightFunc(TrimLeftFunc(s, f), f)
+}
+
+// IndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index in s of the first Unicode
+// code point satisfying f(c), or -1 if none do.
+func IndexFunc(s []byte, f func(r int) bool) int {
+ return indexFunc(s, f, true)
+}
+
+// LastIndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index in s of the last Unicode
+// code point satisfying f(c), or -1 if none do.
+func LastIndexFunc(s []byte, f func(r int) bool) int {
+ return lastIndexFunc(s, f, true)
+}
+
+// indexFunc is the same as IndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func indexFunc(s []byte, f func(r int) bool, truth bool) int {
+ start := 0
+ for start < len(s) {
+ wid := 1
+ rune := int(s[start])
+ if rune >= utf8.RuneSelf {
+ rune, wid = utf8.DecodeRune(s[start:])
+ }
+ if f(rune) == truth {
+ return start
+ }
+ start += wid
+ }
+ return -1
+}
+
+// lastIndexFunc is the same as LastIndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func lastIndexFunc(s []byte, f func(r int) bool, truth bool) int {
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRune(s[0:i])
+ i -= size
+ if f(rune) == truth {
+ return i
+ }
+ }
+ return -1
+}
+
+func makeCutsetFunc(cutset string) func(rune int) bool {
+ return func(rune int) bool {
+ for _, c := range cutset {
+ if c == rune {
+ return true
+ }
+ }
+ return false
+ }
+}
+
+// Trim returns a subslice of s by slicing off all leading and
+// trailing UTF-8-encoded Unicode code points contained in cutset.
+func Trim(s []byte, cutset string) []byte {
+ return TrimFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimLeft returns a subslice of s by slicing off all leading
+// UTF-8-encoded Unicode code points contained in cutset.
+func TrimLeft(s []byte, cutset string) []byte {
+ return TrimLeftFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimRight returns a subslice of s by slicing off all trailing
+// UTF-8-encoded Unicode code points that are contained in cutset.
+func TrimRight(s []byte, cutset string) []byte {
+ return TrimRightFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimSpace returns a subslice of s by slicing off all leading and
+// trailing white space, as defined by Unicode.
+func TrimSpace(s []byte) []byte {
+ return TrimFunc(s, unicode.IsSpace)
+}
+
+// Runes returns a slice of runes (Unicode code points) equivalent to s.
+func Runes(s []byte) []int {
+ t := make([]int, utf8.RuneCount(s))
+ i := 0
+ for len(s) > 0 {
+ r, l := utf8.DecodeRune(s)
+ t[i] = r
+ i++
+ s = s[l:]
+ }
+ return t
+}
+
+// Replace returns a copy of the slice s with the first n
+// non-overlapping instances of old replaced by new.
+// If n < 0, there is no limit on the number of replacements.
+func Replace(s, old, new []byte, n int) []byte {
+ if n == 0 {
+ return s // avoid allocation
+ }
+ // Compute number of replacements.
+ if m := Count(s, old); m == 0 {
+ return s // avoid allocation
+ } else if n <= 0 || m < n {
+ n = m
+ }
+
+ // Apply replacements to buffer.
+ t := make([]byte, len(s)+n*(len(new)-len(old)))
+ w := 0
+ start := 0
+ for i := 0; i < n; i++ {
+ j := start
+ if len(old) == 0 {
+ if i > 0 {
+ _, wid := utf8.DecodeRune(s[start:])
+ j += wid
+ }
+ } else {
+ j += Index(s[start:], old)
+ }
+ w += copy(t[w:], s[start:j])
+ w += copy(t[w:], new)
+ start = j + len(old)
+ }
+ w += copy(t[w:], s[start:])
+ return t[0:w]
+}
diff --git a/libgo/go/bytes/bytes_decl.go b/libgo/go/bytes/bytes_decl.go
new file mode 100644
index 000000000..5d2b9e639
--- /dev/null
+++ b/libgo/go/bytes/bytes_decl.go
@@ -0,0 +1,8 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes
+
+// IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s.
+func IndexByte(s []byte, c byte) int // asm_$GOARCH.s
diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go
new file mode 100644
index 000000000..063686ec5
--- /dev/null
+++ b/libgo/go/bytes/bytes_test.go
@@ -0,0 +1,844 @@
+// 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 bytes_test
+
+import (
+ . "bytes"
+ "testing"
+ "unicode"
+ "utf8"
+)
+
+func eq(a, b []string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := 0; i < len(a); i++ {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func arrayOfString(a [][]byte) []string {
+ result := make([]string, len(a))
+ for j := 0; j < len(a); j++ {
+ result[j] = string(a[j])
+ }
+ return result
+}
+
+// For ease of reading, the test cases use strings that are converted to byte
+// arrays before invoking the functions.
+
+var abcd = "abcd"
+var faces = "☺☻☹"
+var commas = "1,2,3,4"
+var dots = "1....2....3....4"
+
+type BinOpTest struct {
+ a string
+ b string
+ i int
+}
+
+var comparetests = []BinOpTest{
+ {"", "", 0},
+ {"a", "", 1},
+ {"", "a", -1},
+ {"abc", "abc", 0},
+ {"ab", "abc", -1},
+ {"abc", "ab", 1},
+ {"x", "ab", 1},
+ {"ab", "x", -1},
+ {"x", "a", 1},
+ {"b", "x", -1},
+}
+
+func TestCompare(t *testing.T) {
+ for _, tt := range comparetests {
+ a := []byte(tt.a)
+ b := []byte(tt.b)
+ cmp := Compare(a, b)
+ eql := Equal(a, b)
+ if cmp != tt.i {
+ t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp)
+ }
+ if eql != (tt.i == 0) {
+ t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql)
+ }
+ }
+}
+
+var indexTests = []BinOpTest{
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"oofofoofooo", "f", 2},
+ {"oofofoofooo", "foo", 4},
+ {"barfoobarfoo", "foo", 3},
+ {"foo", "", 0},
+ {"foo", "o", 1},
+ {"abcABCabc", "A", 3},
+ // cases with one byte strings - test IndexByte and special case in Index()
+ {"", "a", -1},
+ {"x", "a", -1},
+ {"x", "x", 0},
+ {"abc", "a", 0},
+ {"abc", "b", 1},
+ {"abc", "c", 2},
+ {"abc", "x", -1},
+ {"barfoobarfooyyyzzzyyyzzzyyyzzzyyyxxxzzzyyy", "x", 33},
+ {"foofyfoobarfoobar", "y", 4},
+ {"oooooooooooooooooooooo", "r", -1},
+}
+
+var lastIndexTests = []BinOpTest{
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"foo", "f", 0},
+ {"oofofoofooo", "f", 7},
+ {"oofofoofooo", "foo", 7},
+ {"barfoobarfoo", "foo", 9},
+ {"foo", "", 3},
+ {"foo", "o", 2},
+ {"abcABCabc", "A", 3},
+ {"abcABCabc", "a", 6},
+}
+
+var indexAnyTests = []BinOpTest{
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 0},
+ {"abc", "xyz", -1},
+ {"abc", "xcz", 2},
+ {"ab☺c", "x☺yz", 2},
+ {"aRegExp*", ".(|)*+?^$[]", 7},
+ {dots + dots + dots, " ", -1},
+}
+
+var lastIndexAnyTests = []BinOpTest{
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 2},
+ {"abc", "xyz", -1},
+ {"abc", "ab", 1},
+ {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"a.RegExp*", ".(|)*+?^$[]", 8},
+ {dots + dots + dots, " ", -1},
+}
+
+var indexRuneTests = []BinOpTest{
+ {"", "a", -1},
+ {"", "☺", -1},
+ {"foo", "☹", -1},
+ {"foo", "o", 1},
+ {"foo☺bar", "☺", 3},
+ {"foo☺☻☹bar", "☹", 9},
+}
+
+// Execute f on each test case. funcName should be the name of f; it's used
+// in failure reports.
+func runIndexTests(t *testing.T, f func(s, sep []byte) int, funcName string, testCases []BinOpTest) {
+ for _, test := range testCases {
+ a := []byte(test.a)
+ b := []byte(test.b)
+ actual := f(a, b)
+ if actual != test.i {
+ t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, b, actual, test.i)
+ }
+ }
+}
+
+func runIndexAnyTests(t *testing.T, f func(s []byte, chars string) int, funcName string, testCases []BinOpTest) {
+ for _, test := range testCases {
+ a := []byte(test.a)
+ actual := f(a, test.b)
+ if actual != test.i {
+ t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, test.b, actual, test.i)
+ }
+ }
+}
+
+func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) }
+func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
+func TestIndexAny(t *testing.T) { runIndexAnyTests(t, IndexAny, "IndexAny", indexAnyTests) }
+func TestLastIndexAny(t *testing.T) {
+ runIndexAnyTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests)
+}
+
+func TestIndexByte(t *testing.T) {
+ for _, tt := range indexTests {
+ if len(tt.b) != 1 {
+ continue
+ }
+ a := []byte(tt.a)
+ b := tt.b[0]
+ pos := IndexByte(a, b)
+ if pos != tt.i {
+ t.Errorf(`IndexByte(%q, '%c') = %v`, tt.a, b, pos)
+ }
+ posp := IndexBytePortable(a, b)
+ if posp != tt.i {
+ t.Errorf(`indexBytePortable(%q, '%c') = %v`, tt.a, b, posp)
+ }
+ }
+}
+
+// test a larger buffer with different sizes and alignments
+func TestIndexByteBig(t *testing.T) {
+ const n = 1024
+ b := make([]byte, n)
+ for i := 0; i < n; i++ {
+ // different start alignments
+ b1 := b[i:]
+ for j := 0; j < len(b1); j++ {
+ b1[j] = 'x'
+ pos := IndexByte(b1, 'x')
+ if pos != j {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ b1[j] = 0
+ pos = IndexByte(b1, 'x')
+ if pos != -1 {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ }
+ // different end alignments
+ b1 = b[:i]
+ for j := 0; j < len(b1); j++ {
+ b1[j] = 'x'
+ pos := IndexByte(b1, 'x')
+ if pos != j {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ b1[j] = 0
+ pos = IndexByte(b1, 'x')
+ if pos != -1 {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ }
+ // different start and end alignments
+ b1 = b[i/2 : n-(i+1)/2]
+ for j := 0; j < len(b1); j++ {
+ b1[j] = 'x'
+ pos := IndexByte(b1, 'x')
+ if pos != j {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ b1[j] = 0
+ pos = IndexByte(b1, 'x')
+ if pos != -1 {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ }
+ }
+}
+
+func TestIndexRune(t *testing.T) {
+ for _, tt := range indexRuneTests {
+ a := []byte(tt.a)
+ r, _ := utf8.DecodeRuneInString(tt.b)
+ pos := IndexRune(a, r)
+ if pos != tt.i {
+ t.Errorf(`IndexRune(%q, '%c') = %v`, tt.a, r, pos)
+ }
+ }
+}
+
+func BenchmarkIndexByte4K(b *testing.B) { bmIndex(b, IndexByte, 4<<10) }
+
+func BenchmarkIndexByte4M(b *testing.B) { bmIndex(b, IndexByte, 4<<20) }
+
+func BenchmarkIndexByte64M(b *testing.B) { bmIndex(b, IndexByte, 64<<20) }
+
+func BenchmarkIndexBytePortable4K(b *testing.B) {
+ bmIndex(b, IndexBytePortable, 4<<10)
+}
+
+func BenchmarkIndexBytePortable4M(b *testing.B) {
+ bmIndex(b, IndexBytePortable, 4<<20)
+}
+
+func BenchmarkIndexBytePortable64M(b *testing.B) {
+ bmIndex(b, IndexBytePortable, 64<<20)
+}
+
+var bmbuf []byte
+
+func bmIndex(b *testing.B, index func([]byte, byte) int, n int) {
+ if len(bmbuf) < n {
+ bmbuf = make([]byte, n)
+ }
+ b.SetBytes(int64(n))
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := index(buf, 'x')
+ if j != n-1 {
+ println("bad index", j)
+ panic("bad index")
+ }
+ }
+ buf[n-1] = '0'
+}
+
+type ExplodeTest struct {
+ s string
+ n int
+ a []string
+}
+
+var explodetests = []ExplodeTest{
+ {"", -1, []string{}},
+ {abcd, -1, []string{"a", "b", "c", "d"}},
+ {faces, -1, []string{"☺", "☻", "☹"}},
+ {abcd, 2, []string{"a", "bcd"}},
+}
+
+func TestExplode(t *testing.T) {
+ for _, tt := range explodetests {
+ a := Split([]byte(tt.s), nil, tt.n)
+ result := arrayOfString(a)
+ if !eq(result, tt.a) {
+ t.Errorf(`Explode("%s", %d) = %v; want %v`, tt.s, tt.n, result, tt.a)
+ continue
+ }
+ s := Join(a, []byte{})
+ if string(s) != tt.s {
+ t.Errorf(`Join(Explode("%s", %d), "") = "%s"`, tt.s, tt.n, s)
+ }
+ }
+}
+
+
+type SplitTest struct {
+ s string
+ sep string
+ n int
+ a []string
+}
+
+var splittests = []SplitTest{
+ {abcd, "a", 0, nil},
+ {abcd, "a", -1, []string{"", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1", "2", "3", "4"}},
+ {dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
+ {faces, "☹", -1, []string{"☺☻", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
+ {"1 2", " ", 3, []string{"1", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplit(t *testing.T) {
+ for _, tt := range splittests {
+ a := Split([]byte(tt.s), []byte(tt.sep), tt.n)
+ result := arrayOfString(a)
+ if !eq(result, tt.a) {
+ t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
+ continue
+ }
+ if tt.n == 0 {
+ continue
+ }
+ s := Join(a, []byte(tt.sep))
+ if string(s) != tt.s {
+ t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
+ }
+ }
+}
+
+var splitaftertests = []SplitTest{
+ {abcd, "a", -1, []string{"a", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1,", "2,", "3,", "4"}},
+ {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
+ {faces, "☹", -1, []string{"☺☻☹", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
+ {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
+ {"1 2", " ", 3, []string{"1 ", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplitAfter(t *testing.T) {
+ for _, tt := range splitaftertests {
+ a := SplitAfter([]byte(tt.s), []byte(tt.sep), tt.n)
+ result := arrayOfString(a)
+ if !eq(result, tt.a) {
+ t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
+ continue
+ }
+ s := Join(a, nil)
+ if string(s) != tt.s {
+ t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
+ }
+ }
+}
+
+type FieldsTest struct {
+ s string
+ a []string
+}
+
+var fieldstests = []FieldsTest{
+ {"", []string{}},
+ {" ", []string{}},
+ {" \t ", []string{}},
+ {" abc ", []string{"abc"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
+ {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
+ {"\u2000\u2001\u2002", []string{}},
+ {"\n™\t™\n", []string{"™", "™"}},
+ {faces, []string{faces}},
+}
+
+func TestFields(t *testing.T) {
+ for _, tt := range fieldstests {
+ a := Fields([]byte(tt.s))
+ result := arrayOfString(a)
+ if !eq(result, tt.a) {
+ t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)
+ continue
+ }
+ }
+}
+
+func TestFieldsFunc(t *testing.T) {
+ pred := func(c int) bool { return c == 'X' }
+ var fieldsFuncTests = []FieldsTest{
+ {"", []string{}},
+ {"XX", []string{}},
+ {"XXhiXXX", []string{"hi"}},
+ {"aXXbXXXcX", []string{"a", "b", "c"}},
+ }
+ for _, tt := range fieldsFuncTests {
+ a := FieldsFunc([]byte(tt.s), pred)
+ result := arrayOfString(a)
+ if !eq(result, tt.a) {
+ t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)
+ }
+ }
+}
+
+// Test case for any function which accepts and returns a byte array.
+// For ease of creation, we write the byte arrays as strings.
+type StringTest struct {
+ in, out string
+}
+
+var upperTests = []StringTest{
+ {"", ""},
+ {"abc", "ABC"},
+ {"AbC123", "ABC123"},
+ {"azAZ09_", "AZAZ09_"},
+ {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
+}
+
+var lowerTests = []StringTest{
+ {"", ""},
+ {"abc", "abc"},
+ {"AbC123", "abc123"},
+ {"azAZ09_", "azaz09_"},
+ {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
+}
+
+const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
+
+var trimSpaceTests = []StringTest{
+ {"", ""},
+ {"abc", "abc"},
+ {space + "abc" + space, "abc"},
+ {" ", ""},
+ {" \t\r\n \t\t\r\r\n\n ", ""},
+ {" \t\r\n x\t\t\r\r\n\n ", "x"},
+ {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},
+ {"1 \t\r\n2", "1 \t\r\n2"},
+ {" x\x80", "x\x80"},
+ {" x\xc0", "x\xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x \xc0", "x \xc0"},
+ {"x \xc0 ", "x \xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"},
+ {"x ☺ ", "x ☺"},
+}
+
+// Execute f on each test case. funcName should be the name of f; it's used
+// in failure reports.
+func runStringTests(t *testing.T, f func([]byte) []byte, funcName string, testCases []StringTest) {
+ for _, tc := range testCases {
+ actual := string(f([]byte(tc.in)))
+ if actual != tc.out {
+ t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out)
+ }
+ }
+}
+
+func tenRunes(rune int) string {
+ r := make([]int, 10)
+ for i := range r {
+ r[i] = rune
+ }
+ return string(r)
+}
+
+// User-defined self-inverse mapping function
+func rot13(rune int) int {
+ step := 13
+ if rune >= 'a' && rune <= 'z' {
+ return ((rune - 'a' + step) % 26) + 'a'
+ }
+ if rune >= 'A' && rune <= 'Z' {
+ return ((rune - 'A' + step) % 26) + 'A'
+ }
+ return rune
+}
+
+func TestMap(t *testing.T) {
+ // Run a couple of awful growth/shrinkage tests
+ a := tenRunes('a')
+
+ // 1. Grow. This triggers two reallocations in Map.
+ maxRune := func(rune int) int { return unicode.MaxRune }
+ m := Map(maxRune, []byte(a))
+ expect := tenRunes(unicode.MaxRune)
+ if string(m) != expect {
+ t.Errorf("growing: expected %q got %q", expect, m)
+ }
+
+ // 2. Shrink
+ minRune := func(rune int) int { return 'a' }
+ m = Map(minRune, []byte(tenRunes(unicode.MaxRune)))
+ expect = a
+ if string(m) != expect {
+ t.Errorf("shrinking: expected %q got %q", expect, m)
+ }
+
+ // 3. Rot13
+ m = Map(rot13, []byte("a to zed"))
+ expect = "n gb mrq"
+ if string(m) != expect {
+ t.Errorf("rot13: expected %q got %q", expect, m)
+ }
+
+ // 4. Rot13^2
+ m = Map(rot13, Map(rot13, []byte("a to zed")))
+ expect = "a to zed"
+ if string(m) != expect {
+ t.Errorf("rot13: expected %q got %q", expect, m)
+ }
+
+ // 5. Drop
+ dropNotLatin := func(rune int) int {
+ if unicode.Is(unicode.Latin, rune) {
+ return rune
+ }
+ return -1
+ }
+ m = Map(dropNotLatin, []byte("Hello, 세계"))
+ expect = "Hello"
+ if string(m) != expect {
+ t.Errorf("drop: expected %q got %q", expect, m)
+ }
+}
+
+func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
+
+func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }
+
+func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
+
+type RepeatTest struct {
+ in, out string
+ count int
+}
+
+var RepeatTests = []RepeatTest{
+ {"", "", 0},
+ {"", "", 1},
+ {"", "", 2},
+ {"-", "", 0},
+ {"-", "-", 1},
+ {"-", "----------", 10},
+ {"abc ", "abc abc abc ", 3},
+}
+
+func TestRepeat(t *testing.T) {
+ for _, tt := range RepeatTests {
+ tin := []byte(tt.in)
+ tout := []byte(tt.out)
+ a := Repeat(tin, tt.count)
+ if !Equal(a, tout) {
+ t.Errorf("Repeat(%q, %d) = %q; want %q", tin, tt.count, a, tout)
+ continue
+ }
+ }
+}
+
+func runesEqual(a, b []int) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, r := range a {
+ if r != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+type RunesTest struct {
+ in string
+ out []int
+ lossy bool
+}
+
+var RunesTests = []RunesTest{
+ {"", []int{}, false},
+ {" ", []int{32}, false},
+ {"ABC", []int{65, 66, 67}, false},
+ {"abc", []int{97, 98, 99}, false},
+ {"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
+ {"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
+ {"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
+}
+
+func TestRunes(t *testing.T) {
+ for _, tt := range RunesTests {
+ tin := []byte(tt.in)
+ a := Runes(tin)
+ if !runesEqual(a, tt.out) {
+ t.Errorf("Runes(%q) = %v; want %v", tin, a, tt.out)
+ continue
+ }
+ if !tt.lossy {
+ // can only test reassembly if we didn't lose information
+ s := string(a)
+ if s != tt.in {
+ t.Errorf("string(Runes(%q)) = %x; want %x", tin, s, tin)
+ }
+ }
+ }
+}
+
+
+type TrimTest struct {
+ f func([]byte, string) []byte
+ in, cutset, out string
+}
+
+var trimTests = []TrimTest{
+ {Trim, "abba", "a", "bb"},
+ {Trim, "abba", "ab", ""},
+ {TrimLeft, "abba", "ab", ""},
+ {TrimRight, "abba", "ab", ""},
+ {TrimLeft, "abba", "a", "bba"},
+ {TrimRight, "abba", "a", "abb"},
+ {Trim, "<tag>", "<>", "tag"},
+ {Trim, "* listitem", " *", "listitem"},
+ {Trim, `"quote"`, `"`, "quote"},
+ {Trim, "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+ //empty string tests
+ {Trim, "abba", "", "abba"},
+ {Trim, "", "123", ""},
+ {Trim, "", "", ""},
+ {TrimLeft, "abba", "", "abba"},
+ {TrimLeft, "", "123", ""},
+ {TrimLeft, "", "", ""},
+ {TrimRight, "abba", "", "abba"},
+ {TrimRight, "", "123", ""},
+ {TrimRight, "", "", ""},
+ {TrimRight, "☺\xc0", "☺", "☺\xc0"},
+}
+
+func TestTrim(t *testing.T) {
+ for _, tc := range trimTests {
+ actual := string(tc.f([]byte(tc.in), tc.cutset))
+ var name string
+ switch tc.f {
+ case Trim:
+ name = "Trim"
+ case TrimLeft:
+ name = "TrimLeft"
+ case TrimRight:
+ name = "TrimRight"
+ default:
+ t.Error("Undefined trim function")
+ }
+ if actual != tc.out {
+ t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
+ }
+ }
+}
+
+type predicate struct {
+ f func(r int) bool
+ name string
+}
+
+var isSpace = predicate{unicode.IsSpace, "IsSpace"}
+var isDigit = predicate{unicode.IsDigit, "IsDigit"}
+var isUpper = predicate{unicode.IsUpper, "IsUpper"}
+var isValidRune = predicate{
+ func(r int) bool {
+ return r != utf8.RuneError
+ },
+ "IsValidRune",
+}
+
+type TrimFuncTest struct {
+ f predicate
+ in, out string
+}
+
+func not(p predicate) predicate {
+ return predicate{
+ func(r int) bool {
+ return !p.f(r)
+ },
+ "not " + p.name,
+ }
+}
+
+var trimFuncTests = []TrimFuncTest{
+ {isSpace, space + " hello " + space, "hello"},
+ {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
+ {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
+ {not(isSpace), "hello" + space + "hello", space},
+ {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"},
+ {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"},
+ {not(isValidRune), "\xc0a\xc0", "a"},
+}
+
+func TestTrimFunc(t *testing.T) {
+ for _, tc := range trimFuncTests {
+ actual := string(TrimFunc([]byte(tc.in), tc.f.f))
+ if actual != tc.out {
+ t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out)
+ }
+ }
+}
+
+type IndexFuncTest struct {
+ in string
+ f predicate
+ first, last int
+}
+
+var indexFuncTests = []IndexFuncTest{
+ {"", isValidRune, -1, -1},
+ {"abc", isDigit, -1, -1},
+ {"0123", isDigit, 0, 3},
+ {"a1b", isDigit, 1, 1},
+ {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes
+ {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},
+ {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},
+ {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},
+
+ // tests of invalid UTF-8
+ {"\x801", isDigit, 1, 1},
+ {"\x80abc", isDigit, -1, -1},
+ {"\xc0a\xc0", isValidRune, 1, 1},
+ {"\xc0a\xc0", not(isValidRune), 0, 2},
+ {"\xc0☺\xc0", not(isValidRune), 0, 4},
+ {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},
+ {"ab\xc0a\xc0cd", not(isValidRune), 2, 4},
+ {"a\xe0\x80cd", not(isValidRune), 1, 2},
+}
+
+func TestIndexFunc(t *testing.T) {
+ for _, tc := range indexFuncTests {
+ first := IndexFunc([]byte(tc.in), tc.f.f)
+ if first != tc.first {
+ t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first)
+ }
+ last := LastIndexFunc([]byte(tc.in), tc.f.f)
+ if last != tc.last {
+ t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last)
+ }
+ }
+}
+
+type ReplaceTest struct {
+ in string
+ old, new string
+ n int
+ out string
+}
+
+var ReplaceTests = []ReplaceTest{
+ {"hello", "l", "L", 0, "hello"},
+ {"hello", "l", "L", -1, "heLLo"},
+ {"hello", "x", "X", -1, "hello"},
+ {"", "x", "X", -1, ""},
+ {"radar", "r", "<r>", -1, "<r>ada<r>"},
+ {"", "", "<>", -1, "<>"},
+ {"banana", "a", "<>", -1, "b<>n<>n<>"},
+ {"banana", "a", "<>", 1, "b<>nana"},
+ {"banana", "a", "<>", 1000, "b<>n<>n<>"},
+ {"banana", "an", "<>", -1, "b<><>a"},
+ {"banana", "ana", "<>", -1, "b<>na"},
+ {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
+ {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
+ {"banana", "", "<>", 1, "<>banana"},
+ {"banana", "a", "a", -1, "banana"},
+ {"banana", "a", "a", 1, "banana"},
+ {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
+}
+
+func TestReplace(t *testing.T) {
+ for _, tt := range ReplaceTests {
+ if s := string(Replace([]byte(tt.in), []byte(tt.old), []byte(tt.new), tt.n)); s != tt.out {
+ t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out)
+ }
+ }
+}
+
+type TitleTest struct {
+ in, out string
+}
+
+var TitleTests = []TitleTest{
+ {"", ""},
+ {"a", "A"},
+ {" aaa aaa aaa ", " Aaa Aaa Aaa "},
+ {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "},
+ {"123a456", "123a456"},
+ {"double-blind", "Double-Blind"},
+ {"ÿøû", "Ÿøû"},
+}
+
+func TestTitle(t *testing.T) {
+ for _, tt := range TitleTests {
+ if s := string(Title([]byte(tt.in))); s != tt.out {
+ t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out)
+ }
+ }
+}
diff --git a/libgo/go/bytes/export_test.go b/libgo/go/bytes/export_test.go
new file mode 100644
index 000000000..b65428d9c
--- /dev/null
+++ b/libgo/go/bytes/export_test.go
@@ -0,0 +1,8 @@
+// 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 bytes
+
+// Export func for testing
+var IndexBytePortable = indexBytePortable
diff --git a/libgo/go/bytes/indexbyte.c b/libgo/go/bytes/indexbyte.c
new file mode 100644
index 000000000..a0a963e93
--- /dev/null
+++ b/libgo/go/bytes/indexbyte.c
@@ -0,0 +1,28 @@
+/* indexbyte.c -- implement bytes.IndexByte for Go.
+
+ 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. */
+
+#include <stddef.h>
+
+#include "array.h"
+
+/* This is in C so that the compiler can optimize it appropriately.
+ We deliberately don't split the stack in case it does call the
+ library function, which shouldn't need much stack space. */
+
+int IndexByte (struct __go_open_array, char)
+ asm ("libgo_bytes.bytes.IndexByte")
+ __attribute__ ((no_split_stack));
+
+int
+IndexByte (struct __go_open_array s, char b)
+{
+ char *p;
+
+ p = __builtin_memchr (s.__values, b, s.__count);
+ if (p == NULL)
+ return -1;
+ return p - (char *) s.__values;
+}
diff --git a/libgo/go/cmath/abs.go b/libgo/go/cmath/abs.go
new file mode 100644
index 000000000..725dc4e98
--- /dev/null
+++ b/libgo/go/cmath/abs.go
@@ -0,0 +1,12 @@
+// 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.
+
+// The cmath package provides basic constants
+// and mathematical functions for complex numbers.
+package cmath
+
+import "math"
+
+// Abs returns the absolute value (also called the modulus) of x.
+func Abs(x complex128) float64 { return math.Hypot(real(x), imag(x)) }
diff --git a/libgo/go/cmath/asin.go b/libgo/go/cmath/asin.go
new file mode 100644
index 000000000..d6a3ca480
--- /dev/null
+++ b/libgo/go/cmath/asin.go
@@ -0,0 +1,170 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex circular arc sine
+//
+// DESCRIPTION:
+//
+// Inverse complex sine:
+// 2
+// w = -i clog( iz + csqrt( 1 - z ) ).
+//
+// casin(z) = -i casinh(iz)
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 10100 2.1e-15 3.4e-16
+// IEEE -10,+10 30000 2.2e-14 2.7e-15
+// Larger relative error can be observed for z near zero.
+// Also tested by csin(casin(z)) = z.
+
+// Asin returns the inverse sine of x.
+func Asin(x complex128) complex128 {
+ if imag(x) == 0 {
+ if math.Fabs(real(x)) > 1 {
+ return complex(math.Pi/2, 0) // DOMAIN error
+ }
+ return complex(math.Asin(real(x)), 0)
+ }
+ ct := complex(-imag(x), real(x)) // i * x
+ xx := x * x
+ x1 := complex(1-real(xx), -imag(xx)) // 1 - x*x
+ x2 := Sqrt(x1) // x2 = sqrt(1 - x*x)
+ w := Log(ct + x2)
+ return complex(imag(w), -real(w)) // -i * w
+}
+
+// Asinh returns the inverse hyperbolic sine of x.
+func Asinh(x complex128) complex128 {
+ // TODO check range
+ if imag(x) == 0 {
+ if math.Fabs(real(x)) > 1 {
+ return complex(math.Pi/2, 0) // DOMAIN error
+ }
+ return complex(math.Asinh(real(x)), 0)
+ }
+ xx := x * x
+ x1 := complex(1+real(xx), imag(xx)) // 1 + x*x
+ return Log(x + Sqrt(x1)) // log(x + sqrt(1 + x*x))
+}
+
+// Complex circular arc cosine
+//
+// DESCRIPTION:
+//
+// w = arccos z = PI/2 - arcsin z.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 5200 1.6e-15 2.8e-16
+// IEEE -10,+10 30000 1.8e-14 2.2e-15
+
+// Acos returns the inverse cosine of x.
+func Acos(x complex128) complex128 {
+ w := Asin(x)
+ return complex(math.Pi/2-real(w), -imag(w))
+}
+
+// Acosh returns the inverse hyperbolic cosine of x.
+func Acosh(x complex128) complex128 {
+ w := Acos(x)
+ if imag(w) <= 0 {
+ return complex(-imag(w), real(w)) // i * w
+ }
+ return complex(imag(w), -real(w)) // -i * w
+}
+
+// Complex circular arc tangent
+//
+// DESCRIPTION:
+//
+// If
+// z = x + iy,
+//
+// then
+// 1 ( 2x )
+// Re w = - arctan(-----------) + k PI
+// 2 ( 2 2)
+// (1 - x - y )
+//
+// ( 2 2)
+// 1 (x + (y+1) )
+// Im w = - log(------------)
+// 4 ( 2 2)
+// (x + (y-1) )
+//
+// Where k is an arbitrary integer.
+//
+// catan(z) = -i catanh(iz).
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 5900 1.3e-16 7.8e-18
+// IEEE -10,+10 30000 2.3e-15 8.5e-17
+// The check catan( ctan(z) ) = z, with |x| and |y| < PI/2,
+// had peak relative error 1.5e-16, rms relative error
+// 2.9e-17. See also clog().
+
+// Atan returns the inverse tangent of x.
+func Atan(x complex128) complex128 {
+ if real(x) == 0 && imag(x) > 1 {
+ return NaN()
+ }
+
+ x2 := real(x) * real(x)
+ a := 1 - x2 - imag(x)*imag(x)
+ if a == 0 {
+ return NaN()
+ }
+ t := 0.5 * math.Atan2(2*real(x), a)
+ w := reducePi(t)
+
+ t = imag(x) - 1
+ b := x2 + t*t
+ if b == 0 {
+ return NaN()
+ }
+ t = imag(x) + 1
+ c := (x2 + t*t) / b
+ return complex(w, 0.25*math.Log(c))
+}
+
+// Atanh returns the inverse hyperbolic tangent of x.
+func Atanh(x complex128) complex128 {
+ z := complex(-imag(x), real(x)) // z = i * x
+ z = Atan(z)
+ return complex(imag(z), -real(z)) // z = -i * z
+}
diff --git a/libgo/go/cmath/cmath_test.go b/libgo/go/cmath/cmath_test.go
new file mode 100644
index 000000000..6a595b0a6
--- /dev/null
+++ b/libgo/go/cmath/cmath_test.go
@@ -0,0 +1,853 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import (
+ "math"
+ "testing"
+)
+
+var vc26 = []complex128{
+ (4.97901192488367350108546816 + 7.73887247457810456552351752i),
+ (7.73887247457810456552351752 - 0.27688005719200159404635997i),
+ (-0.27688005719200159404635997 - 5.01060361827107492160848778i),
+ (-5.01060361827107492160848778 + 9.63629370719841737980004837i),
+ (9.63629370719841737980004837 + 2.92637723924396464525443662i),
+ (2.92637723924396464525443662 + 5.22908343145930665230025625i),
+ (5.22908343145930665230025625 + 2.72793991043601025126008608i),
+ (2.72793991043601025126008608 + 1.82530809168085506044576505i),
+ (1.82530809168085506044576505 - 8.68592476857560136238589621i),
+ (-8.68592476857560136238589621 + 4.97901192488367350108546816i),
+}
+var vc = []complex128{
+ (4.9790119248836735e+00 + 7.7388724745781045e+00i),
+ (7.7388724745781045e+00 - 2.7688005719200159e-01i),
+ (-2.7688005719200159e-01 - 5.0106036182710749e+00i),
+ (-5.0106036182710749e+00 + 9.6362937071984173e+00i),
+ (9.6362937071984173e+00 + 2.9263772392439646e+00i),
+ (2.9263772392439646e+00 + 5.2290834314593066e+00i),
+ (5.2290834314593066e+00 + 2.7279399104360102e+00i),
+ (2.7279399104360102e+00 + 1.8253080916808550e+00i),
+ (1.8253080916808550e+00 - 8.6859247685756013e+00i),
+ (-8.6859247685756013e+00 + 4.9790119248836735e+00i),
+}
+
+// The expected results below were computed by the high precision calculators
+// at http://keisan.casio.com/. More exact input values (array vc[], above)
+// were obtained by printing them with "%.26f". The answers were calculated
+// to 26 digits (by using the "Digit number" drop-down control of each
+// calculator).
+
+var abs = []float64{
+ 9.2022120669932650313380972e+00,
+ 7.7438239742296106616261394e+00,
+ 5.0182478202557746902556648e+00,
+ 1.0861137372799545160704002e+01,
+ 1.0070841084922199607011905e+01,
+ 5.9922447613166942183705192e+00,
+ 5.8978784056736762299945176e+00,
+ 3.2822866700678709020367184e+00,
+ 8.8756430028990417290744307e+00,
+ 1.0011785496777731986390856e+01,
+}
+
+var acos = []complex128{
+ (1.0017679804707456328694569 - 2.9138232718554953784519807i),
+ (0.03606427612041407369636057 + 2.7358584434576260925091256i),
+ (1.6249365462333796703711823 + 2.3159537454335901187730929i),
+ (2.0485650849650740120660391 - 3.0795576791204117911123886i),
+ (0.29621132089073067282488147 - 3.0007392508200622519398814i),
+ (1.0664555914934156601503632 - 2.4872865024796011364747111i),
+ (0.48681307452231387690013905 - 2.463655912283054555225301i),
+ (0.6116977071277574248407752 - 1.8734458851737055262693056i),
+ (1.3649311280370181331184214 + 2.8793528632328795424123832i),
+ (2.6189310485682988308904501 - 2.9956543302898767795858704i),
+}
+var acosh = []complex128{
+ (2.9138232718554953784519807 + 1.0017679804707456328694569i),
+ (2.7358584434576260925091256 - 0.03606427612041407369636057i),
+ (2.3159537454335901187730929 - 1.6249365462333796703711823i),
+ (3.0795576791204117911123886 + 2.0485650849650740120660391i),
+ (3.0007392508200622519398814 + 0.29621132089073067282488147i),
+ (2.4872865024796011364747111 + 1.0664555914934156601503632i),
+ (2.463655912283054555225301 + 0.48681307452231387690013905i),
+ (1.8734458851737055262693056 + 0.6116977071277574248407752i),
+ (2.8793528632328795424123832 - 1.3649311280370181331184214i),
+ (2.9956543302898767795858704 + 2.6189310485682988308904501i),
+}
+var asin = []complex128{
+ (0.56902834632415098636186476 + 2.9138232718554953784519807i),
+ (1.5347320506744825455349611 - 2.7358584434576260925091256i),
+ (-0.054140219438483051139860579 - 2.3159537454335901187730929i),
+ (-0.47776875817017739283471738 + 3.0795576791204117911123886i),
+ (1.2745850059041659464064402 + 3.0007392508200622519398814i),
+ (0.50434073530148095908095852 + 2.4872865024796011364747111i),
+ (1.0839832522725827423311826 + 2.463655912283054555225301i),
+ (0.9590986196671391943905465 + 1.8734458851737055262693056i),
+ (0.20586519875787848611290031 - 2.8793528632328795424123832i),
+ (-1.0481347217734022116591284 + 2.9956543302898767795858704i),
+}
+var asinh = []complex128{
+ (2.9113760469415295679342185 + 0.99639459545704326759805893i),
+ (2.7441755423994259061579029 - 0.035468308789000500601119392i),
+ (-2.2962136462520690506126678 - 1.5144663565690151885726707i),
+ (-3.0771233459295725965402455 + 1.0895577967194013849422294i),
+ (3.0048366100923647417557027 + 0.29346979169819220036454168i),
+ (2.4800059370795363157364643 + 1.0545868606049165710424232i),
+ (2.4718773838309585611141821 + 0.47502344364250803363708842i),
+ (1.8910743588080159144378396 + 0.56882925572563602341139174i),
+ (2.8735426423367341878069406 - 1.362376149648891420997548i),
+ (-2.9981750586172477217567878 + 0.5183571985225367505624207i),
+}
+var atan = []complex128{
+ (1.5115747079332741358607654 + 0.091324403603954494382276776i),
+ (1.4424504323482602560806727 - 0.0045416132642803911503770933i),
+ (-1.5593488703630532674484026 - 0.20163295409248362456446431i),
+ (-1.5280619472445889867794105 + 0.081721556230672003746956324i),
+ (1.4759909163240799678221039 + 0.028602969320691644358773586i),
+ (1.4877353772046548932715555 + 0.14566877153207281663773599i),
+ (1.4206983927779191889826 + 0.076830486127880702249439993i),
+ (1.3162236060498933364869556 + 0.16031313000467530644933363i),
+ (1.5473450684303703578810093 - 0.11064907507939082484935782i),
+ (-1.4841462340185253987375812 + 0.049341850305024399493142411i),
+}
+var atanh = []complex128{
+ (0.058375027938968509064640438 + 1.4793488495105334458167782i),
+ (0.12977343497790381229915667 - 1.5661009410463561327262499i),
+ (-0.010576456067347252072200088 - 1.3743698658402284549750563i),
+ (-0.042218595678688358882784918 + 1.4891433968166405606692604i),
+ (0.095218997991316722061828397 + 1.5416884098777110330499698i),
+ (0.079965459366890323857556487 + 1.4252510353873192700350435i),
+ (0.15051245471980726221708301 + 1.4907432533016303804884461i),
+ (0.25082072933993987714470373 + 1.392057665392187516442986i),
+ (0.022896108815797135846276662 - 1.4609224989282864208963021i),
+ (-0.08665624101841876130537396 + 1.5207902036935093480142159i),
+}
+var conj = []complex128{
+ (4.9790119248836735e+00 - 7.7388724745781045e+00i),
+ (7.7388724745781045e+00 + 2.7688005719200159e-01i),
+ (-2.7688005719200159e-01 + 5.0106036182710749e+00i),
+ (-5.0106036182710749e+00 - 9.6362937071984173e+00i),
+ (9.6362937071984173e+00 - 2.9263772392439646e+00i),
+ (2.9263772392439646e+00 - 5.2290834314593066e+00i),
+ (5.2290834314593066e+00 - 2.7279399104360102e+00i),
+ (2.7279399104360102e+00 - 1.8253080916808550e+00i),
+ (1.8253080916808550e+00 + 8.6859247685756013e+00i),
+ (-8.6859247685756013e+00 - 4.9790119248836735e+00i),
+}
+var cos = []complex128{
+ (3.024540920601483938336569e+02 + 1.1073797572517071650045357e+03i),
+ (1.192858682649064973252758e-01 + 2.7857554122333065540970207e-01i),
+ (7.2144394304528306603857962e+01 - 2.0500129667076044169954205e+01i),
+ (2.24921952538403984190541e+03 - 7.317363745602773587049329e+03i),
+ (-9.148222970032421760015498e+00 + 1.953124661113563541862227e+00i),
+ (-9.116081175857732248227078e+01 - 1.992669213569952232487371e+01i),
+ (3.795639179042704640002918e+00 + 6.623513350981458399309662e+00i),
+ (-2.9144840732498869560679084e+00 - 1.214620271628002917638748e+00i),
+ (-7.45123482501299743872481e+02 + 2.8641692314488080814066734e+03i),
+ (-5.371977967039319076416747e+01 + 4.893348341339375830564624e+01i),
+}
+var cosh = []complex128{
+ (8.34638383523018249366948e+00 + 7.2181057886425846415112064e+01i),
+ (1.10421967379919366952251e+03 - 3.1379638689277575379469861e+02i),
+ (3.051485206773701584738512e-01 - 2.6805384730105297848044485e-01i),
+ (-7.33294728684187933370938e+01 + 1.574445942284918251038144e+01i),
+ (-7.478643293945957535757355e+03 + 1.6348382209913353929473321e+03i),
+ (4.622316522966235701630926e+00 - 8.088695185566375256093098e+00i),
+ (-8.544333183278877406197712e+01 + 3.7505836120128166455231717e+01i),
+ (-1.934457815021493925115198e+00 + 7.3725859611767228178358673e+00i),
+ (-2.352958770061749348353548e+00 - 2.034982010440878358915409e+00i),
+ (7.79756457532134748165069e+02 + 2.8549350716819176560377717e+03i),
+}
+var exp = []complex128{
+ (1.669197736864670815125146e+01 + 1.4436895109507663689174096e+02i),
+ (2.2084389286252583447276212e+03 - 6.2759289284909211238261917e+02i),
+ (2.227538273122775173434327e-01 + 7.2468284028334191250470034e-01i),
+ (-6.5182985958153548997881627e-03 - 1.39965837915193860879044e-03i),
+ (-1.4957286524084015746110777e+04 + 3.269676455931135688988042e+03i),
+ (9.218158701983105935659273e+00 - 1.6223985291084956009304582e+01i),
+ (-1.7088175716853040841444505e+02 + 7.501382609870410713795546e+01i),
+ (-3.852461315830959613132505e+00 + 1.4808420423156073221970892e+01i),
+ (-4.586775503301407379786695e+00 - 4.178501081246873415144744e+00i),
+ (4.451337963005453491095747e-05 - 1.62977574205442915935263e-04i),
+}
+var log = []complex128{
+ (2.2194438972179194425697051e+00 + 9.9909115046919291062461269e-01i),
+ (2.0468956191154167256337289e+00 - 3.5762575021856971295156489e-02i),
+ (1.6130808329853860438751244e+00 - 1.6259990074019058442232221e+00i),
+ (2.3851910394823008710032651e+00 + 2.0502936359659111755031062e+00i),
+ (2.3096442270679923004800651e+00 + 2.9483213155446756211881774e-01i),
+ (1.7904660933974656106951860e+00 + 1.0605860367252556281902109e+00i),
+ (1.7745926939841751666177512e+00 + 4.8084556083358307819310911e-01i),
+ (1.1885403350045342425648780e+00 + 5.8969634164776659423195222e-01i),
+ (2.1833107837679082586772505e+00 - 1.3636647724582455028314573e+00i),
+ (2.3037629487273259170991671e+00 + 2.6210913895386013290915234e+00i),
+}
+var log10 = []complex128{
+ (9.6389223745559042474184943e-01 + 4.338997735671419492599631e-01i),
+ (8.8895547241376579493490892e-01 - 1.5531488990643548254864806e-02i),
+ (7.0055210462945412305244578e-01 - 7.0616239649481243222248404e-01i),
+ (1.0358753067322445311676952e+00 + 8.9043121238134980156490909e-01i),
+ (1.003065742975330237172029e+00 + 1.2804396782187887479857811e-01i),
+ (7.7758954439739162532085157e-01 + 4.6060666333341810869055108e-01i),
+ (7.7069581462315327037689152e-01 + 2.0882857371769952195512475e-01i),
+ (5.1617650901191156135137239e-01 + 2.5610186717615977620363299e-01i),
+ (9.4819982567026639742663212e-01 - 5.9223208584446952284914289e-01i),
+ (1.0005115362454417135973429e+00 + 1.1383255270407412817250921e+00i),
+}
+
+type ff struct {
+ r, theta float64
+}
+
+var polar = []ff{
+ {9.2022120669932650313380972e+00, 9.9909115046919291062461269e-01},
+ {7.7438239742296106616261394e+00, -3.5762575021856971295156489e-02},
+ {5.0182478202557746902556648e+00, -1.6259990074019058442232221e+00},
+ {1.0861137372799545160704002e+01, 2.0502936359659111755031062e+00},
+ {1.0070841084922199607011905e+01, 2.9483213155446756211881774e-01},
+ {5.9922447613166942183705192e+00, 1.0605860367252556281902109e+00},
+ {5.8978784056736762299945176e+00, 4.8084556083358307819310911e-01},
+ {3.2822866700678709020367184e+00, 5.8969634164776659423195222e-01},
+ {8.8756430028990417290744307e+00, -1.3636647724582455028314573e+00},
+ {1.0011785496777731986390856e+01, 2.6210913895386013290915234e+00},
+}
+var pow = []complex128{
+ (-2.499956739197529585028819e+00 + 1.759751724335650228957144e+00i),
+ (7.357094338218116311191939e+04 - 5.089973412479151648145882e+04i),
+ (1.320777296067768517259592e+01 - 3.165621914333901498921986e+01i),
+ (-3.123287828297300934072149e-07 - 1.9849567521490553032502223E-7i),
+ (8.0622651468477229614813e+04 - 7.80028727944573092944363e+04i),
+ (-1.0268824572103165858577141e+00 - 4.716844738244989776610672e-01i),
+ (-4.35953819012244175753187e+01 + 2.2036445974645306917648585e+02i),
+ (8.3556092283250594950239e-01 - 1.2261571947167240272593282e+01i),
+ (1.582292972120769306069625e+03 + 1.273564263524278244782512e+04i),
+ (6.592208301642122149025369e-08 + 2.584887236651661903526389e-08i),
+}
+var sin = []complex128{
+ (-1.1073801774240233539648544e+03 + 3.024539773002502192425231e+02i),
+ (1.0317037521400759359744682e+00 - 3.2208979799929570242818e-02i),
+ (-2.0501952097271429804261058e+01 - 7.2137981348240798841800967e+01i),
+ (7.3173638080346338642193078e+03 + 2.249219506193664342566248e+03i),
+ (-1.964375633631808177565226e+00 - 9.0958264713870404464159683e+00i),
+ (1.992783647158514838337674e+01 - 9.11555769410191350416942e+01i),
+ (-6.680335650741921444300349e+00 + 3.763353833142432513086117e+00i),
+ (1.2794028166657459148245993e+00 - 2.7669092099795781155109602e+00i),
+ (2.8641693949535259594188879e+03 + 7.451234399649871202841615e+02i),
+ (-4.893811726244659135553033e+01 - 5.371469305562194635957655e+01i),
+}
+var sinh = []complex128{
+ (8.34559353341652565758198e+00 + 7.2187893208650790476628899e+01i),
+ (1.1042192548260646752051112e+03 - 3.1379650595631635858792056e+02i),
+ (-8.239469336509264113041849e-02 + 9.9273668758439489098514519e-01i),
+ (7.332295456982297798219401e+01 - 1.574585908122833444899023e+01i),
+ (-7.4786432301380582103534216e+03 + 1.63483823493980029604071e+03i),
+ (4.595842179016870234028347e+00 - 8.135290105518580753211484e+00i),
+ (-8.543842533574163435246793e+01 + 3.750798997857594068272375e+01i),
+ (-1.918003500809465688017307e+00 + 7.4358344619793504041350251e+00i),
+ (-2.233816733239658031433147e+00 - 2.143519070805995056229335e+00i),
+ (-7.797564130187551181105341e+02 - 2.8549352346594918614806877e+03i),
+}
+var sqrt = []complex128{
+ (2.6628203086086130543813948e+00 + 1.4531345674282185229796902e+00i),
+ (2.7823278427251986247149295e+00 - 4.9756907317005224529115567e-02i),
+ (1.5397025302089642757361015e+00 - 1.6271336573016637535695727e+00i),
+ (1.7103411581506875260277898e+00 + 2.8170677122737589676157029e+00i),
+ (3.1390392472953103383607947e+00 + 4.6612625849858653248980849e-01i),
+ (2.1117080764822417640789287e+00 + 1.2381170223514273234967850e+00i),
+ (2.3587032281672256703926939e+00 + 5.7827111903257349935720172e-01i),
+ (1.7335262588873410476661577e+00 + 5.2647258220721269141550382e-01i),
+ (2.3131094974708716531499282e+00 - 1.8775429304303785570775490e+00i),
+ (8.1420535745048086240947359e-01 + 3.0575897587277248522656113e+00i),
+}
+var tan = []complex128{
+ (-1.928757919086441129134525e-07 + 1.0000003267499169073251826e+00i),
+ (1.242412685364183792138948e+00 - 3.17149693883133370106696e+00i),
+ (-4.6745126251587795225571826e-05 - 9.9992439225263959286114298e-01i),
+ (4.792363401193648192887116e-09 + 1.0000000070589333451557723e+00i),
+ (2.345740824080089140287315e-03 + 9.947733046570988661022763e-01i),
+ (-2.396030789494815566088809e-05 + 9.9994781345418591429826779e-01i),
+ (-7.370204836644931340905303e-03 + 1.0043553413417138987717748e+00i),
+ (-3.691803847992048527007457e-02 + 9.6475071993469548066328894e-01i),
+ (-2.781955256713729368401878e-08 - 1.000000049848910609006646e+00i),
+ (9.4281590064030478879791249e-05 + 9.9999119340863718183758545e-01i),
+}
+var tanh = []complex128{
+ (1.0000921981225144748819918e+00 + 2.160986245871518020231507e-05i),
+ (9.9999967727531993209562591e-01 - 1.9953763222959658873657676e-07i),
+ (-1.765485739548037260789686e+00 + 1.7024216325552852445168471e+00i),
+ (-9.999189442732736452807108e-01 + 3.64906070494473701938098e-05i),
+ (9.9999999224622333738729767e-01 - 3.560088949517914774813046e-09i),
+ (1.0029324933367326862499343e+00 - 4.948790309797102353137528e-03i),
+ (9.9996113064788012488693567e-01 - 4.226995742097032481451259e-05i),
+ (1.0074784189316340029873945e+00 - 4.194050814891697808029407e-03i),
+ (9.9385534229718327109131502e-01 + 5.144217985914355502713437e-02i),
+ (-1.0000000491604982429364892e+00 - 2.901873195374433112227349e-08i),
+}
+
+// special cases
+var vcAbsSC = []complex128{
+ NaN(),
+}
+var absSC = []float64{
+ math.NaN(),
+}
+var vcAcosSC = []complex128{
+ NaN(),
+}
+var acosSC = []complex128{
+ NaN(),
+}
+var vcAcoshSC = []complex128{
+ NaN(),
+}
+var acoshSC = []complex128{
+ NaN(),
+}
+var vcAsinSC = []complex128{
+ NaN(),
+}
+var asinSC = []complex128{
+ NaN(),
+}
+var vcAsinhSC = []complex128{
+ NaN(),
+}
+var asinhSC = []complex128{
+ NaN(),
+}
+var vcAtanSC = []complex128{
+ NaN(),
+}
+var atanSC = []complex128{
+ NaN(),
+}
+var vcAtanhSC = []complex128{
+ NaN(),
+}
+var atanhSC = []complex128{
+ NaN(),
+}
+var vcConjSC = []complex128{
+ NaN(),
+}
+var conjSC = []complex128{
+ NaN(),
+}
+var vcCosSC = []complex128{
+ NaN(),
+}
+var cosSC = []complex128{
+ NaN(),
+}
+var vcCoshSC = []complex128{
+ NaN(),
+}
+var coshSC = []complex128{
+ NaN(),
+}
+var vcExpSC = []complex128{
+ NaN(),
+}
+var expSC = []complex128{
+ NaN(),
+}
+var vcIsNaNSC = []complex128{
+ complex(math.Inf(-1), math.Inf(-1)),
+ complex(math.Inf(-1), math.NaN()),
+ complex(math.NaN(), math.Inf(-1)),
+ complex(0, math.NaN()),
+ complex(math.NaN(), 0),
+ complex(math.Inf(1), math.Inf(1)),
+ complex(math.Inf(1), math.NaN()),
+ complex(math.NaN(), math.Inf(1)),
+ complex(math.NaN(), math.NaN()),
+}
+var isNaNSC = []bool{
+ false,
+ false,
+ false,
+ true,
+ true,
+ false,
+ false,
+ false,
+ true,
+}
+var vcLogSC = []complex128{
+ NaN(),
+}
+var logSC = []complex128{
+ NaN(),
+}
+var vcLog10SC = []complex128{
+ NaN(),
+}
+var log10SC = []complex128{
+ NaN(),
+}
+var vcPolarSC = []complex128{
+ NaN(),
+}
+var polarSC = []ff{
+ {math.NaN(), math.NaN()},
+}
+var vcPowSC = [][2]complex128{
+ {NaN(), NaN()},
+}
+var powSC = []complex128{
+ NaN(),
+}
+var vcSinSC = []complex128{
+ NaN(),
+}
+var sinSC = []complex128{
+ NaN(),
+}
+var vcSinhSC = []complex128{
+ NaN(),
+}
+var sinhSC = []complex128{
+ NaN(),
+}
+var vcSqrtSC = []complex128{
+ NaN(),
+}
+var sqrtSC = []complex128{
+ NaN(),
+}
+var vcTanSC = []complex128{
+ NaN(),
+}
+var tanSC = []complex128{
+ NaN(),
+}
+var vcTanhSC = []complex128{
+ NaN(),
+}
+var tanhSC = []complex128{
+ NaN(),
+}
+
+// functions borrowed from pkg/math/all_test.go
+func tolerance(a, b, e float64) bool {
+ d := a - b
+ if d < 0 {
+ d = -d
+ }
+
+ if a != 0 {
+ e = e * a
+ if e < 0 {
+ e = -e
+ }
+ }
+ return d < e
+}
+func soclose(a, b, e float64) bool { return tolerance(a, b, e) }
+func veryclose(a, b float64) bool { return tolerance(a, b, 4e-16) }
+func alike(a, b float64) bool {
+ switch {
+ case a != a && b != b: // math.IsNaN(a) && math.IsNaN(b):
+ return true
+ case a == b:
+ return math.Signbit(a) == math.Signbit(b)
+ }
+ return false
+}
+
+func cTolerance(a, b complex128, e float64) bool {
+ d := Abs(a - b)
+ if a != 0 {
+ e = e * Abs(a)
+ if e < 0 {
+ e = -e
+ }
+ }
+ return d < e
+}
+func cSoclose(a, b complex128, e float64) bool { return cTolerance(a, b, e) }
+func cVeryclose(a, b complex128) bool { return cTolerance(a, b, 4e-16) }
+func cAlike(a, b complex128) bool {
+ switch {
+ case IsNaN(a) && IsNaN(b):
+ return true
+ case a == b:
+ return math.Signbit(real(a)) == math.Signbit(real(b)) && math.Signbit(imag(a)) == math.Signbit(imag(b))
+ }
+ return false
+}
+
+func TestAbs(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Abs(vc[i]); !veryclose(abs[i], f) {
+ t.Errorf("Abs(%g) = %g, want %g", vc[i], f, abs[i])
+ }
+ }
+ for i := 0; i < len(vcAbsSC); i++ {
+ if f := Abs(vcAbsSC[i]); !alike(absSC[i], f) {
+ t.Errorf("Abs(%g) = %g, want %g", vcAbsSC[i], f, absSC[i])
+ }
+ }
+}
+func TestAcos(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Acos(vc[i]); !cSoclose(acos[i], f, 1e-14) {
+ t.Errorf("Acos(%g) = %g, want %g", vc[i], f, acos[i])
+ }
+ }
+ for i := 0; i < len(vcAcosSC); i++ {
+ if f := Acos(vcAcosSC[i]); !cAlike(acosSC[i], f) {
+ t.Errorf("Acos(%g) = %g, want %g", vcAcosSC[i], f, acosSC[i])
+ }
+ }
+}
+func TestAcosh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Acosh(vc[i]); !cSoclose(acosh[i], f, 1e-14) {
+ t.Errorf("Acosh(%g) = %g, want %g", vc[i], f, acosh[i])
+ }
+ }
+ for i := 0; i < len(vcAcoshSC); i++ {
+ if f := Acosh(vcAcoshSC[i]); !cAlike(acoshSC[i], f) {
+ t.Errorf("Acosh(%g) = %g, want %g", vcAcoshSC[i], f, acoshSC[i])
+ }
+ }
+}
+func TestAsin(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Asin(vc[i]); !cSoclose(asin[i], f, 1e-14) {
+ t.Errorf("Asin(%g) = %g, want %g", vc[i], f, asin[i])
+ }
+ }
+ for i := 0; i < len(vcAsinSC); i++ {
+ if f := Asin(vcAsinSC[i]); !cAlike(asinSC[i], f) {
+ t.Errorf("Asin(%g) = %g, want %g", vcAsinSC[i], f, asinSC[i])
+ }
+ }
+}
+func TestAsinh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Asinh(vc[i]); !cSoclose(asinh[i], f, 4e-15) {
+ t.Errorf("Asinh(%g) = %g, want %g", vc[i], f, asinh[i])
+ }
+ }
+ for i := 0; i < len(vcAsinhSC); i++ {
+ if f := Asinh(vcAsinhSC[i]); !cAlike(asinhSC[i], f) {
+ t.Errorf("Asinh(%g) = %g, want %g", vcAsinhSC[i], f, asinhSC[i])
+ }
+ }
+}
+func TestAtan(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Atan(vc[i]); !cVeryclose(atan[i], f) {
+ t.Errorf("Atan(%g) = %g, want %g", vc[i], f, atan[i])
+ }
+ }
+ for i := 0; i < len(vcAtanSC); i++ {
+ if f := Atan(vcAtanSC[i]); !cAlike(atanSC[i], f) {
+ t.Errorf("Atan(%g) = %g, want %g", vcAtanSC[i], f, atanSC[i])
+ }
+ }
+}
+func TestAtanh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Atanh(vc[i]); !cVeryclose(atanh[i], f) {
+ t.Errorf("Atanh(%g) = %g, want %g", vc[i], f, atanh[i])
+ }
+ }
+ for i := 0; i < len(vcAtanhSC); i++ {
+ if f := Atanh(vcAtanhSC[i]); !cAlike(atanhSC[i], f) {
+ t.Errorf("Atanh(%g) = %g, want %g", vcAtanhSC[i], f, atanhSC[i])
+ }
+ }
+}
+func TestConj(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Conj(vc[i]); !cVeryclose(conj[i], f) {
+ t.Errorf("Conj(%g) = %g, want %g", vc[i], f, conj[i])
+ }
+ }
+ for i := 0; i < len(vcConjSC); i++ {
+ if f := Conj(vcConjSC[i]); !cAlike(conjSC[i], f) {
+ t.Errorf("Conj(%g) = %g, want %g", vcConjSC[i], f, conjSC[i])
+ }
+ }
+}
+func TestCos(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Cos(vc[i]); !cSoclose(cos[i], f, 3e-15) {
+ t.Errorf("Cos(%g) = %g, want %g", vc[i], f, cos[i])
+ }
+ }
+ for i := 0; i < len(vcCosSC); i++ {
+ if f := Cos(vcCosSC[i]); !cAlike(cosSC[i], f) {
+ t.Errorf("Cos(%g) = %g, want %g", vcCosSC[i], f, cosSC[i])
+ }
+ }
+}
+func TestCosh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Cosh(vc[i]); !cSoclose(cosh[i], f, 2e-15) {
+ t.Errorf("Cosh(%g) = %g, want %g", vc[i], f, cosh[i])
+ }
+ }
+ for i := 0; i < len(vcCoshSC); i++ {
+ if f := Cosh(vcCoshSC[i]); !cAlike(coshSC[i], f) {
+ t.Errorf("Cosh(%g) = %g, want %g", vcCoshSC[i], f, coshSC[i])
+ }
+ }
+}
+func TestExp(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Exp(vc[i]); !cSoclose(exp[i], f, 1e-15) {
+ t.Errorf("Exp(%g) = %g, want %g", vc[i], f, exp[i])
+ }
+ }
+ for i := 0; i < len(vcExpSC); i++ {
+ if f := Exp(vcExpSC[i]); !cAlike(expSC[i], f) {
+ t.Errorf("Exp(%g) = %g, want %g", vcExpSC[i], f, expSC[i])
+ }
+ }
+}
+func TestIsNaN(t *testing.T) {
+ for i := 0; i < len(vcIsNaNSC); i++ {
+ if f := IsNaN(vcIsNaNSC[i]); isNaNSC[i] != f {
+ t.Errorf("IsNaN(%v) = %v, want %v", vcIsNaNSC[i], f, isNaNSC[i])
+ }
+ }
+}
+func TestLog(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Log(vc[i]); !cVeryclose(log[i], f) {
+ t.Errorf("Log(%g) = %g, want %g", vc[i], f, log[i])
+ }
+ }
+ for i := 0; i < len(vcLogSC); i++ {
+ if f := Log(vcLogSC[i]); !cAlike(logSC[i], f) {
+ t.Errorf("Log(%g) = %g, want %g", vcLogSC[i], f, logSC[i])
+ }
+ }
+}
+func TestLog10(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Log10(vc[i]); !cVeryclose(log10[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", vc[i], f, log10[i])
+ }
+ }
+ for i := 0; i < len(vcLog10SC); i++ {
+ if f := Log10(vcLog10SC[i]); !cAlike(log10SC[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", vcLog10SC[i], f, log10SC[i])
+ }
+ }
+}
+func TestPolar(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if r, theta := Polar(vc[i]); !veryclose(polar[i].r, r) && !veryclose(polar[i].theta, theta) {
+ t.Errorf("Polar(%g) = %g, %g want %g, %g", vc[i], r, theta, polar[i].r, polar[i].theta)
+ }
+ }
+ for i := 0; i < len(vcPolarSC); i++ {
+ if r, theta := Polar(vcPolarSC[i]); !alike(polarSC[i].r, r) && !alike(polarSC[i].theta, theta) {
+ t.Errorf("Polar(%g) = %g, %g, want %g, %g", vcPolarSC[i], r, theta, polarSC[i].r, polarSC[i].theta)
+ }
+ }
+}
+func TestPow(t *testing.T) {
+ var a = complex(3.0, 3.0)
+ for i := 0; i < len(vc); i++ {
+ if f := Pow(a, vc[i]); !cSoclose(pow[i], f, 4e-15) {
+ t.Errorf("Pow(%g, %g) = %g, want %g", a, vc[i], f, pow[i])
+ }
+ }
+ for i := 0; i < len(vcPowSC); i++ {
+ if f := Pow(vcPowSC[i][0], vcPowSC[i][0]); !cAlike(powSC[i], f) {
+ t.Errorf("Pow(%g, %g) = %g, want %g", vcPowSC[i][0], vcPowSC[i][0], f, powSC[i])
+ }
+ }
+}
+func TestRect(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Rect(polar[i].r, polar[i].theta); !cVeryclose(vc[i], f) {
+ t.Errorf("Rect(%g, %g) = %g want %g", polar[i].r, polar[i].theta, f, vc[i])
+ }
+ }
+ for i := 0; i < len(vcPolarSC); i++ {
+ if f := Rect(polarSC[i].r, polarSC[i].theta); !cAlike(vcPolarSC[i], f) {
+ t.Errorf("Rect(%g, %g) = %g, want %g", polarSC[i].r, polarSC[i].theta, f, vcPolarSC[i])
+ }
+ }
+}
+func TestSin(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Sin(vc[i]); !cSoclose(sin[i], f, 2e-15) {
+ t.Errorf("Sin(%g) = %g, want %g", vc[i], f, sin[i])
+ }
+ }
+ for i := 0; i < len(vcSinSC); i++ {
+ if f := Sin(vcSinSC[i]); !cAlike(sinSC[i], f) {
+ t.Errorf("Sin(%g) = %g, want %g", vcSinSC[i], f, sinSC[i])
+ }
+ }
+}
+func TestSinh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Sinh(vc[i]); !cSoclose(sinh[i], f, 2e-15) {
+ t.Errorf("Sinh(%g) = %g, want %g", vc[i], f, sinh[i])
+ }
+ }
+ for i := 0; i < len(vcSinhSC); i++ {
+ if f := Sinh(vcSinhSC[i]); !cAlike(sinhSC[i], f) {
+ t.Errorf("Sinh(%g) = %g, want %g", vcSinhSC[i], f, sinhSC[i])
+ }
+ }
+}
+func TestSqrt(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Sqrt(vc[i]); !cVeryclose(sqrt[i], f) {
+ t.Errorf("Sqrt(%g) = %g, want %g", vc[i], f, sqrt[i])
+ }
+ }
+ for i := 0; i < len(vcSqrtSC); i++ {
+ if f := Sqrt(vcSqrtSC[i]); !cAlike(sqrtSC[i], f) {
+ t.Errorf("Sqrt(%g) = %g, want %g", vcSqrtSC[i], f, sqrtSC[i])
+ }
+ }
+}
+func TestTan(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Tan(vc[i]); !cSoclose(tan[i], f, 3e-15) {
+ t.Errorf("Tan(%g) = %g, want %g", vc[i], f, tan[i])
+ }
+ }
+ for i := 0; i < len(vcTanSC); i++ {
+ if f := Tan(vcTanSC[i]); !cAlike(tanSC[i], f) {
+ t.Errorf("Tan(%g) = %g, want %g", vcTanSC[i], f, tanSC[i])
+ }
+ }
+}
+func TestTanh(t *testing.T) {
+ for i := 0; i < len(vc); i++ {
+ if f := Tanh(vc[i]); !cSoclose(tanh[i], f, 2e-15) {
+ t.Errorf("Tanh(%g) = %g, want %g", vc[i], f, tanh[i])
+ }
+ }
+ for i := 0; i < len(vcTanhSC); i++ {
+ if f := Tanh(vcTanhSC[i]); !cAlike(tanhSC[i], f) {
+ t.Errorf("Tanh(%g) = %g, want %g", vcTanhSC[i], f, tanhSC[i])
+ }
+ }
+}
+
+func BenchmarkAbs(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Abs(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAcos(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Acos(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAcosh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Acosh(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAsin(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Asin(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAsinh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Asinh(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAtan(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atan(complex(2.5, 3.5))
+ }
+}
+func BenchmarkAtanh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atanh(complex(2.5, 3.5))
+ }
+}
+func BenchmarkConj(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Conj(complex(2.5, 3.5))
+ }
+}
+func BenchmarkCos(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Cos(complex(2.5, 3.5))
+ }
+}
+func BenchmarkCosh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Cosh(complex(2.5, 3.5))
+ }
+}
+func BenchmarkExp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Exp(complex(2.5, 3.5))
+ }
+}
+func BenchmarkLog(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log(complex(2.5, 3.5))
+ }
+}
+func BenchmarkLog10(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log10(complex(2.5, 3.5))
+ }
+}
+func BenchmarkPhase(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Phase(complex(2.5, 3.5))
+ }
+}
+func BenchmarkPolar(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Polar(complex(2.5, 3.5))
+ }
+}
+func BenchmarkPow(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Pow(complex(2.5, 3.5), complex(2.5, 3.5))
+ }
+}
+func BenchmarkRect(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Rect(2.5, 1.5)
+ }
+}
+func BenchmarkSin(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sin(complex(2.5, 3.5))
+ }
+}
+func BenchmarkSinh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sinh(complex(2.5, 3.5))
+ }
+}
+func BenchmarkSqrt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sqrt(complex(2.5, 3.5))
+ }
+}
+func BenchmarkTan(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Tan(complex(2.5, 3.5))
+ }
+}
+func BenchmarkTanh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Tanh(complex(2.5, 3.5))
+ }
+}
diff --git a/libgo/go/cmath/conj.go b/libgo/go/cmath/conj.go
new file mode 100644
index 000000000..776b57da7
--- /dev/null
+++ b/libgo/go/cmath/conj.go
@@ -0,0 +1,8 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+// Conj returns the complex conjugate of x.
+func Conj(x complex128) complex128 { return complex(real(x), -imag(x)) }
diff --git a/libgo/go/cmath/exp.go b/libgo/go/cmath/exp.go
new file mode 100644
index 000000000..64c1ef409
--- /dev/null
+++ b/libgo/go/cmath/exp.go
@@ -0,0 +1,55 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex exponential function
+//
+// DESCRIPTION:
+//
+// Returns the complex exponential of the complex argument z.
+//
+// If
+// z = x + iy,
+// r = exp(x),
+// then
+// w = r cos y + i r sin y.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 8700 3.7e-17 1.1e-17
+// IEEE -10,+10 30000 3.0e-16 8.7e-17
+
+// Exp returns e**x, the base-e exponential of x.
+func Exp(x complex128) complex128 {
+ r := math.Exp(real(x))
+ s, c := math.Sincos(imag(x))
+ return complex(r*c, r*s)
+}
diff --git a/libgo/go/cmath/isinf.go b/libgo/go/cmath/isinf.go
new file mode 100644
index 000000000..f23d2dea7
--- /dev/null
+++ b/libgo/go/cmath/isinf.go
@@ -0,0 +1,21 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// IsInf returns true if either real(x) or imag(x) is an infinity.
+func IsInf(x complex128) bool {
+ if math.IsInf(real(x), 0) || math.IsInf(imag(x), 0) {
+ return true
+ }
+ return false
+}
+
+// Inf returns a complex infinity, complex(+Inf, +Inf).
+func Inf() complex128 {
+ inf := math.Inf(1)
+ return complex(inf, inf)
+}
diff --git a/libgo/go/cmath/isnan.go b/libgo/go/cmath/isnan.go
new file mode 100644
index 000000000..2063bb835
--- /dev/null
+++ b/libgo/go/cmath/isnan.go
@@ -0,0 +1,25 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// IsNaN returns true if either real(x) or imag(x) is NaN
+// and neither is an infinity.
+func IsNaN(x complex128) bool {
+ switch {
+ case math.IsInf(real(x), 0) || math.IsInf(imag(x), 0):
+ return false
+ case math.IsNaN(real(x)) || math.IsNaN(imag(x)):
+ return true
+ }
+ return false
+}
+
+// NaN returns a complex ``not-a-number'' value.
+func NaN() complex128 {
+ nan := math.NaN()
+ return complex(nan, nan)
+}
diff --git a/libgo/go/cmath/log.go b/libgo/go/cmath/log.go
new file mode 100644
index 000000000..8e6964fee
--- /dev/null
+++ b/libgo/go/cmath/log.go
@@ -0,0 +1,64 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex natural logarithm
+//
+// DESCRIPTION:
+//
+// Returns complex logarithm to the base e (2.718...) of
+// the complex argument z.
+//
+// If
+// z = x + iy, r = sqrt( x**2 + y**2 ),
+// then
+// w = log(r) + i arctan(y/x).
+//
+// The arctangent ranges from -PI to +PI.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 7000 8.5e-17 1.9e-17
+// IEEE -10,+10 30000 5.0e-15 1.1e-16
+//
+// Larger relative error can be observed for z near 1 +i0.
+// In IEEE arithmetic the peak absolute error is 5.2e-16, rms
+// absolute error 1.0e-16.
+
+// Log returns the natural logarithm of x.
+func Log(x complex128) complex128 {
+ return complex(math.Log(Abs(x)), Phase(x))
+}
+
+// Log10 returns the decimal logarithm of x.
+func Log10(x complex128) complex128 {
+ return math.Log10E * Log(x)
+}
diff --git a/libgo/go/cmath/phase.go b/libgo/go/cmath/phase.go
new file mode 100644
index 000000000..2d67aa34c
--- /dev/null
+++ b/libgo/go/cmath/phase.go
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// Phase returns the phase (also called the argument) of x.
+// The returned value is in the range [-Pi, Pi].
+func Phase(x complex128) float64 { return math.Atan2(imag(x), real(x)) }
diff --git a/libgo/go/cmath/polar.go b/libgo/go/cmath/polar.go
new file mode 100644
index 000000000..033676acc
--- /dev/null
+++ b/libgo/go/cmath/polar.go
@@ -0,0 +1,12 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+// Polar returns the absolute value r and phase θ of x,
+// such that x = r * e**θi.
+// The phase is in the range [-Pi, Pi].
+func Polar(x complex128) (r, θ float64) {
+ return Abs(x), Phase(x)
+}
diff --git a/libgo/go/cmath/pow.go b/libgo/go/cmath/pow.go
new file mode 100644
index 000000000..68e1207c6
--- /dev/null
+++ b/libgo/go/cmath/pow.go
@@ -0,0 +1,60 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex power function
+//
+// DESCRIPTION:
+//
+// Raises complex A to the complex Zth power.
+// Definition is per AMS55 # 4.2.8,
+// analytically equivalent to cpow(a,z) = cexp(z clog(a)).
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// IEEE -10,+10 30000 9.4e-15 1.5e-15
+
+// Pow returns x**y, the base-x exponential of y.
+func Pow(x, y complex128) complex128 {
+ modulus := Abs(x)
+ if modulus == 0 {
+ return complex(0, 0)
+ }
+ r := math.Pow(modulus, real(y))
+ arg := Phase(x)
+ theta := real(y) * arg
+ if imag(y) != 0 {
+ r *= math.Exp(-imag(y) * arg)
+ theta += imag(y) * math.Log(modulus)
+ }
+ s, c := math.Sincos(theta)
+ return complex(r*c, r*s)
+}
diff --git a/libgo/go/cmath/rect.go b/libgo/go/cmath/rect.go
new file mode 100644
index 000000000..b955f0bf7
--- /dev/null
+++ b/libgo/go/cmath/rect.go
@@ -0,0 +1,13 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// Rect returns the complex number x with polar coordinates r, θ.
+func Rect(r, θ float64) complex128 {
+ s, c := math.Sincos(θ)
+ return complex(r*c, r*s)
+}
diff --git a/libgo/go/cmath/sin.go b/libgo/go/cmath/sin.go
new file mode 100644
index 000000000..8900ecdde
--- /dev/null
+++ b/libgo/go/cmath/sin.go
@@ -0,0 +1,132 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex circular sine
+//
+// DESCRIPTION:
+//
+// If
+// z = x + iy,
+//
+// then
+//
+// w = sin x cosh y + i cos x sinh y.
+//
+// csin(z) = -i csinh(iz).
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 8400 5.3e-17 1.3e-17
+// IEEE -10,+10 30000 3.8e-16 1.0e-16
+// Also tested by csin(casin(z)) = z.
+
+// Sin returns the sine of x.
+func Sin(x complex128) complex128 {
+ s, c := math.Sincos(real(x))
+ sh, ch := sinhcosh(imag(x))
+ return complex(s*ch, c*sh)
+}
+
+// Complex hyperbolic sine
+//
+// DESCRIPTION:
+//
+// csinh z = (cexp(z) - cexp(-z))/2
+// = sinh x * cos y + i cosh x * sin y .
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// IEEE -10,+10 30000 3.1e-16 8.2e-17
+
+// Sinh returns the hyperbolic sine of x.
+func Sinh(x complex128) complex128 {
+ s, c := math.Sincos(imag(x))
+ sh, ch := sinhcosh(real(x))
+ return complex(c*sh, s*ch)
+}
+
+// Complex circular cosine
+//
+// DESCRIPTION:
+//
+// If
+// z = x + iy,
+//
+// then
+//
+// w = cos x cosh y - i sin x sinh y.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 8400 4.5e-17 1.3e-17
+// IEEE -10,+10 30000 3.8e-16 1.0e-16
+
+// Cos returns the cosine of x.
+func Cos(x complex128) complex128 {
+ s, c := math.Sincos(real(x))
+ sh, ch := sinhcosh(imag(x))
+ return complex(c*ch, -s*sh)
+}
+
+// Complex hyperbolic cosine
+//
+// DESCRIPTION:
+//
+// ccosh(z) = cosh x cos y + i sinh x sin y .
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// IEEE -10,+10 30000 2.9e-16 8.1e-17
+
+// Cosh returns the hyperbolic cosine of x.
+func Cosh(x complex128) complex128 {
+ s, c := math.Sincos(imag(x))
+ sh, ch := sinhcosh(real(x))
+ return complex(c*ch, s*sh)
+}
+
+// calculate sinh and cosh
+func sinhcosh(x float64) (sh, ch float64) {
+ if math.Fabs(x) <= 0.5 {
+ return math.Sinh(x), math.Cosh(x)
+ }
+ e := math.Exp(x)
+ ei := 0.5 / e
+ e *= 0.5
+ return e - ei, e + ei
+}
diff --git a/libgo/go/cmath/sqrt.go b/libgo/go/cmath/sqrt.go
new file mode 100644
index 000000000..e77a9b9df
--- /dev/null
+++ b/libgo/go/cmath/sqrt.go
@@ -0,0 +1,103 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex square root
+//
+// DESCRIPTION:
+//
+// If z = x + iy, r = |z|, then
+//
+// 1/2
+// Re w = [ (r + x)/2 ] ,
+//
+// 1/2
+// Im w = [ (r - x)/2 ] .
+//
+// Cancellation error in r-x or r+x is avoided by using the
+// identity 2 Re w Im w = y.
+//
+// Note that -w is also a square root of z. The root chosen
+// is always in the right half plane and Im w has the same sign as y.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 25000 3.2e-17 9.6e-18
+// IEEE -10,+10 1,000,000 2.9e-16 6.1e-17
+
+// Sqrt returns the square root of x.
+func Sqrt(x complex128) complex128 {
+ if imag(x) == 0 {
+ if real(x) == 0 {
+ return complex(0, 0)
+ }
+ if real(x) < 0 {
+ return complex(0, math.Sqrt(-real(x)))
+ }
+ return complex(math.Sqrt(real(x)), 0)
+ }
+ if real(x) == 0 {
+ if imag(x) < 0 {
+ r := math.Sqrt(-0.5 * imag(x))
+ return complex(r, -r)
+ }
+ r := math.Sqrt(0.5 * imag(x))
+ return complex(r, r)
+ }
+ a := real(x)
+ b := imag(x)
+ var scale float64
+ // Rescale to avoid internal overflow or underflow.
+ if math.Fabs(a) > 4 || math.Fabs(b) > 4 {
+ a *= 0.25
+ b *= 0.25
+ scale = 2
+ } else {
+ a *= 1.8014398509481984e16 // 2**54
+ b *= 1.8014398509481984e16
+ scale = 7.450580596923828125e-9 // 2**-27
+ }
+ r := math.Hypot(a, b)
+ var t float64
+ if a > 0 {
+ t = math.Sqrt(0.5*r + 0.5*a)
+ r = scale * math.Fabs((0.5*b)/t)
+ t *= scale
+ } else {
+ r = math.Sqrt(0.5*r - 0.5*a)
+ t = scale * math.Fabs((0.5*b)/r)
+ r *= scale
+ }
+ if b < 0 {
+ return complex(t, -r)
+ }
+ return complex(t, r)
+}
diff --git a/libgo/go/cmath/tan.go b/libgo/go/cmath/tan.go
new file mode 100644
index 000000000..94b517521
--- /dev/null
+++ b/libgo/go/cmath/tan.go
@@ -0,0 +1,184 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmath
+
+import "math"
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
+// The go code is a simplified version of the original C.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// Complex circular tangent
+//
+// DESCRIPTION:
+//
+// If
+// z = x + iy,
+//
+// then
+//
+// sin 2x + i sinh 2y
+// w = --------------------.
+// cos 2x + cosh 2y
+//
+// On the real axis the denominator is zero at odd multiples
+// of PI/2. The denominator is evaluated by its Taylor
+// series near these points.
+//
+// ctan(z) = -i ctanh(iz).
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 5200 7.1e-17 1.6e-17
+// IEEE -10,+10 30000 7.2e-16 1.2e-16
+// Also tested by ctan * ccot = 1 and catan(ctan(z)) = z.
+
+// Tan returns the tangent of x.
+func Tan(x complex128) complex128 {
+ d := math.Cos(2*real(x)) + math.Cosh(2*imag(x))
+ if math.Fabs(d) < 0.25 {
+ d = tanSeries(x)
+ }
+ if d == 0 {
+ return Inf()
+ }
+ return complex(math.Sin(2*real(x))/d, math.Sinh(2*imag(x))/d)
+}
+
+// Complex hyperbolic tangent
+//
+// DESCRIPTION:
+//
+// tanh z = (sinh 2x + i sin 2y) / (cosh 2x + cos 2y) .
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// IEEE -10,+10 30000 1.7e-14 2.4e-16
+
+// Tanh returns the hyperbolic tangent of x.
+func Tanh(x complex128) complex128 {
+ d := math.Cosh(2*real(x)) + math.Cos(2*imag(x))
+ if d == 0 {
+ return Inf()
+ }
+ return complex(math.Sinh(2*real(x))/d, math.Sin(2*imag(x))/d)
+}
+
+// Program to subtract nearest integer multiple of PI
+func reducePi(x float64) float64 {
+ const (
+ // extended precision value of PI:
+ DP1 = 3.14159265160560607910E0 // ?? 0x400921fb54000000
+ DP2 = 1.98418714791870343106E-9 // ?? 0x3e210b4610000000
+ DP3 = 1.14423774522196636802E-17 // ?? 0x3c6a62633145c06e
+ )
+ t := x / math.Pi
+ if t >= 0 {
+ t += 0.5
+ } else {
+ t -= 0.5
+ }
+ t = float64(int64(t)) // int64(t) = the multiple
+ return ((x - t*DP1) - t*DP2) - t*DP3
+}
+
+// Taylor series expansion for cosh(2y) - cos(2x)
+func tanSeries(z complex128) float64 {
+ const MACHEP = 1.0 / (1 << 53)
+ x := math.Fabs(2 * real(z))
+ y := math.Fabs(2 * imag(z))
+ x = reducePi(x)
+ x = x * x
+ y = y * y
+ x2 := 1.0
+ y2 := 1.0
+ f := 1.0
+ rn := 0.0
+ d := 0.0
+ for {
+ rn += 1
+ f *= rn
+ rn += 1
+ f *= rn
+ x2 *= x
+ y2 *= y
+ t := y2 + x2
+ t /= f
+ d += t
+
+ rn += 1
+ f *= rn
+ rn += 1
+ f *= rn
+ x2 *= x
+ y2 *= y
+ t = y2 - x2
+ t /= f
+ d += t
+ if math.Fabs(t/d) <= MACHEP {
+ break
+ }
+ }
+ return d
+}
+
+// Complex circular cotangent
+//
+// DESCRIPTION:
+//
+// If
+// z = x + iy,
+//
+// then
+//
+// sin 2x - i sinh 2y
+// w = --------------------.
+// cosh 2y - cos 2x
+//
+// On the real axis, the denominator has zeros at even
+// multiples of PI/2. Near these points it is evaluated
+// by a Taylor series.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -10,+10 3000 6.5e-17 1.6e-17
+// IEEE -10,+10 30000 9.2e-16 1.2e-16
+// Also tested by ctan * ccot = 1 + i0.
+
+// Cot returns the cotangent of x.
+func Cot(x complex128) complex128 {
+ d := math.Cosh(2*imag(x)) - math.Cos(2*real(x))
+ if math.Fabs(d) < 0.25 {
+ d = tanSeries(x)
+ }
+ if d == 0 {
+ return Inf()
+ }
+ return complex(math.Sin(2*real(x))/d, -math.Sinh(2*imag(x))/d)
+}
diff --git a/libgo/go/compress/flate/deflate.go b/libgo/go/compress/flate/deflate.go
new file mode 100644
index 000000000..591b35c44
--- /dev/null
+++ b/libgo/go/compress/flate/deflate.go
@@ -0,0 +1,521 @@
+// 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 flate
+
+import (
+ "io"
+ "math"
+ "os"
+)
+
+const (
+ NoCompression = 0
+ BestSpeed = 1
+ fastCompression = 3
+ BestCompression = 9
+ DefaultCompression = -1
+ logMaxOffsetSize = 15 // Standard DEFLATE
+ wideLogMaxOffsetSize = 22 // Wide DEFLATE
+ minMatchLength = 3 // The smallest match that the compressor looks for
+ maxMatchLength = 258 // The longest match for the compressor
+ minOffsetSize = 1 // The shortest offset that makes any sence
+
+ // The maximum number of tokens we put into a single flat block, just too
+ // stop things from getting too large.
+ maxFlateBlockTokens = 1 << 14
+ maxStoreBlockSize = 65535
+ hashBits = 15
+ hashSize = 1 << hashBits
+ hashMask = (1 << hashBits) - 1
+ hashShift = (hashBits + minMatchLength - 1) / minMatchLength
+)
+
+type syncPipeReader struct {
+ *io.PipeReader
+ closeChan chan bool
+}
+
+func (sr *syncPipeReader) CloseWithError(err os.Error) os.Error {
+ retErr := sr.PipeReader.CloseWithError(err)
+ sr.closeChan <- true // finish writer close
+ return retErr
+}
+
+type syncPipeWriter struct {
+ *io.PipeWriter
+ closeChan chan bool
+}
+
+type compressionLevel struct {
+ good, lazy, nice, chain, fastSkipHashing int
+}
+
+var levels = []compressionLevel{
+ {}, // 0
+ // For levels 1-3 we don't bother trying with lazy matches
+ {3, 0, 8, 4, 4},
+ {3, 0, 16, 8, 5},
+ {3, 0, 32, 32, 6},
+ // Levels 4-9 use increasingly more lazy matching
+ // and increasingly stringent conditions for "good enough".
+ {4, 4, 16, 16, math.MaxInt32},
+ {8, 16, 32, 32, math.MaxInt32},
+ {8, 16, 128, 128, math.MaxInt32},
+ {8, 32, 128, 256, math.MaxInt32},
+ {32, 128, 258, 1024, math.MaxInt32},
+ {32, 258, 258, 4096, math.MaxInt32},
+}
+
+func (sw *syncPipeWriter) Close() os.Error {
+ err := sw.PipeWriter.Close()
+ <-sw.closeChan // wait for reader close
+ return err
+}
+
+func syncPipe() (*syncPipeReader, *syncPipeWriter) {
+ r, w := io.Pipe()
+ sr := &syncPipeReader{r, make(chan bool, 1)}
+ sw := &syncPipeWriter{w, sr.closeChan}
+ return sr, sw
+}
+
+type compressor struct {
+ level int
+ logWindowSize uint
+ w *huffmanBitWriter
+ r io.Reader
+ // (1 << logWindowSize) - 1.
+ windowMask int
+
+ eof bool // has eof been reached on input?
+ sync bool // writer wants to flush
+ syncChan chan os.Error
+
+ // hashHead[hashValue] contains the largest inputIndex with the specified hash value
+ hashHead []int
+
+ // If hashHead[hashValue] is within the current window, then
+ // hashPrev[hashHead[hashValue] & windowMask] contains the previous index
+ // with the same hash value.
+ hashPrev []int
+
+ // If we find a match of length >= niceMatch, then we don't bother searching
+ // any further.
+ niceMatch int
+
+ // If we find a match of length >= goodMatch, we only do a half-hearted
+ // effort at doing lazy matching starting at the next character
+ goodMatch int
+
+ // The maximum number of chains we look at when finding a match
+ maxChainLength int
+
+ // The sliding window we use for matching
+ window []byte
+
+ // The index just past the last valid character
+ windowEnd int
+
+ // index in "window" at which current block starts
+ blockStart int
+}
+
+func (d *compressor) flush() os.Error {
+ d.w.flush()
+ return d.w.err
+}
+
+func (d *compressor) fillWindow(index int) (int, os.Error) {
+ if d.sync {
+ return index, nil
+ }
+ wSize := d.windowMask + 1
+ if index >= wSize+wSize-(minMatchLength+maxMatchLength) {
+ // shift the window by wSize
+ copy(d.window, d.window[wSize:2*wSize])
+ index -= wSize
+ d.windowEnd -= wSize
+ if d.blockStart >= wSize {
+ d.blockStart -= wSize
+ } else {
+ d.blockStart = math.MaxInt32
+ }
+ for i, h := range d.hashHead {
+ d.hashHead[i] = max(h-wSize, -1)
+ }
+ for i, h := range d.hashPrev {
+ d.hashPrev[i] = max(h-wSize, -1)
+ }
+ }
+ count, err := d.r.Read(d.window[d.windowEnd:])
+ d.windowEnd += count
+ if count == 0 && err == nil {
+ d.sync = true
+ }
+ if err == os.EOF {
+ d.eof = true
+ err = nil
+ }
+ return index, err
+}
+
+func (d *compressor) writeBlock(tokens []token, index int, eof bool) os.Error {
+ if index > 0 || eof {
+ var window []byte
+ if d.blockStart <= index {
+ window = d.window[d.blockStart:index]
+ }
+ d.blockStart = index
+ d.w.writeBlock(tokens, eof, window)
+ return d.w.err
+ }
+ return nil
+}
+
+// Try to find a match starting at index whose length is greater than prevSize.
+// We only look at chainCount possibilities before giving up.
+func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) {
+ win := d.window[0 : pos+min(maxMatchLength, lookahead)]
+
+ // We quit when we get a match that's at least nice long
+ nice := min(d.niceMatch, len(win)-pos)
+
+ // If we've got a match that's good enough, only look in 1/4 the chain.
+ tries := d.maxChainLength
+ length = prevLength
+ if length >= d.goodMatch {
+ tries >>= 2
+ }
+
+ w0 := win[pos]
+ w1 := win[pos+1]
+ wEnd := win[pos+length]
+ minIndex := pos - (d.windowMask + 1)
+
+ for i := prevHead; tries > 0; tries-- {
+ if w0 == win[i] && w1 == win[i+1] && wEnd == win[i+length] {
+ // The hash function ensures that if win[i] and win[i+1] match, win[i+2] matches
+
+ n := 3
+ for pos+n < len(win) && win[i+n] == win[pos+n] {
+ n++
+ }
+ if n > length && (n > 3 || pos-i <= 4096) {
+ length = n
+ offset = pos - i
+ ok = true
+ if n >= nice {
+ // The match is good enough that we don't try to find a better one.
+ break
+ }
+ wEnd = win[pos+n]
+ }
+ }
+ if i == minIndex {
+ // hashPrev[i & windowMask] has already been overwritten, so stop now.
+ break
+ }
+ if i = d.hashPrev[i&d.windowMask]; i < minIndex || i < 0 {
+ break
+ }
+ }
+ return
+}
+
+func (d *compressor) writeStoredBlock(buf []byte) os.Error {
+ if d.w.writeStoredHeader(len(buf), false); d.w.err != nil {
+ return d.w.err
+ }
+ d.w.writeBytes(buf)
+ return d.w.err
+}
+
+func (d *compressor) storedDeflate() os.Error {
+ buf := make([]byte, maxStoreBlockSize)
+ for {
+ n, err := d.r.Read(buf)
+ if n == 0 && err == nil {
+ d.sync = true
+ }
+ if n > 0 || d.sync {
+ if err := d.writeStoredBlock(buf[0:n]); err != nil {
+ return err
+ }
+ if d.sync {
+ d.syncChan <- nil
+ d.sync = false
+ }
+ }
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ return err
+ }
+ }
+ return nil
+}
+
+func (d *compressor) doDeflate() (err os.Error) {
+ // init
+ d.windowMask = 1<<d.logWindowSize - 1
+ d.hashHead = make([]int, hashSize)
+ d.hashPrev = make([]int, 1<<d.logWindowSize)
+ d.window = make([]byte, 2<<d.logWindowSize)
+ fillInts(d.hashHead, -1)
+ tokens := make([]token, maxFlateBlockTokens, maxFlateBlockTokens+1)
+ l := levels[d.level]
+ d.goodMatch = l.good
+ d.niceMatch = l.nice
+ d.maxChainLength = l.chain
+ lazyMatch := l.lazy
+ length := minMatchLength - 1
+ offset := 0
+ byteAvailable := false
+ isFastDeflate := l.fastSkipHashing != 0
+ index := 0
+ // run
+ if index, err = d.fillWindow(index); err != nil {
+ return
+ }
+ maxOffset := d.windowMask + 1 // (1 << logWindowSize);
+ // only need to change when you refill the window
+ windowEnd := d.windowEnd
+ maxInsertIndex := windowEnd - (minMatchLength - 1)
+ ti := 0
+
+ hash := int(0)
+ if index < maxInsertIndex {
+ hash = int(d.window[index])<<hashShift + int(d.window[index+1])
+ }
+ chainHead := -1
+Loop:
+ for {
+ if index > windowEnd {
+ panic("index > windowEnd")
+ }
+ lookahead := windowEnd - index
+ if lookahead < minMatchLength+maxMatchLength {
+ if index, err = d.fillWindow(index); err != nil {
+ return
+ }
+ windowEnd = d.windowEnd
+ if index > windowEnd {
+ panic("index > windowEnd")
+ }
+ maxInsertIndex = windowEnd - (minMatchLength - 1)
+ lookahead = windowEnd - index
+ if lookahead == 0 {
+ // Flush current output block if any.
+ if byteAvailable {
+ // There is still one pending token that needs to be flushed
+ tokens[ti] = literalToken(uint32(d.window[index-1]) & 0xFF)
+ ti++
+ byteAvailable = false
+ }
+ if ti > 0 {
+ if err = d.writeBlock(tokens[0:ti], index, false); err != nil {
+ return
+ }
+ ti = 0
+ }
+ if d.sync {
+ d.w.writeStoredHeader(0, false)
+ d.w.flush()
+ d.syncChan <- d.w.err
+ d.sync = false
+ }
+
+ // If this was only a sync (not at EOF) keep going.
+ if !d.eof {
+ continue
+ }
+ break Loop
+ }
+ }
+ if index < maxInsertIndex {
+ // Update the hash
+ hash = (hash<<hashShift + int(d.window[index+2])) & hashMask
+ chainHead = d.hashHead[hash]
+ d.hashPrev[index&d.windowMask] = chainHead
+ d.hashHead[hash] = index
+ }
+ prevLength := length
+ prevOffset := offset
+ minIndex := max(index-maxOffset, 0)
+ length = minMatchLength - 1
+ offset = 0
+
+ if chainHead >= minIndex &&
+ (isFastDeflate && lookahead > minMatchLength-1 ||
+ !isFastDeflate && lookahead > prevLength && prevLength < lazyMatch) {
+ if newLength, newOffset, ok := d.findMatch(index, chainHead, minMatchLength-1, lookahead); ok {
+ length = newLength
+ offset = newOffset
+ }
+ }
+ if isFastDeflate && length >= minMatchLength ||
+ !isFastDeflate && prevLength >= minMatchLength && length <= prevLength {
+ // There was a match at the previous step, and the current match is
+ // not better. Output the previous match.
+ if isFastDeflate {
+ tokens[ti] = matchToken(uint32(length-minMatchLength), uint32(offset-minOffsetSize))
+ } else {
+ tokens[ti] = matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize))
+ }
+ ti++
+ // Insert in the hash table all strings up to the end of the match.
+ // index and index-1 are already inserted. If there is not enough
+ // lookahead, the last two strings are not inserted into the hash
+ // table.
+ if length <= l.fastSkipHashing {
+ var newIndex int
+ if isFastDeflate {
+ newIndex = index + length
+ } else {
+ newIndex = prevLength - 1
+ }
+ for index++; index < newIndex; index++ {
+ if index < maxInsertIndex {
+ hash = (hash<<hashShift + int(d.window[index+2])) & hashMask
+ // Get previous value with the same hash.
+ // Our chain should point to the previous value.
+ d.hashPrev[index&d.windowMask] = d.hashHead[hash]
+ // Set the head of the hash chain to us.
+ d.hashHead[hash] = index
+ }
+ }
+ if !isFastDeflate {
+ byteAvailable = false
+ length = minMatchLength - 1
+ }
+ } else {
+ // For matches this long, we don't bother inserting each individual
+ // item into the table.
+ index += length
+ hash = (int(d.window[index])<<hashShift + int(d.window[index+1]))
+ }
+ if ti == maxFlateBlockTokens {
+ // The block includes the current character
+ if err = d.writeBlock(tokens, index, false); err != nil {
+ return
+ }
+ ti = 0
+ }
+ } else {
+ if isFastDeflate || byteAvailable {
+ i := index - 1
+ if isFastDeflate {
+ i = index
+ }
+ tokens[ti] = literalToken(uint32(d.window[i]) & 0xFF)
+ ti++
+ if ti == maxFlateBlockTokens {
+ if err = d.writeBlock(tokens, i+1, false); err != nil {
+ return
+ }
+ ti = 0
+ }
+ }
+ index++
+ if !isFastDeflate {
+ byteAvailable = true
+ }
+ }
+ }
+ return
+}
+
+func (d *compressor) compress(r io.Reader, w io.Writer, level int, logWindowSize uint) (err os.Error) {
+ d.r = r
+ d.w = newHuffmanBitWriter(w)
+ d.level = level
+ d.logWindowSize = logWindowSize
+
+ switch {
+ case level == NoCompression:
+ err = d.storedDeflate()
+ case level == DefaultCompression:
+ d.level = 6
+ fallthrough
+ case 1 <= level && level <= 9:
+ err = d.doDeflate()
+ default:
+ return WrongValueError{"level", 0, 9, int32(level)}
+ }
+
+ if d.sync {
+ d.syncChan <- err
+ d.sync = false
+ }
+ if err != nil {
+ return err
+ }
+ if d.w.writeStoredHeader(0, true); d.w.err != nil {
+ return d.w.err
+ }
+ return d.flush()
+}
+
+// NewWriter returns a new Writer compressing
+// data at the given level. Following zlib, levels
+// range from 1 (BestSpeed) to 9 (BestCompression);
+// higher levels typically run slower but compress more.
+// Level 0 (NoCompression) does not attempt any
+// compression; it only adds the necessary DEFLATE framing.
+func NewWriter(w io.Writer, level int) *Writer {
+ const logWindowSize = logMaxOffsetSize
+ var d compressor
+ d.syncChan = make(chan os.Error, 1)
+ pr, pw := syncPipe()
+ go func() {
+ err := d.compress(pr, w, level, logWindowSize)
+ pr.CloseWithError(err)
+ }()
+ return &Writer{pw, &d}
+}
+
+// A Writer takes data written to it and writes the compressed
+// form of that data to an underlying writer (see NewWriter).
+type Writer struct {
+ w *syncPipeWriter
+ d *compressor
+}
+
+// Write writes data to w, which will eventually write the
+// compressed form of data to its underlying writer.
+func (w *Writer) Write(data []byte) (n int, err os.Error) {
+ if len(data) == 0 {
+ // no point, and nil interferes with sync
+ return
+ }
+ return w.w.Write(data)
+}
+
+// Flush flushes any pending compressed data to the underlying writer.
+// It is useful mainly in compressed network protocols, to ensure that
+// a remote reader has enough data to reconstruct a packet.
+// Flush does not return until the data has been written.
+// If the underlying writer returns an error, Flush returns that error.
+//
+// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
+func (w *Writer) Flush() os.Error {
+ // For more about flushing:
+ // http://www.bolet.org/~pornin/deflate-flush.html
+ if w.d.sync {
+ panic("compress/flate: double Flush")
+ }
+ _, err := w.w.Write(nil)
+ err1 := <-w.d.syncChan
+ if err == nil {
+ err = err1
+ }
+ return err
+}
+
+// Close flushes and closes the writer.
+func (w *Writer) Close() os.Error {
+ return w.w.Close()
+}
diff --git a/libgo/go/compress/flate/deflate_test.go b/libgo/go/compress/flate/deflate_test.go
new file mode 100644
index 000000000..3db955609
--- /dev/null
+++ b/libgo/go/compress/flate/deflate_test.go
@@ -0,0 +1,389 @@
+// 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 flate
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "sync"
+ "testing"
+)
+
+type deflateTest struct {
+ in []byte
+ level int
+ out []byte
+}
+
+type deflateInflateTest struct {
+ in []byte
+}
+
+type reverseBitsTest struct {
+ in uint16
+ bitCount uint8
+ out uint16
+}
+
+var deflateTests = []*deflateTest{
+ &deflateTest{[]byte{}, 0, []byte{1, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11}, -1, []byte{18, 4, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11}, DefaultCompression, []byte{18, 4, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11}, 4, []byte{18, 4, 4, 0, 0, 255, 255}},
+
+ &deflateTest{[]byte{0x11}, 0, []byte{0, 1, 0, 254, 255, 17, 1, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x12}, 0, []byte{0, 2, 0, 253, 255, 17, 18, 1, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0,
+ []byte{0, 8, 0, 247, 255, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0, 0, 255, 255},
+ },
+ &deflateTest{[]byte{}, 1, []byte{1, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11}, 1, []byte{18, 4, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x12}, 1, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 1, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
+ &deflateTest{[]byte{}, 9, []byte{1, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
+ &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
+}
+
+var deflateInflateTests = []*deflateInflateTest{
+ &deflateInflateTest{[]byte{}},
+ &deflateInflateTest{[]byte{0x11}},
+ &deflateInflateTest{[]byte{0x11, 0x12}},
+ &deflateInflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
+ &deflateInflateTest{[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}},
+ &deflateInflateTest{getLargeDataChunk()},
+}
+
+var reverseBitsTests = []*reverseBitsTest{
+ &reverseBitsTest{1, 1, 1},
+ &reverseBitsTest{1, 2, 2},
+ &reverseBitsTest{1, 3, 4},
+ &reverseBitsTest{1, 4, 8},
+ &reverseBitsTest{1, 5, 16},
+ &reverseBitsTest{17, 5, 17},
+ &reverseBitsTest{257, 9, 257},
+ &reverseBitsTest{29, 5, 23},
+}
+
+func getLargeDataChunk() []byte {
+ result := make([]byte, 100000)
+ for i := range result {
+ result[i] = byte(int64(i) * int64(i) & 0xFF)
+ }
+ return result
+}
+
+func TestDeflate(t *testing.T) {
+ for _, h := range deflateTests {
+ buffer := bytes.NewBuffer(nil)
+ w := NewWriter(buffer, h.level)
+ w.Write(h.in)
+ w.Close()
+ if bytes.Compare(buffer.Bytes(), h.out) != 0 {
+ t.Errorf("buffer is wrong; level = %v, buffer.Bytes() = %v, expected output = %v",
+ h.level, buffer.Bytes(), h.out)
+ }
+ }
+}
+
+type syncBuffer struct {
+ buf bytes.Buffer
+ mu sync.RWMutex
+ closed bool
+ ready chan bool
+}
+
+func newSyncBuffer() *syncBuffer {
+ return &syncBuffer{ready: make(chan bool, 1)}
+}
+
+func (b *syncBuffer) Read(p []byte) (n int, err os.Error) {
+ for {
+ b.mu.RLock()
+ n, err = b.buf.Read(p)
+ b.mu.RUnlock()
+ if n > 0 || b.closed {
+ return
+ }
+ <-b.ready
+ }
+ panic("unreachable")
+}
+
+func (b *syncBuffer) Write(p []byte) (n int, err os.Error) {
+ n, err = b.buf.Write(p)
+ _ = b.ready <- true
+ return
+}
+
+func (b *syncBuffer) WriteMode() {
+ b.mu.Lock()
+}
+
+func (b *syncBuffer) ReadMode() {
+ b.mu.Unlock()
+ _ = b.ready <- true
+}
+
+func (b *syncBuffer) Close() os.Error {
+ b.closed = true
+ _ = b.ready <- true
+ return nil
+}
+
+func testSync(t *testing.T, level int, input []byte, name string) {
+ if len(input) == 0 {
+ return
+ }
+
+ t.Logf("--testSync %d, %d, %s", level, len(input), name)
+ buf := newSyncBuffer()
+ buf1 := new(bytes.Buffer)
+ buf.WriteMode()
+ w := NewWriter(io.MultiWriter(buf, buf1), level)
+ r := NewReader(buf)
+
+ // Write half the input and read back.
+ for i := 0; i < 2; i++ {
+ var lo, hi int
+ if i == 0 {
+ lo, hi = 0, (len(input)+1)/2
+ } else {
+ lo, hi = (len(input)+1)/2, len(input)
+ }
+ t.Logf("#%d: write %d-%d", i, lo, hi)
+ if _, err := w.Write(input[lo:hi]); err != nil {
+ t.Errorf("testSync: write: %v", err)
+ return
+ }
+ if i == 0 {
+ if err := w.Flush(); err != nil {
+ t.Errorf("testSync: flush: %v", err)
+ return
+ }
+ } else {
+ if err := w.Close(); err != nil {
+ t.Errorf("testSync: close: %v", err)
+ }
+ }
+ buf.ReadMode()
+ out := make([]byte, hi-lo+1)
+ m, err := io.ReadAtLeast(r, out, hi-lo)
+ t.Logf("#%d: read %d", i, m)
+ if m != hi-lo || err != nil {
+ t.Errorf("testSync/%d (%d, %d, %s): read %d: %d, %v (%d left)", i, level, len(input), name, hi-lo, m, err, buf.buf.Len())
+ return
+ }
+ if !bytes.Equal(input[lo:hi], out[:hi-lo]) {
+ t.Errorf("testSync/%d: read wrong bytes: %x vs %x", i, input[lo:hi], out[:hi-lo])
+ return
+ }
+ if i == 0 && buf.buf.Len() != 0 {
+ t.Errorf("testSync/%d (%d, %d, %s): extra data after %d", i, level, len(input), name, hi-lo)
+ }
+ buf.WriteMode()
+ }
+ buf.ReadMode()
+ out := make([]byte, 10)
+ if n, err := r.Read(out); n > 0 || err != os.EOF {
+ t.Errorf("testSync (%d, %d, %s): final Read: %d, %v (hex: %x)", level, len(input), name, n, err, out[0:n])
+ }
+ if buf.buf.Len() != 0 {
+ t.Errorf("testSync (%d, %d, %s): extra data at end", level, len(input), name)
+ }
+ r.Close()
+
+ // stream should work for ordinary reader too
+ r = NewReader(buf1)
+ out, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Errorf("testSync: read: %s", err)
+ return
+ }
+ r.Close()
+ if !bytes.Equal(input, out) {
+ t.Errorf("testSync: decompress(compress(data)) != data: level=%d input=%s", level, name)
+ }
+}
+
+
+func testToFromWithLevel(t *testing.T, level int, input []byte, name string) os.Error {
+ buffer := bytes.NewBuffer(nil)
+ w := NewWriter(buffer, level)
+ w.Write(input)
+ w.Close()
+ r := NewReader(buffer)
+ out, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Errorf("read: %s", err)
+ return err
+ }
+ r.Close()
+ if !bytes.Equal(input, out) {
+ t.Errorf("decompress(compress(data)) != data: level=%d input=%s", level, name)
+ }
+
+ testSync(t, level, input, name)
+ return nil
+}
+
+func testToFrom(t *testing.T, input []byte, name string) {
+ for i := 0; i < 10; i++ {
+ testToFromWithLevel(t, i, input, name)
+ }
+}
+
+func TestDeflateInflate(t *testing.T) {
+ for i, h := range deflateInflateTests {
+ testToFrom(t, h.in, fmt.Sprintf("#%d", i))
+ }
+}
+
+func TestReverseBits(t *testing.T) {
+ for _, h := range reverseBitsTests {
+ if v := reverseBits(h.in, h.bitCount); v != h.out {
+ t.Errorf("reverseBits(%v,%v) = %v, want %v",
+ h.in, h.bitCount, v, h.out)
+ }
+ }
+}
+
+func TestDeflateInflateString(t *testing.T) {
+ gold := bytes.NewBufferString(getEdata()).Bytes()
+ testToFromWithLevel(t, 1, gold, "2.718281828...")
+}
+
+func getEdata() string {
+ return "2.718281828459045235360287471352662497757247093699959574966967627724076630353547" +
+ "59457138217852516642742746639193200305992181741359662904357290033429526059563073" +
+ "81323286279434907632338298807531952510190115738341879307021540891499348841675092" +
+ "44761460668082264800168477411853742345442437107539077744992069551702761838606261" +
+ "33138458300075204493382656029760673711320070932870912744374704723069697720931014" +
+ "16928368190255151086574637721112523897844250569536967707854499699679468644549059" +
+ "87931636889230098793127736178215424999229576351482208269895193668033182528869398" +
+ "49646510582093923982948879332036250944311730123819706841614039701983767932068328" +
+ "23764648042953118023287825098194558153017567173613320698112509961818815930416903" +
+ "51598888519345807273866738589422879228499892086805825749279610484198444363463244" +
+ "96848756023362482704197862320900216099023530436994184914631409343173814364054625" +
+ "31520961836908887070167683964243781405927145635490613031072085103837505101157477" +
+ "04171898610687396965521267154688957035035402123407849819334321068170121005627880" +
+ "23519303322474501585390473041995777709350366041699732972508868769664035557071622" +
+ "68447162560798826517871341951246652010305921236677194325278675398558944896970964" +
+ "09754591856956380236370162112047742722836489613422516445078182442352948636372141" +
+ "74023889344124796357437026375529444833799801612549227850925778256209262264832627" +
+ "79333865664816277251640191059004916449982893150566047258027786318641551956532442" +
+ "58698294695930801915298721172556347546396447910145904090586298496791287406870504" +
+ "89585867174798546677575732056812884592054133405392200011378630094556068816674001" +
+ "69842055804033637953764520304024322566135278369511778838638744396625322498506549" +
+ "95886234281899707733276171783928034946501434558897071942586398772754710962953741" +
+ "52111513683506275260232648472870392076431005958411661205452970302364725492966693" +
+ "81151373227536450988890313602057248176585118063036442812314965507047510254465011" +
+ "72721155519486685080036853228183152196003735625279449515828418829478761085263981" +
+ "39559900673764829224437528718462457803619298197139914756448826260390338144182326" +
+ "25150974827987779964373089970388867782271383605772978824125611907176639465070633" +
+ "04527954661855096666185664709711344474016070462621568071748187784437143698821855" +
+ "96709591025968620023537185887485696522000503117343920732113908032936344797273559" +
+ "55277349071783793421637012050054513263835440001863239914907054797780566978533580" +
+ "48966906295119432473099587655236812859041383241160722602998330535370876138939639" +
+ "17795745401613722361878936526053815584158718692553860616477983402543512843961294" +
+ "60352913325942794904337299085731580290958631382683291477116396337092400316894586" +
+ "36060645845925126994655724839186564209752685082307544254599376917041977780085362" +
+ "73094171016343490769642372229435236612557250881477922315197477806056967253801718" +
+ "07763603462459278778465850656050780844211529697521890874019660906651803516501792" +
+ "50461950136658543663271254963990854914420001457476081930221206602433009641270489" +
+ "43903971771951806990869986066365832322787093765022601492910115171776359446020232" +
+ "49300280401867723910288097866605651183260043688508817157238669842242201024950551" +
+ "88169480322100251542649463981287367765892768816359831247788652014117411091360116" +
+ "49950766290779436460058519419985601626479076153210387275571269925182756879893027" +
+ "61761146162549356495903798045838182323368612016243736569846703785853305275833337" +
+ "93990752166069238053369887956513728559388349989470741618155012539706464817194670" +
+ "83481972144888987906765037959036696724949925452790337296361626589760394985767413" +
+ "97359441023744329709355477982629614591442936451428617158587339746791897571211956" +
+ "18738578364475844842355558105002561149239151889309946342841393608038309166281881" +
+ "15037152849670597416256282360921680751501777253874025642534708790891372917228286" +
+ "11515915683725241630772254406337875931059826760944203261924285317018781772960235" +
+ "41306067213604600038966109364709514141718577701418060644363681546444005331608778" +
+ "31431744408119494229755993140118886833148328027065538330046932901157441475631399" +
+ "97221703804617092894579096271662260740718749975359212756084414737823303270330168" +
+ "23719364800217328573493594756433412994302485023573221459784328264142168487872167" +
+ "33670106150942434569844018733128101079451272237378861260581656680537143961278887" +
+ "32527373890392890506865324138062796025930387727697783792868409325365880733988457" +
+ "21874602100531148335132385004782716937621800490479559795929059165547050577751430" +
+ "81751126989851884087185640260353055837378324229241856256442550226721559802740126" +
+ "17971928047139600689163828665277009752767069777036439260224372841840883251848770" +
+ "47263844037953016690546593746161932384036389313136432713768884102681121989127522" +
+ "30562567562547017250863497653672886059667527408686274079128565769963137897530346" +
+ "60616669804218267724560530660773899624218340859882071864682623215080288286359746" +
+ "83965435885668550377313129658797581050121491620765676995065971534476347032085321" +
+ "56036748286083786568030730626576334697742956346437167093971930608769634953288468" +
+ "33613038829431040800296873869117066666146800015121143442256023874474325250769387" +
+ "07777519329994213727721125884360871583483562696166198057252661220679754062106208" +
+ "06498829184543953015299820925030054982570433905535701686531205264956148572492573" +
+ "86206917403695213533732531666345466588597286659451136441370331393672118569553952" +
+ "10845840724432383558606310680696492485123263269951460359603729725319836842336390" +
+ "46321367101161928217111502828016044880588023820319814930963695967358327420249882" +
+ "45684941273860566491352526706046234450549227581151709314921879592718001940968866" +
+ "98683703730220047531433818109270803001720593553052070070607223399946399057131158" +
+ "70996357773590271962850611465148375262095653467132900259943976631145459026858989" +
+ "79115837093419370441155121920117164880566945938131183843765620627846310490346293" +
+ "95002945834116482411496975832601180073169943739350696629571241027323913874175492" +
+ "30718624545432220395527352952402459038057445028922468862853365422138157221311632" +
+ "88112052146489805180092024719391710555390113943316681515828843687606961102505171" +
+ "00739276238555338627255353883096067164466237092264680967125406186950214317621166" +
+ "81400975952814939072226011126811531083873176173232352636058381731510345957365382" +
+ "23534992935822836851007810884634349983518404451704270189381994243410090575376257" +
+ "76757111809008816418331920196262341628816652137471732547772778348877436651882875" +
+ "21566857195063719365653903894493664217640031215278702223664636357555035655769488" +
+ "86549500270853923617105502131147413744106134445544192101336172996285694899193369" +
+ "18472947858072915608851039678195942983318648075608367955149663644896559294818785" +
+ "17840387733262470519450504198477420141839477312028158868457072905440575106012852" +
+ "58056594703046836344592652552137008068752009593453607316226118728173928074623094" +
+ "68536782310609792159936001994623799343421068781349734695924646975250624695861690" +
+ "91785739765951993929939955675427146549104568607020990126068187049841780791739240" +
+ "71945996323060254707901774527513186809982284730860766536866855516467702911336827" +
+ "56310722334672611370549079536583453863719623585631261838715677411873852772292259" +
+ "47433737856955384562468010139057278710165129666367644518724656537304024436841408" +
+ "14488732957847348490003019477888020460324660842875351848364959195082888323206522" +
+ "12810419044804724794929134228495197002260131043006241071797150279343326340799596" +
+ "05314460532304885289729176598760166678119379323724538572096075822771784833616135" +
+ "82612896226118129455927462767137794487586753657544861407611931125958512655759734" +
+ "57301533364263076798544338576171533346232527057200530398828949903425956623297578" +
+ "24887350292591668258944568946559926584547626945287805165017206747854178879822768" +
+ "06536650641910973434528878338621726156269582654478205672987756426325321594294418" +
+ "03994321700009054265076309558846589517170914760743713689331946909098190450129030" +
+ "70995662266203031826493657336984195557769637876249188528656866076005660256054457" +
+ "11337286840205574416030837052312242587223438854123179481388550075689381124935386" +
+ "31863528708379984569261998179452336408742959118074745341955142035172618420084550" +
+ "91708456823682008977394558426792142734775608796442792027083121501564063413416171" +
+ "66448069815483764491573900121217041547872591998943825364950514771379399147205219" +
+ "52907939613762110723849429061635760459623125350606853765142311534966568371511660" +
+ "42207963944666211632551577290709784731562782775987881364919512574833287937715714" +
+ "59091064841642678309949723674420175862269402159407924480541255360431317992696739" +
+ "15754241929660731239376354213923061787675395871143610408940996608947141834069836" +
+ "29936753626215452472984642137528910798843813060955526227208375186298370667872244" +
+ "30195793793786072107254277289071732854874374355781966511716618330881129120245204" +
+ "04868220007234403502544820283425418788465360259150644527165770004452109773558589" +
+ "76226554849416217149895323834216001140629507184904277892585527430352213968356790" +
+ "18076406042138307308774460170842688272261177180842664333651780002171903449234264" +
+ "26629226145600433738386833555534345300426481847398921562708609565062934040526494" +
+ "32442614456659212912256488935696550091543064261342526684725949143142393988454324" +
+ "86327461842846655985332312210466259890141712103446084271616619001257195870793217" +
+ "56969854401339762209674945418540711844643394699016269835160784892451405894094639" +
+ "52678073545797003070511636825194877011897640028276484141605872061841852971891540" +
+ "19688253289309149665345753571427318482016384644832499037886069008072709327673127" +
+ "58196656394114896171683298045513972950668760474091542042842999354102582911350224" +
+ "16907694316685742425225090269390348148564513030699251995904363840284292674125734" +
+ "22447765584177886171737265462085498294498946787350929581652632072258992368768457" +
+ "01782303809656788311228930580914057261086588484587310165815116753332767488701482" +
+ "91674197015125597825727074064318086014281490241467804723275976842696339357735429" +
+ "30186739439716388611764209004068663398856841681003872389214483176070116684503887" +
+ "21236436704331409115573328018297798873659091665961240202177855885487617616198937" +
+ "07943800566633648843650891448055710397652146960276625835990519870423001794655367" +
+ "9"
+}
diff --git a/libgo/go/compress/flate/flate_test.go b/libgo/go/compress/flate/flate_test.go
new file mode 100644
index 000000000..bfd3b8381
--- /dev/null
+++ b/libgo/go/compress/flate/flate_test.go
@@ -0,0 +1,139 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test tests some internals of the flate package.
+// The tests in package compress/gzip serve as the
+// end-to-end test of the decompressor.
+
+package flate
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+)
+
+// The Huffman code lengths used by the fixed-format Huffman blocks.
+var fixedHuffmanBits = [...]int{
+ // 0-143 length 8
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+
+ // 144-255 length 9
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+
+ // 256-279 length 7
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+
+ // 280-287 length 8
+ 8, 8, 8, 8, 8, 8, 8, 8,
+}
+
+type InitDecoderTest struct {
+ in []int
+ out huffmanDecoder
+ ok bool
+}
+
+var initDecoderTests = []*InitDecoderTest{
+ // Example from Connell 1973,
+ &InitDecoderTest{
+ []int{3, 5, 2, 4, 3, 5, 5, 4, 4, 3, 4, 5},
+ huffmanDecoder{
+ 2, 5,
+ [maxCodeLen + 1]int{2: 0, 4, 13, 31},
+ [maxCodeLen + 1]int{2: 0, 1, 6, 20},
+ // Paper used different code assignment:
+ // 2, 9, 4, 0, 10, 8, 3, 7, 1, 5, 11, 6
+ // Reordered here so that codes of same length
+ // are assigned to increasing numbers.
+ []int{2, 0, 4, 9, 3, 7, 8, 10, 1, 5, 6, 11},
+ },
+ true,
+ },
+
+ // Example from RFC 1951 section 3.2.2
+ &InitDecoderTest{
+ []int{2, 1, 3, 3},
+ huffmanDecoder{
+ 1, 3,
+ [maxCodeLen + 1]int{1: 0, 2, 7},
+ [maxCodeLen + 1]int{1: 0, 1, 4},
+ []int{1, 0, 2, 3},
+ },
+ true,
+ },
+
+ // Second example from RFC 1951 section 3.2.2
+ &InitDecoderTest{
+ []int{3, 3, 3, 3, 3, 2, 4, 4},
+ huffmanDecoder{
+ 2, 4,
+ [maxCodeLen + 1]int{2: 0, 6, 15},
+ [maxCodeLen + 1]int{2: 0, 1, 8},
+ []int{5, 0, 1, 2, 3, 4, 6, 7},
+ },
+ true,
+ },
+
+ // Static Huffman codes (RFC 1951 section 3.2.6)
+ &InitDecoderTest{
+ fixedHuffmanBits[0:],
+ fixedHuffmanDecoder,
+ true,
+ },
+
+ // Illegal input.
+ &InitDecoderTest{
+ []int{},
+ huffmanDecoder{},
+ false,
+ },
+
+ // Illegal input.
+ &InitDecoderTest{
+ []int{0, 0, 0, 0, 0, 0, 0},
+ huffmanDecoder{},
+ false,
+ },
+}
+
+func TestInitDecoder(t *testing.T) {
+ for i, tt := range initDecoderTests {
+ var h huffmanDecoder
+ if h.init(tt.in) != tt.ok {
+ t.Errorf("test %d: init = %v", i, !tt.ok)
+ continue
+ }
+ if !reflect.DeepEqual(&h, &tt.out) {
+ t.Errorf("test %d:\nhave %v\nwant %v", i, h, tt.out)
+ }
+ }
+}
+
+func TestUncompressedSource(t *testing.T) {
+ decoder := NewReader(bytes.NewBuffer([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11}))
+ output := make([]byte, 1)
+ n, error := decoder.Read(output)
+ if n != 1 || error != nil {
+ t.Fatalf("decoder.Read() = %d, %v, want 1, nil", n, error)
+ }
+ if output[0] != 0x11 {
+ t.Errorf("output[0] = %x, want 0x11", output[0])
+ }
+}
diff --git a/libgo/go/compress/flate/huffman_bit_writer.go b/libgo/go/compress/flate/huffman_bit_writer.go
new file mode 100644
index 000000000..abff82dd6
--- /dev/null
+++ b/libgo/go/compress/flate/huffman_bit_writer.go
@@ -0,0 +1,506 @@
+// 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 flate
+
+import (
+ "io"
+ "math"
+ "os"
+ "strconv"
+)
+
+const (
+ // The largest offset code.
+ offsetCodeCount = 30
+
+ // The largest offset code in the extensions.
+ extendedOffsetCodeCount = 42
+
+ // The special code used to mark the end of a block.
+ endBlockMarker = 256
+
+ // The first length code.
+ lengthCodesStart = 257
+
+ // The number of codegen codes.
+ codegenCodeCount = 19
+ badCode = 255
+)
+
+// The number of extra bits needed by length code X - LENGTH_CODES_START.
+var lengthExtraBits = []int8{
+ /* 257 */ 0, 0, 0,
+ /* 260 */ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2,
+ /* 270 */ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
+ /* 280 */ 4, 5, 5, 5, 5, 0,
+}
+
+// The length indicated by length code X - LENGTH_CODES_START.
+var lengthBase = []uint32{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10,
+ 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+ 64, 80, 96, 112, 128, 160, 192, 224, 255,
+}
+
+// offset code word extra bits.
+var offsetExtraBits = []int8{
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
+ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
+ /* extended window */
+ 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20,
+}
+
+var offsetBase = []uint32{
+ /* normal deflate */
+ 0x000000, 0x000001, 0x000002, 0x000003, 0x000004,
+ 0x000006, 0x000008, 0x00000c, 0x000010, 0x000018,
+ 0x000020, 0x000030, 0x000040, 0x000060, 0x000080,
+ 0x0000c0, 0x000100, 0x000180, 0x000200, 0x000300,
+ 0x000400, 0x000600, 0x000800, 0x000c00, 0x001000,
+ 0x001800, 0x002000, 0x003000, 0x004000, 0x006000,
+
+ /* extended window */
+ 0x008000, 0x00c000, 0x010000, 0x018000, 0x020000,
+ 0x030000, 0x040000, 0x060000, 0x080000, 0x0c0000,
+ 0x100000, 0x180000, 0x200000, 0x300000,
+}
+
+// The odd order in which the codegen code sizes are written.
+var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+type huffmanBitWriter struct {
+ w io.Writer
+ // Data waiting to be written is bytes[0:nbytes]
+ // and then the low nbits of bits.
+ bits uint32
+ nbits uint32
+ bytes [64]byte
+ nbytes int
+ literalFreq []int32
+ offsetFreq []int32
+ codegen []uint8
+ codegenFreq []int32
+ literalEncoding *huffmanEncoder
+ offsetEncoding *huffmanEncoder
+ codegenEncoding *huffmanEncoder
+ err os.Error
+}
+
+type WrongValueError struct {
+ name string
+ from int32
+ to int32
+ value int32
+}
+
+func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
+ return &huffmanBitWriter{
+ w: w,
+ literalFreq: make([]int32, maxLit),
+ offsetFreq: make([]int32, extendedOffsetCodeCount),
+ codegen: make([]uint8, maxLit+extendedOffsetCodeCount+1),
+ codegenFreq: make([]int32, codegenCodeCount),
+ literalEncoding: newHuffmanEncoder(maxLit),
+ offsetEncoding: newHuffmanEncoder(extendedOffsetCodeCount),
+ codegenEncoding: newHuffmanEncoder(codegenCodeCount),
+ }
+}
+
+func (err WrongValueError) String() string {
+ return "huffmanBitWriter: " + err.name + " should belong to [" + strconv.Itoa64(int64(err.from)) + ";" +
+ strconv.Itoa64(int64(err.to)) + "] but actual value is " + strconv.Itoa64(int64(err.value))
+}
+
+func (w *huffmanBitWriter) flushBits() {
+ if w.err != nil {
+ w.nbits = 0
+ return
+ }
+ bits := w.bits
+ w.bits >>= 16
+ w.nbits -= 16
+ n := w.nbytes
+ w.bytes[n] = byte(bits)
+ w.bytes[n+1] = byte(bits >> 8)
+ if n += 2; n >= len(w.bytes) {
+ _, w.err = w.w.Write(w.bytes[0:])
+ n = 0
+ }
+ w.nbytes = n
+}
+
+func (w *huffmanBitWriter) flush() {
+ if w.err != nil {
+ w.nbits = 0
+ return
+ }
+ n := w.nbytes
+ if w.nbits > 8 {
+ w.bytes[n] = byte(w.bits)
+ w.bits >>= 8
+ w.nbits -= 8
+ n++
+ }
+ if w.nbits > 0 {
+ w.bytes[n] = byte(w.bits)
+ w.nbits = 0
+ n++
+ }
+ w.bits = 0
+ _, w.err = w.w.Write(w.bytes[0:n])
+ w.nbytes = 0
+}
+
+func (w *huffmanBitWriter) writeBits(b, nb int32) {
+ w.bits |= uint32(b) << w.nbits
+ if w.nbits += uint32(nb); w.nbits >= 16 {
+ w.flushBits()
+ }
+}
+
+func (w *huffmanBitWriter) writeBytes(bytes []byte) {
+ if w.err != nil {
+ return
+ }
+ n := w.nbytes
+ if w.nbits == 8 {
+ w.bytes[n] = byte(w.bits)
+ w.nbits = 0
+ n++
+ }
+ if w.nbits != 0 {
+ w.err = InternalError("writeBytes with unfinished bits")
+ return
+ }
+ if n != 0 {
+ _, w.err = w.w.Write(w.bytes[0:n])
+ if w.err != nil {
+ return
+ }
+ }
+ w.nbytes = 0
+ _, w.err = w.w.Write(bytes)
+}
+
+// RFC 1951 3.2.7 specifies a special run-length encoding for specifiying
+// the literal and offset lengths arrays (which are concatenated into a single
+// array). This method generates that run-length encoding.
+//
+// The result is written into the codegen array, and the frequencies
+// of each code is written into the codegenFreq array.
+// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
+// information. Code badCode is an end marker
+//
+// numLiterals The number of literals in literalEncoding
+// numOffsets The number of offsets in offsetEncoding
+func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
+ fillInt32s(w.codegenFreq, 0)
+ // Note that we are using codegen both as a temporary variable for holding
+ // a copy of the frequencies, and as the place where we put the result.
+ // This is fine because the output is always shorter than the input used
+ // so far.
+ codegen := w.codegen // cache
+ // Copy the concatenated code sizes to codegen. Put a marker at the end.
+ copyUint8s(codegen[0:numLiterals], w.literalEncoding.codeBits)
+ copyUint8s(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits)
+ codegen[numLiterals+numOffsets] = badCode
+
+ size := codegen[0]
+ count := 1
+ outIndex := 0
+ for inIndex := 1; size != badCode; inIndex++ {
+ // INVARIANT: We have seen "count" copies of size that have not yet
+ // had output generated for them.
+ nextSize := codegen[inIndex]
+ if nextSize == size {
+ count++
+ continue
+ }
+ // We need to generate codegen indicating "count" of size.
+ if size != 0 {
+ codegen[outIndex] = size
+ outIndex++
+ w.codegenFreq[size]++
+ count--
+ for count >= 3 {
+ n := min(count, 6)
+ codegen[outIndex] = 16
+ outIndex++
+ codegen[outIndex] = uint8(n - 3)
+ outIndex++
+ w.codegenFreq[16]++
+ count -= n
+ }
+ } else {
+ for count >= 11 {
+ n := min(count, 138)
+ codegen[outIndex] = 18
+ outIndex++
+ codegen[outIndex] = uint8(n - 11)
+ outIndex++
+ w.codegenFreq[18]++
+ count -= n
+ }
+ if count >= 3 {
+ // count >= 3 && count <= 10
+ codegen[outIndex] = 17
+ outIndex++
+ codegen[outIndex] = uint8(count - 3)
+ outIndex++
+ w.codegenFreq[17]++
+ count = 0
+ }
+ }
+ count--
+ for ; count >= 0; count-- {
+ codegen[outIndex] = size
+ outIndex++
+ w.codegenFreq[size]++
+ }
+ // Set up invariant for next time through the loop.
+ size = nextSize
+ count = 1
+ }
+ // Marker indicating the end of the codegen.
+ codegen[outIndex] = badCode
+}
+
+func (w *huffmanBitWriter) writeCode(code *huffmanEncoder, literal uint32) {
+ if w.err != nil {
+ return
+ }
+ w.writeBits(int32(code.code[literal]), int32(code.codeBits[literal]))
+}
+
+// Write the header of a dynamic Huffman block to the output stream.
+//
+// numLiterals The number of literals specified in codegen
+// numOffsets The number of offsets specified in codegen
+// numCodegens Tne number of codegens used in codegen
+func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, numCodegens int, isEof bool) {
+ if w.err != nil {
+ return
+ }
+ var firstBits int32 = 4
+ if isEof {
+ firstBits = 5
+ }
+ w.writeBits(firstBits, 3)
+ w.writeBits(int32(numLiterals-257), 5)
+ if numOffsets > offsetCodeCount {
+ // Extended version of decompressor
+ w.writeBits(int32(offsetCodeCount+((numOffsets-(1+offsetCodeCount))>>3)), 5)
+ w.writeBits(int32((numOffsets-(1+offsetCodeCount))&0x7), 3)
+ } else {
+ w.writeBits(int32(numOffsets-1), 5)
+ }
+ w.writeBits(int32(numCodegens-4), 4)
+
+ for i := 0; i < numCodegens; i++ {
+ value := w.codegenEncoding.codeBits[codegenOrder[i]]
+ w.writeBits(int32(value), 3)
+ }
+
+ i := 0
+ for {
+ var codeWord int = int(w.codegen[i])
+ i++
+ if codeWord == badCode {
+ break
+ }
+ // The low byte contains the actual code to generate.
+ w.writeCode(w.codegenEncoding, uint32(codeWord))
+
+ switch codeWord {
+ case 16:
+ w.writeBits(int32(w.codegen[i]), 2)
+ i++
+ break
+ case 17:
+ w.writeBits(int32(w.codegen[i]), 3)
+ i++
+ break
+ case 18:
+ w.writeBits(int32(w.codegen[i]), 7)
+ i++
+ break
+ }
+ }
+}
+
+func (w *huffmanBitWriter) writeStoredHeader(length int, isEof bool) {
+ if w.err != nil {
+ return
+ }
+ var flag int32
+ if isEof {
+ flag = 1
+ }
+ w.writeBits(flag, 3)
+ w.flush()
+ w.writeBits(int32(length), 16)
+ w.writeBits(int32(^uint16(length)), 16)
+}
+
+func (w *huffmanBitWriter) writeFixedHeader(isEof bool) {
+ if w.err != nil {
+ return
+ }
+ // Indicate that we are a fixed Huffman block
+ var value int32 = 2
+ if isEof {
+ value = 3
+ }
+ w.writeBits(value, 3)
+}
+
+func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
+ if w.err != nil {
+ return
+ }
+ fillInt32s(w.literalFreq, 0)
+ fillInt32s(w.offsetFreq, 0)
+
+ n := len(tokens)
+ tokens = tokens[0 : n+1]
+ tokens[n] = endBlockMarker
+
+ totalLength := -1 // Subtract 1 for endBlock.
+ for _, t := range tokens {
+ switch t.typ() {
+ case literalType:
+ w.literalFreq[t.literal()]++
+ totalLength++
+ break
+ case matchType:
+ length := t.length()
+ offset := t.offset()
+ totalLength += int(length + 3)
+ w.literalFreq[lengthCodesStart+lengthCode(length)]++
+ w.offsetFreq[offsetCode(offset)]++
+ break
+ }
+ }
+ w.literalEncoding.generate(w.literalFreq, 15)
+ w.offsetEncoding.generate(w.offsetFreq, 15)
+
+ // get the number of literals
+ numLiterals := len(w.literalFreq)
+ for w.literalFreq[numLiterals-1] == 0 {
+ numLiterals--
+ }
+ // get the number of offsets
+ numOffsets := len(w.offsetFreq)
+ for numOffsets > 1 && w.offsetFreq[numOffsets-1] == 0 {
+ numOffsets--
+ }
+ storedBytes := 0
+ if input != nil {
+ storedBytes = len(input)
+ }
+ var extraBits int64
+ var storedSize int64
+ if storedBytes <= maxStoreBlockSize && input != nil {
+ storedSize = int64((storedBytes + 5) * 8)
+ // We only bother calculating the costs of the extra bits required by
+ // the length of offset fields (which will be the same for both fixed
+ // and dynamic encoding), if we need to compare those two encodings
+ // against stored encoding.
+ for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ {
+ // First eight length codes have extra size = 0.
+ extraBits += int64(w.literalFreq[lengthCode]) * int64(lengthExtraBits[lengthCode-lengthCodesStart])
+ }
+ for offsetCode := 4; offsetCode < numOffsets; offsetCode++ {
+ // First four offset codes have extra size = 0.
+ extraBits += int64(w.offsetFreq[offsetCode]) * int64(offsetExtraBits[offsetCode])
+ }
+ } else {
+ storedSize = math.MaxInt32
+ }
+
+ // Figure out which generates smaller code, fixed Huffman, dynamic
+ // Huffman, or just storing the data.
+ var fixedSize int64 = math.MaxInt64
+ if numOffsets <= offsetCodeCount {
+ fixedSize = int64(3) +
+ fixedLiteralEncoding.bitLength(w.literalFreq) +
+ fixedOffsetEncoding.bitLength(w.offsetFreq) +
+ extraBits
+ }
+ // Generate codegen and codegenFrequencies, which indicates how to encode
+ // the literalEncoding and the offsetEncoding.
+ w.generateCodegen(numLiterals, numOffsets)
+ w.codegenEncoding.generate(w.codegenFreq, 7)
+ numCodegens := len(w.codegenFreq)
+ for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
+ numCodegens--
+ }
+ extensionSummand := 0
+ if numOffsets > offsetCodeCount {
+ extensionSummand = 3
+ }
+ dynamicHeader := int64(3+5+5+4+(3*numCodegens)) +
+ // Following line is an extension.
+ int64(extensionSummand) +
+ w.codegenEncoding.bitLength(w.codegenFreq) +
+ int64(extraBits) +
+ int64(w.codegenFreq[16]*2) +
+ int64(w.codegenFreq[17]*3) +
+ int64(w.codegenFreq[18]*7)
+ dynamicSize := dynamicHeader +
+ w.literalEncoding.bitLength(w.literalFreq) +
+ w.offsetEncoding.bitLength(w.offsetFreq)
+
+ if storedSize < fixedSize && storedSize < dynamicSize {
+ w.writeStoredHeader(storedBytes, eof)
+ w.writeBytes(input[0:storedBytes])
+ return
+ }
+ var literalEncoding *huffmanEncoder
+ var offsetEncoding *huffmanEncoder
+
+ if fixedSize <= dynamicSize {
+ w.writeFixedHeader(eof)
+ literalEncoding = fixedLiteralEncoding
+ offsetEncoding = fixedOffsetEncoding
+ } else {
+ // Write the header.
+ w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+ literalEncoding = w.literalEncoding
+ offsetEncoding = w.offsetEncoding
+ }
+
+ // Write the tokens.
+ for _, t := range tokens {
+ switch t.typ() {
+ case literalType:
+ w.writeCode(literalEncoding, t.literal())
+ break
+ case matchType:
+ // Write the length
+ length := t.length()
+ lengthCode := lengthCode(length)
+ w.writeCode(literalEncoding, lengthCode+lengthCodesStart)
+ extraLengthBits := int32(lengthExtraBits[lengthCode])
+ if extraLengthBits > 0 {
+ extraLength := int32(length - lengthBase[lengthCode])
+ w.writeBits(extraLength, extraLengthBits)
+ }
+ // Write the offset
+ offset := t.offset()
+ offsetCode := offsetCode(offset)
+ w.writeCode(offsetEncoding, offsetCode)
+ extraOffsetBits := int32(offsetExtraBits[offsetCode])
+ if extraOffsetBits > 0 {
+ extraOffset := int32(offset - offsetBase[offsetCode])
+ w.writeBits(extraOffset, extraOffsetBits)
+ }
+ break
+ default:
+ panic("unknown token type: " + string(t))
+ }
+ }
+}
diff --git a/libgo/go/compress/flate/huffman_code.go b/libgo/go/compress/flate/huffman_code.go
new file mode 100644
index 000000000..6be605f0a
--- /dev/null
+++ b/libgo/go/compress/flate/huffman_code.go
@@ -0,0 +1,373 @@
+// 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 flate
+
+import (
+ "math"
+ "sort"
+)
+
+type huffmanEncoder struct {
+ codeBits []uint8
+ code []uint16
+}
+
+type literalNode struct {
+ literal uint16
+ freq int32
+}
+
+type chain struct {
+ // The sum of the leaves in this tree
+ freq int32
+
+ // The number of literals to the left of this item at this level
+ leafCount int32
+
+ // The right child of this chain in the previous level.
+ up *chain
+}
+
+type levelInfo struct {
+ // Our level. for better printing
+ level int32
+
+ // The most recent chain generated for this level
+ lastChain *chain
+
+ // The frequency of the next character to add to this level
+ nextCharFreq int32
+
+ // The frequency of the next pair (from level below) to add to this level.
+ // Only valid if the "needed" value of the next lower level is 0.
+ nextPairFreq int32
+
+ // The number of chains remaining to generate for this level before moving
+ // up to the next level
+ needed int32
+
+ // The levelInfo for level+1
+ up *levelInfo
+
+ // The levelInfo for level-1
+ down *levelInfo
+}
+
+func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxInt32} }
+
+func newHuffmanEncoder(size int) *huffmanEncoder {
+ return &huffmanEncoder{make([]uint8, size), make([]uint16, size)}
+}
+
+// Generates a HuffmanCode corresponding to the fixed literal table
+func generateFixedLiteralEncoding() *huffmanEncoder {
+ h := newHuffmanEncoder(maxLit)
+ codeBits := h.codeBits
+ code := h.code
+ var ch uint16
+ for ch = 0; ch < maxLit; ch++ {
+ var bits uint16
+ var size uint8
+ switch {
+ case ch < 144:
+ // size 8, 000110000 .. 10111111
+ bits = ch + 48
+ size = 8
+ break
+ case ch < 256:
+ // size 9, 110010000 .. 111111111
+ bits = ch + 400 - 144
+ size = 9
+ break
+ case ch < 280:
+ // size 7, 0000000 .. 0010111
+ bits = ch - 256
+ size = 7
+ break
+ default:
+ // size 8, 11000000 .. 11000111
+ bits = ch + 192 - 280
+ size = 8
+ }
+ codeBits[ch] = size
+ code[ch] = reverseBits(bits, size)
+ }
+ return h
+}
+
+func generateFixedOffsetEncoding() *huffmanEncoder {
+ h := newHuffmanEncoder(30)
+ codeBits := h.codeBits
+ code := h.code
+ for ch := uint16(0); ch < 30; ch++ {
+ codeBits[ch] = 5
+ code[ch] = reverseBits(ch, 5)
+ }
+ return h
+}
+
+var fixedLiteralEncoding *huffmanEncoder = generateFixedLiteralEncoding()
+var fixedOffsetEncoding *huffmanEncoder = generateFixedOffsetEncoding()
+
+func (h *huffmanEncoder) bitLength(freq []int32) int64 {
+ var total int64
+ for i, f := range freq {
+ if f != 0 {
+ total += int64(f) * int64(h.codeBits[i])
+ }
+ }
+ return total
+}
+
+// Generate elements in the chain using an iterative algorithm.
+func (h *huffmanEncoder) generateChains(top *levelInfo, list []literalNode) {
+ n := len(list)
+ list = list[0 : n+1]
+ list[n] = maxNode()
+
+ l := top
+ for {
+ if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
+ // We've run out of both leafs and pairs.
+ // End all calculations for this level.
+ // To m sure we never come back to this level or any lower level,
+ // set nextPairFreq impossibly large.
+ l.lastChain = nil
+ l.needed = 0
+ l = l.up
+ l.nextPairFreq = math.MaxInt32
+ continue
+ }
+
+ prevFreq := l.lastChain.freq
+ if l.nextCharFreq < l.nextPairFreq {
+ // The next item on this row is a leaf node.
+ n := l.lastChain.leafCount + 1
+ l.lastChain = &chain{l.nextCharFreq, n, l.lastChain.up}
+ l.nextCharFreq = list[n].freq
+ } else {
+ // The next item on this row is a pair from the previous row.
+ // nextPairFreq isn't valid until we generate two
+ // more values in the level below
+ l.lastChain = &chain{l.nextPairFreq, l.lastChain.leafCount, l.down.lastChain}
+ l.down.needed = 2
+ }
+
+ if l.needed--; l.needed == 0 {
+ // We've done everything we need to do for this level.
+ // Continue calculating one level up. Fill in nextPairFreq
+ // of that level with the sum of the two nodes we've just calculated on
+ // this level.
+ up := l.up
+ if up == nil {
+ // All done!
+ return
+ }
+ up.nextPairFreq = prevFreq + l.lastChain.freq
+ l = up
+ } else {
+ // If we stole from below, move down temporarily to replenish it.
+ for l.down.needed > 0 {
+ l = l.down
+ }
+ }
+ }
+}
+
+// Return the number of literals assigned to each bit size in the Huffman encoding
+//
+// This method is only called when list.length >= 3
+// The cases of 0, 1, and 2 literals are handled by special case code.
+//
+// list An array of the literals with non-zero frequencies
+// and their associated frequencies. The array is in order of increasing
+// frequency, and has as its last element a special element with frequency
+// MaxInt32
+// maxBits The maximum number of bits that should be used to encode any literal.
+// return An integer array in which array[i] indicates the number of literals
+// that should be encoded in i bits.
+func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
+ n := int32(len(list))
+ list = list[0 : n+1]
+ list[n] = maxNode()
+
+ // The tree can't have greater depth than n - 1, no matter what. This
+ // saves a little bit of work in some small cases
+ maxBits = minInt32(maxBits, n-1)
+
+ // Create information about each of the levels.
+ // A bogus "Level 0" whose sole purpose is so that
+ // level1.prev.needed==0. This makes level1.nextPairFreq
+ // be a legitimate value that never gets chosen.
+ top := &levelInfo{needed: 0}
+ chain2 := &chain{list[1].freq, 2, new(chain)}
+ for level := int32(1); level <= maxBits; level++ {
+ // For every level, the first two items are the first two characters.
+ // We initialize the levels as if we had already figured this out.
+ top = &levelInfo{
+ level: level,
+ lastChain: chain2,
+ nextCharFreq: list[2].freq,
+ nextPairFreq: list[0].freq + list[1].freq,
+ down: top,
+ }
+ top.down.up = top
+ if level == 1 {
+ top.nextPairFreq = math.MaxInt32
+ }
+ }
+
+ // We need a total of 2*n - 2 items at top level and have already generated 2.
+ top.needed = 2*n - 4
+
+ l := top
+ for {
+ if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
+ // We've run out of both leafs and pairs.
+ // End all calculations for this level.
+ // To m sure we never come back to this level or any lower level,
+ // set nextPairFreq impossibly large.
+ l.lastChain = nil
+ l.needed = 0
+ l = l.up
+ l.nextPairFreq = math.MaxInt32
+ continue
+ }
+
+ prevFreq := l.lastChain.freq
+ if l.nextCharFreq < l.nextPairFreq {
+ // The next item on this row is a leaf node.
+ n := l.lastChain.leafCount + 1
+ l.lastChain = &chain{l.nextCharFreq, n, l.lastChain.up}
+ l.nextCharFreq = list[n].freq
+ } else {
+ // The next item on this row is a pair from the previous row.
+ // nextPairFreq isn't valid until we generate two
+ // more values in the level below
+ l.lastChain = &chain{l.nextPairFreq, l.lastChain.leafCount, l.down.lastChain}
+ l.down.needed = 2
+ }
+
+ if l.needed--; l.needed == 0 {
+ // We've done everything we need to do for this level.
+ // Continue calculating one level up. Fill in nextPairFreq
+ // of that level with the sum of the two nodes we've just calculated on
+ // this level.
+ up := l.up
+ if up == nil {
+ // All done!
+ break
+ }
+ up.nextPairFreq = prevFreq + l.lastChain.freq
+ l = up
+ } else {
+ // If we stole from below, move down temporarily to replenish it.
+ for l.down.needed > 0 {
+ l = l.down
+ }
+ }
+ }
+
+ // Somethings is wrong if at the end, the top level is null or hasn't used
+ // all of the leaves.
+ if top.lastChain.leafCount != n {
+ panic("top.lastChain.leafCount != n")
+ }
+
+ bitCount := make([]int32, maxBits+1)
+ bits := 1
+ for chain := top.lastChain; chain.up != nil; chain = chain.up {
+ // chain.leafCount gives the number of literals requiring at least "bits"
+ // bits to encode.
+ bitCount[bits] = chain.leafCount - chain.up.leafCount
+ bits++
+ }
+ return bitCount
+}
+
+// Look at the leaves and assign them a bit count and an encoding as specified
+// in RFC 1951 3.2.2
+func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalNode) {
+ code := uint16(0)
+ for n, bits := range bitCount {
+ code <<= 1
+ if n == 0 || bits == 0 {
+ continue
+ }
+ // The literals list[len(list)-bits] .. list[len(list)-bits]
+ // are encoded using "bits" bits, and get the values
+ // code, code + 1, .... The code values are
+ // assigned in literal order (not frequency order).
+ chunk := list[len(list)-int(bits):]
+ sortByLiteral(chunk)
+ for _, node := range chunk {
+ h.codeBits[node.literal] = uint8(n)
+ h.code[node.literal] = reverseBits(code, uint8(n))
+ code++
+ }
+ list = list[0 : len(list)-int(bits)]
+ }
+}
+
+// Update this Huffman Code object to be the minimum code for the specified frequency count.
+//
+// freq An array of frequencies, in which frequency[i] gives the frequency of literal i.
+// maxBits The maximum number of bits to use for any literal.
+func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
+ list := make([]literalNode, len(freq)+1)
+ // Number of non-zero literals
+ count := 0
+ // Set list to be the set of all non-zero literals and their frequencies
+ for i, f := range freq {
+ if f != 0 {
+ list[count] = literalNode{uint16(i), f}
+ count++
+ } else {
+ h.codeBits[i] = 0
+ }
+ }
+ // If freq[] is shorter than codeBits[], fill rest of codeBits[] with zeros
+ h.codeBits = h.codeBits[0:len(freq)]
+ list = list[0:count]
+ if count <= 2 {
+ // Handle the small cases here, because they are awkward for the general case code. With
+ // two or fewer literals, everything has bit length 1.
+ for i, node := range list {
+ // "list" is in order of increasing literal value.
+ h.codeBits[node.literal] = 1
+ h.code[node.literal] = uint16(i)
+ }
+ return
+ }
+ sortByFreq(list)
+
+ // Get the number of literals for each bit count
+ bitCount := h.bitCounts(list, maxBits)
+ // And do the assignment
+ h.assignEncodingAndSize(bitCount, list)
+}
+
+type literalNodeSorter struct {
+ a []literalNode
+ less func(i, j int) bool
+}
+
+func (s literalNodeSorter) Len() int { return len(s.a) }
+
+func (s literalNodeSorter) Less(i, j int) bool {
+ return s.less(i, j)
+}
+
+func (s literalNodeSorter) Swap(i, j int) { s.a[i], s.a[j] = s.a[j], s.a[i] }
+
+func sortByFreq(a []literalNode) {
+ s := &literalNodeSorter{a, func(i, j int) bool { return a[i].freq < a[j].freq }}
+ sort.Sort(s)
+}
+
+func sortByLiteral(a []literalNode) {
+ s := &literalNodeSorter{a, func(i, j int) bool { return a[i].literal < a[j].literal }}
+ sort.Sort(s)
+}
diff --git a/libgo/go/compress/flate/inflate.go b/libgo/go/compress/flate/inflate.go
new file mode 100644
index 000000000..7dc8cf93b
--- /dev/null
+++ b/libgo/go/compress/flate/inflate.go
@@ -0,0 +1,620 @@
+// 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.
+
+// The flate package implements the DEFLATE compressed data
+// format, described in RFC 1951. The gzip and zlib packages
+// implement access to DEFLATE-based file formats.
+package flate
+
+import (
+ "bufio"
+ "io"
+ "os"
+ "strconv"
+)
+
+const (
+ maxCodeLen = 16 // max length of Huffman code
+ maxHist = 32768 // max history required
+ maxLit = 286
+ maxDist = 32
+ numCodes = 19 // number of codes in Huffman meta-code
+)
+
+// A CorruptInputError reports the presence of corrupt input at a given offset.
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+ return "flate: corrupt input before offset " + strconv.Itoa64(int64(e))
+}
+
+// An InternalError reports an error in the flate code itself.
+type InternalError string
+
+func (e InternalError) String() string { return "flate: internal error: " + string(e) }
+
+// A ReadError reports an error encountered while reading input.
+type ReadError struct {
+ Offset int64 // byte offset where error occurred
+ Error os.Error // error returned by underlying Read
+}
+
+func (e *ReadError) String() string {
+ return "flate: read error at offset " + strconv.Itoa64(e.Offset) + ": " + e.Error.String()
+}
+
+// A WriteError reports an error encountered while writing output.
+type WriteError struct {
+ Offset int64 // byte offset where error occurred
+ Error os.Error // error returned by underlying Write
+}
+
+func (e *WriteError) String() string {
+ return "flate: write error at offset " + strconv.Itoa64(e.Offset) + ": " + e.Error.String()
+}
+
+// Huffman decoder is based on
+// J. Brian Connell, ``A Huffman-Shannon-Fano Code,''
+// Proceedings of the IEEE, 61(7) (July 1973), pp 1046-1047.
+type huffmanDecoder struct {
+ // min, max code length
+ min, max int
+
+ // limit[i] = largest code word of length i
+ // Given code v of length n,
+ // need more bits if v > limit[n].
+ limit [maxCodeLen + 1]int
+
+ // base[i] = smallest code word of length i - seq number
+ base [maxCodeLen + 1]int
+
+ // codes[seq number] = output code.
+ // Given code v of length n, value is
+ // codes[v - base[n]].
+ codes []int
+}
+
+// Initialize Huffman decoding tables from array of code lengths.
+func (h *huffmanDecoder) init(bits []int) bool {
+ // TODO(rsc): Return false sometimes.
+
+ // Count number of codes of each length,
+ // compute min and max length.
+ var count [maxCodeLen + 1]int
+ var min, max int
+ for _, n := range bits {
+ if n == 0 {
+ continue
+ }
+ if min == 0 || n < min {
+ min = n
+ }
+ if n > max {
+ max = n
+ }
+ count[n]++
+ }
+ if max == 0 {
+ return false
+ }
+
+ h.min = min
+ h.max = max
+
+ // For each code range, compute
+ // nextcode (first code of that length),
+ // limit (last code of that length), and
+ // base (offset from first code to sequence number).
+ code := 0
+ seq := 0
+ var nextcode [maxCodeLen]int
+ for i := min; i <= max; i++ {
+ n := count[i]
+ nextcode[i] = code
+ h.base[i] = code - seq
+ code += n
+ seq += n
+ h.limit[i] = code - 1
+ code <<= 1
+ }
+
+ // Make array mapping sequence numbers to codes.
+ if len(h.codes) < len(bits) {
+ h.codes = make([]int, len(bits))
+ }
+ for i, n := range bits {
+ if n == 0 {
+ continue
+ }
+ code := nextcode[n]
+ nextcode[n]++
+ seq := code - h.base[n]
+ h.codes[seq] = i
+ }
+ return true
+}
+
+// Hard-coded Huffman tables for DEFLATE algorithm.
+// See RFC 1951, section 3.2.6.
+var fixedHuffmanDecoder = huffmanDecoder{
+ 7, 9,
+ [maxCodeLen + 1]int{7: 23, 199, 511},
+ [maxCodeLen + 1]int{7: 0, 24, 224},
+ []int{
+ // length 7: 256-279
+ 256, 257, 258, 259, 260, 261, 262,
+ 263, 264, 265, 266, 267, 268, 269,
+ 270, 271, 272, 273, 274, 275, 276,
+ 277, 278, 279,
+
+ // length 8: 0-143
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ 92, 93, 94, 95, 96, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116,
+ 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132,
+ 133, 134, 135, 136, 137, 138, 139, 140,
+ 141, 142, 143,
+
+ // length 8: 280-287
+ 280, 281, 282, 283, 284, 285, 286, 287,
+
+ // length 9: 144-255
+ 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231,
+ 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252, 253, 254, 255,
+ },
+}
+
+// The actual read interface needed by NewReader.
+// If the passed in io.Reader does not also have ReadByte,
+// the NewReader will introduce its own buffering.
+type Reader interface {
+ io.Reader
+ ReadByte() (c byte, err os.Error)
+}
+
+// Decompress state.
+type decompressor struct {
+ // Input/output sources.
+ r Reader
+ w io.Writer
+ roffset int64
+ woffset int64
+
+ // Input bits, in top of b.
+ b uint32
+ nb uint
+
+ // Huffman decoders for literal/length, distance.
+ h1, h2 huffmanDecoder
+
+ // Length arrays used to define Huffman codes.
+ bits [maxLit + maxDist]int
+ codebits [numCodes]int
+
+ // Output history, buffer.
+ hist [maxHist]byte
+ hp int // current output position in buffer
+ hw int // have written hist[0:hw] already
+ hfull bool // buffer has filled at least once
+
+ // Temporary buffer (avoids repeated allocation).
+ buf [4]byte
+}
+
+func (f *decompressor) inflate() (err os.Error) {
+ final := false
+ for err == nil && !final {
+ for f.nb < 1+2 {
+ if err = f.moreBits(); err != nil {
+ return
+ }
+ }
+ final = f.b&1 == 1
+ f.b >>= 1
+ typ := f.b & 3
+ f.b >>= 2
+ f.nb -= 1 + 2
+ switch typ {
+ case 0:
+ err = f.dataBlock()
+ case 1:
+ // compressed, fixed Huffman tables
+ err = f.decodeBlock(&fixedHuffmanDecoder, nil)
+ case 2:
+ // compressed, dynamic Huffman tables
+ if err = f.readHuffman(); err == nil {
+ err = f.decodeBlock(&f.h1, &f.h2)
+ }
+ default:
+ // 3 is reserved.
+ err = CorruptInputError(f.roffset)
+ }
+ }
+ return
+}
+
+// RFC 1951 section 3.2.7.
+// Compression with dynamic Huffman codes
+
+var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+func (f *decompressor) readHuffman() os.Error {
+ // HLIT[5], HDIST[5], HCLEN[4].
+ for f.nb < 5+5+4 {
+ if err := f.moreBits(); err != nil {
+ return err
+ }
+ }
+ nlit := int(f.b&0x1F) + 257
+ f.b >>= 5
+ ndist := int(f.b&0x1F) + 1
+ f.b >>= 5
+ nclen := int(f.b&0xF) + 4
+ f.b >>= 4
+ f.nb -= 5 + 5 + 4
+
+ // (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
+ for i := 0; i < nclen; i++ {
+ for f.nb < 3 {
+ if err := f.moreBits(); err != nil {
+ return err
+ }
+ }
+ f.codebits[codeOrder[i]] = int(f.b & 0x7)
+ f.b >>= 3
+ f.nb -= 3
+ }
+ for i := nclen; i < len(codeOrder); i++ {
+ f.codebits[codeOrder[i]] = 0
+ }
+ if !f.h1.init(f.codebits[0:]) {
+ return CorruptInputError(f.roffset)
+ }
+
+ // HLIT + 257 code lengths, HDIST + 1 code lengths,
+ // using the code length Huffman code.
+ for i, n := 0, nlit+ndist; i < n; {
+ x, err := f.huffSym(&f.h1)
+ if err != nil {
+ return err
+ }
+ if x < 16 {
+ // Actual length.
+ f.bits[i] = x
+ i++
+ continue
+ }
+ // Repeat previous length or zero.
+ var rep int
+ var nb uint
+ var b int
+ switch x {
+ default:
+ return InternalError("unexpected length code")
+ case 16:
+ rep = 3
+ nb = 2
+ if i == 0 {
+ return CorruptInputError(f.roffset)
+ }
+ b = f.bits[i-1]
+ case 17:
+ rep = 3
+ nb = 3
+ b = 0
+ case 18:
+ rep = 11
+ nb = 7
+ b = 0
+ }
+ for f.nb < nb {
+ if err := f.moreBits(); err != nil {
+ return err
+ }
+ }
+ rep += int(f.b & uint32(1<<nb-1))
+ f.b >>= nb
+ f.nb -= nb
+ if i+rep > n {
+ return CorruptInputError(f.roffset)
+ }
+ for j := 0; j < rep; j++ {
+ f.bits[i] = b
+ i++
+ }
+ }
+
+ if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) {
+ return CorruptInputError(f.roffset)
+ }
+
+ return nil
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively. If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error {
+ for {
+ v, err := f.huffSym(hl)
+ if err != nil {
+ return err
+ }
+ var n uint // number of bits extra
+ var length int
+ switch {
+ case v < 256:
+ f.hist[f.hp] = byte(v)
+ f.hp++
+ if f.hp == len(f.hist) {
+ if err = f.flush(); err != nil {
+ return err
+ }
+ }
+ continue
+ case v == 256:
+ return nil
+ // otherwise, reference to older data
+ case v < 265:
+ length = v - (257 - 3)
+ n = 0
+ case v < 269:
+ length = v*2 - (265*2 - 11)
+ n = 1
+ case v < 273:
+ length = v*4 - (269*4 - 19)
+ n = 2
+ case v < 277:
+ length = v*8 - (273*8 - 35)
+ n = 3
+ case v < 281:
+ length = v*16 - (277*16 - 67)
+ n = 4
+ case v < 285:
+ length = v*32 - (281*32 - 131)
+ n = 5
+ default:
+ length = 258
+ n = 0
+ }
+ if n > 0 {
+ for f.nb < n {
+ if err = f.moreBits(); err != nil {
+ return err
+ }
+ }
+ length += int(f.b & uint32(1<<n-1))
+ f.b >>= n
+ f.nb -= n
+ }
+
+ var dist int
+ if hd == nil {
+ for f.nb < 5 {
+ if err = f.moreBits(); err != nil {
+ return err
+ }
+ }
+ dist = int(reverseByte[(f.b&0x1F)<<3])
+ f.b >>= 5
+ f.nb -= 5
+ } else {
+ if dist, err = f.huffSym(hd); err != nil {
+ return err
+ }
+ }
+
+ switch {
+ case dist < 4:
+ dist++
+ case dist >= 30:
+ return CorruptInputError(f.roffset)
+ default:
+ nb := uint(dist-2) >> 1
+ // have 1 bit in bottom of dist, need nb more.
+ extra := (dist & 1) << nb
+ for f.nb < nb {
+ if err = f.moreBits(); err != nil {
+ return err
+ }
+ }
+ extra |= int(f.b & uint32(1<<nb-1))
+ f.b >>= nb
+ f.nb -= nb
+ dist = 1<<(nb+1) + 1 + extra
+ }
+
+ // Copy history[-dist:-dist+length] into output.
+ if dist > len(f.hist) {
+ return InternalError("bad history distance")
+ }
+
+ // No check on length; encoding can be prescient.
+ if !f.hfull && dist > f.hp {
+ return CorruptInputError(f.roffset)
+ }
+
+ p := f.hp - dist
+ if p < 0 {
+ p += len(f.hist)
+ }
+ for i := 0; i < length; i++ {
+ f.hist[f.hp] = f.hist[p]
+ f.hp++
+ p++
+ if f.hp == len(f.hist) {
+ if err = f.flush(); err != nil {
+ return err
+ }
+ }
+ if p == len(f.hist) {
+ p = 0
+ }
+ }
+ }
+ panic("unreached")
+}
+
+// Copy a single uncompressed data block from input to output.
+func (f *decompressor) dataBlock() os.Error {
+ // Uncompressed.
+ // Discard current half-byte.
+ f.nb = 0
+ f.b = 0
+
+ // Length then ones-complement of length.
+ nr, err := io.ReadFull(f.r, f.buf[0:4])
+ f.roffset += int64(nr)
+ if err != nil {
+ return &ReadError{f.roffset, err}
+ }
+ n := int(f.buf[0]) | int(f.buf[1])<<8
+ nn := int(f.buf[2]) | int(f.buf[3])<<8
+ if uint16(nn) != uint16(^n) {
+ return CorruptInputError(f.roffset)
+ }
+
+ if n == 0 {
+ // 0-length block means sync
+ return f.flush()
+ }
+
+ // Read len bytes into history,
+ // writing as history fills.
+ for n > 0 {
+ m := len(f.hist) - f.hp
+ if m > n {
+ m = n
+ }
+ m, err := io.ReadFull(f.r, f.hist[f.hp:f.hp+m])
+ f.roffset += int64(m)
+ if err != nil {
+ return &ReadError{f.roffset, err}
+ }
+ n -= m
+ f.hp += m
+ if f.hp == len(f.hist) {
+ if err = f.flush(); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (f *decompressor) moreBits() os.Error {
+ c, err := f.r.ReadByte()
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return err
+ }
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
+ return nil
+}
+
+// Read the next Huffman-encoded symbol from f according to h.
+func (f *decompressor) huffSym(h *huffmanDecoder) (int, os.Error) {
+ for n := uint(h.min); n <= uint(h.max); n++ {
+ lim := h.limit[n]
+ if lim == -1 {
+ continue
+ }
+ for f.nb < n {
+ if err := f.moreBits(); err != nil {
+ return 0, err
+ }
+ }
+ v := int(f.b & uint32(1<<n-1))
+ v <<= 16 - n
+ v = int(reverseByte[v>>8]) | int(reverseByte[v&0xFF])<<8 // reverse bits
+ if v <= lim {
+ f.b >>= n
+ f.nb -= n
+ return h.codes[v-h.base[n]], nil
+ }
+ }
+ return 0, CorruptInputError(f.roffset)
+}
+
+// Flush any buffered output to the underlying writer.
+func (f *decompressor) flush() os.Error {
+ if f.hw == f.hp {
+ return nil
+ }
+ n, err := f.w.Write(f.hist[f.hw:f.hp])
+ if n != f.hp-f.hw && err == nil {
+ err = io.ErrShortWrite
+ }
+ if err != nil {
+ return &WriteError{f.woffset, err}
+ }
+ f.woffset += int64(f.hp - f.hw)
+ f.hw = f.hp
+ if f.hp == len(f.hist) {
+ f.hp = 0
+ f.hw = 0
+ f.hfull = true
+ }
+ return nil
+}
+
+func makeReader(r io.Reader) Reader {
+ if rr, ok := r.(Reader); ok {
+ return rr
+ }
+ return bufio.NewReader(r)
+}
+
+// decompress reads DEFLATE-compressed data from r and writes
+// the uncompressed data to w.
+func (f *decompressor) decompress(r io.Reader, w io.Writer) os.Error {
+ f.r = makeReader(r)
+ f.w = w
+ f.woffset = 0
+ if err := f.inflate(); err != nil {
+ return err
+ }
+ if err := f.flush(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// NewReader returns a new ReadCloser that can be used
+// to read the uncompressed version of r. It is the caller's
+// responsibility to call Close on the ReadCloser when
+// finished reading.
+func NewReader(r io.Reader) io.ReadCloser {
+ var f decompressor
+ pr, pw := io.Pipe()
+ go func() { pw.CloseWithError(f.decompress(r, pw)) }()
+ return pr
+}
diff --git a/libgo/go/compress/flate/reverse_bits.go b/libgo/go/compress/flate/reverse_bits.go
new file mode 100644
index 000000000..c1a02720d
--- /dev/null
+++ b/libgo/go/compress/flate/reverse_bits.go
@@ -0,0 +1,48 @@
+// 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 flate
+
+var reverseByte = [256]byte{
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+}
+
+func reverseUint16(v uint16) uint16 {
+ return uint16(reverseByte[v>>8]) | uint16(reverseByte[v&0xFF])<<8
+}
+
+func reverseBits(number uint16, bitLength byte) uint16 {
+ return reverseUint16(number << uint8(16-bitLength))
+}
diff --git a/libgo/go/compress/flate/token.go b/libgo/go/compress/flate/token.go
new file mode 100644
index 000000000..38aea5fa6
--- /dev/null
+++ b/libgo/go/compress/flate/token.go
@@ -0,0 +1,103 @@
+// 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 flate
+
+const (
+ // 2 bits: type 0 = literal 1=EOF 2=Match 3=Unused
+ // 8 bits: xlength = length - MIN_MATCH_LENGTH
+ // 22 bits xoffset = offset - MIN_OFFSET_SIZE, or literal
+ lengthShift = 22
+ offsetMask = 1<<lengthShift - 1
+ typeMask = 3 << 30
+ literalType = 0 << 30
+ matchType = 1 << 30
+)
+
+// The length code for length X (MIN_MATCH_LENGTH <= X <= MAX_MATCH_LENGTH)
+// is lengthCodes[length - MIN_MATCH_LENGTH]
+var lengthCodes = [...]uint32{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8,
+ 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+ 13, 13, 13, 13, 14, 14, 14, 14, 15, 15,
+ 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+ 17, 17, 17, 17, 17, 17, 17, 17, 18, 18,
+ 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+ 19, 19, 19, 19, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 28,
+}
+
+var offsetCodes = [...]uint32{
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+}
+
+type token uint32
+
+// Convert a literal into a literal token.
+func literalToken(literal uint32) token { return token(literalType + literal) }
+
+// Convert a < xlength, xoffset > pair into a match token.
+func matchToken(xlength uint32, xoffset uint32) token {
+ return token(matchType + xlength<<lengthShift + xoffset)
+}
+
+// Returns the type of a token
+func (t token) typ() uint32 { return uint32(t) & typeMask }
+
+// Returns the literal of a literal token
+func (t token) literal() uint32 { return uint32(t - literalType) }
+
+// Returns the extra offset of a match token
+func (t token) offset() uint32 { return uint32(t) & offsetMask }
+
+func (t token) length() uint32 { return uint32((t - matchType) >> lengthShift) }
+
+func lengthCode(len uint32) uint32 { return lengthCodes[len] }
+
+// Returns the offset code corresponding to a specific offset
+func offsetCode(off uint32) uint32 {
+ const n = uint32(len(offsetCodes))
+ switch {
+ case off < n:
+ return offsetCodes[off]
+ case off>>7 < n:
+ return offsetCodes[off>>7] + 14
+ default:
+ return offsetCodes[off>>14] + 28
+ }
+ panic("unreachable")
+}
diff --git a/libgo/go/compress/flate/util.go b/libgo/go/compress/flate/util.go
new file mode 100644
index 000000000..aca5c78b2
--- /dev/null
+++ b/libgo/go/compress/flate/util.go
@@ -0,0 +1,72 @@
+// 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 flate
+
+func min(left int, right int) int {
+ if left < right {
+ return left
+ }
+ return right
+}
+
+func minInt32(left int32, right int32) int32 {
+ if left < right {
+ return left
+ }
+ return right
+}
+
+func max(left int, right int) int {
+ if left > right {
+ return left
+ }
+ return right
+}
+
+func fillInts(a []int, value int) {
+ for i := range a {
+ a[i] = value
+ }
+}
+
+func fillInt32s(a []int32, value int32) {
+ for i := range a {
+ a[i] = value
+ }
+}
+
+func fillBytes(a []byte, value byte) {
+ for i := range a {
+ a[i] = value
+ }
+}
+
+func fillInt8s(a []int8, value int8) {
+ for i := range a {
+ a[i] = value
+ }
+}
+
+func fillUint8s(a []uint8, value uint8) {
+ for i := range a {
+ a[i] = value
+ }
+}
+
+func copyInt8s(dst []int8, src []int8) int {
+ cnt := min(len(dst), len(src))
+ for i := 0; i < cnt; i++ {
+ dst[i] = src[i]
+ }
+ return cnt
+}
+
+func copyUint8s(dst []uint8, src []uint8) int {
+ cnt := min(len(dst), len(src))
+ for i := 0; i < cnt; i++ {
+ dst[i] = src[i]
+ }
+ return cnt
+}
diff --git a/libgo/go/compress/gzip/gunzip.go b/libgo/go/compress/gzip/gunzip.go
new file mode 100644
index 000000000..3c0b3c5e5
--- /dev/null
+++ b/libgo/go/compress/gzip/gunzip.go
@@ -0,0 +1,230 @@
+// 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.
+
+// The gzip package implements reading and writing of
+// gzip format compressed files, as specified in RFC 1952.
+package gzip
+
+import (
+ "bufio"
+ "compress/flate"
+ "hash"
+ "hash/crc32"
+ "io"
+ "os"
+)
+
+// BUG(nigeltao): Comments and Names don't properly map UTF-8 character codes outside of
+// the 0x00-0x7f range to ISO 8859-1 (Latin-1).
+
+const (
+ gzipID1 = 0x1f
+ gzipID2 = 0x8b
+ gzipDeflate = 8
+ flagText = 1 << 0
+ flagHdrCrc = 1 << 1
+ flagExtra = 1 << 2
+ flagName = 1 << 3
+ flagComment = 1 << 4
+)
+
+func makeReader(r io.Reader) flate.Reader {
+ if rr, ok := r.(flate.Reader); ok {
+ return rr
+ }
+ return bufio.NewReader(r)
+}
+
+var HeaderError os.Error = os.ErrorString("invalid gzip header")
+var ChecksumError os.Error = os.ErrorString("gzip checksum error")
+
+// The gzip file stores a header giving metadata about the compressed file.
+// That header is exposed as the fields of the Compressor and Decompressor structs.
+type Header struct {
+ Comment string // comment
+ Extra []byte // "extra data"
+ Mtime uint32 // modification time (seconds since January 1, 1970)
+ Name string // file name
+ OS byte // operating system type
+}
+
+// An Decompressor is an io.Reader that can be read to retrieve
+// uncompressed data from a gzip-format compressed file.
+//
+// In general, a gzip file can be a concatenation of gzip files,
+// each with its own header. Reads from the Decompressor
+// return the concatenation of the uncompressed data of each.
+// Only the first header is recorded in the Decompressor fields.
+//
+// Gzip files store a length and checksum of the uncompressed data.
+// The Decompressor will return a ChecksumError when Read
+// reaches the end of the uncompressed data if it does not
+// have the expected length or checksum. Clients should treat data
+// returned by Read as tentative until they receive the successful
+// (zero length, nil error) Read marking the end of the data.
+type Decompressor struct {
+ Header
+ r flate.Reader
+ decompressor io.ReadCloser
+ digest hash.Hash32
+ size uint32
+ flg byte
+ buf [512]byte
+ err os.Error
+}
+
+// NewReader creates a new Decompressor reading the given reader.
+// The implementation buffers input and may read more data than necessary from r.
+// It is the caller's responsibility to call Close on the Decompressor when done.
+func NewReader(r io.Reader) (*Decompressor, os.Error) {
+ z := new(Decompressor)
+ z.r = makeReader(r)
+ z.digest = crc32.NewIEEE()
+ if err := z.readHeader(true); err != nil {
+ z.err = err
+ return nil, err
+ }
+ return z, nil
+}
+
+// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
+func get4(p []byte) uint32 {
+ return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
+}
+
+func (z *Decompressor) readString() (string, os.Error) {
+ var err os.Error
+ for i := 0; ; i++ {
+ if i >= len(z.buf) {
+ return "", HeaderError
+ }
+ z.buf[i], err = z.r.ReadByte()
+ if err != nil {
+ return "", err
+ }
+ if z.buf[i] == 0 {
+ // GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
+ // TODO(nigeltao): Convert from ISO 8859-1 (Latin-1) to UTF-8.
+ return string(z.buf[0:i]), nil
+ }
+ }
+ panic("not reached")
+}
+
+func (z *Decompressor) read2() (uint32, os.Error) {
+ _, err := io.ReadFull(z.r, z.buf[0:2])
+ if err != nil {
+ return 0, err
+ }
+ return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil
+}
+
+func (z *Decompressor) readHeader(save bool) os.Error {
+ _, err := io.ReadFull(z.r, z.buf[0:10])
+ if err != nil {
+ return err
+ }
+ if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate {
+ return HeaderError
+ }
+ z.flg = z.buf[3]
+ if save {
+ z.Mtime = get4(z.buf[4:8])
+ // z.buf[8] is xfl, ignored
+ z.OS = z.buf[9]
+ }
+ z.digest.Reset()
+ z.digest.Write(z.buf[0:10])
+
+ if z.flg&flagExtra != 0 {
+ n, err := z.read2()
+ if err != nil {
+ return err
+ }
+ data := make([]byte, n)
+ if _, err = io.ReadFull(z.r, data); err != nil {
+ return err
+ }
+ if save {
+ z.Extra = data
+ }
+ }
+
+ var s string
+ if z.flg&flagName != 0 {
+ if s, err = z.readString(); err != nil {
+ return err
+ }
+ if save {
+ z.Name = s
+ }
+ }
+
+ if z.flg&flagComment != 0 {
+ if s, err = z.readString(); err != nil {
+ return err
+ }
+ if save {
+ z.Comment = s
+ }
+ }
+
+ if z.flg&flagHdrCrc != 0 {
+ n, err := z.read2()
+ if err != nil {
+ return err
+ }
+ sum := z.digest.Sum32() & 0xFFFF
+ if n != sum {
+ return HeaderError
+ }
+ }
+
+ z.digest.Reset()
+ z.decompressor = flate.NewReader(z.r)
+ return nil
+}
+
+func (z *Decompressor) Read(p []byte) (n int, err os.Error) {
+ if z.err != nil {
+ return 0, z.err
+ }
+ if len(p) == 0 {
+ return 0, nil
+ }
+
+ n, err = z.decompressor.Read(p)
+ z.digest.Write(p[0:n])
+ z.size += uint32(n)
+ if n != 0 || err != os.EOF {
+ z.err = err
+ return
+ }
+
+ // Finished file; check checksum + size.
+ if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil {
+ z.err = err
+ return 0, err
+ }
+ crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8])
+ sum := z.digest.Sum32()
+ if sum != crc32 || isize != z.size {
+ z.err = ChecksumError
+ return 0, z.err
+ }
+
+ // File is ok; is there another?
+ if err = z.readHeader(false); err != nil {
+ z.err = err
+ return
+ }
+
+ // Yes. Reset and read from it.
+ z.digest.Reset()
+ z.size = 0
+ return z.Read(p)
+}
+
+// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
+func (z *Decompressor) Close() os.Error { return z.decompressor.Close() }
diff --git a/libgo/go/compress/gzip/gunzip_test.go b/libgo/go/compress/gzip/gunzip_test.go
new file mode 100644
index 000000000..1c08c7374
--- /dev/null
+++ b/libgo/go/compress/gzip/gunzip_test.go
@@ -0,0 +1,305 @@
+// 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 gzip
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "testing"
+)
+
+type gunzipTest struct {
+ name string
+ desc string
+ raw string
+ gzip []byte
+ err os.Error
+}
+
+var gunzipTests = []gunzipTest{
+ { // has 1 empty fixed-huffman block
+ "empty.txt",
+ "empty.txt",
+ "",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xf7, 0x5e, 0x14, 0x4a,
+ 0x00, 0x03, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ nil,
+ },
+ { // has 1 non-empty fixed huffman block
+ "hello.txt",
+ "hello.txt",
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+ 0x00, 0x00,
+ },
+ nil,
+ },
+ { // concatenation
+ "hello.txt",
+ "hello.txt x2",
+ "hello world\n" +
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+ 0x00, 0x00,
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+ 0x00, 0x00,
+ },
+ nil,
+ },
+ { // has a fixed huffman block with some length-distance pairs
+ "shesells.txt",
+ "shesells.txt",
+ "she sells seashells by the seashore\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0x72, 0x66, 0x8b, 0x4a,
+ 0x00, 0x03, 0x73, 0x68, 0x65, 0x73, 0x65, 0x6c,
+ 0x6c, 0x73, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x2b,
+ 0xce, 0x48, 0x55, 0x28, 0x4e, 0xcd, 0xc9, 0x29,
+ 0x06, 0x92, 0x89, 0xc5, 0x19, 0x60, 0x56, 0x52,
+ 0xa5, 0x42, 0x09, 0x58, 0x18, 0x28, 0x90, 0x5f,
+ 0x94, 0xca, 0x05, 0x00, 0x76, 0xb0, 0x3b, 0xeb,
+ 0x24, 0x00, 0x00, 0x00,
+ },
+ nil,
+ },
+ { // has dynamic huffman blocks
+ "gettysburg",
+ "gettysburg",
+ " Four score and seven years ago our fathers brought forth on\n" +
+ "this continent, a new nation, conceived in Liberty, and dedicated\n" +
+ "to the proposition that all men are created equal.\n" +
+ " Now we are engaged in a great Civil War, testing whether that\n" +
+ "nation, or any nation so conceived and so dedicated, can long\n" +
+ "endure.\n" +
+ " We are met on a great battle-field of that war.\n" +
+ " We have come to dedicate a portion of that field, as a final\n" +
+ "resting place for those who here gave their lives that that\n" +
+ "nation might live. It is altogether fitting and proper that\n" +
+ "we should do this.\n" +
+ " But, in a larger sense, we can not dedicate — we can not\n" +
+ "consecrate — we can not hallow — this ground.\n" +
+ " The brave men, living and dead, who struggled here, have\n" +
+ "consecrated it, far above our poor power to add or detract.\n" +
+ "The world will little note, nor long remember what we say here,\n" +
+ "but it can never forget what they did here.\n" +
+ " It is for us the living, rather, to be dedicated here to the\n" +
+ "unfinished work which they who fought here have thus far so\n" +
+ "nobly advanced. It is rather for us to be here dedicated to\n" +
+ "the great task remaining before us — that from these honored\n" +
+ "dead we take increased devotion to that cause for which they\n" +
+ "gave the last full measure of devotion —\n" +
+ " that we here highly resolve that these dead shall not have\n" +
+ "died in vain — that this nation, under God, shall have a new\n" +
+ "birth of freedom — and that government of the people, by the\n" +
+ "people, for the people, shall not perish from this earth.\n" +
+ "\n" +
+ "Abraham Lincoln, November 19, 1863, Gettysburg, Pennsylvania\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xd1, 0x12, 0x2b, 0x4a,
+ 0x00, 0x03, 0x67, 0x65, 0x74, 0x74, 0x79, 0x73,
+ 0x62, 0x75, 0x72, 0x67, 0x00, 0x65, 0x54, 0xcd,
+ 0x6e, 0xd4, 0x30, 0x10, 0xbe, 0xfb, 0x29, 0xe6,
+ 0x01, 0x42, 0xa5, 0x0a, 0x09, 0xc1, 0x11, 0x90,
+ 0x40, 0x48, 0xa8, 0xe2, 0x80, 0xd4, 0xf3, 0x24,
+ 0x9e, 0x24, 0x56, 0xbd, 0x9e, 0xc5, 0x76, 0x76,
+ 0x95, 0x1b, 0x0f, 0xc1, 0x13, 0xf2, 0x24, 0x7c,
+ 0x63, 0x77, 0x9b, 0x4a, 0x5c, 0xaa, 0x6e, 0x6c,
+ 0xcf, 0x7c, 0x7f, 0x33, 0x44, 0x5f, 0x74, 0xcb,
+ 0x54, 0x26, 0xcd, 0x42, 0x9c, 0x3c, 0x15, 0xb9,
+ 0x48, 0xa2, 0x5d, 0x38, 0x17, 0xe2, 0x45, 0xc9,
+ 0x4e, 0x67, 0xae, 0xab, 0xe0, 0xf7, 0x98, 0x75,
+ 0x5b, 0xd6, 0x4a, 0xb3, 0xe6, 0xba, 0x92, 0x26,
+ 0x57, 0xd7, 0x50, 0x68, 0xd2, 0x54, 0x43, 0x92,
+ 0x54, 0x07, 0x62, 0x4a, 0x72, 0xa5, 0xc4, 0x35,
+ 0x68, 0x1a, 0xec, 0x60, 0x92, 0x70, 0x11, 0x4f,
+ 0x21, 0xd1, 0xf7, 0x30, 0x4a, 0xae, 0xfb, 0xd0,
+ 0x9a, 0x78, 0xf1, 0x61, 0xe2, 0x2a, 0xde, 0x55,
+ 0x25, 0xd4, 0xa6, 0x73, 0xd6, 0xb3, 0x96, 0x60,
+ 0xef, 0xf0, 0x9b, 0x2b, 0x71, 0x8c, 0x74, 0x02,
+ 0x10, 0x06, 0xac, 0x29, 0x8b, 0xdd, 0x25, 0xf9,
+ 0xb5, 0x71, 0xbc, 0x73, 0x44, 0x0f, 0x7a, 0xa5,
+ 0xab, 0xb4, 0x33, 0x49, 0x0b, 0x2f, 0xbd, 0x03,
+ 0xd3, 0x62, 0x17, 0xe9, 0x73, 0xb8, 0x84, 0x48,
+ 0x8f, 0x9c, 0x07, 0xaa, 0x52, 0x00, 0x6d, 0xa1,
+ 0xeb, 0x2a, 0xc6, 0xa0, 0x95, 0x76, 0x37, 0x78,
+ 0x9a, 0x81, 0x65, 0x7f, 0x46, 0x4b, 0x45, 0x5f,
+ 0xe1, 0x6d, 0x42, 0xe8, 0x01, 0x13, 0x5c, 0x38,
+ 0x51, 0xd4, 0xb4, 0x38, 0x49, 0x7e, 0xcb, 0x62,
+ 0x28, 0x1e, 0x3b, 0x82, 0x93, 0x54, 0x48, 0xf1,
+ 0xd2, 0x7d, 0xe4, 0x5a, 0xa3, 0xbc, 0x99, 0x83,
+ 0x44, 0x4f, 0x3a, 0x77, 0x36, 0x57, 0xce, 0xcf,
+ 0x2f, 0x56, 0xbe, 0x80, 0x90, 0x9e, 0x84, 0xea,
+ 0x51, 0x1f, 0x8f, 0xcf, 0x90, 0xd4, 0x60, 0xdc,
+ 0x5e, 0xb4, 0xf7, 0x10, 0x0b, 0x26, 0xe0, 0xff,
+ 0xc4, 0xd1, 0xe5, 0x67, 0x2e, 0xe7, 0xc8, 0x93,
+ 0x98, 0x05, 0xb8, 0xa8, 0x45, 0xc0, 0x4d, 0x09,
+ 0xdc, 0x84, 0x16, 0x2b, 0x0d, 0x9a, 0x21, 0x53,
+ 0x04, 0x8b, 0xd2, 0x0b, 0xbd, 0xa2, 0x4c, 0xa7,
+ 0x60, 0xee, 0xd9, 0xe1, 0x1d, 0xd1, 0xb7, 0x4a,
+ 0x30, 0x8f, 0x63, 0xd5, 0xa5, 0x8b, 0x33, 0x87,
+ 0xda, 0x1a, 0x18, 0x79, 0xf3, 0xe3, 0xa6, 0x17,
+ 0x94, 0x2e, 0xab, 0x6e, 0xa0, 0xe3, 0xcd, 0xac,
+ 0x50, 0x8c, 0xca, 0xa7, 0x0d, 0x76, 0x37, 0xd1,
+ 0x23, 0xe7, 0x05, 0x57, 0x8b, 0xa4, 0x22, 0x83,
+ 0xd9, 0x62, 0x52, 0x25, 0xad, 0x07, 0xbb, 0xbf,
+ 0xbf, 0xff, 0xbc, 0xfa, 0xee, 0x20, 0x73, 0x91,
+ 0x29, 0xff, 0x7f, 0x02, 0x71, 0x62, 0x84, 0xb5,
+ 0xf6, 0xb5, 0x25, 0x6b, 0x41, 0xde, 0x92, 0xb7,
+ 0x76, 0x3f, 0x91, 0x91, 0x31, 0x1b, 0x41, 0x84,
+ 0x62, 0x30, 0x0a, 0x37, 0xa4, 0x5e, 0x18, 0x3a,
+ 0x99, 0x08, 0xa5, 0xe6, 0x6d, 0x59, 0x22, 0xec,
+ 0x33, 0x39, 0x86, 0x26, 0xf5, 0xab, 0x66, 0xc8,
+ 0x08, 0x20, 0xcf, 0x0c, 0xd7, 0x47, 0x45, 0x21,
+ 0x0b, 0xf6, 0x59, 0xd5, 0xfe, 0x5c, 0x8d, 0xaa,
+ 0x12, 0x7b, 0x6f, 0xa1, 0xf0, 0x52, 0x33, 0x4f,
+ 0xf5, 0xce, 0x59, 0xd3, 0xab, 0x66, 0x10, 0xbf,
+ 0x06, 0xc4, 0x31, 0x06, 0x73, 0xd6, 0x80, 0xa2,
+ 0x78, 0xc2, 0x45, 0xcb, 0x03, 0x65, 0x39, 0xc9,
+ 0x09, 0xd1, 0x06, 0x04, 0x33, 0x1a, 0x5a, 0xf1,
+ 0xde, 0x01, 0xb8, 0x71, 0x83, 0xc4, 0xb5, 0xb3,
+ 0xc3, 0x54, 0x65, 0x33, 0x0d, 0x5a, 0xf7, 0x9b,
+ 0x90, 0x7c, 0x27, 0x1f, 0x3a, 0x58, 0xa3, 0xd8,
+ 0xfd, 0x30, 0x5f, 0xb7, 0xd2, 0x66, 0xa2, 0x93,
+ 0x1c, 0x28, 0xb7, 0xe9, 0x1b, 0x0c, 0xe1, 0x28,
+ 0x47, 0x26, 0xbb, 0xe9, 0x7d, 0x7e, 0xdc, 0x96,
+ 0x10, 0x92, 0x50, 0x56, 0x7c, 0x06, 0xe2, 0x27,
+ 0xb4, 0x08, 0xd3, 0xda, 0x7b, 0x98, 0x34, 0x73,
+ 0x9f, 0xdb, 0xf6, 0x62, 0xed, 0x31, 0x41, 0x13,
+ 0xd3, 0xa2, 0xa8, 0x4b, 0x3a, 0xc6, 0x1d, 0xe4,
+ 0x2f, 0x8c, 0xf8, 0xfb, 0x97, 0x64, 0xf4, 0xb6,
+ 0x2f, 0x80, 0x5a, 0xf3, 0x56, 0xe0, 0x40, 0x50,
+ 0xd5, 0x19, 0xd0, 0x1e, 0xfc, 0xca, 0xe5, 0xc9,
+ 0xd4, 0x60, 0x00, 0x81, 0x2e, 0xa3, 0xcc, 0xb6,
+ 0x52, 0xf0, 0xb4, 0xdb, 0x69, 0x99, 0xce, 0x7a,
+ 0x32, 0x4c, 0x08, 0xed, 0xaa, 0x10, 0x10, 0xe3,
+ 0x6f, 0xee, 0x99, 0x68, 0x95, 0x9f, 0x04, 0x71,
+ 0xb2, 0x49, 0x2f, 0x62, 0xa6, 0x5e, 0xb4, 0xef,
+ 0x02, 0xed, 0x4f, 0x27, 0xde, 0x4a, 0x0f, 0xfd,
+ 0xc1, 0xcc, 0xdd, 0x02, 0x8f, 0x08, 0x16, 0x54,
+ 0xdf, 0xda, 0xca, 0xe0, 0x82, 0xf1, 0xb4, 0x31,
+ 0x7a, 0xa9, 0x81, 0xfe, 0x90, 0xb7, 0x3e, 0xdb,
+ 0xd3, 0x35, 0xc0, 0x20, 0x80, 0x33, 0x46, 0x4a,
+ 0x63, 0xab, 0xd1, 0x0d, 0x29, 0xd2, 0xe2, 0x84,
+ 0xb8, 0xdb, 0xfa, 0xe9, 0x89, 0x44, 0x86, 0x7c,
+ 0xe8, 0x0b, 0xe6, 0x02, 0x6a, 0x07, 0x9b, 0x96,
+ 0xd0, 0xdb, 0x2e, 0x41, 0x4c, 0xa1, 0xd5, 0x57,
+ 0x45, 0x14, 0xfb, 0xe3, 0xa6, 0x72, 0x5b, 0x87,
+ 0x6e, 0x0c, 0x6d, 0x5b, 0xce, 0xe0, 0x2f, 0xe2,
+ 0x21, 0x81, 0x95, 0xb0, 0xe8, 0xb6, 0x32, 0x0b,
+ 0xb2, 0x98, 0x13, 0x52, 0x5d, 0xfb, 0xec, 0x63,
+ 0x17, 0x8a, 0x9e, 0x23, 0x22, 0x36, 0xee, 0xcd,
+ 0xda, 0xdb, 0xcf, 0x3e, 0xf1, 0xc7, 0xf1, 0x01,
+ 0x12, 0x93, 0x0a, 0xeb, 0x6f, 0xf2, 0x02, 0x15,
+ 0x96, 0x77, 0x5d, 0xef, 0x9c, 0xfb, 0x88, 0x91,
+ 0x59, 0xf9, 0x84, 0xdd, 0x9b, 0x26, 0x8d, 0x80,
+ 0xf9, 0x80, 0x66, 0x2d, 0xac, 0xf7, 0x1f, 0x06,
+ 0xba, 0x7f, 0xff, 0xee, 0xed, 0x40, 0x5f, 0xa5,
+ 0xd6, 0xbd, 0x8c, 0x5b, 0x46, 0xd2, 0x7e, 0x48,
+ 0x4a, 0x65, 0x8f, 0x08, 0x42, 0x60, 0xf7, 0x0f,
+ 0xb9, 0x16, 0x0b, 0x0c, 0x1a, 0x06, 0x00, 0x00,
+ },
+ nil,
+ },
+ { // has 1 non-empty fixed huffman block then garbage
+ "hello.txt",
+ "hello.txt + garbage",
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+ 0x00, 0x00, 'g', 'a', 'r', 'b', 'a', 'g', 'e', '!', '!', '!',
+ },
+ HeaderError,
+ },
+ { // has 1 non-empty fixed huffman block not enough header
+ "hello.txt",
+ "hello.txt + garbage",
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
+ 0x00, 0x00, gzipID1,
+ },
+ io.ErrUnexpectedEOF,
+ },
+ { // has 1 non-empty fixed huffman block but corrupt checksum
+ "hello.txt",
+ "hello.txt + corrupt checksum",
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00,
+ 0x00, 0x00,
+ },
+ ChecksumError,
+ },
+ { // has 1 non-empty fixed huffman block but corrupt size
+ "hello.txt",
+ "hello.txt + corrupt size",
+ "hello world\n",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xc8, 0x58, 0x13, 0x4a,
+ 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xcb, 0x48, 0xcd, 0xc9,
+ 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0xff, 0x00,
+ 0x00, 0x00,
+ },
+ ChecksumError,
+ },
+}
+
+func TestDecompressor(t *testing.T) {
+ b := new(bytes.Buffer)
+ for _, tt := range gunzipTests {
+ in := bytes.NewBuffer(tt.gzip)
+ gzip, err := NewReader(in)
+ if err != nil {
+ t.Errorf("%s: NewReader: %s", tt.name, err)
+ continue
+ }
+ defer gzip.Close()
+ if tt.name != gzip.Name {
+ t.Errorf("%s: got name %s", tt.name, gzip.Name)
+ }
+ b.Reset()
+ n, err := io.Copy(b, gzip)
+ if err != tt.err {
+ t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err)
+ }
+ s := b.String()
+ if s != tt.raw {
+ t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
+ }
+ }
+}
diff --git a/libgo/go/compress/gzip/gzip.go b/libgo/go/compress/gzip/gzip.go
new file mode 100644
index 000000000..8860d10af
--- /dev/null
+++ b/libgo/go/compress/gzip/gzip.go
@@ -0,0 +1,187 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gzip
+
+import (
+ "compress/flate"
+ "hash"
+ "hash/crc32"
+ "io"
+ "os"
+)
+
+// These constants are copied from the flate package, so that code that imports
+// "compress/gzip" does not also have to import "compress/flate".
+const (
+ NoCompression = flate.NoCompression
+ BestSpeed = flate.BestSpeed
+ BestCompression = flate.BestCompression
+ DefaultCompression = flate.DefaultCompression
+)
+
+// A Compressor is an io.WriteCloser that satisfies writes by compressing data written
+// to its wrapped io.Writer.
+type Compressor struct {
+ Header
+ w io.Writer
+ level int
+ compressor io.WriteCloser
+ digest hash.Hash32
+ size uint32
+ closed bool
+ buf [10]byte
+ err os.Error
+}
+
+// NewWriter calls NewWriterLevel with the default compression level.
+func NewWriter(w io.Writer) (*Compressor, os.Error) {
+ return NewWriterLevel(w, DefaultCompression)
+}
+
+// NewWriterLevel creates a new Compressor writing to the given writer.
+// Writes may be buffered and not flushed until Close.
+// Callers that wish to set the fields in Compressor.Header must
+// do so before the first call to Write or Close.
+// It is the caller's responsibility to call Close on the WriteCloser when done.
+// level is the compression level, which can be DefaultCompression, NoCompression,
+// or any integer value between BestSpeed and BestCompression (inclusive).
+func NewWriterLevel(w io.Writer, level int) (*Compressor, os.Error) {
+ z := new(Compressor)
+ z.OS = 255 // unknown
+ z.w = w
+ z.level = level
+ z.digest = crc32.NewIEEE()
+ return z, nil
+}
+
+// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
+func put2(p []byte, v uint16) {
+ p[0] = uint8(v >> 0)
+ p[1] = uint8(v >> 8)
+}
+
+func put4(p []byte, v uint32) {
+ p[0] = uint8(v >> 0)
+ p[1] = uint8(v >> 8)
+ p[2] = uint8(v >> 16)
+ p[3] = uint8(v >> 24)
+}
+
+// writeBytes writes a length-prefixed byte slice to z.w.
+func (z *Compressor) writeBytes(b []byte) os.Error {
+ if len(b) > 0xffff {
+ return os.NewError("gzip.Write: Extra data is too large")
+ }
+ put2(z.buf[0:2], uint16(len(b)))
+ _, err := z.w.Write(z.buf[0:2])
+ if err != nil {
+ return err
+ }
+ _, err = z.w.Write(b)
+ return err
+}
+
+// writeString writes a string (in ISO 8859-1 (Latin-1) format) to z.w.
+func (z *Compressor) writeString(s string) os.Error {
+ // GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
+ // TODO(nigeltao): Convert from UTF-8 to ISO 8859-1 (Latin-1).
+ for _, v := range s {
+ if v == 0 || v > 0x7f {
+ return os.NewError("gzip.Write: non-ASCII header string")
+ }
+ }
+ _, err := io.WriteString(z.w, s)
+ if err != nil {
+ return err
+ }
+ // GZIP strings are NUL-terminated.
+ z.buf[0] = 0
+ _, err = z.w.Write(z.buf[0:1])
+ return err
+}
+
+func (z *Compressor) Write(p []byte) (int, os.Error) {
+ if z.err != nil {
+ return 0, z.err
+ }
+ var n int
+ // Write the GZIP header lazily.
+ if z.compressor == nil {
+ z.buf[0] = gzipID1
+ z.buf[1] = gzipID2
+ z.buf[2] = gzipDeflate
+ z.buf[3] = 0
+ if z.Extra != nil {
+ z.buf[3] |= 0x04
+ }
+ if z.Name != "" {
+ z.buf[3] |= 0x08
+ }
+ if z.Comment != "" {
+ z.buf[3] |= 0x10
+ }
+ put4(z.buf[4:8], z.Mtime)
+ if z.level == BestCompression {
+ z.buf[8] = 2
+ } else if z.level == BestSpeed {
+ z.buf[8] = 4
+ } else {
+ z.buf[8] = 0
+ }
+ z.buf[9] = z.OS
+ n, z.err = z.w.Write(z.buf[0:10])
+ if z.err != nil {
+ return n, z.err
+ }
+ if z.Extra != nil {
+ z.err = z.writeBytes(z.Extra)
+ if z.err != nil {
+ return n, z.err
+ }
+ }
+ if z.Name != "" {
+ z.err = z.writeString(z.Name)
+ if z.err != nil {
+ return n, z.err
+ }
+ }
+ if z.Comment != "" {
+ z.err = z.writeString(z.Comment)
+ if z.err != nil {
+ return n, z.err
+ }
+ }
+ z.compressor = flate.NewWriter(z.w, z.level)
+ }
+ z.size += uint32(len(p))
+ z.digest.Write(p)
+ n, z.err = z.compressor.Write(p)
+ return n, z.err
+}
+
+// Calling Close does not close the wrapped io.Writer originally passed to NewWriter.
+func (z *Compressor) Close() os.Error {
+ if z.err != nil {
+ return z.err
+ }
+ if z.closed {
+ return nil
+ }
+ z.closed = true
+ if z.compressor == nil {
+ z.Write(nil)
+ if z.err != nil {
+ return z.err
+ }
+ }
+ z.err = z.compressor.Close()
+ if z.err != nil {
+ return z.err
+ }
+ put4(z.buf[0:4], z.digest.Sum32())
+ put4(z.buf[4:8], z.size)
+ _, z.err = z.w.Write(z.buf[0:8])
+ return z.err
+}
diff --git a/libgo/go/compress/gzip/gzip_test.go b/libgo/go/compress/gzip/gzip_test.go
new file mode 100644
index 000000000..23f351405
--- /dev/null
+++ b/libgo/go/compress/gzip/gzip_test.go
@@ -0,0 +1,84 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gzip
+
+import (
+ "io"
+ "io/ioutil"
+ "testing"
+)
+
+// pipe creates two ends of a pipe that gzip and gunzip, and runs dfunc at the
+// writer end and ifunc at the reader end.
+func pipe(t *testing.T, dfunc func(*Compressor), cfunc func(*Decompressor)) {
+ piper, pipew := io.Pipe()
+ defer piper.Close()
+ go func() {
+ defer pipew.Close()
+ compressor, err := NewWriter(pipew)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ defer compressor.Close()
+ dfunc(compressor)
+ }()
+ decompressor, err := NewReader(piper)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ defer decompressor.Close()
+ cfunc(decompressor)
+}
+
+// Tests that an empty payload still forms a valid GZIP stream.
+func TestEmpty(t *testing.T) {
+ pipe(t,
+ func(compressor *Compressor) {},
+ func(decompressor *Decompressor) {
+ b, err := ioutil.ReadAll(decompressor)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ if len(b) != 0 {
+ t.Fatalf("did not read an empty slice")
+ }
+ })
+}
+
+// Tests that gzipping and then gunzipping is the identity function.
+func TestWriter(t *testing.T) {
+ pipe(t,
+ func(compressor *Compressor) {
+ compressor.Comment = "comment"
+ compressor.Extra = []byte("extra")
+ compressor.Mtime = 1e8
+ compressor.Name = "name"
+ _, err := compressor.Write([]byte("payload"))
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ },
+ func(decompressor *Decompressor) {
+ b, err := ioutil.ReadAll(decompressor)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ if string(b) != "payload" {
+ t.Fatalf("payload is %q, want %q", string(b), "payload")
+ }
+ if decompressor.Comment != "comment" {
+ t.Fatalf("comment is %q, want %q", decompressor.Comment, "comment")
+ }
+ if string(decompressor.Extra) != "extra" {
+ t.Fatalf("extra is %q, want %q", decompressor.Extra, "extra")
+ }
+ if decompressor.Mtime != 1e8 {
+ t.Fatalf("mtime is %d, want %d", decompressor.Mtime, uint32(1e8))
+ }
+ if decompressor.Name != "name" {
+ t.Fatalf("name is %q, want %q", decompressor.Name, "name")
+ }
+ })
+}
diff --git a/libgo/go/compress/zlib/reader.go b/libgo/go/compress/zlib/reader.go
new file mode 100644
index 000000000..721f6ec55
--- /dev/null
+++ b/libgo/go/compress/zlib/reader.go
@@ -0,0 +1,112 @@
+// 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.
+
+/*
+The zlib package implements reading and writing of zlib
+format compressed data, as specified in RFC 1950.
+
+The implementation provides filters that uncompress during reading
+and compress during writing. For example, to write compressed data
+to a buffer:
+
+ var b bytes.Buffer
+ w, err := zlib.NewWriter(&b)
+ w.Write([]byte("hello, world\n"))
+ w.Close()
+
+and to read that data back:
+
+ r, err := zlib.NewReader(&b)
+ io.Copy(os.Stdout, r)
+ r.Close()
+*/
+package zlib
+
+import (
+ "bufio"
+ "compress/flate"
+ "hash"
+ "hash/adler32"
+ "io"
+ "os"
+)
+
+const zlibDeflate = 8
+
+var ChecksumError os.Error = os.ErrorString("zlib checksum error")
+var HeaderError os.Error = os.ErrorString("invalid zlib header")
+var UnsupportedError os.Error = os.ErrorString("unsupported zlib format")
+
+type reader struct {
+ r flate.Reader
+ decompressor io.ReadCloser
+ digest hash.Hash32
+ err os.Error
+ scratch [4]byte
+}
+
+// NewReader creates a new io.ReadCloser that satisfies reads by decompressing data read from r.
+// The implementation buffers input and may read more data than necessary from r.
+// It is the caller's responsibility to call Close on the ReadCloser when done.
+func NewReader(r io.Reader) (io.ReadCloser, os.Error) {
+ z := new(reader)
+ if fr, ok := r.(flate.Reader); ok {
+ z.r = fr
+ } else {
+ z.r = bufio.NewReader(r)
+ }
+ _, err := io.ReadFull(z.r, z.scratch[0:2])
+ if err != nil {
+ return nil, err
+ }
+ h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
+ if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
+ return nil, HeaderError
+ }
+ if z.scratch[1]&0x20 != 0 {
+ // BUG(nigeltao): The zlib package does not implement the FDICT flag.
+ return nil, UnsupportedError
+ }
+ z.digest = adler32.New()
+ z.decompressor = flate.NewReader(z.r)
+ return z, nil
+}
+
+func (z *reader) Read(p []byte) (n int, err os.Error) {
+ if z.err != nil {
+ return 0, z.err
+ }
+ if len(p) == 0 {
+ return 0, nil
+ }
+
+ n, err = z.decompressor.Read(p)
+ z.digest.Write(p[0:n])
+ if n != 0 || err != os.EOF {
+ z.err = err
+ return
+ }
+
+ // Finished file; check checksum.
+ if _, err := io.ReadFull(z.r, z.scratch[0:4]); err != nil {
+ z.err = err
+ return 0, err
+ }
+ // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
+ checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
+ if checksum != z.digest.Sum32() {
+ z.err = ChecksumError
+ return 0, z.err
+ }
+ return
+}
+
+// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
+func (z *reader) Close() os.Error {
+ if z.err != nil {
+ return z.err
+ }
+ z.err = z.decompressor.Close()
+ return z.err
+}
diff --git a/libgo/go/compress/zlib/reader_test.go b/libgo/go/compress/zlib/reader_test.go
new file mode 100644
index 000000000..eaefc3a36
--- /dev/null
+++ b/libgo/go/compress/zlib/reader_test.go
@@ -0,0 +1,95 @@
+// 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 zlib
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "testing"
+)
+
+type zlibTest struct {
+ desc string
+ raw string
+ compressed []byte
+ err os.Error
+}
+
+// Compare-to-golden test data was generated by the ZLIB example program at
+// http://www.zlib.net/zpipe.c
+
+var zlibTests = []zlibTest{
+ {
+ "empty",
+ "",
+ []byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01},
+ nil,
+ },
+ {
+ "goodbye",
+ "goodbye, world",
+ []byte{
+ 0x78, 0x9c, 0x4b, 0xcf, 0xcf, 0x4f, 0x49, 0xaa,
+ 0x4c, 0xd5, 0x51, 0x28, 0xcf, 0x2f, 0xca, 0x49,
+ 0x01, 0x00, 0x28, 0xa5, 0x05, 0x5e,
+ },
+ nil,
+ },
+ {
+ "bad header",
+ "",
+ []byte{0x78, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01},
+ HeaderError,
+ },
+ {
+ "bad checksum",
+ "",
+ []byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff},
+ ChecksumError,
+ },
+ {
+ "not enough data",
+ "",
+ []byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00},
+ io.ErrUnexpectedEOF,
+ },
+ {
+ "excess data is silently ignored",
+ "",
+ []byte{
+ 0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x78, 0x9c, 0xff,
+ },
+ nil,
+ },
+}
+
+func TestDecompressor(t *testing.T) {
+ b := new(bytes.Buffer)
+ for _, tt := range zlibTests {
+ in := bytes.NewBuffer(tt.compressed)
+ zlib, err := NewReader(in)
+ if err != nil {
+ if err != tt.err {
+ t.Errorf("%s: NewReader: %s", tt.desc, err)
+ }
+ continue
+ }
+ defer zlib.Close()
+ b.Reset()
+ n, err := io.Copy(b, zlib)
+ if err != nil {
+ if err != tt.err {
+ t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
+ }
+ continue
+ }
+ s := b.String()
+ if s != tt.raw {
+ t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
+ }
+ }
+}
diff --git a/libgo/go/compress/zlib/testdata/e.txt b/libgo/go/compress/zlib/testdata/e.txt
new file mode 100644
index 000000000..76cf2a7b6
--- /dev/null
+++ b/libgo/go/compress/zlib/testdata/e.txt
@@ -0,0 +1 @@
+2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274663919320030599218174135966290435729003342952605956307381323286279434907632338298807531952510190115738341879307021540891499348841675092447614606680822648001684774118537423454424371075390777449920695517027618386062613313845830007520449338265602976067371132007093287091274437470472306969772093101416928368190255151086574637721112523897844250569536967707854499699679468644549059879316368892300987931277361782154249992295763514822082698951936680331825288693984964651058209392398294887933203625094431173012381970684161403970198376793206832823764648042953118023287825098194558153017567173613320698112509961818815930416903515988885193458072738667385894228792284998920868058257492796104841984443634632449684875602336248270419786232090021609902353043699418491463140934317381436405462531520961836908887070167683964243781405927145635490613031072085103837505101157477041718986106873969655212671546889570350354021234078498193343210681701210056278802351930332247450158539047304199577770935036604169973297250886876966403555707162268447162560798826517871341951246652010305921236677194325278675398558944896970964097545918569563802363701621120477427228364896134225164450781824423529486363721417402388934412479635743702637552944483379980161254922785092577825620926226483262779333865664816277251640191059004916449982893150566047258027786318641551956532442586982946959308019152987211725563475463964479101459040905862984967912874068705048958586717479854667757573205681288459205413340539220001137863009455606881667400169842055804033637953764520304024322566135278369511778838638744396625322498506549958862342818997077332761717839280349465014345588970719425863987727547109629537415211151368350627526023264847287039207643100595841166120545297030236472549296669381151373227536450988890313602057248176585118063036442812314965507047510254465011727211555194866850800368532281831521960037356252794495158284188294787610852639813955990067376482922443752871846245780361929819713991475644882626039033814418232625150974827987779964373089970388867782271383605772978824125611907176639465070633045279546618550966661856647097113444740160704626215680717481877844371436988218559670959102596862002353718588748569652200050311734392073211390803293634479727355955277349071783793421637012050054513263835440001863239914907054797780566978533580489669062951194324730995876552368128590413832411607226029983305353708761389396391779574540161372236187893652605381558415871869255386061647798340254351284396129460352913325942794904337299085731580290958631382683291477116396337092400316894586360606458459251269946557248391865642097526850823075442545993769170419777800853627309417101634349076964237222943523661255725088147792231519747780605696725380171807763603462459278778465850656050780844211529697521890874019660906651803516501792504619501366585436632712549639908549144200014574760819302212066024330096412704894390397177195180699086998606636583232278709376502260149291011517177635944602023249300280401867723910288097866605651183260043688508817157238669842242201024950551881694803221002515426494639812873677658927688163598312477886520141174110913601164995076629077943646005851941998560162647907615321038727557126992518275687989302761761146162549356495903798045838182323368612016243736569846703785853305275833337939907521660692380533698879565137285593883499894707416181550125397064648171946708348197214488898790676503795903669672494992545279033729636162658976039498576741397359441023744329709355477982629614591442936451428617158587339746791897571211956187385783644758448423555581050025611492391518893099463428413936080383091662818811503715284967059741625628236092168075150177725387402564253470879089137291722828611515915683725241630772254406337875931059826760944203261924285317018781772960235413060672136046000389661093647095141417185777014180606443636815464440053316087783143174440811949422975599314011888683314832802706553833004693290115744147563139997221703804617092894579096271662260740718749975359212756084414737823303270330168237193648002173285734935947564334129943024850235732214597843282641421684878721673367010615094243456984401873312810107945127223737886126058165668053714396127888732527373890392890506865324138062796025930387727697783792868409325365880733988457218746021005311483351323850047827169376218004904795597959290591655470505777514308175112698985188408718564026035305583737832422924185625644255022672155980274012617971928047139600689163828665277009752767069777036439260224372841840883251848770472638440379530166905465937461619323840363893131364327137688841026811219891275223056256756254701725086349765367288605966752740868627407912856576996313789753034660616669804218267724560530660773899624218340859882071864682623215080288286359746839654358856685503773131296587975810501214916207656769950659715344763470320853215603674828608378656803073062657633469774295634643716709397193060876963495328846833613038829431040800296873869117066666146800015121143442256023874474325250769387077775193299942137277211258843608715834835626961661980572526612206797540621062080649882918454395301529982092503005498257043390553570168653120526495614857249257386206917403695213533732531666345466588597286659451136441370331393672118569553952108458407244323835586063106806964924851232632699514603596037297253198368423363904632136710116192821711150282801604488058802382031981493096369596735832742024988245684941273860566491352526706046234450549227581151709314921879592718001940968866986837037302200475314338181092708030017205935530520700706072233999463990571311587099635777359027196285061146514837526209565346713290025994397663114545902685898979115837093419370441155121920117164880566945938131183843765620627846310490346293950029458341164824114969758326011800731699437393506966295712410273239138741754923071862454543222039552735295240245903805744502892246886285336542213815722131163288112052146489805180092024719391710555390113943316681515828843687606961102505171007392762385553386272553538830960671644662370922646809671254061869502143176211668140097595281493907222601112681153108387317617323235263605838173151034595736538223534992935822836851007810884634349983518404451704270189381994243410090575376257767571118090088164183319201962623416288166521374717325477727783488774366518828752156685719506371936565390389449366421764003121527870222366463635755503565576948886549500270853923617105502131147413744106134445544192101336172996285694899193369184729478580729156088510396781959429833186480756083679551496636448965592948187851784038773326247051945050419847742014183947731202815886845707290544057510601285258056594703046836344592652552137008068752009593453607316226118728173928074623094685367823106097921599360019946237993434210687813497346959246469752506246958616909178573976595199392993995567542714654910456860702099012606818704984178079173924071945996323060254707901774527513186809982284730860766536866855516467702911336827563107223346726113705490795365834538637196235856312618387156774118738527722922594743373785695538456246801013905727871016512966636764451872465653730402443684140814488732957847348490003019477888020460324660842875351848364959195082888323206522128104190448047247949291342284951970022601310430062410717971502793433263407995960531446053230488528972917659876016667811937932372453857209607582277178483361613582612896226118129455927462767137794487586753657544861407611931125958512655759734573015333642630767985443385761715333462325270572005303988289499034259566232975782488735029259166825894456894655992658454762694528780516501720674785417887982276806536650641910973434528878338621726156269582654478205672987756426325321594294418039943217000090542650763095588465895171709147607437136893319469090981904501290307099566226620303182649365733698419555776963787624918852865686607600566025605445711337286840205574416030837052312242587223438854123179481388550075689381124935386318635287083799845692619981794523364087429591180747453419551420351726184200845509170845682368200897739455842679214273477560879644279202708312150156406341341617166448069815483764491573900121217041547872591998943825364950514771379399147205219529079396137621107238494290616357604596231253506068537651423115349665683715116604220796394466621163255157729070978473156278277598788136491951257483328793771571459091064841642678309949723674420175862269402159407924480541255360431317992696739157542419296607312393763542139230617876753958711436104089409966089471418340698362993675362621545247298464213752891079884381306095552622720837518629837066787224430195793793786072107254277289071732854874374355781966511716618330881129120245204048682200072344035025448202834254187884653602591506445271657700044521097735585897622655484941621714989532383421600114062950718490427789258552743035221396835679018076406042138307308774460170842688272261177180842664333651780002171903449234264266292261456004337383868335555343453004264818473989215627086095650629340405264943244261445665921291225648893569655009154306426134252668472594914314239398845432486327461842846655985332312210466259890141712103446084271616619001257195870793217569698544013397622096749454185407118446433946990162698351607848924514058940946395267807354579700307051163682519487701189764002827648414160587206184185297189154019688253289309149665345753571427318482016384644832499037886069008072709327673127581966563941148961716832980455139729506687604740915420428429993541025829113502241690769431668574242522509026939034814856451303069925199590436384028429267412573422447765584177886171737265462085498294498946787350929581652632072258992368768457017823038096567883112289305809140572610865884845873101658151167533327674887014829167419701512559782572707406431808601428149024146780472327597684269633935773542930186739439716388611764209004068663398856841681003872389214483176070116684503887212364367043314091155733280182977988736590916659612402021778558854876176161989370794380056663364884365089144805571039765214696027662583599051987042300179465536788
diff --git a/libgo/go/compress/zlib/testdata/pi.txt b/libgo/go/compress/zlib/testdata/pi.txt
new file mode 100644
index 000000000..58d8f3b6d
--- /dev/null
+++ b/libgo/go/compress/zlib/testdata/pi.txt
@@ -0,0 +1 @@
+3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275900994657640789512694683983525957098258226205224894077267194782684826014769909026401363944374553050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382686838689427741559918559252459539594310499725246808459872736446958486538367362226260991246080512438843904512441365497627807977156914359977001296160894416948685558484063534220722258284886481584560285060168427394522674676788952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288797108931456691368672287489405601015033086179286809208747609178249385890097149096759852613655497818931297848216829989487226588048575640142704775551323796414515237462343645428584447952658678210511413547357395231134271661021359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435064302184531910484810053706146806749192781911979399520614196634287544406437451237181921799983910159195618146751426912397489409071864942319615679452080951465502252316038819301420937621378559566389377870830390697920773467221825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539057962685610055081066587969981635747363840525714591028970641401109712062804390397595156771577004203378699360072305587631763594218731251471205329281918261861258673215791984148488291644706095752706957220917567116722910981690915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398315019701651511685171437657618351556508849099898599823873455283316355076479185358932261854896321329330898570642046752590709154814165498594616371802709819943099244889575712828905923233260972997120844335732654893823911932597463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100449293215160842444859637669838952286847831235526582131449576857262433441893039686426243410773226978028073189154411010446823252716201052652272111660396665573092547110557853763466820653109896526918620564769312570586356620185581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318586769751456614068007002378776591344017127494704205622305389945613140711270004078547332699390814546646458807972708266830634328587856983052358089330657574067954571637752542021149557615814002501262285941302164715509792592309907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111790429782856475032031986915140287080859904801094121472213179476477726224142548545403321571853061422881375850430633217518297986622371721591607716692547487389866549494501146540628433663937900397692656721463853067360965712091807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862947265473642523081770367515906735023507283540567040386743513622224771589150495309844489333096340878076932599397805419341447377441842631298608099888687413260472156951623965864573021631598193195167353812974167729478672422924654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001593776471651228935786015881617557829735233446042815126272037343146531977774160319906655418763979293344195215413418994854447345673831624993419131814809277771038638773431772075456545322077709212019051660962804909263601975988281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267945612753181340783303362542327839449753824372058353114771199260638133467768796959703098339130771098704085913374641442822772634659470474587847787201927715280731767907707157213444730605700733492436931138350493163128404251219256517980694113528013147013047816437885185290928545201165839341965621349143415956258658655705526904965209858033850722426482939728584783163057777560688876446248246857926039535277348030480290058760758251047470916439613626760449256274204208320856611906254543372131535958450687724602901618766795240616342522577195429162991930645537799140373404328752628889639958794757291746426357455254079091451357111369410911939325191076020825202618798531887705842972591677813149699009019211697173727847684726860849003377024242916513005005168323364350389517029893922334517220138128069650117844087451960121228599371623130171144484640903890644954440061986907548516026327505298349187407866808818338510228334508504860825039302133219715518430635455007668282949304137765527939751754613953984683393638304746119966538581538420568533862186725233402830871123282789212507712629463229563989898935821167456270102183564622013496715188190973038119800497340723961036854066431939509790190699639552453005450580685501956730229219139339185680344903982059551002263535361920419947455385938102343955449597783779023742161727111723643435439478221818528624085140066604433258885698670543154706965747458550332323342107301545940516553790686627333799585115625784322988273723198987571415957811196358330059408730681216028764962867446047746491599505497374256269010490377819868359381465741268049256487985561453723478673303904688383436346553794986419270563872931748723320837601123029911367938627089438799362016295154133714248928307220126901475466847653576164773794675200490757155527819653621323926406160136358155907422020203187277605277219005561484255518792530343513984425322341576233610642506390497500865627109535919465897514131034822769306247435363256916078154781811528436679570611086153315044521274739245449454236828860613408414863776700961207151249140430272538607648236341433462351897576645216413767969031495019108575984423919862916421939949072362346468441173940326591840443780513338945257423995082965912285085558215725031071257012668302402929525220118726767562204154205161841634847565169998116141010029960783869092916030288400269104140792886215078424516709087000699282120660418371806535567252532567532861291042487761825829765157959847035622262934860034158722980534989650226291748788202734209222245339856264766914905562842503912757710284027998066365825488926488025456610172967026640765590429099456815065265305371829412703369313785178609040708667114965583434347693385781711386455873678123014587687126603489139095620099393610310291616152881384379099042317473363948045759314931405297634757481193567091101377517210080315590248530906692037671922033229094334676851422144773793937517034436619910403375111735471918550464490263655128162288244625759163330391072253837421821408835086573917715096828874782656995995744906617583441375223970968340800535598491754173818839994469748676265516582765848358845314277568790029095170283529716344562129640435231176006651012412006597558512761785838292041974844236080071930457618932349229279650198751872127267507981255470958904556357921221033346697499235630254947802490114195212382815309114079073860251522742995818072471625916685451333123948049470791191532673430282441860414263639548000448002670496248201792896476697583183271314251702969234889627668440323260927524960357996469256504936818360900323809293459588970695365349406034021665443755890045632882250545255640564482465151875471196218443965825337543885690941130315095261793780029741207665147939425902989695946995565761218656196733786236256125216320862869222103274889218654364802296780705765615144632046927906821207388377814233562823608963208068222468012248261177185896381409183903673672220888321513755600372798394004152970028783076670944474560134556417254370906979396122571429894671543578468788614445812314593571984922528471605049221242470141214780573455105008019086996033027634787081081754501193071412233908663938339529425786905076431006383519834389341596131854347546495569781038293097164651438407007073604112373599843452251610507027056235266012764848308407611830130527932054274628654036036745328651057065874882256981579367897669742205750596834408697350201410206723585020072452256326513410559240190274216248439140359989535394590944070469120914093870012645600162374288021092764579310657922955249887275846101264836999892256959688159205600101655256375678
diff --git a/libgo/go/compress/zlib/writer.go b/libgo/go/compress/zlib/writer.go
new file mode 100644
index 000000000..031586cd2
--- /dev/null
+++ b/libgo/go/compress/zlib/writer.go
@@ -0,0 +1,106 @@
+// 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 zlib
+
+import (
+ "compress/flate"
+ "hash"
+ "hash/adler32"
+ "io"
+ "os"
+)
+
+// These constants are copied from the flate package, so that code that imports
+// "compress/zlib" does not also have to import "compress/flate".
+const (
+ NoCompression = flate.NoCompression
+ BestSpeed = flate.BestSpeed
+ BestCompression = flate.BestCompression
+ DefaultCompression = flate.DefaultCompression
+)
+
+type writer struct {
+ w io.Writer
+ compressor io.WriteCloser
+ digest hash.Hash32
+ err os.Error
+ scratch [4]byte
+}
+
+// NewWriter calls NewWriterLevel with the default compression level.
+func NewWriter(w io.Writer) (io.WriteCloser, os.Error) {
+ return NewWriterLevel(w, DefaultCompression)
+}
+
+// NewWriterLevel creates a new io.WriteCloser that satisfies writes by compressing data written to w.
+// It is the caller's responsibility to call Close on the WriteCloser when done.
+// level is the compression level, which can be DefaultCompression, NoCompression,
+// or any integer value between BestSpeed and BestCompression (inclusive).
+func NewWriterLevel(w io.Writer, level int) (io.WriteCloser, os.Error) {
+ z := new(writer)
+ // ZLIB has a two-byte header (as documented in RFC 1950).
+ // The first four bits is the CINFO (compression info), which is 7 for the default deflate window size.
+ // The next four bits is the CM (compression method), which is 8 for deflate.
+ z.scratch[0] = 0x78
+ // The next two bits is the FLEVEL (compression level). The four values are:
+ // 0=fastest, 1=fast, 2=default, 3=best.
+ // The next bit, FDICT, is unused, in this implementation.
+ // The final five FCHECK bits form a mod-31 checksum.
+ switch level {
+ case 0, 1:
+ z.scratch[1] = 0x01
+ case 2, 3, 4, 5:
+ z.scratch[1] = 0x5e
+ case 6, -1:
+ z.scratch[1] = 0x9c
+ case 7, 8, 9:
+ z.scratch[1] = 0xda
+ default:
+ return nil, os.NewError("level out of range")
+ }
+ _, err := w.Write(z.scratch[0:2])
+ if err != nil {
+ return nil, err
+ }
+ z.w = w
+ z.compressor = flate.NewWriter(w, level)
+ z.digest = adler32.New()
+ return z, nil
+}
+
+func (z *writer) Write(p []byte) (n int, err os.Error) {
+ if z.err != nil {
+ return 0, z.err
+ }
+ if len(p) == 0 {
+ return 0, nil
+ }
+ n, err = z.compressor.Write(p)
+ if err != nil {
+ z.err = err
+ return
+ }
+ z.digest.Write(p)
+ return
+}
+
+// Calling Close does not close the wrapped io.Writer originally passed to NewWriter.
+func (z *writer) Close() os.Error {
+ if z.err != nil {
+ return z.err
+ }
+ z.err = z.compressor.Close()
+ if z.err != nil {
+ return z.err
+ }
+ checksum := z.digest.Sum32()
+ // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
+ z.scratch[0] = uint8(checksum >> 24)
+ z.scratch[1] = uint8(checksum >> 16)
+ z.scratch[2] = uint8(checksum >> 8)
+ z.scratch[3] = uint8(checksum >> 0)
+ _, z.err = z.w.Write(z.scratch[0:4])
+ return z.err
+}
diff --git a/libgo/go/compress/zlib/writer_test.go b/libgo/go/compress/zlib/writer_test.go
new file mode 100644
index 000000000..fa9e78e8e
--- /dev/null
+++ b/libgo/go/compress/zlib/writer_test.go
@@ -0,0 +1,106 @@
+// 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 zlib
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+var filenames = []string{
+ "testdata/e.txt",
+ "testdata/pi.txt",
+}
+
+// Tests that compressing and then decompressing the given file at the given compression level
+// yields equivalent bytes to the original file.
+func testFileLevel(t *testing.T, fn string, level int) {
+ // Read the file, as golden output.
+ golden, err := os.Open(fn, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Errorf("%s (level=%d): %v", fn, level, err)
+ return
+ }
+ defer golden.Close()
+
+ // Read the file again, and push it through a pipe that compresses at the write end, and decompresses at the read end.
+ raw, err := os.Open(fn, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Errorf("%s (level=%d): %v", fn, level, err)
+ return
+ }
+ piper, pipew := io.Pipe()
+ defer piper.Close()
+ go func() {
+ defer raw.Close()
+ defer pipew.Close()
+ zlibw, err := NewWriterLevel(pipew, level)
+ if err != nil {
+ t.Errorf("%s (level=%d): %v", fn, level, err)
+ return
+ }
+ defer zlibw.Close()
+ var b [1024]byte
+ for {
+ n, err0 := raw.Read(b[0:])
+ if err0 != nil && err0 != os.EOF {
+ t.Errorf("%s (level=%d): %v", fn, level, err0)
+ return
+ }
+ _, err1 := zlibw.Write(b[0:n])
+ if err1 == os.EPIPE {
+ // Fail, but do not report the error, as some other (presumably reportable) error broke the pipe.
+ return
+ }
+ if err1 != nil {
+ t.Errorf("%s (level=%d): %v", fn, level, err1)
+ return
+ }
+ if err0 == os.EOF {
+ break
+ }
+ }
+ }()
+ zlibr, err := NewReader(piper)
+ if err != nil {
+ t.Errorf("%s (level=%d): %v", fn, level, err)
+ return
+ }
+ defer zlibr.Close()
+
+ // Compare the two.
+ b0, err0 := ioutil.ReadAll(golden)
+ b1, err1 := ioutil.ReadAll(zlibr)
+ if err0 != nil {
+ t.Errorf("%s (level=%d): %v", fn, level, err0)
+ return
+ }
+ if err1 != nil {
+ t.Errorf("%s (level=%d): %v", fn, level, err1)
+ return
+ }
+ if len(b0) != len(b1) {
+ t.Errorf("%s (level=%d): length mismatch %d versus %d", fn, level, len(b0), len(b1))
+ return
+ }
+ for i := 0; i < len(b0); i++ {
+ if b0[i] != b1[i] {
+ t.Errorf("%s (level=%d): mismatch at %d, 0x%02x versus 0x%02x\n", fn, level, i, b0[i], b1[i])
+ return
+ }
+ }
+}
+
+func TestWriter(t *testing.T) {
+ for _, fn := range filenames {
+ testFileLevel(t, fn, DefaultCompression)
+ testFileLevel(t, fn, NoCompression)
+ for level := BestSpeed; level <= BestCompression; level++ {
+ testFileLevel(t, fn, level)
+ }
+ }
+}
diff --git a/libgo/go/container/heap/heap.go b/libgo/go/container/heap/heap.go
new file mode 100644
index 000000000..4435a57c4
--- /dev/null
+++ b/libgo/go/container/heap/heap.go
@@ -0,0 +1,102 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package provides heap operations for any type that implements
+// heap.Interface.
+//
+package heap
+
+import "sort"
+
+// Any type that implements heap.Interface may be used as a
+// min-heap with the following invariants (established after
+// Init has been called):
+//
+// !h.Less(j, i) for 0 <= i < h.Len() and j = 2*i+1 or 2*i+2 and j < h.Len()
+//
+type Interface interface {
+ sort.Interface
+ Push(x interface{})
+ Pop() interface{}
+}
+
+
+// A heaper must be initialized before any of the heap operations
+// can be used. Init is idempotent with respect to the heap invariants
+// and may be called whenever the heap invariants may have been invalidated.
+// Its complexity is O(n) where n = h.Len().
+//
+func Init(h Interface) {
+ // heapify
+ n := h.Len()
+ for i := n/2 - 1; i >= 0; i-- {
+ down(h, i, n)
+ }
+}
+
+
+// Push pushes the element x onto the heap. The complexity is
+// O(log(n)) where n = h.Len().
+//
+func Push(h Interface, x interface{}) {
+ h.Push(x)
+ up(h, h.Len()-1)
+}
+
+
+// Pop removes the minimum element (according to Less) from the heap
+// and returns it. The complexity is O(log(n)) where n = h.Len().
+// Same as Remove(h, 0).
+//
+func Pop(h Interface) interface{} {
+ n := h.Len() - 1
+ h.Swap(0, n)
+ down(h, 0, n)
+ return h.Pop()
+}
+
+
+// Remove removes the element at index i from the heap.
+// The complexity is O(log(n)) where n = h.Len().
+//
+func Remove(h Interface, i int) interface{} {
+ n := h.Len() - 1
+ if n != i {
+ h.Swap(i, n)
+ down(h, i, n)
+ up(h, i)
+ }
+ return h.Pop()
+}
+
+
+func up(h Interface, j int) {
+ for {
+ i := (j - 1) / 2 // parent
+ if i == j || h.Less(i, j) {
+ break
+ }
+ h.Swap(i, j)
+ j = i
+ }
+}
+
+
+func down(h Interface, i, n int) {
+ for {
+ j1 := 2*i + 1
+ if j1 >= n {
+ break
+ }
+ j := j1 // left child
+ if j2 := j1 + 1; j2 < n && !h.Less(j1, j2) {
+ j = j2 // = 2*i + 2 // right child
+ }
+ if h.Less(i, j) {
+ break
+ }
+ h.Swap(i, j)
+ i = j
+ }
+}
diff --git a/libgo/go/container/heap/heap_test.go b/libgo/go/container/heap/heap_test.go
new file mode 100644
index 000000000..89d444dd5
--- /dev/null
+++ b/libgo/go/container/heap/heap_test.go
@@ -0,0 +1,166 @@
+// 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 heap
+
+import (
+ "testing"
+ "container/vector"
+)
+
+
+type myHeap struct {
+ // A vector.Vector implements sort.Interface except for Less,
+ // and it implements Push and Pop as required for heap.Interface.
+ vector.Vector
+}
+
+
+func (h *myHeap) Less(i, j int) bool { return h.At(i).(int) < h.At(j).(int) }
+
+
+func (h *myHeap) verify(t *testing.T, i int) {
+ n := h.Len()
+ j1 := 2*i + 1
+ j2 := 2*i + 2
+ if j1 < n {
+ if h.Less(j1, i) {
+ t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h.At(i), j1, h.At(j1))
+ return
+ }
+ h.verify(t, j1)
+ }
+ if j2 < n {
+ if h.Less(j2, i) {
+ t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h.At(i), j1, h.At(j2))
+ return
+ }
+ h.verify(t, j2)
+ }
+}
+
+
+func TestInit0(t *testing.T) {
+ h := new(myHeap)
+ for i := 20; i > 0; i-- {
+ h.Push(0) // all elements are the same
+ }
+ Init(h)
+ h.verify(t, 0)
+
+ for i := 1; h.Len() > 0; i++ {
+ x := Pop(h).(int)
+ h.verify(t, 0)
+ if x != 0 {
+ t.Errorf("%d.th pop got %d; want %d", i, x, 0)
+ }
+ }
+}
+
+
+func TestInit1(t *testing.T) {
+ h := new(myHeap)
+ for i := 20; i > 0; i-- {
+ h.Push(i) // all elements are different
+ }
+ Init(h)
+ h.verify(t, 0)
+
+ for i := 1; h.Len() > 0; i++ {
+ x := Pop(h).(int)
+ h.verify(t, 0)
+ if x != i {
+ t.Errorf("%d.th pop got %d; want %d", i, x, i)
+ }
+ }
+}
+
+
+func Test(t *testing.T) {
+ h := new(myHeap)
+ h.verify(t, 0)
+
+ for i := 20; i > 10; i-- {
+ h.Push(i)
+ }
+ Init(h)
+ h.verify(t, 0)
+
+ for i := 10; i > 0; i-- {
+ Push(h, i)
+ h.verify(t, 0)
+ }
+
+ for i := 1; h.Len() > 0; i++ {
+ x := Pop(h).(int)
+ if i < 20 {
+ Push(h, 20+i)
+ }
+ h.verify(t, 0)
+ if x != i {
+ t.Errorf("%d.th pop got %d; want %d", i, x, i)
+ }
+ }
+}
+
+
+func TestRemove0(t *testing.T) {
+ h := new(myHeap)
+ for i := 0; i < 10; i++ {
+ h.Push(i)
+ }
+ h.verify(t, 0)
+
+ for h.Len() > 0 {
+ i := h.Len() - 1
+ x := Remove(h, i).(int)
+ if x != i {
+ t.Errorf("Remove(%d) got %d; want %d", i, x, i)
+ }
+ h.verify(t, 0)
+ }
+}
+
+
+func TestRemove1(t *testing.T) {
+ h := new(myHeap)
+ for i := 0; i < 10; i++ {
+ h.Push(i)
+ }
+ h.verify(t, 0)
+
+ for i := 0; h.Len() > 0; i++ {
+ x := Remove(h, 0).(int)
+ if x != i {
+ t.Errorf("Remove(0) got %d; want %d", x, i)
+ }
+ h.verify(t, 0)
+ }
+}
+
+
+func TestRemove2(t *testing.T) {
+ N := 10
+
+ h := new(myHeap)
+ for i := 0; i < N; i++ {
+ h.Push(i)
+ }
+ h.verify(t, 0)
+
+ m := make(map[int]bool)
+ for h.Len() > 0 {
+ m[Remove(h, (h.Len()-1)/2).(int)] = true
+ h.verify(t, 0)
+ }
+
+ if len(m) != N {
+ t.Errorf("len(m) = %d; want %d", len(m), N)
+ }
+ for i := 0; i < len(m); i++ {
+ if !m[i] {
+ t.Errorf("m[%d] doesn't exist", i)
+ }
+ }
+}
diff --git a/libgo/go/container/list/list.go b/libgo/go/container/list/list.go
new file mode 100755
index 000000000..c1ebcddaa
--- /dev/null
+++ b/libgo/go/container/list/list.go
@@ -0,0 +1,211 @@
+// 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.
+
+// The list package implements a doubly linked list.
+//
+// To iterate over a list (where l is a *List):
+// for e := l.Front(); e != nil; e = e.Next() {
+// // do something with e.Value
+// }
+//
+package list
+
+// Element is an element in the linked list.
+type Element struct {
+ // Next and previous pointers in the doubly-linked list of elements.
+ // The front of the list has prev = nil, and the back has next = nil.
+ next, prev *Element
+
+ // The list to which this element belongs.
+ list *List
+
+ // The contents of this list element.
+ Value interface{}
+}
+
+// Next returns the next list element or nil.
+func (e *Element) Next() *Element { return e.next }
+
+// Prev returns the previous list element or nil.
+func (e *Element) Prev() *Element { return e.prev }
+
+// List represents a doubly linked list.
+// The zero value for List is an empty list ready to use.
+type List struct {
+ front, back *Element
+ len int
+}
+
+// Init initializes or clears a List.
+func (l *List) Init() *List {
+ l.front = nil
+ l.back = nil
+ l.len = 0
+ return l
+}
+
+// New returns an initialized list.
+func New() *List { return new(List) }
+
+// Front returns the first element in the list.
+func (l *List) Front() *Element { return l.front }
+
+// Back returns the last element in the list.
+func (l *List) Back() *Element { return l.back }
+
+// Remove removes the element from the list
+// and returns its Value.
+func (l *List) Remove(e *Element) interface{} {
+ l.remove(e)
+ e.list = nil // do what remove does not
+ return e.Value
+}
+
+// remove the element from the list, but do not clear the Element's list field.
+// This is so that other List methods may use remove when relocating Elements
+// without needing to restore the list field.
+func (l *List) remove(e *Element) {
+ if e.list != l {
+ return
+ }
+ if e.prev == nil {
+ l.front = e.next
+ } else {
+ e.prev.next = e.next
+ }
+ if e.next == nil {
+ l.back = e.prev
+ } else {
+ e.next.prev = e.prev
+ }
+
+ e.prev = nil
+ e.next = nil
+ l.len--
+}
+
+func (l *List) insertBefore(e *Element, mark *Element) {
+ if mark.prev == nil {
+ // new front of the list
+ l.front = e
+ } else {
+ mark.prev.next = e
+ }
+ e.prev = mark.prev
+ mark.prev = e
+ e.next = mark
+ l.len++
+}
+
+func (l *List) insertAfter(e *Element, mark *Element) {
+ if mark.next == nil {
+ // new back of the list
+ l.back = e
+ } else {
+ mark.next.prev = e
+ }
+ e.next = mark.next
+ mark.next = e
+ e.prev = mark
+ l.len++
+}
+
+func (l *List) insertFront(e *Element) {
+ if l.front == nil {
+ // empty list
+ l.front, l.back = e, e
+ e.prev, e.next = nil, nil
+ l.len = 1
+ return
+ }
+ l.insertBefore(e, l.front)
+}
+
+func (l *List) insertBack(e *Element) {
+ if l.back == nil {
+ // empty list
+ l.front, l.back = e, e
+ e.prev, e.next = nil, nil
+ l.len = 1
+ return
+ }
+ l.insertAfter(e, l.back)
+}
+
+// PushFront inserts the value at the front of the list and returns a new Element containing the value.
+func (l *List) PushFront(value interface{}) *Element {
+ e := &Element{nil, nil, l, value}
+ l.insertFront(e)
+ return e
+}
+
+// PushBack inserts the value at the back of the list and returns a new Element containing the value.
+func (l *List) PushBack(value interface{}) *Element {
+ e := &Element{nil, nil, l, value}
+ l.insertBack(e)
+ return e
+}
+
+// InsertBefore inserts the value immediately before mark and returns a new Element containing the value.
+func (l *List) InsertBefore(value interface{}, mark *Element) *Element {
+ if mark.list != l {
+ return nil
+ }
+ e := &Element{nil, nil, l, value}
+ l.insertBefore(e, mark)
+ return e
+}
+
+// InsertAfter inserts the value immediately after mark and returns a new Element containing the value.
+func (l *List) InsertAfter(value interface{}, mark *Element) *Element {
+ if mark.list != l {
+ return nil
+ }
+ e := &Element{nil, nil, l, value}
+ l.insertAfter(e, mark)
+ return e
+}
+
+// MoveToFront moves the element to the front of the list.
+func (l *List) MoveToFront(e *Element) {
+ if e.list != l || l.front == e {
+ return
+ }
+ l.remove(e)
+ l.insertFront(e)
+}
+
+// MoveToBack moves the element to the back of the list.
+func (l *List) MoveToBack(e *Element) {
+ if e.list != l || l.back == e {
+ return
+ }
+ l.remove(e)
+ l.insertBack(e)
+}
+
+// Len returns the number of elements in the list.
+func (l *List) Len() int { return l.len }
+
+// PushBackList inserts each element of ol at the back of the list.
+func (l *List) PushBackList(ol *List) {
+ last := ol.Back()
+ for e := ol.Front(); e != nil; e = e.Next() {
+ l.PushBack(e.Value)
+ if e == last {
+ break
+ }
+ }
+}
+
+// PushFrontList inserts each element of ol at the front of the list. The ordering of the passed list is preserved.
+func (l *List) PushFrontList(ol *List) {
+ first := ol.Front()
+ for e := ol.Back(); e != nil; e = e.Prev() {
+ l.PushFront(e.Value)
+ if e == first {
+ break
+ }
+ }
+}
diff --git a/libgo/go/container/list/list_test.go b/libgo/go/container/list/list_test.go
new file mode 100755
index 000000000..1d44ff84e
--- /dev/null
+++ b/libgo/go/container/list/list_test.go
@@ -0,0 +1,209 @@
+// 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 list
+
+import (
+ "testing"
+)
+
+func checkListPointers(t *testing.T, l *List, es []*Element) {
+ if len(es) == 0 {
+ if l.front != nil || l.back != nil {
+ t.Errorf("l.front/l.back = %v/%v should be nil/nil", l.front, l.back)
+ }
+ return
+ }
+
+ if l.front != es[0] {
+ t.Errorf("l.front = %v, want %v", l.front, es[0])
+ }
+ if last := es[len(es)-1]; l.back != last {
+ t.Errorf("l.back = %v, want %v", l.back, last)
+ }
+
+ for i, e := range es {
+ var e_prev, e_next *Element = nil, nil
+ if i > 0 {
+ e_prev = es[i-1]
+ }
+ if i < len(es)-1 {
+ e_next = es[i+1]
+ }
+ if e.prev != e_prev {
+ t.Errorf("elt #%d (%v) has prev=%v, want %v", i, e, e.prev, e_prev)
+ }
+ if e.next != e_next {
+ t.Errorf("elt #%d (%v) has next=%v, want %v", i, e, e.next, e_next)
+ }
+ }
+}
+
+func checkListLen(t *testing.T, l *List, n int) {
+ if an := l.Len(); an != n {
+ t.Errorf("l.Len() = %d, want %d", an, n)
+ }
+}
+
+func TestList(t *testing.T) {
+ l := New()
+ checkListPointers(t, l, []*Element{})
+ checkListLen(t, l, 0)
+
+ // Single element list
+ e := l.PushFront("a")
+ checkListLen(t, l, 1)
+ checkListPointers(t, l, []*Element{e})
+ l.MoveToFront(e)
+ checkListPointers(t, l, []*Element{e})
+ l.MoveToBack(e)
+ checkListPointers(t, l, []*Element{e})
+ checkListLen(t, l, 1)
+ l.Remove(e)
+ checkListPointers(t, l, []*Element{})
+ checkListLen(t, l, 0)
+
+ // Bigger list
+ e2 := l.PushFront(2)
+ e1 := l.PushFront(1)
+ e3 := l.PushBack(3)
+ e4 := l.PushBack("banana")
+ checkListPointers(t, l, []*Element{e1, e2, e3, e4})
+ checkListLen(t, l, 4)
+
+ l.Remove(e2)
+ checkListPointers(t, l, []*Element{e1, e3, e4})
+ checkListLen(t, l, 3)
+
+ l.MoveToFront(e3) // move from middle
+ checkListPointers(t, l, []*Element{e3, e1, e4})
+
+ l.MoveToFront(e1)
+ l.MoveToBack(e3) // move from middle
+ checkListPointers(t, l, []*Element{e1, e4, e3})
+
+ l.MoveToFront(e3) // move from back
+ checkListPointers(t, l, []*Element{e3, e1, e4})
+ l.MoveToFront(e3) // should be no-op
+ checkListPointers(t, l, []*Element{e3, e1, e4})
+
+ l.MoveToBack(e3) // move from front
+ checkListPointers(t, l, []*Element{e1, e4, e3})
+ l.MoveToBack(e3) // should be no-op
+ checkListPointers(t, l, []*Element{e1, e4, e3})
+
+ e2 = l.InsertBefore(2, e1) // insert before front
+ checkListPointers(t, l, []*Element{e2, e1, e4, e3})
+ l.Remove(e2)
+ e2 = l.InsertBefore(2, e4) // insert before middle
+ checkListPointers(t, l, []*Element{e1, e2, e4, e3})
+ l.Remove(e2)
+ e2 = l.InsertBefore(2, e3) // insert before back
+ checkListPointers(t, l, []*Element{e1, e4, e2, e3})
+ l.Remove(e2)
+
+ e2 = l.InsertAfter(2, e1) // insert after front
+ checkListPointers(t, l, []*Element{e1, e2, e4, e3})
+ l.Remove(e2)
+ e2 = l.InsertAfter(2, e4) // insert after middle
+ checkListPointers(t, l, []*Element{e1, e4, e2, e3})
+ l.Remove(e2)
+ e2 = l.InsertAfter(2, e3) // insert after back
+ checkListPointers(t, l, []*Element{e1, e4, e3, e2})
+ l.Remove(e2)
+
+ // Check standard iteration.
+ sum := 0
+ for e := l.Front(); e != nil; e = e.Next() {
+ if i, ok := e.Value.(int); ok {
+ sum += i
+ }
+ }
+ if sum != 4 {
+ t.Errorf("sum over l.Iter() = %d, want 4", sum)
+ }
+
+ // Clear all elements by iterating
+ var next *Element
+ for e := l.Front(); e != nil; e = next {
+ next = e.Next()
+ l.Remove(e)
+ }
+ checkListPointers(t, l, []*Element{})
+ checkListLen(t, l, 0)
+}
+
+func checkList(t *testing.T, l *List, es []interface{}) {
+ if l.Len() != len(es) {
+ t.Errorf("list has len=%v, want %v", l.Len(), len(es))
+ return
+ }
+ i := 0
+ for e := l.Front(); e != nil; e = e.Next() {
+ le := e.Value.(int)
+ if le != es[i] {
+ t.Errorf("elt #%d has value=%v, want %v", i, le, es[i])
+ }
+ i++
+ }
+}
+
+func TestExtending(t *testing.T) {
+ l1 := New()
+ l2 := New()
+
+ l1.PushBack(1)
+ l1.PushBack(2)
+ l1.PushBack(3)
+
+ l2.PushBack(4)
+ l2.PushBack(5)
+
+ l3 := New()
+ l3.PushBackList(l1)
+ checkList(t, l3, []interface{}{1, 2, 3})
+ l3.PushBackList(l2)
+ checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
+
+ l3 = New()
+ l3.PushFrontList(l2)
+ checkList(t, l3, []interface{}{4, 5})
+ l3.PushFrontList(l1)
+ checkList(t, l3, []interface{}{1, 2, 3, 4, 5})
+
+ checkList(t, l1, []interface{}{1, 2, 3})
+ checkList(t, l2, []interface{}{4, 5})
+
+ l3 = New()
+ l3.PushBackList(l1)
+ checkList(t, l3, []interface{}{1, 2, 3})
+ l3.PushBackList(l3)
+ checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+ l3 = New()
+ l3.PushFrontList(l1)
+ checkList(t, l3, []interface{}{1, 2, 3})
+ l3.PushFrontList(l3)
+ checkList(t, l3, []interface{}{1, 2, 3, 1, 2, 3})
+
+ l3 = New()
+ l1.PushBackList(l3)
+ checkList(t, l1, []interface{}{1, 2, 3})
+ l1.PushFrontList(l3)
+ checkList(t, l1, []interface{}{1, 2, 3})
+}
+
+func TestRemove(t *testing.T) {
+ l := New()
+ e1 := l.PushBack(1)
+ e2 := l.PushBack(2)
+ checkListPointers(t, l, []*Element{e1, e2})
+ e := l.Front()
+ l.Remove(e)
+ checkListPointers(t, l, []*Element{e2})
+ checkListLen(t, l, 1)
+ l.Remove(e)
+ checkListPointers(t, l, []*Element{e2})
+ checkListLen(t, l, 1)
+}
diff --git a/libgo/go/container/ring/ring.go b/libgo/go/container/ring/ring.go
new file mode 100644
index 000000000..335afbc3c
--- /dev/null
+++ b/libgo/go/container/ring/ring.go
@@ -0,0 +1,153 @@
+// 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.
+
+// The ring package implements operations on circular lists.
+package ring
+
+// A Ring is an element of a circular list, or ring.
+// Rings do not have a beginning or end; a pointer to any ring element
+// serves as reference to the entire ring. Empty rings are represented
+// as nil Ring pointers. The zero value for a Ring is a one-element
+// ring with a nil Value.
+//
+type Ring struct {
+ next, prev *Ring
+ Value interface{} // for use by client; untouched by this library
+}
+
+
+func (r *Ring) init() *Ring {
+ r.next = r
+ r.prev = r
+ return r
+}
+
+
+// Next returns the next ring element. r must not be empty.
+func (r *Ring) Next() *Ring {
+ if r.next == nil {
+ return r.init()
+ }
+ return r.next
+}
+
+
+// Prev returns the previous ring element. r must not be empty.
+func (r *Ring) Prev() *Ring {
+ if r.next == nil {
+ return r.init()
+ }
+ return r.prev
+}
+
+
+// Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0)
+// in the ring and returns that ring element. r must not be empty.
+//
+func (r *Ring) Move(n int) *Ring {
+ if r.next == nil {
+ return r.init()
+ }
+ switch {
+ case n < 0:
+ for ; n < 0; n++ {
+ r = r.prev
+ }
+ case n > 0:
+ for ; n > 0; n-- {
+ r = r.next
+ }
+ }
+ return r
+}
+
+
+// New creates a ring of n elements.
+func New(n int) *Ring {
+ if n <= 0 {
+ return nil
+ }
+ r := new(Ring)
+ p := r
+ for i := 1; i < n; i++ {
+ p.next = &Ring{prev: p}
+ p = p.next
+ }
+ p.next = r
+ r.prev = p
+ return r
+}
+
+
+// Link connects ring r with with ring s such that r.Next()
+// becomes s and returns the original value for r.Next().
+// r must not be empty.
+//
+// If r and s point to the same ring, linking
+// them removes the elements between r and s from the ring.
+// The removed elements form a subring and the result is a
+// reference to that subring (if no elements were removed,
+// the result is still the original value for r.Next(),
+// and not nil).
+//
+// If r and s point to different rings, linking
+// them creates a single ring with the elements of s inserted
+// after r. The result points to the element following the
+// last element of s after insertion.
+//
+func (r *Ring) Link(s *Ring) *Ring {
+ n := r.Next()
+ if s != nil {
+ p := s.Prev()
+ // Note: Cannot use multiple assignment because
+ // evaluation order of LHS is not specified.
+ r.next = s
+ s.prev = r
+ n.prev = p
+ p.next = n
+ }
+ return n
+}
+
+
+// Unlink removes n % r.Len() elements from the ring r, starting
+// at r.Next(). If n % r.Len() == 0, r remains unchanged.
+// The result is the removed subring. r must not be empty.
+//
+func (r *Ring) Unlink(n int) *Ring {
+ if n <= 0 {
+ return nil
+ }
+ return r.Link(r.Move(n + 1))
+}
+
+
+// Len computes the number of elements in ring r.
+// It executes in time proportional to the number of elements.
+//
+func (r *Ring) Len() int {
+ n := 0
+ if r != nil {
+ n = 1
+ for p := r.Next(); p != r; p = p.next {
+ n++
+ }
+ }
+ return n
+}
+
+
+func (r *Ring) Iter() <-chan interface{} {
+ c := make(chan interface{})
+ go func() {
+ if r != nil {
+ c <- r.Value
+ for p := r.Next(); p != r; p = p.next {
+ c <- p.Value
+ }
+ }
+ close(c)
+ }()
+ return c
+}
diff --git a/libgo/go/container/ring/ring_test.go b/libgo/go/container/ring/ring_test.go
new file mode 100644
index 000000000..ee3c41128
--- /dev/null
+++ b/libgo/go/container/ring/ring_test.go
@@ -0,0 +1,240 @@
+// 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 ring
+
+import (
+ "fmt"
+ "testing"
+)
+
+
+// For debugging - keep around.
+func dump(r *Ring) {
+ if r == nil {
+ fmt.Println("empty")
+ return
+ }
+ i, n := 0, r.Len()
+ for p := r; i < n; p = p.next {
+ fmt.Printf("%4d: %p = {<- %p | %p ->}\n", i, p, p.prev, p.next)
+ i++
+ }
+ fmt.Println()
+}
+
+
+func verify(t *testing.T, r *Ring, N int, sum int) {
+ // Len
+ n := r.Len()
+ if n != N {
+ t.Errorf("r.Len() == %d; expected %d", n, N)
+ }
+
+ // iteration
+ n = 0
+ s := 0
+ for p := range r.Iter() {
+ n++
+ if p != nil {
+ s += p.(int)
+ }
+ }
+ if n != N {
+ t.Errorf("number of forward iterations == %d; expected %d", n, N)
+ }
+ if sum >= 0 && s != sum {
+ t.Errorf("forward ring sum = %d; expected %d", s, sum)
+ }
+
+ if r == nil {
+ return
+ }
+
+ // connections
+ if r.next != nil {
+ var p *Ring // previous element
+ for q := r; p == nil || q != r; q = q.next {
+ if p != nil && p != q.prev {
+ t.Errorf("prev = %p, expected q.prev = %p\n", p, q.prev)
+ }
+ p = q
+ }
+ if p != r.prev {
+ t.Errorf("prev = %p, expected r.prev = %p\n", p, r.prev)
+ }
+ }
+
+ // Next, Prev
+ if r.Next() != r.next {
+ t.Errorf("r.Next() != r.next")
+ }
+ if r.Prev() != r.prev {
+ t.Errorf("r.Prev() != r.prev")
+ }
+
+ // Move
+ if r.Move(0) != r {
+ t.Errorf("r.Move(0) != r")
+ }
+ if r.Move(N) != r {
+ t.Errorf("r.Move(%d) != r", N)
+ }
+ if r.Move(-N) != r {
+ t.Errorf("r.Move(%d) != r", -N)
+ }
+ for i := 0; i < 10; i++ {
+ ni := N + i
+ mi := ni % N
+ if r.Move(ni) != r.Move(mi) {
+ t.Errorf("r.Move(%d) != r.Move(%d)", ni, mi)
+ }
+ if r.Move(-ni) != r.Move(-mi) {
+ t.Errorf("r.Move(%d) != r.Move(%d)", -ni, -mi)
+ }
+ }
+}
+
+
+func TestCornerCases(t *testing.T) {
+ var (
+ r0 *Ring
+ r1 Ring
+ )
+ // Basics
+ verify(t, r0, 0, 0)
+ verify(t, &r1, 1, 0)
+ // Insert
+ r1.Link(r0)
+ verify(t, r0, 0, 0)
+ verify(t, &r1, 1, 0)
+ // Insert
+ r1.Link(r0)
+ verify(t, r0, 0, 0)
+ verify(t, &r1, 1, 0)
+ // Unlink
+ r1.Unlink(0)
+ verify(t, &r1, 1, 0)
+}
+
+
+func makeN(n int) *Ring {
+ r := New(n)
+ for i := 1; i <= n; i++ {
+ r.Value = i
+ r = r.Next()
+ }
+ return r
+}
+
+
+func sum(r *Ring) int {
+ s := 0
+ for p := range r.Iter() {
+ s += p.(int)
+ }
+ return s
+}
+
+
+func sumN(n int) int { return (n*n + n) / 2 }
+
+
+func TestNew(t *testing.T) {
+ for i := 0; i < 10; i++ {
+ r := New(i)
+ verify(t, r, i, -1)
+ }
+ for i := 0; i < 10; i++ {
+ r := makeN(i)
+ verify(t, r, i, sumN(i))
+ }
+}
+
+
+func TestLink1(t *testing.T) {
+ r1a := makeN(1)
+ var r1b Ring
+ r2a := r1a.Link(&r1b)
+ verify(t, r2a, 2, 1)
+ if r2a != r1a {
+ t.Errorf("a) 2-element link failed")
+ }
+
+ r2b := r2a.Link(r2a.Next())
+ verify(t, r2b, 2, 1)
+ if r2b != r2a.Next() {
+ t.Errorf("b) 2-element link failed")
+ }
+
+ r1c := r2b.Link(r2b)
+ verify(t, r1c, 1, 1)
+ verify(t, r2b, 1, 0)
+}
+
+
+func TestLink2(t *testing.T) {
+ var r0 *Ring
+ r1a := &Ring{Value: 42}
+ r1b := &Ring{Value: 77}
+ r10 := makeN(10)
+
+ r1a.Link(r0)
+ verify(t, r1a, 1, 42)
+
+ r1a.Link(r1b)
+ verify(t, r1a, 2, 42+77)
+
+ r10.Link(r0)
+ verify(t, r10, 10, sumN(10))
+
+ r10.Link(r1a)
+ verify(t, r10, 12, sumN(10)+42+77)
+}
+
+
+func TestLink3(t *testing.T) {
+ var r Ring
+ n := 1
+ for i := 1; i < 100; i++ {
+ n += i
+ verify(t, r.Link(New(i)), n, -1)
+ }
+}
+
+
+func TestUnlink(t *testing.T) {
+ r10 := makeN(10)
+ s10 := r10.Move(6)
+
+ sum10 := sumN(10)
+
+ verify(t, r10, 10, sum10)
+ verify(t, s10, 10, sum10)
+
+ r0 := r10.Unlink(0)
+ verify(t, r0, 0, 0)
+
+ r1 := r10.Unlink(1)
+ verify(t, r1, 1, 2)
+ verify(t, r10, 9, sum10-2)
+
+ r9 := r10.Unlink(9)
+ verify(t, r9, 9, sum10-2)
+ verify(t, r10, 9, sum10-2)
+}
+
+
+func TestLinkUnlink(t *testing.T) {
+ for i := 1; i < 4; i++ {
+ ri := New(i)
+ for j := 0; j < i; j++ {
+ rj := ri.Unlink(j)
+ verify(t, rj, j, -1)
+ verify(t, ri, i-j, -1)
+ ri.Link(rj)
+ verify(t, ri, i, -1)
+ }
+ }
+}
diff --git a/libgo/go/container/vector/defs.go b/libgo/go/container/vector/defs.go
new file mode 100644
index 000000000..a2febb6de
--- /dev/null
+++ b/libgo/go/container/vector/defs.go
@@ -0,0 +1,51 @@
+// 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.
+
+// The vector package implements containers for managing sequences
+// of elements. Vectors grow and shrink dynamically as necessary.
+package vector
+
+
+// Vector is a container for numbered sequences of elements of type interface{}.
+// A vector's length and capacity adjusts automatically as necessary.
+// The zero value for Vector is an empty vector ready to use.
+type Vector []interface{}
+
+
+// IntVector is a container for numbered sequences of elements of type int.
+// A vector's length and capacity adjusts automatically as necessary.
+// The zero value for IntVector is an empty vector ready to use.
+type IntVector []int
+
+
+// StringVector is a container for numbered sequences of elements of type string.
+// A vector's length and capacity adjusts automatically as necessary.
+// The zero value for StringVector is an empty vector ready to use.
+type StringVector []string
+
+
+// Initial underlying array size
+const initialSize = 8
+
+
+// Partial sort.Interface support
+
+// LessInterface provides partial support of the sort.Interface.
+type LessInterface interface {
+ Less(y interface{}) bool
+}
+
+
+// Less returns a boolean denoting whether the i'th element is less than the j'th element.
+func (p *Vector) Less(i, j int) bool { return (*p)[i].(LessInterface).Less((*p)[j]) }
+
+
+// sort.Interface support
+
+// Less returns a boolean denoting whether the i'th element is less than the j'th element.
+func (p *IntVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] }
+
+
+// Less returns a boolean denoting whether the i'th element is less than the j'th element.
+func (p *StringVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] }
diff --git a/libgo/go/container/vector/intvector.go b/libgo/go/container/vector/intvector.go
new file mode 100644
index 000000000..5ad9e294b
--- /dev/null
+++ b/libgo/go/container/vector/intvector.go
@@ -0,0 +1,208 @@
+// 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.
+
+// CAUTION: If this file is not vector.go, it was generated
+// automatically from vector.go - DO NOT EDIT in that case!
+
+package vector
+
+
+func (p *IntVector) realloc(length, capacity int) (b []int) {
+ if capacity < initialSize {
+ capacity = initialSize
+ }
+ if capacity < length {
+ capacity = length
+ }
+ b = make(IntVector, length, capacity)
+ copy(b, *p)
+ *p = b
+ return
+}
+
+
+// Insert n elements at position i.
+func (p *IntVector) Expand(i, n int) {
+ a := *p
+
+ // make sure we have enough space
+ len0 := len(a)
+ len1 := len0 + n
+ if len1 <= cap(a) {
+ // enough space - just expand
+ a = a[0:len1]
+ } else {
+ // not enough space - double capacity
+ capb := cap(a) * 2
+ if capb < len1 {
+ // still not enough - use required length
+ capb = len1
+ }
+ // capb >= len1
+ a = p.realloc(len1, capb)
+ }
+
+ // make a hole
+ for j := len0 - 1; j >= i; j-- {
+ a[j+n] = a[j]
+ }
+
+ *p = a
+}
+
+
+// Insert n elements at the end of a vector.
+func (p *IntVector) Extend(n int) { p.Expand(len(*p), n) }
+
+
+// Resize changes the length and capacity of a vector.
+// If the new length is shorter than the current length, Resize discards
+// trailing elements. If the new length is longer than the current length,
+// Resize adds the respective zero values for the additional elements. The capacity
+// parameter is ignored unless the new length or capacity is longer than the current
+// capacity. The resized vector's capacity may be larger than the requested capacity.
+func (p *IntVector) Resize(length, capacity int) *IntVector {
+ a := *p
+
+ if length > cap(a) || capacity > cap(a) {
+ // not enough space or larger capacity requested explicitly
+ a = p.realloc(length, capacity)
+ } else if length < len(a) {
+ // clear trailing elements
+ for i := range a[length:] {
+ var zero int
+ a[length+i] = zero
+ }
+ }
+
+ *p = a[0:length]
+ return p
+}
+
+
+// Len returns the number of elements in the vector.
+// Same as len(*p).
+func (p *IntVector) Len() int { return len(*p) }
+
+
+// Cap returns the capacity of the vector; that is, the
+// maximum length the vector can grow without resizing.
+// Same as cap(*p).
+func (p *IntVector) Cap() int { return cap(*p) }
+
+
+// At returns the i'th element of the vector.
+func (p *IntVector) At(i int) int { return (*p)[i] }
+
+
+// Set sets the i'th element of the vector to value x.
+func (p *IntVector) Set(i int, x int) { (*p)[i] = x }
+
+
+// Last returns the element in the vector of highest index.
+func (p *IntVector) Last() int { return (*p)[len(*p)-1] }
+
+
+// Copy makes a copy of the vector and returns it.
+func (p *IntVector) Copy() IntVector {
+ arr := make(IntVector, len(*p))
+ copy(arr, *p)
+ return arr
+}
+
+
+// Insert inserts into the vector an element of value x before
+// the current element at index i.
+func (p *IntVector) Insert(i int, x int) {
+ p.Expand(i, 1)
+ (*p)[i] = x
+}
+
+
+// Delete deletes the i'th element of the vector. The gap is closed so the old
+// element at index i+1 has index i afterwards.
+func (p *IntVector) Delete(i int) {
+ a := *p
+ n := len(a)
+
+ copy(a[i:n-1], a[i+1:n])
+ var zero int
+ a[n-1] = zero // support GC, zero out entry
+ *p = a[0 : n-1]
+}
+
+
+// InsertVector inserts into the vector the contents of the vector
+// x such that the 0th element of x appears at index i after insertion.
+func (p *IntVector) InsertVector(i int, x *IntVector) {
+ b := *x
+
+ p.Expand(i, len(b))
+ copy((*p)[i:i+len(b)], b)
+}
+
+
+// Cut deletes elements i through j-1, inclusive.
+func (p *IntVector) Cut(i, j int) {
+ a := *p
+ n := len(a)
+ m := n - (j - i)
+
+ copy(a[i:m], a[j:n])
+ for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
+ var zero int
+ a[k] = zero // support GC, zero out entries
+ }
+
+ *p = a[0:m]
+}
+
+
+// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
+// The elements are copied. The original vector is unchanged.
+func (p *IntVector) Slice(i, j int) *IntVector {
+ var s IntVector
+ s.realloc(j-i, 0) // will fail in Init() if j < i
+ copy(s, (*p)[i:j])
+ return &s
+}
+
+
+// Convenience wrappers
+
+// Push appends x to the end of the vector.
+func (p *IntVector) Push(x int) { p.Insert(len(*p), x) }
+
+
+// Pop deletes the last element of the vector.
+func (p *IntVector) Pop() int {
+ a := *p
+
+ i := len(a) - 1
+ x := a[i]
+ var zero int
+ a[i] = zero // support GC, zero out entry
+ *p = a[0:i]
+ return x
+}
+
+
+// AppendVector appends the entire vector x to the end of this vector.
+func (p *IntVector) AppendVector(x *IntVector) { p.InsertVector(len(*p), x) }
+
+
+// Swap exchanges the elements at indexes i and j.
+func (p *IntVector) Swap(i, j int) {
+ a := *p
+ a[i], a[j] = a[j], a[i]
+}
+
+
+// Do calls function f for each element of the vector, in order.
+// The behavior of Do is undefined if f changes *p.
+func (p *IntVector) Do(f func(elem int)) {
+ for _, e := range *p {
+ f(e)
+ }
+}
diff --git a/libgo/go/container/vector/intvector_test.go b/libgo/go/container/vector/intvector_test.go
new file mode 100644
index 000000000..1e38a1982
--- /dev/null
+++ b/libgo/go/container/vector/intvector_test.go
@@ -0,0 +1,344 @@
+// 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.
+
+// CAUTION: If this file is not vector_test.go, it was generated
+// automatically from vector_test.go - DO NOT EDIT in that case!
+
+package vector
+
+import "testing"
+
+
+func TestIntZeroLen(t *testing.T) {
+ a := new(IntVector)
+ if a.Len() != 0 {
+ t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
+ }
+ if len(*a) != 0 {
+ t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
+ }
+ var b IntVector
+ if b.Len() != 0 {
+ t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
+ }
+ if len(b) != 0 {
+ t.Errorf("%T: B4) expected 0, got %d", b, len(b))
+ }
+}
+
+
+func TestIntResize(t *testing.T) {
+ var a IntVector
+ checkSize(t, &a, 0, 0)
+ checkSize(t, a.Resize(0, 5), 0, 5)
+ checkSize(t, a.Resize(1, 0), 1, 5)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ checkSize(t, a.Resize(5, 0), 5, 10)
+ checkSize(t, a.Resize(3, 8), 3, 10)
+ checkSize(t, a.Resize(0, 100), 0, 100)
+ checkSize(t, a.Resize(11, 100), 11, 100)
+}
+
+
+func TestIntResize2(t *testing.T) {
+ var a IntVector
+ checkSize(t, &a, 0, 0)
+ a.Push(int2IntValue(1))
+ a.Push(int2IntValue(2))
+ a.Push(int2IntValue(3))
+ a.Push(int2IntValue(4))
+ checkSize(t, &a, 4, 4)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ for i := 4; i < a.Len(); i++ {
+ if a.At(i) != intzero {
+ t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, intzero, a.At(i))
+ }
+ }
+ for i := 4; i < len(a); i++ {
+ if a[i] != intzero {
+ t.Errorf("%T: expected a[%d] == %v; found %v", a, i, intzero, a[i])
+ }
+ }
+}
+
+
+func checkIntZero(t *testing.T, a *IntVector, i int) {
+ for j := 0; j < i; j++ {
+ if a.At(j) == intzero {
+ t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
+ }
+ if (*a)[j] == intzero {
+ t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
+ }
+ }
+ for ; i < a.Len(); i++ {
+ if a.At(i) != intzero {
+ t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, intzero, a.At(i))
+ }
+ if (*a)[i] != intzero {
+ t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, intzero, (*a)[i])
+ }
+ }
+}
+
+
+func TestIntTrailingElements(t *testing.T) {
+ var a IntVector
+ for i := 0; i < 10; i++ {
+ a.Push(int2IntValue(i + 1))
+ }
+ checkIntZero(t, &a, 10)
+ checkSize(t, &a, 10, 16)
+ checkSize(t, a.Resize(5, 0), 5, 16)
+ checkSize(t, a.Resize(10, 0), 10, 16)
+ checkIntZero(t, &a, 5)
+}
+
+
+func TestIntAccess(t *testing.T) {
+ const n = 100
+ var a IntVector
+ a.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2IntValue(val(i)))
+ }
+ for i := 0; i < n; i++ {
+ if elem2IntValue(a.At(i)) != int2IntValue(val(i)) {
+ t.Error(i)
+ }
+ }
+ var b IntVector
+ b.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ b[i] = int2IntValue(val(i))
+ }
+ for i := 0; i < n; i++ {
+ if elem2IntValue(b[i]) != int2IntValue(val(i)) {
+ t.Error(i)
+ }
+ }
+}
+
+
+func TestIntInsertDeleteClear(t *testing.T) {
+ const n = 100
+ var a IntVector
+
+ for i := 0; i < n; i++ {
+ if a.Len() != i {
+ t.Errorf("%T: A) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: A) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ a.Insert(0, int2IntValue(val(i)))
+ if elem2IntValue(a.Last()) != int2IntValue(val(0)) {
+ t.Errorf("%T: B", a)
+ }
+ }
+ for i := n - 1; i >= 0; i-- {
+ if elem2IntValue(a.Last()) != int2IntValue(val(0)) {
+ t.Errorf("%T: C", a)
+ }
+ if elem2IntValue(a.At(0)) != int2IntValue(val(i)) {
+ t.Errorf("%T: D", a)
+ }
+ if elem2IntValue(a[0]) != int2IntValue(val(i)) {
+ t.Errorf("%T: D2", a)
+ }
+ a.Delete(0)
+ if a.Len() != i {
+ t.Errorf("%T: E) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: E) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ }
+
+ if a.Len() != 0 {
+ t.Errorf("%T: F) wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: F) wrong len() %d (expected 0)", a, len(a))
+ }
+ for i := 0; i < n; i++ {
+ a.Push(int2IntValue(val(i)))
+ if a.Len() != i+1 {
+ t.Errorf("%T: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
+ }
+ if len(a) != i+1 {
+ t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
+ }
+ if elem2IntValue(a.Last()) != int2IntValue(val(i)) {
+ t.Errorf("%T: H", a)
+ }
+ }
+ a.Resize(0, 0)
+ if a.Len() != 0 {
+ t.Errorf("%T: I wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
+ }
+
+ const m = 5
+ for j := 0; j < m; j++ {
+ a.Push(int2IntValue(j))
+ for i := 0; i < n; i++ {
+ x := val(i)
+ a.Push(int2IntValue(x))
+ if elem2IntValue(a.Pop()) != int2IntValue(x) {
+ t.Errorf("%T: J", a)
+ }
+ if a.Len() != j+1 {
+ t.Errorf("%T: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
+ }
+ if len(a) != j+1 {
+ t.Errorf("%T: K) wrong len() %d (expected %d)", a, len(a), j+1)
+ }
+ }
+ }
+ if a.Len() != m {
+ t.Errorf("%T: L) wrong Len() %d (expected %d)", a, a.Len(), m)
+ }
+ if len(a) != m {
+ t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
+ }
+}
+
+
+func verify_sliceInt(t *testing.T, x *IntVector, elt, i, j int) {
+ for k := i; k < j; k++ {
+ if elem2IntValue(x.At(k)) != int2IntValue(elt) {
+ t.Errorf("%T: M) wrong [%d] element %v (expected %v)", x, k, elem2IntValue(x.At(k)), int2IntValue(elt))
+ }
+ }
+
+ s := x.Slice(i, j)
+ for k, n := 0, j-i; k < n; k++ {
+ if elem2IntValue(s.At(k)) != int2IntValue(elt) {
+ t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2IntValue(x.At(k)), int2IntValue(elt))
+ }
+ }
+}
+
+
+func verify_patternInt(t *testing.T, x *IntVector, a, b, c int) {
+ n := a + b + c
+ if x.Len() != n {
+ t.Errorf("%T: O) wrong Len() %d (expected %d)", x, x.Len(), n)
+ }
+ if len(*x) != n {
+ t.Errorf("%T: O) wrong len() %d (expected %d)", x, len(*x), n)
+ }
+ verify_sliceInt(t, x, 0, 0, a)
+ verify_sliceInt(t, x, 1, a, a+b)
+ verify_sliceInt(t, x, 0, a+b, n)
+}
+
+
+func make_vectorInt(elt, len int) *IntVector {
+ x := new(IntVector).Resize(len, 0)
+ for i := 0; i < len; i++ {
+ x.Set(i, int2IntValue(elt))
+ }
+ return x
+}
+
+
+func TestIntInsertVector(t *testing.T) {
+ // 1
+ a := make_vectorInt(0, 0)
+ b := make_vectorInt(1, 10)
+ a.InsertVector(0, b)
+ verify_patternInt(t, a, 0, 10, 0)
+ // 2
+ a = make_vectorInt(0, 10)
+ b = make_vectorInt(1, 0)
+ a.InsertVector(5, b)
+ verify_patternInt(t, a, 5, 0, 5)
+ // 3
+ a = make_vectorInt(0, 10)
+ b = make_vectorInt(1, 3)
+ a.InsertVector(3, b)
+ verify_patternInt(t, a, 3, 3, 7)
+ // 4
+ a = make_vectorInt(0, 10)
+ b = make_vectorInt(1, 1000)
+ a.InsertVector(8, b)
+ verify_patternInt(t, a, 8, 1000, 2)
+}
+
+
+func TestIntDo(t *testing.T) {
+ const n = 25
+ const salt = 17
+ a := new(IntVector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2IntValue(salt*i))
+ }
+ count := 0
+ a.Do(func(e int) {
+ i := intf2IntValue(e)
+ if i != int2IntValue(count*salt) {
+ t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(a), "should visit", n, "values; did visit", count)
+ }
+
+ b := new(IntVector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ (*b)[i] = int2IntValue(salt * i)
+ }
+ count = 0
+ b.Do(func(e int) {
+ i := intf2IntValue(e)
+ if i != int2IntValue(count*salt) {
+ t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(b), "b) should visit", n, "values; did visit", count)
+ }
+
+ var c IntVector
+ c.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ c[i] = int2IntValue(salt * i)
+ }
+ count = 0
+ c.Do(func(e int) {
+ i := intf2IntValue(e)
+ if i != int2IntValue(count*salt) {
+ t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(c), "c) should visit", n, "values; did visit", count)
+ }
+
+}
+
+
+func TestIntVectorCopy(t *testing.T) {
+ // verify Copy() returns a copy, not simply a slice of the original vector
+ const Len = 10
+ var src IntVector
+ for i := 0; i < Len; i++ {
+ src.Push(int2IntValue(i * i))
+ }
+ dest := src.Copy()
+ for i := 0; i < Len; i++ {
+ src[i] = int2IntValue(-1)
+ v := elem2IntValue(dest[i])
+ if v != int2IntValue(i*i) {
+ t.Error(tname(src), "expected", i*i, "got", v)
+ }
+ }
+}
diff --git a/libgo/go/container/vector/nogen_test.go b/libgo/go/container/vector/nogen_test.go
new file mode 100644
index 000000000..790d3749f
--- /dev/null
+++ b/libgo/go/container/vector/nogen_test.go
@@ -0,0 +1,76 @@
+// 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 vector
+
+
+import (
+ "fmt"
+ "sort"
+ "testing"
+)
+
+var (
+ zero interface{}
+ intzero int
+ strzero string
+)
+
+
+func int2Value(x int) int { return x }
+func int2IntValue(x int) int { return x }
+func int2StrValue(x int) string { return string(x) }
+
+
+func elem2Value(x interface{}) int { return x.(int) }
+func elem2IntValue(x int) int { return x }
+func elem2StrValue(x string) string { return x }
+
+
+func intf2Value(x interface{}) int { return x.(int) }
+func intf2IntValue(x interface{}) int { return x.(int) }
+func intf2StrValue(x interface{}) string { return x.(string) }
+
+
+type VectorInterface interface {
+ Len() int
+ Cap() int
+}
+
+
+func checkSize(t *testing.T, v VectorInterface, len, cap int) {
+ if v.Len() != len {
+ t.Errorf("%T expected len = %d; found %d", v, len, v.Len())
+ }
+ if v.Cap() < cap {
+ t.Errorf("%T expected cap >= %d; found %d", v, cap, v.Cap())
+ }
+}
+
+
+func val(i int) int { return i*991 - 1234 }
+
+
+func TestSorting(t *testing.T) {
+ const n = 100
+
+ a := new(IntVector).Resize(n, 0)
+ for i := n - 1; i >= 0; i-- {
+ a.Set(i, n-1-i)
+ }
+ if sort.IsSorted(a) {
+ t.Error("int vector not sorted")
+ }
+
+ b := new(StringVector).Resize(n, 0)
+ for i := n - 1; i >= 0; i-- {
+ b.Set(i, fmt.Sprint(n-1-i))
+ }
+ if sort.IsSorted(b) {
+ t.Error("string vector not sorted")
+ }
+}
+
+
+func tname(x interface{}) string { return fmt.Sprintf("%T: ", x) }
diff --git a/libgo/go/container/vector/numbers_test.go b/libgo/go/container/vector/numbers_test.go
new file mode 100644
index 000000000..d540ace05
--- /dev/null
+++ b/libgo/go/container/vector/numbers_test.go
@@ -0,0 +1,122 @@
+// 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 vector
+
+import (
+ "fmt"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+
+const memTestN = 1000000
+
+
+func s(n uint64) string {
+ str := fmt.Sprintf("%d", n)
+ lens := len(str)
+ a := make([]string, (lens+2)/3)
+ start := lens
+ for i := range a {
+ start -= 3
+ if start < 0 {
+ start = 0
+ }
+ a[len(a)-i-1] = str[start:lens]
+ lens -= 3
+ }
+ return strings.Join(a, " ")
+}
+
+
+func TestVectorNums(t *testing.T) {
+ var v Vector
+ c := int(0)
+ runtime.GC()
+ m0 := runtime.MemStats
+ v.Resize(memTestN, memTestN)
+ for i := 0; i < memTestN; i++ {
+ v.Set(i, c)
+ }
+ runtime.GC()
+ m := runtime.MemStats
+ v.Resize(0, 0)
+ runtime.GC()
+ n := m.Alloc - m0.Alloc
+ t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
+}
+
+
+func TestIntVectorNums(t *testing.T) {
+ var v IntVector
+ c := int(0)
+ runtime.GC()
+ m0 := runtime.MemStats
+ v.Resize(memTestN, memTestN)
+ for i := 0; i < memTestN; i++ {
+ v.Set(i, c)
+ }
+ runtime.GC()
+ m := runtime.MemStats
+ v.Resize(0, 0)
+ runtime.GC()
+ n := m.Alloc - m0.Alloc
+ t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
+}
+
+
+func TestStringVectorNums(t *testing.T) {
+ var v StringVector
+ c := ""
+ runtime.GC()
+ m0 := runtime.MemStats
+ v.Resize(memTestN, memTestN)
+ for i := 0; i < memTestN; i++ {
+ v.Set(i, c)
+ }
+ runtime.GC()
+ m := runtime.MemStats
+ v.Resize(0, 0)
+ runtime.GC()
+ n := m.Alloc - m0.Alloc
+ t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
+}
+
+
+func BenchmarkVectorNums(b *testing.B) {
+ c := int(0)
+ var v Vector
+ b.StopTimer()
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ v.Push(c)
+ }
+}
+
+
+func BenchmarkIntVectorNums(b *testing.B) {
+ c := int(0)
+ var v IntVector
+ b.StopTimer()
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ v.Push(c)
+ }
+}
+
+
+func BenchmarkStringVectorNums(b *testing.B) {
+ c := ""
+ var v StringVector
+ b.StopTimer()
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ v.Push(c)
+ }
+}
diff --git a/libgo/go/container/vector/stringvector.go b/libgo/go/container/vector/stringvector.go
new file mode 100644
index 000000000..852685f5a
--- /dev/null
+++ b/libgo/go/container/vector/stringvector.go
@@ -0,0 +1,208 @@
+// 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.
+
+// CAUTION: If this file is not vector.go, it was generated
+// automatically from vector.go - DO NOT EDIT in that case!
+
+package vector
+
+
+func (p *StringVector) realloc(length, capacity int) (b []string) {
+ if capacity < initialSize {
+ capacity = initialSize
+ }
+ if capacity < length {
+ capacity = length
+ }
+ b = make(StringVector, length, capacity)
+ copy(b, *p)
+ *p = b
+ return
+}
+
+
+// Insert n elements at position i.
+func (p *StringVector) Expand(i, n int) {
+ a := *p
+
+ // make sure we have enough space
+ len0 := len(a)
+ len1 := len0 + n
+ if len1 <= cap(a) {
+ // enough space - just expand
+ a = a[0:len1]
+ } else {
+ // not enough space - double capacity
+ capb := cap(a) * 2
+ if capb < len1 {
+ // still not enough - use required length
+ capb = len1
+ }
+ // capb >= len1
+ a = p.realloc(len1, capb)
+ }
+
+ // make a hole
+ for j := len0 - 1; j >= i; j-- {
+ a[j+n] = a[j]
+ }
+
+ *p = a
+}
+
+
+// Insert n elements at the end of a vector.
+func (p *StringVector) Extend(n int) { p.Expand(len(*p), n) }
+
+
+// Resize changes the length and capacity of a vector.
+// If the new length is shorter than the current length, Resize discards
+// trailing elements. If the new length is longer than the current length,
+// Resize adds the respective zero values for the additional elements. The capacity
+// parameter is ignored unless the new length or capacity is longer than the current
+// capacity. The resized vector's capacity may be larger than the requested capacity.
+func (p *StringVector) Resize(length, capacity int) *StringVector {
+ a := *p
+
+ if length > cap(a) || capacity > cap(a) {
+ // not enough space or larger capacity requested explicitly
+ a = p.realloc(length, capacity)
+ } else if length < len(a) {
+ // clear trailing elements
+ for i := range a[length:] {
+ var zero string
+ a[length+i] = zero
+ }
+ }
+
+ *p = a[0:length]
+ return p
+}
+
+
+// Len returns the number of elements in the vector.
+// Same as len(*p).
+func (p *StringVector) Len() int { return len(*p) }
+
+
+// Cap returns the capacity of the vector; that is, the
+// maximum length the vector can grow without resizing.
+// Same as cap(*p).
+func (p *StringVector) Cap() int { return cap(*p) }
+
+
+// At returns the i'th element of the vector.
+func (p *StringVector) At(i int) string { return (*p)[i] }
+
+
+// Set sets the i'th element of the vector to value x.
+func (p *StringVector) Set(i int, x string) { (*p)[i] = x }
+
+
+// Last returns the element in the vector of highest index.
+func (p *StringVector) Last() string { return (*p)[len(*p)-1] }
+
+
+// Copy makes a copy of the vector and returns it.
+func (p *StringVector) Copy() StringVector {
+ arr := make(StringVector, len(*p))
+ copy(arr, *p)
+ return arr
+}
+
+
+// Insert inserts into the vector an element of value x before
+// the current element at index i.
+func (p *StringVector) Insert(i int, x string) {
+ p.Expand(i, 1)
+ (*p)[i] = x
+}
+
+
+// Delete deletes the i'th element of the vector. The gap is closed so the old
+// element at index i+1 has index i afterwards.
+func (p *StringVector) Delete(i int) {
+ a := *p
+ n := len(a)
+
+ copy(a[i:n-1], a[i+1:n])
+ var zero string
+ a[n-1] = zero // support GC, zero out entry
+ *p = a[0 : n-1]
+}
+
+
+// InsertVector inserts into the vector the contents of the vector
+// x such that the 0th element of x appears at index i after insertion.
+func (p *StringVector) InsertVector(i int, x *StringVector) {
+ b := *x
+
+ p.Expand(i, len(b))
+ copy((*p)[i:i+len(b)], b)
+}
+
+
+// Cut deletes elements i through j-1, inclusive.
+func (p *StringVector) Cut(i, j int) {
+ a := *p
+ n := len(a)
+ m := n - (j - i)
+
+ copy(a[i:m], a[j:n])
+ for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
+ var zero string
+ a[k] = zero // support GC, zero out entries
+ }
+
+ *p = a[0:m]
+}
+
+
+// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
+// The elements are copied. The original vector is unchanged.
+func (p *StringVector) Slice(i, j int) *StringVector {
+ var s StringVector
+ s.realloc(j-i, 0) // will fail in Init() if j < i
+ copy(s, (*p)[i:j])
+ return &s
+}
+
+
+// Convenience wrappers
+
+// Push appends x to the end of the vector.
+func (p *StringVector) Push(x string) { p.Insert(len(*p), x) }
+
+
+// Pop deletes the last element of the vector.
+func (p *StringVector) Pop() string {
+ a := *p
+
+ i := len(a) - 1
+ x := a[i]
+ var zero string
+ a[i] = zero // support GC, zero out entry
+ *p = a[0:i]
+ return x
+}
+
+
+// AppendVector appends the entire vector x to the end of this vector.
+func (p *StringVector) AppendVector(x *StringVector) { p.InsertVector(len(*p), x) }
+
+
+// Swap exchanges the elements at indexes i and j.
+func (p *StringVector) Swap(i, j int) {
+ a := *p
+ a[i], a[j] = a[j], a[i]
+}
+
+
+// Do calls function f for each element of the vector, in order.
+// The behavior of Do is undefined if f changes *p.
+func (p *StringVector) Do(f func(elem string)) {
+ for _, e := range *p {
+ f(e)
+ }
+}
diff --git a/libgo/go/container/vector/stringvector_test.go b/libgo/go/container/vector/stringvector_test.go
new file mode 100644
index 000000000..776ae26de
--- /dev/null
+++ b/libgo/go/container/vector/stringvector_test.go
@@ -0,0 +1,344 @@
+// 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.
+
+// CAUTION: If this file is not vector_test.go, it was generated
+// automatically from vector_test.go - DO NOT EDIT in that case!
+
+package vector
+
+import "testing"
+
+
+func TestStrZeroLen(t *testing.T) {
+ a := new(StringVector)
+ if a.Len() != 0 {
+ t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
+ }
+ if len(*a) != 0 {
+ t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
+ }
+ var b StringVector
+ if b.Len() != 0 {
+ t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
+ }
+ if len(b) != 0 {
+ t.Errorf("%T: B4) expected 0, got %d", b, len(b))
+ }
+}
+
+
+func TestStrResize(t *testing.T) {
+ var a StringVector
+ checkSize(t, &a, 0, 0)
+ checkSize(t, a.Resize(0, 5), 0, 5)
+ checkSize(t, a.Resize(1, 0), 1, 5)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ checkSize(t, a.Resize(5, 0), 5, 10)
+ checkSize(t, a.Resize(3, 8), 3, 10)
+ checkSize(t, a.Resize(0, 100), 0, 100)
+ checkSize(t, a.Resize(11, 100), 11, 100)
+}
+
+
+func TestStrResize2(t *testing.T) {
+ var a StringVector
+ checkSize(t, &a, 0, 0)
+ a.Push(int2StrValue(1))
+ a.Push(int2StrValue(2))
+ a.Push(int2StrValue(3))
+ a.Push(int2StrValue(4))
+ checkSize(t, &a, 4, 4)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ for i := 4; i < a.Len(); i++ {
+ if a.At(i) != strzero {
+ t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, strzero, a.At(i))
+ }
+ }
+ for i := 4; i < len(a); i++ {
+ if a[i] != strzero {
+ t.Errorf("%T: expected a[%d] == %v; found %v", a, i, strzero, a[i])
+ }
+ }
+}
+
+
+func checkStrZero(t *testing.T, a *StringVector, i int) {
+ for j := 0; j < i; j++ {
+ if a.At(j) == strzero {
+ t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
+ }
+ if (*a)[j] == strzero {
+ t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
+ }
+ }
+ for ; i < a.Len(); i++ {
+ if a.At(i) != strzero {
+ t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, strzero, a.At(i))
+ }
+ if (*a)[i] != strzero {
+ t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, strzero, (*a)[i])
+ }
+ }
+}
+
+
+func TestStrTrailingElements(t *testing.T) {
+ var a StringVector
+ for i := 0; i < 10; i++ {
+ a.Push(int2StrValue(i + 1))
+ }
+ checkStrZero(t, &a, 10)
+ checkSize(t, &a, 10, 16)
+ checkSize(t, a.Resize(5, 0), 5, 16)
+ checkSize(t, a.Resize(10, 0), 10, 16)
+ checkStrZero(t, &a, 5)
+}
+
+
+func TestStrAccess(t *testing.T) {
+ const n = 100
+ var a StringVector
+ a.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2StrValue(val(i)))
+ }
+ for i := 0; i < n; i++ {
+ if elem2StrValue(a.At(i)) != int2StrValue(val(i)) {
+ t.Error(i)
+ }
+ }
+ var b StringVector
+ b.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ b[i] = int2StrValue(val(i))
+ }
+ for i := 0; i < n; i++ {
+ if elem2StrValue(b[i]) != int2StrValue(val(i)) {
+ t.Error(i)
+ }
+ }
+}
+
+
+func TestStrInsertDeleteClear(t *testing.T) {
+ const n = 100
+ var a StringVector
+
+ for i := 0; i < n; i++ {
+ if a.Len() != i {
+ t.Errorf("%T: A) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: A) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ a.Insert(0, int2StrValue(val(i)))
+ if elem2StrValue(a.Last()) != int2StrValue(val(0)) {
+ t.Errorf("%T: B", a)
+ }
+ }
+ for i := n - 1; i >= 0; i-- {
+ if elem2StrValue(a.Last()) != int2StrValue(val(0)) {
+ t.Errorf("%T: C", a)
+ }
+ if elem2StrValue(a.At(0)) != int2StrValue(val(i)) {
+ t.Errorf("%T: D", a)
+ }
+ if elem2StrValue(a[0]) != int2StrValue(val(i)) {
+ t.Errorf("%T: D2", a)
+ }
+ a.Delete(0)
+ if a.Len() != i {
+ t.Errorf("%T: E) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: E) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ }
+
+ if a.Len() != 0 {
+ t.Errorf("%T: F) wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: F) wrong len() %d (expected 0)", a, len(a))
+ }
+ for i := 0; i < n; i++ {
+ a.Push(int2StrValue(val(i)))
+ if a.Len() != i+1 {
+ t.Errorf("%T: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
+ }
+ if len(a) != i+1 {
+ t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
+ }
+ if elem2StrValue(a.Last()) != int2StrValue(val(i)) {
+ t.Errorf("%T: H", a)
+ }
+ }
+ a.Resize(0, 0)
+ if a.Len() != 0 {
+ t.Errorf("%T: I wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
+ }
+
+ const m = 5
+ for j := 0; j < m; j++ {
+ a.Push(int2StrValue(j))
+ for i := 0; i < n; i++ {
+ x := val(i)
+ a.Push(int2StrValue(x))
+ if elem2StrValue(a.Pop()) != int2StrValue(x) {
+ t.Errorf("%T: J", a)
+ }
+ if a.Len() != j+1 {
+ t.Errorf("%T: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
+ }
+ if len(a) != j+1 {
+ t.Errorf("%T: K) wrong len() %d (expected %d)", a, len(a), j+1)
+ }
+ }
+ }
+ if a.Len() != m {
+ t.Errorf("%T: L) wrong Len() %d (expected %d)", a, a.Len(), m)
+ }
+ if len(a) != m {
+ t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
+ }
+}
+
+
+func verify_sliceStr(t *testing.T, x *StringVector, elt, i, j int) {
+ for k := i; k < j; k++ {
+ if elem2StrValue(x.At(k)) != int2StrValue(elt) {
+ t.Errorf("%T: M) wrong [%d] element %v (expected %v)", x, k, elem2StrValue(x.At(k)), int2StrValue(elt))
+ }
+ }
+
+ s := x.Slice(i, j)
+ for k, n := 0, j-i; k < n; k++ {
+ if elem2StrValue(s.At(k)) != int2StrValue(elt) {
+ t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2StrValue(x.At(k)), int2StrValue(elt))
+ }
+ }
+}
+
+
+func verify_patternStr(t *testing.T, x *StringVector, a, b, c int) {
+ n := a + b + c
+ if x.Len() != n {
+ t.Errorf("%T: O) wrong Len() %d (expected %d)", x, x.Len(), n)
+ }
+ if len(*x) != n {
+ t.Errorf("%T: O) wrong len() %d (expected %d)", x, len(*x), n)
+ }
+ verify_sliceStr(t, x, 0, 0, a)
+ verify_sliceStr(t, x, 1, a, a+b)
+ verify_sliceStr(t, x, 0, a+b, n)
+}
+
+
+func make_vectorStr(elt, len int) *StringVector {
+ x := new(StringVector).Resize(len, 0)
+ for i := 0; i < len; i++ {
+ x.Set(i, int2StrValue(elt))
+ }
+ return x
+}
+
+
+func TestStrInsertVector(t *testing.T) {
+ // 1
+ a := make_vectorStr(0, 0)
+ b := make_vectorStr(1, 10)
+ a.InsertVector(0, b)
+ verify_patternStr(t, a, 0, 10, 0)
+ // 2
+ a = make_vectorStr(0, 10)
+ b = make_vectorStr(1, 0)
+ a.InsertVector(5, b)
+ verify_patternStr(t, a, 5, 0, 5)
+ // 3
+ a = make_vectorStr(0, 10)
+ b = make_vectorStr(1, 3)
+ a.InsertVector(3, b)
+ verify_patternStr(t, a, 3, 3, 7)
+ // 4
+ a = make_vectorStr(0, 10)
+ b = make_vectorStr(1, 1000)
+ a.InsertVector(8, b)
+ verify_patternStr(t, a, 8, 1000, 2)
+}
+
+
+func TestStrDo(t *testing.T) {
+ const n = 25
+ const salt = 17
+ a := new(StringVector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2StrValue(salt*i))
+ }
+ count := 0
+ a.Do(func(e string) {
+ i := intf2StrValue(e)
+ if i != int2StrValue(count*salt) {
+ t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(a), "should visit", n, "values; did visit", count)
+ }
+
+ b := new(StringVector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ (*b)[i] = int2StrValue(salt * i)
+ }
+ count = 0
+ b.Do(func(e string) {
+ i := intf2StrValue(e)
+ if i != int2StrValue(count*salt) {
+ t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(b), "b) should visit", n, "values; did visit", count)
+ }
+
+ var c StringVector
+ c.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ c[i] = int2StrValue(salt * i)
+ }
+ count = 0
+ c.Do(func(e string) {
+ i := intf2StrValue(e)
+ if i != int2StrValue(count*salt) {
+ t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(c), "c) should visit", n, "values; did visit", count)
+ }
+
+}
+
+
+func TestStrVectorCopy(t *testing.T) {
+ // verify Copy() returns a copy, not simply a slice of the original vector
+ const Len = 10
+ var src StringVector
+ for i := 0; i < Len; i++ {
+ src.Push(int2StrValue(i * i))
+ }
+ dest := src.Copy()
+ for i := 0; i < Len; i++ {
+ src[i] = int2StrValue(-1)
+ v := elem2StrValue(dest[i])
+ if v != int2StrValue(i*i) {
+ t.Error(tname(src), "expected", i*i, "got", v)
+ }
+ }
+}
diff --git a/libgo/go/container/vector/vector.go b/libgo/go/container/vector/vector.go
new file mode 100644
index 000000000..f43e4d23c
--- /dev/null
+++ b/libgo/go/container/vector/vector.go
@@ -0,0 +1,208 @@
+// 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.
+
+// CAUTION: If this file is not vector.go, it was generated
+// automatically from vector.go - DO NOT EDIT in that case!
+
+package vector
+
+
+func (p *Vector) realloc(length, capacity int) (b []interface{}) {
+ if capacity < initialSize {
+ capacity = initialSize
+ }
+ if capacity < length {
+ capacity = length
+ }
+ b = make(Vector, length, capacity)
+ copy(b, *p)
+ *p = b
+ return
+}
+
+
+// Insert n elements at position i.
+func (p *Vector) Expand(i, n int) {
+ a := *p
+
+ // make sure we have enough space
+ len0 := len(a)
+ len1 := len0 + n
+ if len1 <= cap(a) {
+ // enough space - just expand
+ a = a[0:len1]
+ } else {
+ // not enough space - double capacity
+ capb := cap(a) * 2
+ if capb < len1 {
+ // still not enough - use required length
+ capb = len1
+ }
+ // capb >= len1
+ a = p.realloc(len1, capb)
+ }
+
+ // make a hole
+ for j := len0 - 1; j >= i; j-- {
+ a[j+n] = a[j]
+ }
+
+ *p = a
+}
+
+
+// Insert n elements at the end of a vector.
+func (p *Vector) Extend(n int) { p.Expand(len(*p), n) }
+
+
+// Resize changes the length and capacity of a vector.
+// If the new length is shorter than the current length, Resize discards
+// trailing elements. If the new length is longer than the current length,
+// Resize adds the respective zero values for the additional elements. The capacity
+// parameter is ignored unless the new length or capacity is longer than the current
+// capacity. The resized vector's capacity may be larger than the requested capacity.
+func (p *Vector) Resize(length, capacity int) *Vector {
+ a := *p
+
+ if length > cap(a) || capacity > cap(a) {
+ // not enough space or larger capacity requested explicitly
+ a = p.realloc(length, capacity)
+ } else if length < len(a) {
+ // clear trailing elements
+ for i := range a[length:] {
+ var zero interface{}
+ a[length+i] = zero
+ }
+ }
+
+ *p = a[0:length]
+ return p
+}
+
+
+// Len returns the number of elements in the vector.
+// Same as len(*p).
+func (p *Vector) Len() int { return len(*p) }
+
+
+// Cap returns the capacity of the vector; that is, the
+// maximum length the vector can grow without resizing.
+// Same as cap(*p).
+func (p *Vector) Cap() int { return cap(*p) }
+
+
+// At returns the i'th element of the vector.
+func (p *Vector) At(i int) interface{} { return (*p)[i] }
+
+
+// Set sets the i'th element of the vector to value x.
+func (p *Vector) Set(i int, x interface{}) { (*p)[i] = x }
+
+
+// Last returns the element in the vector of highest index.
+func (p *Vector) Last() interface{} { return (*p)[len(*p)-1] }
+
+
+// Copy makes a copy of the vector and returns it.
+func (p *Vector) Copy() Vector {
+ arr := make(Vector, len(*p))
+ copy(arr, *p)
+ return arr
+}
+
+
+// Insert inserts into the vector an element of value x before
+// the current element at index i.
+func (p *Vector) Insert(i int, x interface{}) {
+ p.Expand(i, 1)
+ (*p)[i] = x
+}
+
+
+// Delete deletes the i'th element of the vector. The gap is closed so the old
+// element at index i+1 has index i afterwards.
+func (p *Vector) Delete(i int) {
+ a := *p
+ n := len(a)
+
+ copy(a[i:n-1], a[i+1:n])
+ var zero interface{}
+ a[n-1] = zero // support GC, zero out entry
+ *p = a[0 : n-1]
+}
+
+
+// InsertVector inserts into the vector the contents of the vector
+// x such that the 0th element of x appears at index i after insertion.
+func (p *Vector) InsertVector(i int, x *Vector) {
+ b := *x
+
+ p.Expand(i, len(b))
+ copy((*p)[i:i+len(b)], b)
+}
+
+
+// Cut deletes elements i through j-1, inclusive.
+func (p *Vector) Cut(i, j int) {
+ a := *p
+ n := len(a)
+ m := n - (j - i)
+
+ copy(a[i:m], a[j:n])
+ for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
+ var zero interface{}
+ a[k] = zero // support GC, zero out entries
+ }
+
+ *p = a[0:m]
+}
+
+
+// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
+// The elements are copied. The original vector is unchanged.
+func (p *Vector) Slice(i, j int) *Vector {
+ var s Vector
+ s.realloc(j-i, 0) // will fail in Init() if j < i
+ copy(s, (*p)[i:j])
+ return &s
+}
+
+
+// Convenience wrappers
+
+// Push appends x to the end of the vector.
+func (p *Vector) Push(x interface{}) { p.Insert(len(*p), x) }
+
+
+// Pop deletes the last element of the vector.
+func (p *Vector) Pop() interface{} {
+ a := *p
+
+ i := len(a) - 1
+ x := a[i]
+ var zero interface{}
+ a[i] = zero // support GC, zero out entry
+ *p = a[0:i]
+ return x
+}
+
+
+// AppendVector appends the entire vector x to the end of this vector.
+func (p *Vector) AppendVector(x *Vector) { p.InsertVector(len(*p), x) }
+
+
+// Swap exchanges the elements at indexes i and j.
+func (p *Vector) Swap(i, j int) {
+ a := *p
+ a[i], a[j] = a[j], a[i]
+}
+
+
+// Do calls function f for each element of the vector, in order.
+// The behavior of Do is undefined if f changes *p.
+func (p *Vector) Do(f func(elem interface{})) {
+ for _, e := range *p {
+ f(e)
+ }
+}
diff --git a/libgo/go/container/vector/vector_test.go b/libgo/go/container/vector/vector_test.go
new file mode 100644
index 000000000..a9c4ceb55
--- /dev/null
+++ b/libgo/go/container/vector/vector_test.go
@@ -0,0 +1,344 @@
+// 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.
+
+// CAUTION: If this file is not vector_test.go, it was generated
+// automatically from vector_test.go - DO NOT EDIT in that case!
+
+package vector
+
+import "testing"
+
+
+func TestZeroLen(t *testing.T) {
+ a := new(Vector)
+ if a.Len() != 0 {
+ t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
+ }
+ if len(*a) != 0 {
+ t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
+ }
+ var b Vector
+ if b.Len() != 0 {
+ t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
+ }
+ if len(b) != 0 {
+ t.Errorf("%T: B4) expected 0, got %d", b, len(b))
+ }
+}
+
+
+func TestResize(t *testing.T) {
+ var a Vector
+ checkSize(t, &a, 0, 0)
+ checkSize(t, a.Resize(0, 5), 0, 5)
+ checkSize(t, a.Resize(1, 0), 1, 5)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ checkSize(t, a.Resize(5, 0), 5, 10)
+ checkSize(t, a.Resize(3, 8), 3, 10)
+ checkSize(t, a.Resize(0, 100), 0, 100)
+ checkSize(t, a.Resize(11, 100), 11, 100)
+}
+
+
+func TestResize2(t *testing.T) {
+ var a Vector
+ checkSize(t, &a, 0, 0)
+ a.Push(int2Value(1))
+ a.Push(int2Value(2))
+ a.Push(int2Value(3))
+ a.Push(int2Value(4))
+ checkSize(t, &a, 4, 4)
+ checkSize(t, a.Resize(10, 0), 10, 10)
+ for i := 4; i < a.Len(); i++ {
+ if a.At(i) != zero {
+ t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, zero, a.At(i))
+ }
+ }
+ for i := 4; i < len(a); i++ {
+ if a[i] != zero {
+ t.Errorf("%T: expected a[%d] == %v; found %v", a, i, zero, a[i])
+ }
+ }
+}
+
+
+func checkZero(t *testing.T, a *Vector, i int) {
+ for j := 0; j < i; j++ {
+ if a.At(j) == zero {
+ t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
+ }
+ if (*a)[j] == zero {
+ t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
+ }
+ }
+ for ; i < a.Len(); i++ {
+ if a.At(i) != zero {
+ t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, zero, a.At(i))
+ }
+ if (*a)[i] != zero {
+ t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, zero, (*a)[i])
+ }
+ }
+}
+
+
+func TestTrailingElements(t *testing.T) {
+ var a Vector
+ for i := 0; i < 10; i++ {
+ a.Push(int2Value(i + 1))
+ }
+ checkZero(t, &a, 10)
+ checkSize(t, &a, 10, 16)
+ checkSize(t, a.Resize(5, 0), 5, 16)
+ checkSize(t, a.Resize(10, 0), 10, 16)
+ checkZero(t, &a, 5)
+}
+
+
+func TestAccess(t *testing.T) {
+ const n = 100
+ var a Vector
+ a.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2Value(val(i)))
+ }
+ for i := 0; i < n; i++ {
+ if elem2Value(a.At(i)) != int2Value(val(i)) {
+ t.Error(i)
+ }
+ }
+ var b Vector
+ b.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ b[i] = int2Value(val(i))
+ }
+ for i := 0; i < n; i++ {
+ if elem2Value(b[i]) != int2Value(val(i)) {
+ t.Error(i)
+ }
+ }
+}
+
+
+func TestInsertDeleteClear(t *testing.T) {
+ const n = 100
+ var a Vector
+
+ for i := 0; i < n; i++ {
+ if a.Len() != i {
+ t.Errorf("%T: A) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: A) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ a.Insert(0, int2Value(val(i)))
+ if elem2Value(a.Last()) != int2Value(val(0)) {
+ t.Errorf("%T: B", a)
+ }
+ }
+ for i := n - 1; i >= 0; i-- {
+ if elem2Value(a.Last()) != int2Value(val(0)) {
+ t.Errorf("%T: C", a)
+ }
+ if elem2Value(a.At(0)) != int2Value(val(i)) {
+ t.Errorf("%T: D", a)
+ }
+ if elem2Value(a[0]) != int2Value(val(i)) {
+ t.Errorf("%T: D2", a)
+ }
+ a.Delete(0)
+ if a.Len() != i {
+ t.Errorf("%T: E) wrong Len() %d (expected %d)", a, a.Len(), i)
+ }
+ if len(a) != i {
+ t.Errorf("%T: E) wrong len() %d (expected %d)", a, len(a), i)
+ }
+ }
+
+ if a.Len() != 0 {
+ t.Errorf("%T: F) wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: F) wrong len() %d (expected 0)", a, len(a))
+ }
+ for i := 0; i < n; i++ {
+ a.Push(int2Value(val(i)))
+ if a.Len() != i+1 {
+ t.Errorf("%T: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
+ }
+ if len(a) != i+1 {
+ t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
+ }
+ if elem2Value(a.Last()) != int2Value(val(i)) {
+ t.Errorf("%T: H", a)
+ }
+ }
+ a.Resize(0, 0)
+ if a.Len() != 0 {
+ t.Errorf("%T: I wrong Len() %d (expected 0)", a, a.Len())
+ }
+ if len(a) != 0 {
+ t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
+ }
+
+ const m = 5
+ for j := 0; j < m; j++ {
+ a.Push(int2Value(j))
+ for i := 0; i < n; i++ {
+ x := val(i)
+ a.Push(int2Value(x))
+ if elem2Value(a.Pop()) != int2Value(x) {
+ t.Errorf("%T: J", a)
+ }
+ if a.Len() != j+1 {
+ t.Errorf("%T: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
+ }
+ if len(a) != j+1 {
+ t.Errorf("%T: K) wrong len() %d (expected %d)", a, len(a), j+1)
+ }
+ }
+ }
+ if a.Len() != m {
+ t.Errorf("%T: L) wrong Len() %d (expected %d)", a, a.Len(), m)
+ }
+ if len(a) != m {
+ t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
+ }
+}
+
+
+func verify_slice(t *testing.T, x *Vector, elt, i, j int) {
+ for k := i; k < j; k++ {
+ if elem2Value(x.At(k)) != int2Value(elt) {
+ t.Errorf("%T: M) wrong [%d] element %v (expected %v)", x, k, elem2Value(x.At(k)), int2Value(elt))
+ }
+ }
+
+ s := x.Slice(i, j)
+ for k, n := 0, j-i; k < n; k++ {
+ if elem2Value(s.At(k)) != int2Value(elt) {
+ t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2Value(x.At(k)), int2Value(elt))
+ }
+ }
+}
+
+
+func verify_pattern(t *testing.T, x *Vector, a, b, c int) {
+ n := a + b + c
+ if x.Len() != n {
+ t.Errorf("%T: O) wrong Len() %d (expected %d)", x, x.Len(), n)
+ }
+ if len(*x) != n {
+ t.Errorf("%T: O) wrong len() %d (expected %d)", x, len(*x), n)
+ }
+ verify_slice(t, x, 0, 0, a)
+ verify_slice(t, x, 1, a, a+b)
+ verify_slice(t, x, 0, a+b, n)
+}
+
+
+func make_vector(elt, len int) *Vector {
+ x := new(Vector).Resize(len, 0)
+ for i := 0; i < len; i++ {
+ x.Set(i, int2Value(elt))
+ }
+ return x
+}
+
+
+func TestInsertVector(t *testing.T) {
+ // 1
+ a := make_vector(0, 0)
+ b := make_vector(1, 10)
+ a.InsertVector(0, b)
+ verify_pattern(t, a, 0, 10, 0)
+ // 2
+ a = make_vector(0, 10)
+ b = make_vector(1, 0)
+ a.InsertVector(5, b)
+ verify_pattern(t, a, 5, 0, 5)
+ // 3
+ a = make_vector(0, 10)
+ b = make_vector(1, 3)
+ a.InsertVector(3, b)
+ verify_pattern(t, a, 3, 3, 7)
+ // 4
+ a = make_vector(0, 10)
+ b = make_vector(1, 1000)
+ a.InsertVector(8, b)
+ verify_pattern(t, a, 8, 1000, 2)
+}
+
+
+func TestDo(t *testing.T) {
+ const n = 25
+ const salt = 17
+ a := new(Vector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ a.Set(i, int2Value(salt*i))
+ }
+ count := 0
+ a.Do(func(e interface{}) {
+ i := intf2Value(e)
+ if i != int2Value(count*salt) {
+ t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(a), "should visit", n, "values; did visit", count)
+ }
+
+ b := new(Vector).Resize(n, 0)
+ for i := 0; i < n; i++ {
+ (*b)[i] = int2Value(salt * i)
+ }
+ count = 0
+ b.Do(func(e interface{}) {
+ i := intf2Value(e)
+ if i != int2Value(count*salt) {
+ t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(b), "b) should visit", n, "values; did visit", count)
+ }
+
+ var c Vector
+ c.Resize(n, 0)
+ for i := 0; i < n; i++ {
+ c[i] = int2Value(salt * i)
+ }
+ count = 0
+ c.Do(func(e interface{}) {
+ i := intf2Value(e)
+ if i != int2Value(count*salt) {
+ t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
+ }
+ count++
+ })
+ if count != n {
+ t.Error(tname(c), "c) should visit", n, "values; did visit", count)
+ }
+
+}
+
+
+func TestVectorCopy(t *testing.T) {
+ // verify Copy() returns a copy, not simply a slice of the original vector
+ const Len = 10
+ var src Vector
+ for i := 0; i < Len; i++ {
+ src.Push(int2Value(i * i))
+ }
+ dest := src.Copy()
+ for i := 0; i < Len; i++ {
+ src[i] = int2Value(-1)
+ v := elem2Value(dest[i])
+ if v != int2Value(i*i) {
+ t.Error(tname(src), "expected", i*i, "got", v)
+ }
+ }
+}
diff --git a/libgo/go/crypto/aes/aes_test.go b/libgo/go/crypto/aes/aes_test.go
new file mode 100644
index 000000000..2136d447d
--- /dev/null
+++ b/libgo/go/crypto/aes/aes_test.go
@@ -0,0 +1,350 @@
+// 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 aes
+
+import (
+ "testing"
+)
+
+// See const.go for overview of math here.
+
+// Test that powx is initialized correctly.
+// (Can adapt this code to generate it too.)
+func TestPowx(t *testing.T) {
+ p := 1
+ for i := 0; i < len(powx); i++ {
+ if powx[i] != byte(p) {
+ t.Errorf("powx[%d] = %#x, want %#x", i, powx[i], p)
+ }
+ p <<= 1
+ if p&0x100 != 0 {
+ p ^= poly
+ }
+ }
+}
+
+// Multiply b and c as GF(2) polynomials modulo poly
+func mul(b, c uint32) uint32 {
+ i := b
+ j := c
+ s := uint32(0)
+ for k := uint32(1); k < 0x100 && j != 0; k <<= 1 {
+ // Invariant: k == 1<<n, i == b * xⁿ
+
+ if j&k != 0 {
+ // s += i in GF(2); xor in binary
+ s ^= i
+ j ^= k // turn off bit to end loop early
+ }
+
+ // i *= x in GF(2) modulo the polynomial
+ i <<= 1
+ if i&0x100 != 0 {
+ i ^= poly
+ }
+ }
+ return s
+}
+
+// Test all mul inputs against bit-by-bit n² algorithm.
+func TestMul(t *testing.T) {
+ for i := uint32(0); i < 256; i++ {
+ for j := uint32(0); j < 256; j++ {
+ // Multiply i, j bit by bit.
+ s := uint8(0)
+ for k := uint(0); k < 8; k++ {
+ for l := uint(0); l < 8; l++ {
+ if i&(1<<k) != 0 && j&(1<<l) != 0 {
+ s ^= powx[k+l]
+ }
+ }
+ }
+ if x := mul(i, j); x != uint32(s) {
+ t.Fatalf("mul(%#x, %#x) = %#x, want %#x", i, j, x, s)
+ }
+ }
+ }
+}
+
+// Check that S-boxes are inverses of each other.
+// They have more structure that we could test,
+// but if this sanity check passes, we'll assume
+// the cut and paste from the FIPS PDF worked.
+func TestSboxes(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ if j := sbox0[sbox1[i]]; j != byte(i) {
+ t.Errorf("sbox0[sbox1[%#x]] = %#x", i, j)
+ }
+ if j := sbox1[sbox0[i]]; j != byte(i) {
+ t.Errorf("sbox1[sbox0[%#x]] = %#x", i, j)
+ }
+ }
+}
+
+// Test that encryption tables are correct.
+// (Can adapt this code to generate them too.)
+func TestTe(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ s := uint32(sbox0[i])
+ s2 := mul(s, 2)
+ s3 := mul(s, 3)
+ w := s2<<24 | s<<16 | s<<8 | s3
+ for j := 0; j < 4; j++ {
+ if x := te[j][i]; x != w {
+ t.Fatalf("te[%d][%d] = %#x, want %#x", j, i, x, w)
+ }
+ w = w<<24 | w>>8
+ }
+ }
+}
+
+// Test that decryption tables are correct.
+// (Can adapt this code to generate them too.)
+func TestTd(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ s := uint32(sbox1[i])
+ s9 := mul(s, 0x9)
+ sb := mul(s, 0xb)
+ sd := mul(s, 0xd)
+ se := mul(s, 0xe)
+ w := se<<24 | s9<<16 | sd<<8 | sb
+ for j := 0; j < 4; j++ {
+ if x := td[j][i]; x != w {
+ t.Fatalf("td[%d][%d] = %#x, want %#x", j, i, x, w)
+ }
+ w = w<<24 | w>>8
+ }
+ }
+}
+
+// Test vectors are from FIPS 197:
+// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+// Appendix A of FIPS 197: Key expansion examples
+type KeyTest struct {
+ key []byte
+ enc []uint32
+ dec []uint32 // decryption expansion; not in FIPS 197, computed from C implementation.
+}
+
+var keyTests = []KeyTest{
+ {
+ // A.1. Expansion of a 128-bit Cipher Key
+ []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
+ []uint32{
+ 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c,
+ 0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605,
+ 0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f,
+ 0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b,
+ 0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00,
+ 0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc,
+ 0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd,
+ 0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f,
+ 0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f,
+ 0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e,
+ 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
+ },
+ []uint32{
+ 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
+ 0xc7b5a63, 0x1319eafe, 0xb0398890, 0x664cfbb4,
+ 0xdf7d925a, 0x1f62b09d, 0xa320626e, 0xd6757324,
+ 0x12c07647, 0xc01f22c7, 0xbc42d2f3, 0x7555114a,
+ 0x6efcd876, 0xd2df5480, 0x7c5df034, 0xc917c3b9,
+ 0x6ea30afc, 0xbc238cf6, 0xae82a4b4, 0xb54a338d,
+ 0x90884413, 0xd280860a, 0x12a12842, 0x1bc89739,
+ 0x7c1f13f7, 0x4208c219, 0xc021ae48, 0x969bf7b,
+ 0xcc7505eb, 0x3e17d1ee, 0x82296c51, 0xc9481133,
+ 0x2b3708a7, 0xf262d405, 0xbc3ebdbf, 0x4b617d62,
+ 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x9cf4f3c,
+ },
+ },
+ {
+ // A.2. Expansion of a 192-bit Cipher Key
+ []byte{
+ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
+ },
+ []uint32{
+ 0x8e73b0f7, 0xda0e6452, 0xc810f32b, 0x809079e5,
+ 0x62f8ead2, 0x522c6b7b, 0xfe0c91f7, 0x2402f5a5,
+ 0xec12068e, 0x6c827f6b, 0x0e7a95b9, 0x5c56fec2,
+ 0x4db7b4bd, 0x69b54118, 0x85a74796, 0xe92538fd,
+ 0xe75fad44, 0xbb095386, 0x485af057, 0x21efb14f,
+ 0xa448f6d9, 0x4d6dce24, 0xaa326360, 0x113b30e6,
+ 0xa25e7ed5, 0x83b1cf9a, 0x27f93943, 0x6a94f767,
+ 0xc0a69407, 0xd19da4e1, 0xec1786eb, 0x6fa64971,
+ 0x485f7032, 0x22cb8755, 0xe26d1352, 0x33f0b7b3,
+ 0x40beeb28, 0x2f18a259, 0x6747d26b, 0x458c553e,
+ 0xa7e1466c, 0x9411f1df, 0x821f750a, 0xad07d753,
+ 0xca400538, 0x8fcc5006, 0x282d166a, 0xbc3ce7b5,
+ 0xe98ba06f, 0x448c773c, 0x8ecc7204, 0x01002202,
+ },
+ nil,
+ },
+ {
+ // A.3. Expansion of a 256-bit Cipher Key
+ []byte{
+ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
+ },
+ []uint32{
+ 0x603deb10, 0x15ca71be, 0x2b73aef0, 0x857d7781,
+ 0x1f352c07, 0x3b6108d7, 0x2d9810a3, 0x0914dff4,
+ 0x9ba35411, 0x8e6925af, 0xa51a8b5f, 0x2067fcde,
+ 0xa8b09c1a, 0x93d194cd, 0xbe49846e, 0xb75d5b9a,
+ 0xd59aecb8, 0x5bf3c917, 0xfee94248, 0xde8ebe96,
+ 0xb5a9328a, 0x2678a647, 0x98312229, 0x2f6c79b3,
+ 0x812c81ad, 0xdadf48ba, 0x24360af2, 0xfab8b464,
+ 0x98c5bfc9, 0xbebd198e, 0x268c3ba7, 0x09e04214,
+ 0x68007bac, 0xb2df3316, 0x96e939e4, 0x6c518d80,
+ 0xc814e204, 0x76a9fb8a, 0x5025c02d, 0x59c58239,
+ 0xde136967, 0x6ccc5a71, 0xfa256395, 0x9674ee15,
+ 0x5886ca5d, 0x2e2f31d7, 0x7e0af1fa, 0x27cf73c3,
+ 0x749c47ab, 0x18501dda, 0xe2757e4f, 0x7401905a,
+ 0xcafaaae3, 0xe4d59b34, 0x9adf6ace, 0xbd10190d,
+ 0xfe4890d1, 0xe6188d0b, 0x046df344, 0x706c631e,
+ },
+ nil,
+ },
+}
+
+// Test key expansion against FIPS 197 examples.
+func TestExpandKey(t *testing.T) {
+L:
+ for i, tt := range keyTests {
+ enc := make([]uint32, len(tt.enc))
+ var dec []uint32
+ if tt.dec != nil {
+ dec = make([]uint32, len(tt.dec))
+ }
+ expandKey(tt.key, enc, dec)
+ for j, v := range enc {
+ if v != tt.enc[j] {
+ t.Errorf("key %d: enc[%d] = %#x, want %#x", i, j, v, tt.enc[j])
+ continue L
+ }
+ }
+ if dec != nil {
+ for j, v := range dec {
+ if v != tt.dec[j] {
+ t.Errorf("key %d: dec[%d] = %#x, want %#x", i, j, v, tt.dec[j])
+ continue L
+ }
+ }
+ }
+ }
+}
+
+// Appendix B, C of FIPS 197: Cipher examples, Example vectors.
+type CryptTest struct {
+ key []byte
+ in []byte
+ out []byte
+}
+
+var encryptTests = []CryptTest{
+ {
+ // Appendix B.
+ []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
+ []byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34},
+ []byte{0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32},
+ },
+ {
+ // Appendix C.1. AES-128
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+ []byte{0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a},
+ },
+ {
+ // Appendix C.2. AES-192
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ },
+ []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+ []byte{0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91},
+ },
+ {
+ // Appendix C.3. AES-256
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ },
+ []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+ []byte{0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89},
+ },
+}
+
+// Test encryptBlock against FIPS 197 examples.
+func TestEncryptBlock(t *testing.T) {
+ for i, tt := range encryptTests {
+ n := len(tt.key) + 28
+ enc := make([]uint32, n)
+ dec := make([]uint32, n)
+ expandKey(tt.key, enc, dec)
+ out := make([]byte, len(tt.in))
+ encryptBlock(enc, out, tt.in)
+ for j, v := range out {
+ if v != tt.out[j] {
+ t.Errorf("encryptBlock %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
+ break
+ }
+ }
+ }
+}
+
+// Test decryptBlock against FIPS 197 examples.
+func TestDecryptBlock(t *testing.T) {
+ for i, tt := range encryptTests {
+ n := len(tt.key) + 28
+ enc := make([]uint32, n)
+ dec := make([]uint32, n)
+ expandKey(tt.key, enc, dec)
+ plain := make([]byte, len(tt.in))
+ decryptBlock(dec, plain, tt.out)
+ for j, v := range plain {
+ if v != tt.in[j] {
+ t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
+ break
+ }
+ }
+ }
+}
+
+// Test Cipher Encrypt method against FIPS 197 examples.
+func TestCipherEncrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ out := make([]byte, len(tt.in))
+ c.Encrypt(out, tt.in)
+ for j, v := range out {
+ if v != tt.out[j] {
+ t.Errorf("Cipher.Encrypt %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
+ break
+ }
+ }
+ }
+}
+
+// Test Cipher Decrypt against FIPS 197 examples.
+func TestCipherDecrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ plain := make([]byte, len(tt.in))
+ c.Decrypt(plain, tt.out)
+ for j, v := range plain {
+ if v != tt.in[j] {
+ t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
+ break
+ }
+ }
+ }
+}
diff --git a/libgo/go/crypto/aes/block.go b/libgo/go/crypto/aes/block.go
new file mode 100644
index 000000000..130cd011c
--- /dev/null
+++ b/libgo/go/crypto/aes/block.go
@@ -0,0 +1,176 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This Go implementation is derived in part from the reference
+// ANSI C implementation, which carries the following notice:
+//
+// rijndael-alg-fst.c
+//
+// @version 3.0 (December 2000)
+//
+// Optimised ANSI C code for the Rijndael cipher (now AES)
+//
+// @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+// @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+// @author Paulo Barreto <paulo.barreto@terra.com.br>
+//
+// This code is hereby placed in the public domain.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// See FIPS 197 for specification, and see Daemen and Rijmen's Rijndael submission
+// for implementation details.
+// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+// http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf
+
+package aes
+
+// Encrypt one block from src into dst, using the expanded key xk.
+func encryptBlock(xk []uint32, dst, src []byte) {
+ var s0, s1, s2, s3, t0, t1, t2, t3 uint32
+
+ s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+ s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11])
+ s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15])
+
+ // First round just XORs input with key.
+ s0 ^= xk[0]
+ s1 ^= xk[1]
+ s2 ^= xk[2]
+ s3 ^= xk[3]
+
+ // Middle rounds shuffle using tables.
+ // Number of rounds is set by length of expanded key.
+ nr := len(xk)/4 - 2 // - 2: one above, one more below
+ k := 4
+ for r := 0; r < nr; r++ {
+ t0 = xk[k+0] ^ te[0][s0>>24] ^ te[1][s1>>16&0xff] ^ te[2][s2>>8&0xff] ^ te[3][s3&0xff]
+ t1 = xk[k+1] ^ te[0][s1>>24] ^ te[1][s2>>16&0xff] ^ te[2][s3>>8&0xff] ^ te[3][s0&0xff]
+ t2 = xk[k+2] ^ te[0][s2>>24] ^ te[1][s3>>16&0xff] ^ te[2][s0>>8&0xff] ^ te[3][s1&0xff]
+ t3 = xk[k+3] ^ te[0][s3>>24] ^ te[1][s0>>16&0xff] ^ te[2][s1>>8&0xff] ^ te[3][s2&0xff]
+ k += 4
+ s0, s1, s2, s3 = t0, t1, t2, t3
+ }
+
+ // Last round uses s-box directly and XORs to produce output.
+ s0 = uint32(sbox0[t0>>24])<<24 | uint32(sbox0[t1>>16&0xff])<<16 | uint32(sbox0[t2>>8&0xff])<<8 | uint32(sbox0[t3&0xff])
+ s1 = uint32(sbox0[t1>>24])<<24 | uint32(sbox0[t2>>16&0xff])<<16 | uint32(sbox0[t3>>8&0xff])<<8 | uint32(sbox0[t0&0xff])
+ s2 = uint32(sbox0[t2>>24])<<24 | uint32(sbox0[t3>>16&0xff])<<16 | uint32(sbox0[t0>>8&0xff])<<8 | uint32(sbox0[t1&0xff])
+ s3 = uint32(sbox0[t3>>24])<<24 | uint32(sbox0[t0>>16&0xff])<<16 | uint32(sbox0[t1>>8&0xff])<<8 | uint32(sbox0[t2&0xff])
+
+ s0 ^= xk[k+0]
+ s1 ^= xk[k+1]
+ s2 ^= xk[k+2]
+ s3 ^= xk[k+3]
+
+ dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0)
+ dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1)
+ dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2)
+ dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3)
+}
+
+// Decrypt one block from src into dst, using the expanded key xk.
+func decryptBlock(xk []uint32, dst, src []byte) {
+ var s0, s1, s2, s3, t0, t1, t2, t3 uint32
+
+ s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+ s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11])
+ s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15])
+
+ // First round just XORs input with key.
+ s0 ^= xk[0]
+ s1 ^= xk[1]
+ s2 ^= xk[2]
+ s3 ^= xk[3]
+
+ // Middle rounds shuffle using tables.
+ // Number of rounds is set by length of expanded key.
+ nr := len(xk)/4 - 2 // - 2: one above, one more below
+ k := 4
+ for r := 0; r < nr; r++ {
+ t0 = xk[k+0] ^ td[0][s0>>24] ^ td[1][s3>>16&0xff] ^ td[2][s2>>8&0xff] ^ td[3][s1&0xff]
+ t1 = xk[k+1] ^ td[0][s1>>24] ^ td[1][s0>>16&0xff] ^ td[2][s3>>8&0xff] ^ td[3][s2&0xff]
+ t2 = xk[k+2] ^ td[0][s2>>24] ^ td[1][s1>>16&0xff] ^ td[2][s0>>8&0xff] ^ td[3][s3&0xff]
+ t3 = xk[k+3] ^ td[0][s3>>24] ^ td[1][s2>>16&0xff] ^ td[2][s1>>8&0xff] ^ td[3][s0&0xff]
+ k += 4
+ s0, s1, s2, s3 = t0, t1, t2, t3
+ }
+
+ // Last round uses s-box directly and XORs to produce output.
+ s0 = uint32(sbox1[t0>>24])<<24 | uint32(sbox1[t3>>16&0xff])<<16 | uint32(sbox1[t2>>8&0xff])<<8 | uint32(sbox1[t1&0xff])
+ s1 = uint32(sbox1[t1>>24])<<24 | uint32(sbox1[t0>>16&0xff])<<16 | uint32(sbox1[t3>>8&0xff])<<8 | uint32(sbox1[t2&0xff])
+ s2 = uint32(sbox1[t2>>24])<<24 | uint32(sbox1[t1>>16&0xff])<<16 | uint32(sbox1[t0>>8&0xff])<<8 | uint32(sbox1[t3&0xff])
+ s3 = uint32(sbox1[t3>>24])<<24 | uint32(sbox1[t2>>16&0xff])<<16 | uint32(sbox1[t1>>8&0xff])<<8 | uint32(sbox1[t0&0xff])
+
+ s0 ^= xk[k+0]
+ s1 ^= xk[k+1]
+ s2 ^= xk[k+2]
+ s3 ^= xk[k+3]
+
+ dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0)
+ dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1)
+ dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2)
+ dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3)
+}
+
+// Apply sbox0 to each byte in w.
+func subw(w uint32) uint32 {
+ return uint32(sbox0[w>>24])<<24 |
+ uint32(sbox0[w>>16&0xff])<<16 |
+ uint32(sbox0[w>>8&0xff])<<8 |
+ uint32(sbox0[w&0xff])
+}
+
+// Rotate
+func rotw(w uint32) uint32 { return w<<8 | w>>24 }
+
+// Key expansion algorithm. See FIPS-197, Figure 11.
+// Their rcon[i] is our powx[i-1] << 24.
+func expandKey(key []byte, enc, dec []uint32) {
+ // Encryption key setup.
+ var i int
+ nk := len(key) / 4
+ for i = 0; i < nk; i++ {
+ enc[i] = uint32(key[4*i])<<24 | uint32(key[4*i+1])<<16 | uint32(key[4*i+2])<<8 | uint32(key[4*i+3])
+ }
+ for ; i < len(enc); i++ {
+ t := enc[i-1]
+ if i%nk == 0 {
+ t = subw(rotw(t)) ^ (uint32(powx[i/nk-1]) << 24)
+ } else if nk > 6 && i%nk == 4 {
+ t = subw(t)
+ }
+ enc[i] = enc[i-nk] ^ t
+ }
+
+ // Derive decryption key from encryption key.
+ // Reverse the 4-word round key sets from enc to produce dec.
+ // All sets but the first and last get the MixColumn transform applied.
+ if dec == nil {
+ return
+ }
+ n := len(enc)
+ for i := 0; i < n; i += 4 {
+ ei := n - i - 4
+ for j := 0; j < 4; j++ {
+ x := enc[ei+j]
+ if i > 0 && i+4 < n {
+ x = td[0][sbox0[x>>24]] ^ td[1][sbox0[x>>16&0xff]] ^ td[2][sbox0[x>>8&0xff]] ^ td[3][sbox0[x&0xff]]
+ }
+ dec[i+j] = x
+ }
+ }
+}
diff --git a/libgo/go/crypto/aes/cipher.go b/libgo/go/crypto/aes/cipher.go
new file mode 100644
index 000000000..3a9d02318
--- /dev/null
+++ b/libgo/go/crypto/aes/cipher.go
@@ -0,0 +1,71 @@
+// 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 aes
+
+import (
+ "os"
+ "strconv"
+)
+
+// The AES block size in bytes.
+const BlockSize = 16
+
+// A Cipher is an instance of AES encryption using a particular key.
+type Cipher struct {
+ enc []uint32
+ dec []uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new Cipher.
+// The key argument should be the AES key,
+// either 16, 24, or 32 bytes to select
+// AES-128, AES-192, or AES-256.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ k := len(key)
+ switch k {
+ default:
+ return nil, KeySizeError(k)
+ case 16, 24, 32:
+ break
+ }
+
+ n := k + 28
+ c := &Cipher{make([]uint32, n), make([]uint32, n)}
+ expandKey(key, c.enc, c.dec)
+ return c, nil
+}
+
+// BlockSize returns the AES block size, 16 bytes.
+// It is necessary to satisfy the Cipher interface in the
+// package "crypto/block".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 16-byte buffer src using the key k
+// and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.enc, dst, src) }
+
+// Decrypt decrypts the 16-byte buffer src using the key k
+// and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c.dec, dst, src) }
+
+// Reset zeros the key data, so that it will no longer
+// appear in the process's memory.
+func (c *Cipher) Reset() {
+ for i := 0; i < len(c.enc); i++ {
+ c.enc[i] = 0
+ }
+ for i := 0; i < len(c.dec); i++ {
+ c.dec[i] = 0
+ }
+}
diff --git a/libgo/go/crypto/aes/const.go b/libgo/go/crypto/aes/const.go
new file mode 100644
index 000000000..97a5b64ec
--- /dev/null
+++ b/libgo/go/crypto/aes/const.go
@@ -0,0 +1,362 @@
+// 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.
+
+// AES constants - 8720 bytes of initialized data.
+
+// This package implements AES encryption (formerly Rijndael),
+// as defined in U.S. Federal Information Processing Standards Publication 197.
+package aes
+
+// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+// AES is based on the mathematical behavior of binary polynomials
+// (polynomials over GF(2)) modulo the irreducible polynomial x⁸ + x⁴ + x² + x + 1.
+// Addition of these binary polynomials corresponds to binary xor.
+// Reducing mod poly corresponds to binary xor with poly every
+// time a 0x100 bit appears.
+const poly = 1<<8 | 1<<4 | 1<<3 | 1<<1 | 1<<0 // x⁸ + x⁴ + x² + x + 1
+
+// Powers of x mod poly in GF(2).
+var powx = [16]byte{
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+}
+
+// FIPS-197 Figure 7. S-box substitution values in hexadecimal format.
+var sbox0 = [256]byte{
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
+}
+
+// FIPS-197 Figure 14. Inverse S-box substitution values in hexadecimal format.
+var sbox1 = [256]byte{
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
+}
+
+// Lookup tables for encryption.
+// These can be recomputed by adapting the tests in aes_test.go.
+
+var te = [4][256]uint32{
+ {
+ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
+ 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
+ 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
+ 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
+ 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
+ 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
+ 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
+ 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
+ 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
+ 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
+ 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
+ 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
+ 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
+ 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
+ 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
+ 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
+ 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
+ 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
+ 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
+ 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
+ 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
+ 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
+ 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
+ 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
+ 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
+ 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
+ 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
+ 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
+ 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
+ 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
+ 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
+ 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a,
+ },
+ {
+ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5,
+ 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676,
+ 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
+ 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0,
+ 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc,
+ 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
+ 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a,
+ 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575,
+ 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
+ 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484,
+ 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b,
+ 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
+ 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585,
+ 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8,
+ 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
+ 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2,
+ 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717,
+ 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
+ 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888,
+ 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb,
+ 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
+ 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979,
+ 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9,
+ 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
+ 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6,
+ 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a,
+ 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
+ 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e,
+ 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494,
+ 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
+ 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868,
+ 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
+ },
+ {
+ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5,
+ 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76,
+ 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
+ 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0,
+ 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc,
+ 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
+ 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a,
+ 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75,
+ 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
+ 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384,
+ 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b,
+ 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
+ 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185,
+ 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8,
+ 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
+ 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2,
+ 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17,
+ 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
+ 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88,
+ 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb,
+ 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
+ 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279,
+ 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9,
+ 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
+ 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6,
+ 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a,
+ 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
+ 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e,
+ 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394,
+ 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
+ 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068,
+ 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
+ },
+ {
+ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491,
+ 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec,
+ 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
+ 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
+ 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83,
+ 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
+ 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f,
+ 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea,
+ 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
+ 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713,
+ 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6,
+ 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
+ 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411,
+ 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b,
+ 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
+ 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf,
+ 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e,
+ 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
+ 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b,
+ 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad,
+ 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
+ 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2,
+ 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049,
+ 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
+ 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197,
+ 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
+ 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
+ 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927,
+ 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733,
+ 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
+ 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0,
+ 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
+ },
+}
+
+// Lookup tables for decryption.
+// These can be recomputed by adapting the tests in aes_test.go.
+
+var td = [4][256]uint32{
+ {
+ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
+ 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
+ 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
+ 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
+ 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
+ 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
+ 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
+ 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
+ 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
+ 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
+ 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
+ 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
+ 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
+ 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
+ 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
+ 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
+ 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
+ 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
+ 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
+ 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
+ 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
+ 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
+ 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
+ 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
+ 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
+ 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
+ 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
+ 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
+ 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
+ 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
+ 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
+ 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742,
+ },
+ {
+ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303,
+ 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3,
+ 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9,
+ 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8,
+ 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a,
+ 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b,
+ 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab,
+ 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682,
+ 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe,
+ 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10,
+ 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015,
+ 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee,
+ 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72,
+ 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e,
+ 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
+ 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9,
+ 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e,
+ 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611,
+ 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3,
+ 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390,
+ 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf,
+ 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af,
+ 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb,
+ 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8,
+ 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266,
+ 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6,
+ 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551,
+ 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647,
+ 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1,
+ 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db,
+ 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95,
+ 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857,
+ },
+ {
+ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3,
+ 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562,
+ 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3,
+ 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9,
+ 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce,
+ 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908,
+ 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655,
+ 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16,
+ 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6,
+ 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e,
+ 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050,
+ 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8,
+ 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a,
+ 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436,
+ 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
+ 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e,
+ 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb,
+ 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6,
+ 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1,
+ 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233,
+ 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad,
+ 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3,
+ 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b,
+ 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15,
+ 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2,
+ 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791,
+ 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665,
+ 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6,
+ 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47,
+ 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844,
+ 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d,
+ 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8,
+ },
+ {
+ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b,
+ 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5,
+ 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b,
+ 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e,
+ 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d,
+ 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9,
+ 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66,
+ 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced,
+ 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4,
+ 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd,
+ 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60,
+ 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79,
+ 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c,
+ 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24,
+ 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
+ 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814,
+ 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b,
+ 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084,
+ 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077,
+ 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22,
+ 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f,
+ 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582,
+ 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb,
+ 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef,
+ 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035,
+ 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17,
+ 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46,
+ 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d,
+ 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a,
+ 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678,
+ 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff,
+ 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0,
+ },
+}
diff --git a/libgo/go/crypto/block/cbc.go b/libgo/go/crypto/block/cbc.go
new file mode 100644
index 000000000..23229c09f
--- /dev/null
+++ b/libgo/go/crypto/block/cbc.go
@@ -0,0 +1,71 @@
+// 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.
+
+// Cipher block chaining (CBC) mode.
+
+// CBC provides confidentiality by xoring (chaining) each plaintext block
+// with the previous ciphertext block before applying the block cipher.
+
+// See NIST SP 800-38A, pp 10-11
+
+package block
+
+import (
+ "io"
+)
+
+type cbcCipher struct {
+ c Cipher
+ blockSize int
+ iv []byte
+ tmp []byte
+}
+
+func newCBC(c Cipher, iv []byte) *cbcCipher {
+ n := c.BlockSize()
+ x := new(cbcCipher)
+ x.c = c
+ x.blockSize = n
+ x.iv = dup(iv)
+ x.tmp = make([]byte, n)
+ return x
+}
+
+func (x *cbcCipher) BlockSize() int { return x.blockSize }
+
+func (x *cbcCipher) Encrypt(dst, src []byte) {
+ for i := 0; i < x.blockSize; i++ {
+ x.iv[i] ^= src[i]
+ }
+ x.c.Encrypt(x.iv, x.iv)
+ for i := 0; i < x.blockSize; i++ {
+ dst[i] = x.iv[i]
+ }
+}
+
+func (x *cbcCipher) Decrypt(dst, src []byte) {
+ x.c.Decrypt(x.tmp, src)
+ for i := 0; i < x.blockSize; i++ {
+ x.tmp[i] ^= x.iv[i]
+ x.iv[i] = src[i]
+ dst[i] = x.tmp[i]
+ }
+}
+
+// NewCBCDecrypter returns a reader that reads data from r and decrypts it using c
+// in cipher block chaining (CBC) mode with the initialization vector iv.
+// The returned Reader does not buffer or read ahead except
+// as required by the cipher's block size.
+func NewCBCDecrypter(c Cipher, iv []byte, r io.Reader) io.Reader {
+ return NewECBDecrypter(newCBC(c, iv), r)
+}
+
+// NewCBCEncrypter returns a writer that encrypts data using c
+// in cipher block chaining (CBC) mode with the initialization vector iv
+// and writes the encrypted data to w.
+// The returned Writer does no buffering except as required
+// by the cipher's block size, so there is no need for a Flush method.
+func NewCBCEncrypter(c Cipher, iv []byte, w io.Writer) io.Writer {
+ return NewECBEncrypter(newCBC(c, iv), w)
+}
diff --git a/libgo/go/crypto/block/cfb.go b/libgo/go/crypto/block/cfb.go
new file mode 100644
index 000000000..f20c0a04f
--- /dev/null
+++ b/libgo/go/crypto/block/cfb.go
@@ -0,0 +1,96 @@
+// 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.
+
+// Cipher feedback (CFB) mode.
+
+// CFB provides confidentiality by feeding a fraction of
+// the previous ciphertext in as the plaintext for the next
+// block operation.
+
+// See NIST SP 800-38A, pp 11-13
+
+package block
+
+import (
+ "io"
+)
+
+type cfbCipher struct {
+ c Cipher
+ blockSize int // our block size (s/8)
+ cipherSize int // underlying cipher block size
+ iv []byte
+ tmp []byte
+}
+
+func newCFB(c Cipher, s int, iv []byte) *cfbCipher {
+ if s == 0 || s%8 != 0 {
+ panic("crypto/block: invalid CFB mode")
+ }
+ b := c.BlockSize()
+ x := new(cfbCipher)
+ x.c = c
+ x.blockSize = s / 8
+ x.cipherSize = b
+ x.iv = dup(iv)
+ x.tmp = make([]byte, b)
+ return x
+}
+
+func (x *cfbCipher) BlockSize() int { return x.blockSize }
+
+func (x *cfbCipher) Encrypt(dst, src []byte) {
+ // Encrypt old IV and xor prefix with src to make dst.
+ x.c.Encrypt(x.tmp, x.iv)
+ for i := 0; i < x.blockSize; i++ {
+ dst[i] = src[i] ^ x.tmp[i]
+ }
+
+ // Slide unused IV pieces down and insert dst at end.
+ for i := 0; i < x.cipherSize-x.blockSize; i++ {
+ x.iv[i] = x.iv[i+x.blockSize]
+ }
+ off := x.cipherSize - x.blockSize
+ for i := off; i < x.cipherSize; i++ {
+ x.iv[i] = dst[i-off]
+ }
+}
+
+func (x *cfbCipher) Decrypt(dst, src []byte) {
+ // Encrypt [sic] old IV and xor prefix with src to make dst.
+ x.c.Encrypt(x.tmp, x.iv)
+ for i := 0; i < x.blockSize; i++ {
+ dst[i] = src[i] ^ x.tmp[i]
+ }
+
+ // Slide unused IV pieces down and insert src at top.
+ for i := 0; i < x.cipherSize-x.blockSize; i++ {
+ x.iv[i] = x.iv[i+x.blockSize]
+ }
+ off := x.cipherSize - x.blockSize
+ for i := off; i < x.cipherSize; i++ {
+ // Reconstruct src = dst ^ x.tmp
+ // in case we overwrote src (src == dst).
+ x.iv[i] = dst[i-off] ^ x.tmp[i-off]
+ }
+}
+
+// NewCFBDecrypter returns a reader that reads data from r and decrypts it using c
+// in s-bit cipher feedback (CFB) mode with the initialization vector iv.
+// The returned Reader does not buffer or read ahead except
+// as required by the cipher's block size.
+// Modes for s not a multiple of 8 are unimplemented.
+func NewCFBDecrypter(c Cipher, s int, iv []byte, r io.Reader) io.Reader {
+ return NewECBDecrypter(newCFB(c, s, iv), r)
+}
+
+// NewCFBEncrypter returns a writer that encrypts data using c
+// in s-bit cipher feedback (CFB) mode with the initialization vector iv
+// and writes the encrypted data to w.
+// The returned Writer does no buffering except as required
+// by the cipher's block size, so there is no need for a Flush method.
+// Modes for s not a multiple of 8 are unimplemented.
+func NewCFBEncrypter(c Cipher, s int, iv []byte, w io.Writer) io.Writer {
+ return NewECBEncrypter(newCFB(c, s, iv), w)
+}
diff --git a/libgo/go/crypto/block/cfb_aes_test.go b/libgo/go/crypto/block/cfb_aes_test.go
new file mode 100644
index 000000000..e400c182a
--- /dev/null
+++ b/libgo/go/crypto/block/cfb_aes_test.go
@@ -0,0 +1,311 @@
+// 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.
+
+// CFB AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 29-52.
+
+package block
+
+import (
+ "bytes"
+ "crypto/aes"
+ "io"
+ "testing"
+)
+
+type cfbTest struct {
+ name string
+ s int
+ key []byte
+ iv []byte
+ in []byte
+ out []byte
+}
+
+var cfbAESTests = []cfbTest{
+ {
+ "CFB1-AES128",
+ 1,
+ commonKey128,
+ commonIV,
+ []byte{
+ 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
+ 1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
+ },
+ []byte{
+ 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1,
+ 1<<7 | 0<<6 | 1<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1,
+ },
+ },
+ {
+ "CFB1-AES192",
+ 1,
+ commonKey192,
+ commonIV,
+ []byte{
+ 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
+ 1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
+ },
+ []byte{
+ 1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1,
+ 0<<7 | 1<<6 | 0<<5 | 1<<4 | 1<<3 | 0<<2 | 0<<1,
+ },
+ },
+ {
+ "CFB1-AES256",
+ 1,
+ commonKey256,
+ commonIV,
+ []byte{
+ 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1,
+ 1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1,
+ },
+ []byte{
+ 1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 0<<1,
+ 0<<7 | 0<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1,
+ },
+ },
+
+ {
+ "CFB8-AES128",
+ 8,
+ commonKey128,
+ commonIV,
+ []byte{
+ 0x6b,
+ 0xc1,
+ 0xbe,
+ 0xe2,
+ 0x2e,
+ 0x40,
+ 0x9f,
+ 0x96,
+ 0xe9,
+ 0x3d,
+ 0x7e,
+ 0x11,
+ 0x73,
+ 0x93,
+ 0x17,
+ 0x2a,
+ 0xae,
+ 0x2d,
+ },
+ []byte{
+ 0x3b,
+ 0x79,
+ 0x42,
+ 0x4c,
+ 0x9c,
+ 0x0d,
+ 0xd4,
+ 0x36,
+ 0xba,
+ 0xce,
+ 0x9e,
+ 0x0e,
+ 0xd4,
+ 0x58,
+ 0x6a,
+ 0x4f,
+ 0x32,
+ 0xb9,
+ },
+ },
+
+ {
+ "CFB8-AES192",
+ 8,
+ commonKey192,
+ commonIV,
+ []byte{
+ 0x6b,
+ 0xc1,
+ 0xbe,
+ 0xe2,
+ 0x2e,
+ 0x40,
+ 0x9f,
+ 0x96,
+ 0xe9,
+ 0x3d,
+ 0x7e,
+ 0x11,
+ 0x73,
+ 0x93,
+ 0x17,
+ 0x2a,
+ 0xae,
+ 0x2d,
+ },
+ []byte{
+ 0xcd,
+ 0xa2,
+ 0x52,
+ 0x1e,
+ 0xf0,
+ 0xa9,
+ 0x05,
+ 0xca,
+ 0x44,
+ 0xcd,
+ 0x05,
+ 0x7c,
+ 0xbf,
+ 0x0d,
+ 0x47,
+ 0xa0,
+ 0x67,
+ 0x8a,
+ },
+ },
+
+ {
+ "CFB8-AES256",
+ 8,
+ commonKey256,
+ commonIV,
+ []byte{
+ 0x6b,
+ 0xc1,
+ 0xbe,
+ 0xe2,
+ 0x2e,
+ 0x40,
+ 0x9f,
+ 0x96,
+ 0xe9,
+ 0x3d,
+ 0x7e,
+ 0x11,
+ 0x73,
+ 0x93,
+ 0x17,
+ 0x2a,
+ 0xae,
+ 0x2d,
+ },
+ []byte{
+ 0xdc,
+ 0x1f,
+ 0x1a,
+ 0x85,
+ 0x20,
+ 0xa6,
+ 0x4d,
+ 0xb5,
+ 0x5f,
+ 0xcc,
+ 0x8a,
+ 0xc5,
+ 0x54,
+ 0x84,
+ 0x4e,
+ 0x88,
+ 0x97,
+ 0x00,
+ },
+ },
+
+ {
+ "CFB128-AES128",
+ 128,
+ commonKey128,
+ commonIV,
+ []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+ },
+ []byte{
+ 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
+ 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b,
+ 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf,
+ 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6,
+ },
+ },
+
+ {
+ "CFB128-AES192",
+ 128,
+ commonKey192,
+ commonIV,
+ []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+ },
+ []byte{
+ 0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
+ 0x67, 0xce, 0x7f, 0x7f, 0x81, 0x17, 0x36, 0x21, 0x96, 0x1a, 0x2b, 0x70, 0x17, 0x1d, 0x3d, 0x7a,
+ 0x2e, 0x1e, 0x8a, 0x1d, 0xd5, 0x9b, 0x88, 0xb1, 0xc8, 0xe6, 0x0f, 0xed, 0x1e, 0xfa, 0xc4, 0xc9,
+ 0xc0, 0x5f, 0x9f, 0x9c, 0xa9, 0x83, 0x4f, 0xa0, 0x42, 0xae, 0x8f, 0xba, 0x58, 0x4b, 0x09, 0xff,
+ },
+ },
+
+ {
+ "CFB128-AES256",
+ 128,
+ commonKey256,
+ commonIV,
+ []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+ },
+ []byte{
+ 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
+ 0x39, 0xff, 0xed, 0x14, 0x3b, 0x28, 0xb1, 0xc8, 0x32, 0x11, 0x3c, 0x63, 0x31, 0xe5, 0x40, 0x7b,
+ 0xdf, 0x10, 0x13, 0x24, 0x15, 0xe5, 0x4b, 0x92, 0xa1, 0x3e, 0xd0, 0xa8, 0x26, 0x7a, 0xe2, 0xf9,
+ 0x75, 0xa3, 0x85, 0x74, 0x1a, 0xb9, 0xce, 0xf8, 0x20, 0x31, 0x62, 0x3d, 0x55, 0xb1, 0xe4, 0x71,
+ },
+ },
+}
+
+func TestCFB_AES(t *testing.T) {
+ for _, tt := range cfbAESTests {
+ test := tt.name
+
+ if tt.s == 1 {
+ // 1-bit CFB not implemented
+ continue
+ }
+
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ continue
+ }
+
+ var crypt bytes.Buffer
+ w := NewCFBEncrypter(c, tt.s, tt.iv, &crypt)
+ var r io.Reader = bytes.NewBuffer(tt.in)
+ n, err := io.Copy(w, r)
+ if n != int64(len(tt.in)) || err != nil {
+ t.Errorf("%s: CFBEncrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in))
+ } else if d := crypt.Bytes(); !same(tt.out, d) {
+ t.Errorf("%s: CFBEncrypter\nhave %x\nwant %x", test, d, tt.out)
+ }
+
+ var plain bytes.Buffer
+ r = NewCFBDecrypter(c, tt.s, tt.iv, bytes.NewBuffer(tt.out))
+ w = &plain
+ n, err = io.Copy(w, r)
+ if n != int64(len(tt.out)) || err != nil {
+ t.Errorf("%s: CFBDecrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out))
+ } else if d := plain.Bytes(); !same(tt.in, d) {
+ t.Errorf("%s: CFBDecrypter\nhave %x\nwant %x", test, d, tt.in)
+ }
+
+ if t.Failed() {
+ break
+ }
+ }
+}
diff --git a/libgo/go/crypto/block/cipher.go b/libgo/go/crypto/block/cipher.go
new file mode 100644
index 000000000..e1099e9a1
--- /dev/null
+++ b/libgo/go/crypto/block/cipher.go
@@ -0,0 +1,57 @@
+// 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.
+
+// The block package is deprecated, use cipher instead.
+// The block package implements standard block cipher modes
+// that can be wrapped around low-level block cipher implementations.
+// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html
+// and NIST Special Publication 800-38A.
+package block
+
+// A Cipher represents an implementation of block cipher
+// using a given key. It provides the capability to encrypt
+// or decrypt individual blocks. The mode implementations
+// extend that capability to streams of blocks.
+type Cipher interface {
+ // BlockSize returns the cipher's block size.
+ BlockSize() int
+
+ // Encrypt encrypts the first block in src into dst.
+ // Src and dst may point at the same memory.
+ Encrypt(dst, src []byte)
+
+ // Decrypt decrypts the first block in src into dst.
+ // Src and dst may point at the same memory.
+ Decrypt(dst, src []byte)
+}
+
+// Utility routines
+
+func shift1(dst, src []byte) byte {
+ var b byte
+ for i := len(src) - 1; i >= 0; i-- {
+ bb := src[i] >> 7
+ dst[i] = src[i]<<1 | b
+ b = bb
+ }
+ return b
+}
+
+func same(p, q []byte) bool {
+ if len(p) != len(q) {
+ return false
+ }
+ for i := 0; i < len(p); i++ {
+ if p[i] != q[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func dup(p []byte) []byte {
+ q := make([]byte, len(p))
+ copy(q, p)
+ return q
+}
diff --git a/libgo/go/crypto/block/cmac.go b/libgo/go/crypto/block/cmac.go
new file mode 100644
index 000000000..b85cde72e
--- /dev/null
+++ b/libgo/go/crypto/block/cmac.go
@@ -0,0 +1,105 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CMAC message authentication code, defined in
+// NIST Special Publication SP 800-38B.
+
+package block
+
+import (
+ "hash"
+ "os"
+)
+
+const (
+ // minimal irreducible polynomial of degree b
+ r64 = 0x1b
+ r128 = 0x87
+)
+
+type cmac struct {
+ k1, k2, ci, digest []byte
+ p int // position in ci
+ c Cipher
+}
+
+// TODO(rsc): Should this return an error instead of panic?
+
+// NewCMAC returns a new instance of a CMAC message authentication code
+// digest using the given Cipher.
+func NewCMAC(c Cipher) hash.Hash {
+ var r byte
+ n := c.BlockSize()
+ switch n {
+ case 64 / 8:
+ r = r64
+ case 128 / 8:
+ r = r128
+ default:
+ panic("crypto/block: NewCMAC: invalid cipher block size")
+ }
+
+ d := new(cmac)
+ d.c = c
+ d.k1 = make([]byte, n)
+ d.k2 = make([]byte, n)
+ d.ci = make([]byte, n)
+ d.digest = make([]byte, n)
+
+ // Subkey generation, p. 7
+ c.Encrypt(d.k1, d.k1)
+ if shift1(d.k1, d.k1) != 0 {
+ d.k1[n-1] ^= r
+ }
+ if shift1(d.k2, d.k1) != 0 {
+ d.k2[n-1] ^= r
+ }
+
+ return d
+}
+
+// Reset clears the digest state, starting a new digest.
+func (d *cmac) Reset() {
+ for i := range d.ci {
+ d.ci[i] = 0
+ }
+ d.p = 0
+}
+
+// Write adds the given data to the digest state.
+func (d *cmac) Write(p []byte) (n int, err os.Error) {
+ // Xor input into ci.
+ for _, c := range p {
+ // If ci is full, encrypt and start over.
+ if d.p >= len(d.ci) {
+ d.c.Encrypt(d.ci, d.ci)
+ d.p = 0
+ }
+ d.ci[d.p] ^= c
+ d.p++
+ }
+ return len(p), nil
+}
+
+// Sum returns the CMAC digest, one cipher block in length,
+// of the data written with Write.
+func (d *cmac) Sum() []byte {
+ // Finish last block, mix in key, encrypt.
+ // Don't edit ci, in case caller wants
+ // to keep digesting after call to Sum.
+ k := d.k1
+ if d.p < len(d.digest) {
+ k = d.k2
+ }
+ for i := 0; i < len(d.ci); i++ {
+ d.digest[i] = d.ci[i] ^ k[i]
+ }
+ if d.p < len(d.digest) {
+ d.digest[d.p] ^= 0x80
+ }
+ d.c.Encrypt(d.digest, d.digest)
+ return d.digest
+}
+
+func (d *cmac) Size() int { return len(d.digest) }
diff --git a/libgo/go/crypto/block/cmac_aes_test.go b/libgo/go/crypto/block/cmac_aes_test.go
new file mode 100644
index 000000000..0a4a1a418
--- /dev/null
+++ b/libgo/go/crypto/block/cmac_aes_test.go
@@ -0,0 +1,130 @@
+// 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.
+
+// CMAC test vectors. See NIST SP 800-38B, Appendix D.
+
+package block
+
+import (
+ "crypto/aes"
+ "testing"
+)
+
+type cmacAESTest struct {
+ key []byte
+ in []byte
+ digest []byte
+}
+
+var cmacAESTests = []cmacAESTest{
+ {
+ commonKey128,
+ nil,
+ []byte{0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46},
+ },
+ {
+ commonKey128,
+ []byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+ []byte{0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c},
+ },
+ {
+ commonKey128,
+ []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ },
+ []byte{0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27},
+ },
+ {
+ commonKey128,
+ []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+ },
+ []byte{0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe},
+ },
+ {
+ commonKey192,
+ nil,
+ []byte{0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67},
+ },
+ {
+ commonKey192,
+ []byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+ []byte{0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84},
+ },
+ {
+ commonKey192,
+ []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ },
+ []byte{0x8a, 0x1d, 0xe5, 0xbe, 0x2e, 0xb3, 0x1a, 0xad, 0x08, 0x9a, 0x82, 0xe6, 0xee, 0x90, 0x8b, 0x0e},
+ },
+ {
+ commonKey192,
+ []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+ },
+ []byte{0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11},
+ },
+ {
+ commonKey256,
+ nil,
+ []byte{0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83},
+ },
+ {
+ commonKey256,
+ []byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+ []byte{0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c},
+ },
+ {
+ commonKey256,
+ []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ },
+ []byte{0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2, 0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6},
+ },
+ {
+ commonKey256,
+ []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+ },
+ []byte{0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10},
+ },
+}
+
+func TestCMAC_AES(t *testing.T) {
+ for i, tt := range cmacAESTests {
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("test %d: NewCipher: %s", i, err)
+ continue
+ }
+ d := NewCMAC(c)
+ n, err := d.Write(tt.in)
+ if err != nil || n != len(tt.in) {
+ t.Errorf("test %d: Write %d: %d, %s", i, len(tt.in), n, err)
+ continue
+ }
+ sum := d.Sum()
+ if !same(sum, tt.digest) {
+ x := d.(*cmac)
+ t.Errorf("test %d: digest mismatch\n\twant %x\n\thave %x\n\tk1 %x\n\tk2 %x", i, tt.digest, sum, x.k1, x.k2)
+ continue
+ }
+ }
+}
diff --git a/libgo/go/crypto/block/ctr.go b/libgo/go/crypto/block/ctr.go
new file mode 100644
index 000000000..5d65c0c9a
--- /dev/null
+++ b/libgo/go/crypto/block/ctr.go
@@ -0,0 +1,67 @@
+// 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.
+
+// Counter (CTR) mode.
+
+// CTR converts a block cipher into a stream cipher by
+// repeatedly encrypting an incrementing counter and
+// xoring the resulting stream of data with the input.
+
+// See NIST SP 800-38A, pp 13-15
+
+package block
+
+import (
+ "io"
+)
+
+type ctrStream struct {
+ c Cipher
+ ctr []byte
+ out []byte
+}
+
+func newCTRStream(c Cipher, ctr []byte) *ctrStream {
+ x := new(ctrStream)
+ x.c = c
+ x.ctr = dup(ctr)
+ x.out = make([]byte, len(ctr))
+ return x
+}
+
+func (x *ctrStream) Next() []byte {
+ // Next block is encryption of counter.
+ x.c.Encrypt(x.out, x.ctr)
+
+ // Increment counter
+ for i := len(x.ctr) - 1; i >= 0; i-- {
+ x.ctr[i]++
+ if x.ctr[i] != 0 {
+ break
+ }
+ }
+
+ return x.out
+}
+
+// NewCTRReader returns a reader that reads data from r, decrypts (or encrypts)
+// it using c in counter (CTR) mode with the initialization vector iv.
+// The returned Reader does not buffer and has no block size.
+// In CTR mode, encryption and decryption are the same operation:
+// a CTR reader applied to an encrypted stream produces a decrypted
+// stream and vice versa.
+func NewCTRReader(c Cipher, iv []byte, r io.Reader) io.Reader {
+ return newXorReader(newCTRStream(c, iv), r)
+}
+
+// NewCTRWriter returns a writer that encrypts (or decrypts) data using c
+// in counter (CTR) mode with the initialization vector iv
+// and writes the encrypted data to w.
+// The returned Writer does not buffer and has no block size.
+// In CTR mode, encryption and decryption are the same operation:
+// a CTR writer applied to an decrypted stream produces an encrypted
+// stream and vice versa.
+func NewCTRWriter(c Cipher, iv []byte, w io.Writer) io.Writer {
+ return newXorWriter(newCTRStream(c, iv), w)
+}
diff --git a/libgo/go/crypto/block/eax.go b/libgo/go/crypto/block/eax.go
new file mode 100644
index 000000000..3f3b96431
--- /dev/null
+++ b/libgo/go/crypto/block/eax.go
@@ -0,0 +1,253 @@
+// 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.
+
+// EAX mode, not a NIST standard (yet).
+// EAX provides encryption and authentication.
+// EAX targets the same uses as NIST's CCM mode,
+// but EAX adds the ability to run in streaming mode.
+
+// See
+// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/eax/eax-spec.pdf
+// http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
+// What those papers call OMAC is now called CMAC.
+
+package block
+
+import (
+ "fmt"
+ "hash"
+ "io"
+ "os"
+)
+
+// An EAXTagError is returned when the message has failed to authenticate,
+// because the tag at the end of the message stream (Read) does not match
+// the tag computed from the message itself (Computed).
+type EAXTagError struct {
+ Read []byte
+ Computed []byte
+}
+
+func (e *EAXTagError) String() string {
+ return fmt.Sprintf("crypto/block: EAX tag mismatch: read %x but computed %x", e.Read, e.Computed)
+}
+
+func setupEAX(c Cipher, iv, hdr []byte, tagBytes int) (ctrIV, tag []byte, cmac hash.Hash) {
+ n := len(iv)
+ if n != c.BlockSize() {
+ panic(fmt.Sprintln("crypto/block: EAX: iv length", n, "!=", c.BlockSize()))
+ }
+ buf := make([]byte, n) // zeroed
+
+ // tag = CMAC(0 + iv) ^ CMAC(1 + hdr) ^ CMAC(2 + data)
+ cmac = NewCMAC(c)
+ cmac.Write(buf) // 0
+ cmac.Write(iv)
+ sum := cmac.Sum()
+ ctrIV = dup(sum)
+ tag = dup(sum[0:tagBytes])
+
+ cmac.Reset()
+ buf[n-1] = 1
+ cmac.Write(buf) // 1
+ cmac.Write(hdr)
+ sum = cmac.Sum()
+ for i := 0; i < tagBytes; i++ {
+ tag[i] ^= sum[i]
+ }
+
+ cmac.Reset()
+ buf[n-1] = 2 // 2
+ cmac.Write(buf)
+
+ return
+}
+
+func finishEAX(tag []byte, cmac hash.Hash) {
+ // Finish CMAC #2 and xor into tag.
+ sum := cmac.Sum()
+ for i := range tag {
+ tag[i] ^= sum[i]
+ }
+}
+
+// Writer adapter. Tees writes into both w and cmac.
+// Knows that cmac never returns write errors.
+type cmacWriter struct {
+ w io.Writer
+ cmac hash.Hash
+}
+
+func (cw *cmacWriter) Write(p []byte) (n int, err os.Error) {
+ n, err = cw.w.Write(p)
+ cw.cmac.Write(p[0:n])
+ return
+}
+
+// An eaxEncrypter implements the EAX encryption mode.
+type eaxEncrypter struct {
+ ctr io.Writer // CTR encrypter
+ cw cmacWriter // CTR's output stream
+ tag []byte
+}
+
+// NewEAXEncrypter creates and returns a new EAX encrypter
+// using the given cipher c, initialization vector iv, associated data hdr,
+// and tag length tagBytes. The encrypter's Write method encrypts
+// the data it receives and writes that data to w.
+// The encrypter's Close method writes a final authenticating tag to w.
+func NewEAXEncrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, w io.Writer) io.WriteCloser {
+ x := new(eaxEncrypter)
+
+ // Create new CTR instance writing to both
+ // w for encrypted output and cmac for digesting.
+ x.cw.w = w
+ var ctrIV []byte
+ ctrIV, x.tag, x.cw.cmac = setupEAX(c, iv, hdr, tagBytes)
+ x.ctr = NewCTRWriter(c, ctrIV, &x.cw)
+ return x
+}
+
+func (x *eaxEncrypter) Write(p []byte) (n int, err os.Error) {
+ return x.ctr.Write(p)
+}
+
+func (x *eaxEncrypter) Close() os.Error {
+ x.ctr = nil // crash if Write is called again
+
+ // Write tag.
+ finishEAX(x.tag, x.cw.cmac)
+ n, err := x.cw.w.Write(x.tag)
+ if n != len(x.tag) && err == nil {
+ err = io.ErrShortWrite
+ }
+
+ return err
+}
+
+// Reader adapter. Returns data read from r but hangs
+// on to the last len(tag) bytes for itself (returns EOF len(tag)
+// bytes early). Also tees all data returned from Read into
+// the cmac digest. The "don't return the last t bytes"
+// and the "tee into digest" functionality could be separated,
+// but the latter half is trivial.
+type cmacReader struct {
+ r io.Reader
+ cmac hash.Hash
+ tag []byte
+ tmp []byte
+}
+
+func (cr *cmacReader) Read(p []byte) (n int, err os.Error) {
+ // TODO(rsc): Maybe fall back to simpler code if
+ // we recognize the underlying r as a ByteBuffer
+ // or ByteReader. Then we can just take the last piece
+ // off at the start.
+
+ // First, read a tag-sized chunk.
+ // It's probably not the tag (unless there's no data).
+ tag := cr.tag
+ if len(tag) < cap(tag) {
+ nt := len(tag)
+ nn, err1 := io.ReadFull(cr.r, tag[nt:cap(tag)])
+ tag = tag[0 : nt+nn]
+ cr.tag = tag
+ if err1 != nil {
+ return 0, err1
+ }
+ }
+
+ tagBytes := len(tag)
+ if len(p) > 4*tagBytes {
+ // If p is big, try to read directly into p to avoid a copy.
+ n, err = cr.r.Read(p[tagBytes:])
+ if n == 0 {
+ goto out
+ }
+ // copy old tag into p
+ for i := 0; i < tagBytes; i++ {
+ p[i] = tag[i]
+ }
+ // copy new tag out of p
+ for i := 0; i < tagBytes; i++ {
+ tag[i] = p[n+i]
+ }
+ goto out
+ }
+
+ // Otherwise, read into p and then slide data
+ n, err = cr.r.Read(p)
+ if n == 0 {
+ goto out
+ }
+
+ // copy tag+p into p+tmp and then swap tmp, tag
+ tmp := cr.tmp
+ for i := n + tagBytes - 1; i >= 0; i-- {
+ var c byte
+ if i < tagBytes {
+ c = tag[i]
+ } else {
+ c = p[i-tagBytes]
+ }
+ if i < n {
+ p[i] = c
+ } else {
+ tmp[i] = c
+ }
+ }
+ cr.tmp, cr.tag = tag, tmp
+
+out:
+ cr.cmac.Write(p[0:n])
+ return
+}
+
+type eaxDecrypter struct {
+ ctr io.Reader
+ cr cmacReader
+ tag []byte
+}
+
+// NewEAXDecrypter creates and returns a new EAX decrypter
+// using the given cipher c, initialization vector iv, associated data hdr,
+// and tag length tagBytes. The encrypter's Read method decrypts and
+// returns data read from r. At r's EOF, the encrypter checks the final
+// authenticating tag and returns an EAXTagError if the tag is invalid.
+// In that case, the message should be discarded.
+// Note that the data stream returned from Read cannot be
+// assumed to be valid, authenticated data until Read returns
+// 0, nil to signal the end of the data.
+func NewEAXDecrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, r io.Reader) io.Reader {
+ x := new(eaxDecrypter)
+
+ x.cr.r = r
+ x.cr.tag = make([]byte, 0, tagBytes)
+ x.cr.tmp = make([]byte, 0, tagBytes)
+ var ctrIV []byte
+ ctrIV, x.tag, x.cr.cmac = setupEAX(c, iv, hdr, tagBytes)
+ x.ctr = NewCTRReader(c, ctrIV, &x.cr)
+ return x
+}
+
+func (x *eaxDecrypter) checkTag() os.Error {
+ x.ctr = nil // crash if Read is called again
+
+ finishEAX(x.tag, x.cr.cmac)
+ if !same(x.tag, x.cr.tag) {
+ e := new(EAXTagError)
+ e.Computed = dup(x.tag)
+ e.Read = dup(x.cr.tag)
+ return e
+ }
+ return nil
+}
+
+func (x *eaxDecrypter) Read(p []byte) (n int, err os.Error) {
+ n, err = x.ctr.Read(p)
+ if n == 0 && err == nil {
+ err = x.checkTag()
+ }
+ return n, err
+}
diff --git a/libgo/go/crypto/block/eax_aes_test.go b/libgo/go/crypto/block/eax_aes_test.go
new file mode 100644
index 000000000..93aa771be
--- /dev/null
+++ b/libgo/go/crypto/block/eax_aes_test.go
@@ -0,0 +1,140 @@
+// 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 block
+
+import (
+ "bytes"
+ "crypto/aes"
+ "fmt"
+ "io"
+ "testing"
+)
+
+// Test vectors from http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
+
+type eaxAESTest struct {
+ msg []byte
+ key []byte
+ nonce []byte
+ header []byte
+ cipher []byte
+}
+
+var eaxAESTests = []eaxAESTest{
+ {
+ []byte{},
+ []byte{0x23, 0x39, 0x52, 0xDE, 0xE4, 0xD5, 0xED, 0x5F, 0x9B, 0x9C, 0x6D, 0x6F, 0xF8, 0x0F, 0xF4, 0x78},
+ []byte{0x62, 0xEC, 0x67, 0xF9, 0xC3, 0xA4, 0xA4, 0x07, 0xFC, 0xB2, 0xA8, 0xC4, 0x90, 0x31, 0xA8, 0xB3},
+ []byte{0x6B, 0xFB, 0x91, 0x4F, 0xD0, 0x7E, 0xAE, 0x6B},
+ []byte{0xE0, 0x37, 0x83, 0x0E, 0x83, 0x89, 0xF2, 0x7B, 0x02, 0x5A, 0x2D, 0x65, 0x27, 0xE7, 0x9D, 0x01},
+ },
+ {
+ []byte{0xF7, 0xFB},
+ []byte{0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B, 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4},
+ []byte{0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84, 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD},
+ []byte{0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA},
+ []byte{0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D, 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79, 0x67, 0xE5},
+ },
+ {
+ []byte{0x1A, 0x47, 0xCB, 0x49, 0x33},
+ []byte{0x01, 0xF7, 0x4A, 0xD6, 0x40, 0x77, 0xF2, 0xE7, 0x04, 0xC0, 0xF6, 0x0A, 0xDA, 0x3D, 0xD5, 0x23},
+ []byte{0x70, 0xC3, 0xDB, 0x4F, 0x0D, 0x26, 0x36, 0x84, 0x00, 0xA1, 0x0E, 0xD0, 0x5D, 0x2B, 0xFF, 0x5E},
+ []byte{0x23, 0x4A, 0x34, 0x63, 0xC1, 0x26, 0x4A, 0xC6},
+ []byte{0xD8, 0x51, 0xD5, 0xBA, 0xE0, 0x3A, 0x59, 0xF2, 0x38, 0xA2, 0x3E, 0x39, 0x19, 0x9D, 0xC9, 0x26, 0x66, 0x26, 0xC4, 0x0F, 0x80},
+ },
+ {
+ []byte{0x48, 0x1C, 0x9E, 0x39, 0xB1},
+ []byte{0xD0, 0x7C, 0xF6, 0xCB, 0xB7, 0xF3, 0x13, 0xBD, 0xDE, 0x66, 0xB7, 0x27, 0xAF, 0xD3, 0xC5, 0xE8},
+ []byte{0x84, 0x08, 0xDF, 0xFF, 0x3C, 0x1A, 0x2B, 0x12, 0x92, 0xDC, 0x19, 0x9E, 0x46, 0xB7, 0xD6, 0x17},
+ []byte{0x33, 0xCC, 0xE2, 0xEA, 0xBF, 0xF5, 0xA7, 0x9D},
+ []byte{0x63, 0x2A, 0x9D, 0x13, 0x1A, 0xD4, 0xC1, 0x68, 0xA4, 0x22, 0x5D, 0x8E, 0x1F, 0xF7, 0x55, 0x93, 0x99, 0x74, 0xA7, 0xBE, 0xDE},
+ },
+ {
+ []byte{0x40, 0xD0, 0xC0, 0x7D, 0xA5, 0xE4},
+ []byte{0x35, 0xB6, 0xD0, 0x58, 0x00, 0x05, 0xBB, 0xC1, 0x2B, 0x05, 0x87, 0x12, 0x45, 0x57, 0xD2, 0xC2},
+ []byte{0xFD, 0xB6, 0xB0, 0x66, 0x76, 0xEE, 0xDC, 0x5C, 0x61, 0xD7, 0x42, 0x76, 0xE1, 0xF8, 0xE8, 0x16},
+ []byte{0xAE, 0xB9, 0x6E, 0xAE, 0xBE, 0x29, 0x70, 0xE9},
+ []byte{0x07, 0x1D, 0xFE, 0x16, 0xC6, 0x75, 0xCB, 0x06, 0x77, 0xE5, 0x36, 0xF7, 0x3A, 0xFE, 0x6A, 0x14, 0xB7, 0x4E, 0xE4, 0x98, 0x44, 0xDD},
+ },
+ {
+ []byte{0x4D, 0xE3, 0xB3, 0x5C, 0x3F, 0xC0, 0x39, 0x24, 0x5B, 0xD1, 0xFB, 0x7D},
+ []byte{0xBD, 0x8E, 0x6E, 0x11, 0x47, 0x5E, 0x60, 0xB2, 0x68, 0x78, 0x4C, 0x38, 0xC6, 0x2F, 0xEB, 0x22},
+ []byte{0x6E, 0xAC, 0x5C, 0x93, 0x07, 0x2D, 0x8E, 0x85, 0x13, 0xF7, 0x50, 0x93, 0x5E, 0x46, 0xDA, 0x1B},
+ []byte{0xD4, 0x48, 0x2D, 0x1C, 0xA7, 0x8D, 0xCE, 0x0F},
+ []byte{0x83, 0x5B, 0xB4, 0xF1, 0x5D, 0x74, 0x3E, 0x35, 0x0E, 0x72, 0x84, 0x14, 0xAB, 0xB8, 0x64, 0x4F, 0xD6, 0xCC, 0xB8, 0x69, 0x47, 0xC5, 0xE1, 0x05, 0x90, 0x21, 0x0A, 0x4F},
+ },
+ {
+ []byte{0x8B, 0x0A, 0x79, 0x30, 0x6C, 0x9C, 0xE7, 0xED, 0x99, 0xDA, 0xE4, 0xF8, 0x7F, 0x8D, 0xD6, 0x16, 0x36},
+ []byte{0x7C, 0x77, 0xD6, 0xE8, 0x13, 0xBE, 0xD5, 0xAC, 0x98, 0xBA, 0xA4, 0x17, 0x47, 0x7A, 0x2E, 0x7D},
+ []byte{0x1A, 0x8C, 0x98, 0xDC, 0xD7, 0x3D, 0x38, 0x39, 0x3B, 0x2B, 0xF1, 0x56, 0x9D, 0xEE, 0xFC, 0x19},
+ []byte{0x65, 0xD2, 0x01, 0x79, 0x90, 0xD6, 0x25, 0x28},
+ []byte{0x02, 0x08, 0x3E, 0x39, 0x79, 0xDA, 0x01, 0x48, 0x12, 0xF5, 0x9F, 0x11, 0xD5, 0x26, 0x30, 0xDA, 0x30, 0x13, 0x73, 0x27, 0xD1, 0x06, 0x49, 0xB0, 0xAA, 0x6E, 0x1C, 0x18, 0x1D, 0xB6, 0x17, 0xD7, 0xF2},
+ },
+ {
+ []byte{0x1B, 0xDA, 0x12, 0x2B, 0xCE, 0x8A, 0x8D, 0xBA, 0xF1, 0x87, 0x7D, 0x96, 0x2B, 0x85, 0x92, 0xDD, 0x2D, 0x56},
+ []byte{0x5F, 0xFF, 0x20, 0xCA, 0xFA, 0xB1, 0x19, 0xCA, 0x2F, 0xC7, 0x35, 0x49, 0xE2, 0x0F, 0x5B, 0x0D},
+ []byte{0xDD, 0xE5, 0x9B, 0x97, 0xD7, 0x22, 0x15, 0x6D, 0x4D, 0x9A, 0xFF, 0x2B, 0xC7, 0x55, 0x98, 0x26},
+ []byte{0x54, 0xB9, 0xF0, 0x4E, 0x6A, 0x09, 0x18, 0x9A},
+ []byte{0x2E, 0xC4, 0x7B, 0x2C, 0x49, 0x54, 0xA4, 0x89, 0xAF, 0xC7, 0xBA, 0x48, 0x97, 0xED, 0xCD, 0xAE, 0x8C, 0xC3, 0x3B, 0x60, 0x45, 0x05, 0x99, 0xBD, 0x02, 0xC9, 0x63, 0x82, 0x90, 0x2A, 0xEF, 0x7F, 0x83, 0x2A},
+ },
+ {
+ []byte{0x6C, 0xF3, 0x67, 0x20, 0x87, 0x2B, 0x85, 0x13, 0xF6, 0xEA, 0xB1, 0xA8, 0xA4, 0x44, 0x38, 0xD5, 0xEF, 0x11},
+ []byte{0xA4, 0xA4, 0x78, 0x2B, 0xCF, 0xFD, 0x3E, 0xC5, 0xE7, 0xEF, 0x6D, 0x8C, 0x34, 0xA5, 0x61, 0x23},
+ []byte{0xB7, 0x81, 0xFC, 0xF2, 0xF7, 0x5F, 0xA5, 0xA8, 0xDE, 0x97, 0xA9, 0xCA, 0x48, 0xE5, 0x22, 0xEC},
+ []byte{0x89, 0x9A, 0x17, 0x58, 0x97, 0x56, 0x1D, 0x7E},
+ []byte{0x0D, 0xE1, 0x8F, 0xD0, 0xFD, 0xD9, 0x1E, 0x7A, 0xF1, 0x9F, 0x1D, 0x8E, 0xE8, 0x73, 0x39, 0x38, 0xB1, 0xE8, 0xE7, 0xF6, 0xD2, 0x23, 0x16, 0x18, 0x10, 0x2F, 0xDB, 0x7F, 0xE5, 0x5F, 0xF1, 0x99, 0x17, 0x00},
+ },
+ {
+ []byte{0xCA, 0x40, 0xD7, 0x44, 0x6E, 0x54, 0x5F, 0xFA, 0xED, 0x3B, 0xD1, 0x2A, 0x74, 0x0A, 0x65, 0x9F, 0xFB, 0xBB, 0x3C, 0xEA, 0xB7},
+ []byte{0x83, 0x95, 0xFC, 0xF1, 0xE9, 0x5B, 0xEB, 0xD6, 0x97, 0xBD, 0x01, 0x0B, 0xC7, 0x66, 0xAA, 0xC3},
+ []byte{0x22, 0xE7, 0xAD, 0xD9, 0x3C, 0xFC, 0x63, 0x93, 0xC5, 0x7E, 0xC0, 0xB3, 0xC1, 0x7D, 0x6B, 0x44},
+ []byte{0x12, 0x67, 0x35, 0xFC, 0xC3, 0x20, 0xD2, 0x5A},
+ []byte{0xCB, 0x89, 0x20, 0xF8, 0x7A, 0x6C, 0x75, 0xCF, 0xF3, 0x96, 0x27, 0xB5, 0x6E, 0x3E, 0xD1, 0x97, 0xC5, 0x52, 0xD2, 0x95, 0xA7, 0xCF, 0xC4, 0x6A, 0xFC, 0x25, 0x3B, 0x46, 0x52, 0xB1, 0xAF, 0x37, 0x95, 0xB1, 0x24, 0xAB, 0x6E},
+ },
+}
+
+func TestEAXEncrypt_AES(t *testing.T) {
+ b := new(bytes.Buffer)
+ for i, tt := range eaxAESTests {
+ test := fmt.Sprintf("test %d", i)
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ }
+ b.Reset()
+ enc := NewEAXEncrypter(c, tt.nonce, tt.header, 16, b)
+ n, err := io.Copy(enc, bytes.NewBuffer(tt.msg))
+ if n != int64(len(tt.msg)) || err != nil {
+ t.Fatalf("%s: io.Copy into encrypter: %d, %s", test, n, err)
+ }
+ err = enc.Close()
+ if err != nil {
+ t.Fatalf("%s: enc.Close: %s", test, err)
+ }
+ if d := b.Bytes(); !same(d, tt.cipher) {
+ t.Fatalf("%s: got %x want %x", test, d, tt.cipher)
+ }
+ }
+}
+
+func TestEAXDecrypt_AES(t *testing.T) {
+ b := new(bytes.Buffer)
+ for i, tt := range eaxAESTests {
+ test := fmt.Sprintf("test %d", i)
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ }
+ b.Reset()
+ dec := NewEAXDecrypter(c, tt.nonce, tt.header, 16, bytes.NewBuffer(tt.cipher))
+ n, err := io.Copy(b, dec)
+ if n != int64(len(tt.msg)) || err != nil {
+ t.Fatalf("%s: io.Copy into decrypter: %d, %s", test, n, err)
+ }
+ if d := b.Bytes(); !same(d, tt.msg) {
+ t.Fatalf("%s: got %x want %x", test, d, tt.msg)
+ }
+ }
+}
diff --git a/libgo/go/crypto/block/ecb.go b/libgo/go/crypto/block/ecb.go
new file mode 100644
index 000000000..cf09f7cb3
--- /dev/null
+++ b/libgo/go/crypto/block/ecb.go
@@ -0,0 +1,270 @@
+// 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.
+
+// Electronic codebook (ECB) mode.
+// ECB is a fancy name for ``encrypt and decrypt each block separately.''
+// It's a pretty bad thing to do for any large amount of data (more than one block),
+// because the individual blocks can still be identified, duplicated, and reordered.
+// The ECB implementation exists mainly to provide buffering for
+// the other modes, which wrap it by providing modified Ciphers.
+
+// See NIST SP 800-38A, pp 9-10
+
+package block
+
+import (
+ "io"
+ "os"
+ "strconv"
+)
+
+type ecbDecrypter struct {
+ c Cipher
+ r io.Reader
+ blockSize int // block size
+
+ // Buffered data.
+ // The buffer buf is used as storage for both
+ // plain or crypt; at least one of those is nil at any given time.
+ buf []byte
+ plain []byte // plain text waiting to be read
+ crypt []byte // ciphertext waiting to be decrypted
+}
+
+// Read into x.crypt until it has a full block or EOF or an error happens.
+func (x *ecbDecrypter) fillCrypt() os.Error {
+ var err os.Error
+ for len(x.crypt) < x.blockSize {
+ off := len(x.crypt)
+ var m int
+ m, err = x.r.Read(x.crypt[off:x.blockSize])
+ x.crypt = x.crypt[0 : off+m]
+ if m == 0 {
+ break
+ }
+
+ // If an error happened but we got enough
+ // data to do some decryption, we can decrypt
+ // first and report the error (with some data) later.
+ // But if we don't have enough to decrypt,
+ // have to stop now.
+ if err != nil && len(x.crypt) < x.blockSize {
+ break
+ }
+ }
+ return err
+}
+
+// Read from plain text buffer into p.
+func (x *ecbDecrypter) readPlain(p []byte) int {
+ n := len(x.plain)
+ if n > len(p) {
+ n = len(p)
+ }
+ for i := 0; i < n; i++ {
+ p[i] = x.plain[i]
+ }
+ if n < len(x.plain) {
+ x.plain = x.plain[n:]
+ } else {
+ x.plain = nil
+ }
+ return n
+}
+
+type ecbFragmentError int
+
+func (n ecbFragmentError) String() string {
+ return "crypto/block: " + strconv.Itoa(int(n)) + "-byte fragment at EOF"
+}
+
+func (x *ecbDecrypter) Read(p []byte) (n int, err os.Error) {
+ if len(p) == 0 {
+ return
+ }
+
+ // If there's no plaintext waiting and p is not big enough
+ // to hold a whole cipher block, we'll have to work in the
+ // cipher text buffer. Set it to non-nil so that the
+ // code below will fill it.
+ if x.plain == nil && len(p) < x.blockSize && x.crypt == nil {
+ x.crypt = x.buf[0:0]
+ }
+
+ // If there is a leftover cipher text buffer,
+ // try to accumulate a full block.
+ if x.crypt != nil {
+ err = x.fillCrypt()
+ if err != nil || len(x.crypt) == 0 {
+ return
+ }
+ x.c.Decrypt(x.crypt, x.crypt)
+ x.plain = x.crypt
+ x.crypt = nil
+ }
+
+ // If there is a leftover plain text buffer, read from it.
+ if x.plain != nil {
+ n = x.readPlain(p)
+ return
+ }
+
+ // Read and decrypt directly in caller's buffer.
+ n, err = io.ReadAtLeast(x.r, p, x.blockSize)
+ if err == os.EOF && n > 0 {
+ // EOF is only okay on block boundary
+ err = os.ErrorString("block fragment at EOF during decryption")
+ return
+ }
+ var i int
+ for i = 0; i+x.blockSize <= n; i += x.blockSize {
+ a := p[i : i+x.blockSize]
+ x.c.Decrypt(a, a)
+ }
+
+ // There might be an encrypted fringe remaining.
+ // Save it for next time.
+ if i < n {
+ p = p[i:n]
+ copy(x.buf, p)
+ x.crypt = x.buf[0:len(p)]
+ n = i
+ }
+
+ return
+}
+
+// NewECBDecrypter returns a reader that reads data from r and decrypts it using c.
+// It decrypts by calling c.Decrypt on each block in sequence;
+// this mode is known as electronic codebook mode, or ECB.
+// The returned Reader does not buffer or read ahead except
+// as required by the cipher's block size.
+func NewECBDecrypter(c Cipher, r io.Reader) io.Reader {
+ x := new(ecbDecrypter)
+ x.c = c
+ x.r = r
+ x.blockSize = c.BlockSize()
+ x.buf = make([]byte, x.blockSize)
+ return x
+}
+
+type ecbEncrypter struct {
+ c Cipher
+ w io.Writer
+ blockSize int
+
+ // Buffered data.
+ // The buffer buf is used as storage for both
+ // plain or crypt. If both are non-nil, plain
+ // follows crypt in buf.
+ buf []byte
+ plain []byte // plain text waiting to be encrypted
+ crypt []byte // encrypted text waiting to be written
+}
+
+// Flush the x.crypt buffer to x.w.
+func (x *ecbEncrypter) flushCrypt() os.Error {
+ if len(x.crypt) == 0 {
+ return nil
+ }
+ n, err := x.w.Write(x.crypt)
+ if n < len(x.crypt) {
+ x.crypt = x.crypt[n:]
+ if err == nil {
+ err = io.ErrShortWrite
+ }
+ }
+ if err != nil {
+ return err
+ }
+ x.crypt = nil
+ return nil
+}
+
+// Slide x.plain down to the beginning of x.buf.
+// Plain is known to have less than one block of data,
+// so this is cheap enough.
+func (x *ecbEncrypter) slidePlain() {
+ if len(x.plain) == 0 {
+ x.plain = x.buf[0:0]
+ } else if cap(x.plain) < cap(x.buf) {
+ copy(x.buf, x.plain)
+ x.plain = x.buf[0:len(x.plain)]
+ }
+}
+
+// Fill x.plain from the data in p.
+// Return the number of bytes copied.
+func (x *ecbEncrypter) fillPlain(p []byte) int {
+ off := len(x.plain)
+ n := len(p)
+ if max := cap(x.plain) - off; n > max {
+ n = max
+ }
+ x.plain = x.plain[0 : off+n]
+ for i := 0; i < n; i++ {
+ x.plain[off+i] = p[i]
+ }
+ return n
+}
+
+// Encrypt x.plain; record encrypted range as x.crypt.
+func (x *ecbEncrypter) encrypt() {
+ var i int
+ n := len(x.plain)
+ for i = 0; i+x.blockSize <= n; i += x.blockSize {
+ a := x.plain[i : i+x.blockSize]
+ x.c.Encrypt(a, a)
+ }
+ x.crypt = x.plain[0:i]
+ x.plain = x.plain[i:n]
+}
+
+func (x *ecbEncrypter) Write(p []byte) (n int, err os.Error) {
+ for {
+ // If there is data waiting to be written, write it.
+ // This can happen on the first iteration
+ // if a write failed in an earlier call.
+ if err = x.flushCrypt(); err != nil {
+ return
+ }
+
+ // Now that encrypted data is gone (flush ran),
+ // perhaps we need to slide the plaintext down.
+ x.slidePlain()
+
+ // Fill plaintext buffer from p.
+ m := x.fillPlain(p)
+ if m == 0 {
+ break
+ }
+ n += m
+ p = p[m:]
+
+ // Encrypt, adjusting crypt and plain.
+ x.encrypt()
+
+ // Write x.crypt.
+ if err = x.flushCrypt(); err != nil {
+ break
+ }
+ }
+ return
+}
+
+// NewECBEncrypter returns a writer that encrypts data using c and writes it to w.
+// It encrypts by calling c.Encrypt on each block in sequence;
+// this mode is known as electronic codebook mode, or ECB.
+// The returned Writer does no buffering except as required
+// by the cipher's block size, so there is no need for a Flush method.
+func NewECBEncrypter(c Cipher, w io.Writer) io.Writer {
+ x := new(ecbEncrypter)
+ x.c = c
+ x.w = w
+ x.blockSize = c.BlockSize()
+
+ // Create a buffer that is an integral number of blocks.
+ x.buf = make([]byte, 8192/x.blockSize*x.blockSize)
+ return x
+}
diff --git a/libgo/go/crypto/block/ecb_aes_test.go b/libgo/go/crypto/block/ecb_aes_test.go
new file mode 100644
index 000000000..14481d096
--- /dev/null
+++ b/libgo/go/crypto/block/ecb_aes_test.go
@@ -0,0 +1,127 @@
+// 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.
+
+// ECB AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 24-27.
+
+package block
+
+import (
+ "bytes"
+ "crypto/aes"
+ "io"
+ "testing"
+)
+
+type ecbTest struct {
+ name string
+ key []byte
+ in []byte
+ out []byte
+}
+
+var commonInput = []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+}
+
+var commonKey128 = []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
+
+var commonKey192 = []byte{
+ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
+}
+
+var commonKey256 = []byte{
+ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
+}
+
+var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
+
+var ecbAESTests = []ecbTest{
+ // FIPS 197, Appendix B, C
+ {
+ "FIPS-197 Appendix B",
+ commonKey128,
+ []byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34},
+ []byte{0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32},
+ },
+
+ // NIST SP 800-38A pp 24-27
+ {
+ "ECB-AES128",
+ commonKey128,
+ commonInput,
+ []byte{
+ 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97,
+ 0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d, 0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf,
+ 0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23, 0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88,
+ 0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f, 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4,
+ },
+ },
+ {
+ "ECB-AES192",
+ commonKey192,
+ commonInput,
+ []byte{
+ 0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f, 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc,
+ 0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad, 0x77, 0x34, 0xec, 0xb3, 0xec, 0xee, 0x4e, 0xef,
+ 0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a, 0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e,
+ 0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72, 0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e,
+ },
+ },
+ {
+ "ECB-AES256",
+ commonKey256,
+ commonInput,
+ []byte{
+ 0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8,
+ 0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26, 0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70,
+ 0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9, 0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d,
+ 0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff, 0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7,
+ },
+ },
+}
+
+func TestECB_AES(t *testing.T) {
+ for _, tt := range ecbAESTests {
+ test := tt.name
+
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ continue
+ }
+
+ var crypt bytes.Buffer
+ w := NewECBEncrypter(c, &crypt)
+ var r io.Reader = bytes.NewBuffer(tt.in)
+ n, err := io.Copy(w, r)
+ if n != int64(len(tt.in)) || err != nil {
+ t.Errorf("%s: ECBReader io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in))
+ } else if d := crypt.Bytes(); !same(tt.out, d) {
+ t.Errorf("%s: ECBReader\nhave %x\nwant %x", test, d, tt.out)
+ }
+
+ var plain bytes.Buffer
+ r = NewECBDecrypter(c, bytes.NewBuffer(tt.out))
+ w = &plain
+ n, err = io.Copy(w, r)
+ if n != int64(len(tt.out)) || err != nil {
+ t.Errorf("%s: ECBWriter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out))
+ } else if d := plain.Bytes(); !same(tt.in, d) {
+ t.Errorf("%s: ECBWriter\nhave %x\nwant %x", test, d, tt.in)
+ }
+
+ if t.Failed() {
+ break
+ }
+ }
+}
diff --git a/libgo/go/crypto/block/ecb_test.go b/libgo/go/crypto/block/ecb_test.go
new file mode 100644
index 000000000..6f79d929a
--- /dev/null
+++ b/libgo/go/crypto/block/ecb_test.go
@@ -0,0 +1,181 @@
+// 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 block
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "testing"
+ "testing/iotest"
+)
+
+// Simple Cipher for testing: adds an incrementing amount
+// to each byte in each
+type IncCipher struct {
+ blockSize int
+ delta byte
+ encrypting bool
+}
+
+func (c *IncCipher) BlockSize() int { return c.blockSize }
+
+func (c *IncCipher) Encrypt(dst, src []byte) {
+ if !c.encrypting {
+ panic("encrypt: not encrypting")
+ }
+ if len(src) != c.blockSize || len(dst) != c.blockSize {
+ panic(fmt.Sprintln("encrypt: wrong block size", c.blockSize, len(src), len(dst)))
+ }
+ c.delta++
+ for i, b := range src {
+ dst[i] = b + c.delta
+ }
+}
+
+func (c *IncCipher) Decrypt(dst, src []byte) {
+ if c.encrypting {
+ panic("decrypt: not decrypting")
+ }
+ if len(src) != c.blockSize || len(dst) != c.blockSize {
+ panic(fmt.Sprintln("decrypt: wrong block size ", c.blockSize, " ", len(src), " ", len(dst)))
+ }
+ c.delta--
+ for i, b := range src {
+ dst[i] = b + c.delta
+ }
+}
+
+func TestECBEncrypter(t *testing.T) {
+ var plain, crypt [256]byte
+ for i := 0; i < len(plain); i++ {
+ plain[i] = byte(i)
+ }
+ b := new(bytes.Buffer)
+ for block := 1; block <= 64; block *= 2 {
+ // compute encrypted version
+ delta := byte(0)
+ for i := 0; i < len(crypt); i++ {
+ if i%block == 0 {
+ delta++
+ }
+ crypt[i] = plain[i] + delta
+ }
+
+ for frag := 0; frag < 2; frag++ {
+ c := &IncCipher{block, 0, true}
+ b.Reset()
+ r := bytes.NewBuffer(plain[0:])
+ w := NewECBEncrypter(c, b)
+
+ // copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ...
+ // if frag != 0, move the 1 to the end to cause fragmentation.
+ if frag == 0 {
+ _, err := io.Copyn(w, r, 1)
+ if err != nil {
+ t.Errorf("block=%d frag=0: first Copyn: %s", block, err)
+ continue
+ }
+ }
+ for n := 1; n <= len(plain)/2; n *= 2 {
+ _, err := io.Copyn(w, r, int64(n))
+ if err != nil {
+ t.Errorf("block=%d frag=%d: Copyn %d: %s", block, frag, n, err)
+ }
+ }
+ if frag != 0 {
+ _, err := io.Copyn(w, r, 1)
+ if err != nil {
+ t.Errorf("block=%d frag=1: last Copyn: %s", block, err)
+ continue
+ }
+ }
+
+ // check output
+ data := b.Bytes()
+ if len(data) != len(crypt) {
+ t.Errorf("block=%d frag=%d: want %d bytes, got %d", block, frag, len(crypt), len(data))
+ continue
+ }
+
+ if string(data) != string(crypt[0:]) {
+ t.Errorf("block=%d frag=%d: want %x got %x", block, frag, data, crypt)
+ }
+ }
+ }
+}
+
+func testECBDecrypter(t *testing.T, maxio int) {
+ var readers = []func(io.Reader) io.Reader{
+ func(r io.Reader) io.Reader { return r },
+ iotest.OneByteReader,
+ iotest.HalfReader,
+ }
+ var plain, crypt [256]byte
+ for i := 0; i < len(plain); i++ {
+ plain[i] = byte(255 - i)
+ }
+ b := new(bytes.Buffer)
+ for block := 1; block <= 64 && block <= maxio; block *= 2 {
+ // compute encrypted version
+ delta := byte(0)
+ for i := 0; i < len(crypt); i++ {
+ if i%block == 0 {
+ delta++
+ }
+ crypt[i] = plain[i] + delta
+ }
+
+ for mode := 0; mode < len(readers); mode++ {
+ for frag := 0; frag < 2; frag++ {
+ test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio)
+ c := &IncCipher{block, 0, false}
+ b.Reset()
+ r := NewECBDecrypter(c, readers[mode](bytes.NewBuffer(crypt[0:maxio])))
+
+ // read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ...
+ // if frag == 1, move the 1 to the end to cause fragmentation.
+ if frag == 0 {
+ _, err := io.Copyn(b, r, 1)
+ if err != nil {
+ t.Errorf("%s: first Copyn: %s", test, err)
+ continue
+ }
+ }
+ for n := 1; n <= maxio/2; n *= 2 {
+ _, err := io.Copyn(b, r, int64(n))
+ if err != nil {
+ t.Errorf("%s: Copyn %d: %s", test, n, err)
+ }
+ }
+ if frag != 0 {
+ _, err := io.Copyn(b, r, 1)
+ if err != nil {
+ t.Errorf("%s: last Copyn: %s", test, err)
+ continue
+ }
+ }
+
+ // check output
+ data := b.Bytes()
+ if len(data) != maxio {
+ t.Errorf("%s: want %d bytes, got %d", test, maxio, len(data))
+ continue
+ }
+
+ if string(data) != string(plain[0:maxio]) {
+ t.Errorf("%s: input=%x want %x got %x", test, crypt[0:maxio], plain[0:maxio], data)
+ }
+ }
+ }
+ }
+}
+
+func TestECBDecrypter(t *testing.T) {
+ // Do shorter I/O sizes first; they're easier to debug.
+ for n := 1; n <= 256 && !t.Failed(); n *= 2 {
+ testECBDecrypter(t, n)
+ }
+}
diff --git a/libgo/go/crypto/block/ofb.go b/libgo/go/crypto/block/ofb.go
new file mode 100644
index 000000000..11aaaa4d7
--- /dev/null
+++ b/libgo/go/crypto/block/ofb.go
@@ -0,0 +1,60 @@
+// 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.
+
+// Output feedback (OFB) mode.
+
+// OFB converts a block cipher into a stream cipher by
+// repeatedly encrypting an initialization vector and
+// xoring the resulting stream of data with the input.
+
+// See NIST SP 800-38A, pp 13-15
+
+package block
+
+import (
+ "fmt"
+ "io"
+)
+
+type ofbStream struct {
+ c Cipher
+ iv []byte
+}
+
+func newOFBStream(c Cipher, iv []byte) *ofbStream {
+ x := new(ofbStream)
+ x.c = c
+ n := len(iv)
+ if n != c.BlockSize() {
+ panic(fmt.Sprintln("crypto/block: newOFBStream: invalid iv size", n, "!=", c.BlockSize()))
+ }
+ x.iv = dup(iv)
+ return x
+}
+
+func (x *ofbStream) Next() []byte {
+ x.c.Encrypt(x.iv, x.iv)
+ return x.iv
+}
+
+// NewOFBReader returns a reader that reads data from r, decrypts (or encrypts)
+// it using c in output feedback (OFB) mode with the initialization vector iv.
+// The returned Reader does not buffer and has no block size.
+// In OFB mode, encryption and decryption are the same operation:
+// an OFB reader applied to an encrypted stream produces a decrypted
+// stream and vice versa.
+func NewOFBReader(c Cipher, iv []byte, r io.Reader) io.Reader {
+ return newXorReader(newOFBStream(c, iv), r)
+}
+
+// NewOFBWriter returns a writer that encrypts (or decrypts) data using c
+// in cipher feedback (OFB) mode with the initialization vector iv
+// and writes the encrypted data to w.
+// The returned Writer does not buffer and has no block size.
+// In OFB mode, encryption and decryption are the same operation:
+// an OFB writer applied to an decrypted stream produces an encrypted
+// stream and vice versa.
+func NewOFBWriter(c Cipher, iv []byte, w io.Writer) io.Writer {
+ return newXorWriter(newOFBStream(c, iv), w)
+}
diff --git a/libgo/go/crypto/block/ofb_aes_test.go b/libgo/go/crypto/block/ofb_aes_test.go
new file mode 100644
index 000000000..9c527a6b3
--- /dev/null
+++ b/libgo/go/crypto/block/ofb_aes_test.go
@@ -0,0 +1,108 @@
+// 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.
+
+// OFB AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 52-55.
+
+package block
+
+import (
+ "bytes"
+ "crypto/aes"
+ "io"
+ "testing"
+)
+
+type ofbTest struct {
+ name string
+ key []byte
+ iv []byte
+ in []byte
+ out []byte
+}
+
+var ofbAESTests = []ofbTest{
+ // NIST SP 800-38A pp 52-55
+ {
+ "OFB-AES128",
+ commonKey128,
+ commonIV,
+ commonInput,
+ []byte{
+ 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
+ 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25,
+ 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc,
+ 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e,
+ },
+ },
+ {
+ "OFB-AES192",
+ commonKey192,
+ commonIV,
+ commonInput,
+ []byte{
+ 0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
+ 0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01,
+ 0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2,
+ 0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a,
+ },
+ },
+ {
+ "OFB-AES256",
+ commonKey256,
+ commonIV,
+ commonInput,
+ []byte{
+ 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
+ 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d,
+ 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08,
+ 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84,
+ },
+ },
+}
+
+func TestOFB_AES(t *testing.T) {
+ for _, tt := range ofbAESTests {
+ test := tt.name
+
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ continue
+ }
+
+ for j := 0; j <= 5; j += 5 {
+ var crypt bytes.Buffer
+ in := tt.in[0 : len(tt.in)-j]
+ w := NewOFBWriter(c, tt.iv, &crypt)
+ var r io.Reader = bytes.NewBuffer(in)
+ n, err := io.Copy(w, r)
+ if n != int64(len(in)) || err != nil {
+ t.Errorf("%s/%d: OFBWriter io.Copy = %d, %v want %d, nil", test, len(in), n, err, len(in))
+ } else if d, out := crypt.Bytes(), tt.out[0:len(in)]; !same(out, d) {
+ t.Errorf("%s/%d: OFBWriter\ninpt %x\nhave %x\nwant %x", test, len(in), in, d, out)
+ }
+ }
+
+ for j := 0; j <= 7; j += 7 {
+ var plain bytes.Buffer
+ out := tt.out[0 : len(tt.out)-j]
+ r := NewOFBReader(c, tt.iv, bytes.NewBuffer(out))
+ w := &plain
+ n, err := io.Copy(w, r)
+ if n != int64(len(out)) || err != nil {
+ t.Errorf("%s/%d: OFBReader io.Copy = %d, %v want %d, nil", test, len(out), n, err, len(out))
+ } else if d, in := plain.Bytes(), tt.in[0:len(out)]; !same(in, d) {
+ t.Errorf("%s/%d: OFBReader\nhave %x\nwant %x", test, len(out), d, in)
+ }
+ }
+
+ if t.Failed() {
+ break
+ }
+ }
+}
diff --git a/libgo/go/crypto/block/xor.go b/libgo/go/crypto/block/xor.go
new file mode 100644
index 000000000..9d8b17224
--- /dev/null
+++ b/libgo/go/crypto/block/xor.go
@@ -0,0 +1,124 @@
+// 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.
+
+// Encrypt/decrypt data by xor with a pseudo-random data stream.
+
+package block
+
+import (
+ "io"
+ "os"
+)
+
+// A dataStream is an interface to an unending stream of data,
+// used by XorReader and XorWriter to model a pseudo-random generator.
+// Calls to Next() return sequential blocks of data from the stream.
+// Each call must return at least one byte: there is no EOF.
+type dataStream interface {
+ Next() []byte
+}
+
+type xorReader struct {
+ r io.Reader
+ rand dataStream // pseudo-random
+ buf []byte // data available from last call to rand
+}
+
+func newXorReader(rand dataStream, r io.Reader) io.Reader {
+ x := new(xorReader)
+ x.r = r
+ x.rand = rand
+ return x
+}
+
+func (x *xorReader) Read(p []byte) (n int, err os.Error) {
+ n, err = x.r.Read(p)
+
+ // xor input with stream.
+ bp := 0
+ buf := x.buf
+ for i := 0; i < n; i++ {
+ if bp >= len(buf) {
+ buf = x.rand.Next()
+ bp = 0
+ }
+ p[i] ^= buf[bp]
+ bp++
+ }
+ x.buf = buf[bp:]
+ return n, err
+}
+
+type xorWriter struct {
+ w io.Writer
+ rand dataStream // pseudo-random
+ buf []byte // last buffer returned by rand
+ extra []byte // extra random data (use before buf)
+ work []byte // work space
+}
+
+func newXorWriter(rand dataStream, w io.Writer) io.Writer {
+ x := new(xorWriter)
+ x.w = w
+ x.rand = rand
+ x.work = make([]byte, 4096)
+ return x
+}
+
+func (x *xorWriter) Write(p []byte) (n int, err os.Error) {
+ for len(p) > 0 {
+ // Determine next chunk of random data
+ // and xor with p into x.work.
+ var chunk []byte
+ m := len(p)
+ if nn := len(x.extra); nn > 0 {
+ // extra points into work, so edit directly
+ if m > nn {
+ m = nn
+ }
+ for i := 0; i < m; i++ {
+ x.extra[i] ^= p[i]
+ }
+ chunk = x.extra[0:m]
+ } else {
+ // xor p ^ buf into work, refreshing buf as needed
+ if nn := len(x.work); m > nn {
+ m = nn
+ }
+ bp := 0
+ buf := x.buf
+ for i := 0; i < m; i++ {
+ if bp >= len(buf) {
+ buf = x.rand.Next()
+ bp = 0
+ }
+ x.work[i] = buf[bp] ^ p[i]
+ bp++
+ }
+ x.buf = buf[bp:]
+ chunk = x.work[0:m]
+ }
+
+ // Write chunk.
+ var nn int
+ nn, err = x.w.Write(chunk)
+ if nn != len(chunk) && err == nil {
+ err = io.ErrShortWrite
+ }
+ if nn < len(chunk) {
+ // Reconstruct the random bits from the unwritten
+ // data and save them for next time.
+ for i := nn; i < m; i++ {
+ chunk[i] ^= p[i]
+ }
+ x.extra = chunk[nn:]
+ }
+ n += nn
+ if err != nil {
+ return
+ }
+ p = p[m:]
+ }
+ return
+}
diff --git a/libgo/go/crypto/block/xor_test.go b/libgo/go/crypto/block/xor_test.go
new file mode 100644
index 000000000..50f6bb08d
--- /dev/null
+++ b/libgo/go/crypto/block/xor_test.go
@@ -0,0 +1,168 @@
+// 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 block
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "testing"
+ "testing/iotest"
+)
+
+// Simple "pseudo-random" stream for testing.
+type incStream struct {
+ buf []byte
+ n byte
+}
+
+func newIncStream(blockSize int) *incStream {
+ x := new(incStream)
+ x.buf = make([]byte, blockSize)
+ return x
+}
+
+func (x *incStream) Next() []byte {
+ x.n++
+ for i := range x.buf {
+ x.buf[i] = x.n
+ x.n++
+ }
+ return x.buf
+}
+
+func testXorWriter(t *testing.T, maxio int) {
+ var plain, crypt [256]byte
+ for i := 0; i < len(plain); i++ {
+ plain[i] = byte(i)
+ }
+ b := new(bytes.Buffer)
+ for block := 1; block <= 64 && block <= maxio; block *= 2 {
+ // compute encrypted version
+ n := byte(0)
+ for i := 0; i < len(crypt); i++ {
+ if i%block == 0 {
+ n++
+ }
+ crypt[i] = plain[i] ^ n
+ n++
+ }
+
+ for frag := 0; frag < 2; frag++ {
+ test := fmt.Sprintf("block=%d frag=%d maxio=%d", block, frag, maxio)
+ b.Reset()
+ r := bytes.NewBuffer(plain[0:])
+ s := newIncStream(block)
+ w := newXorWriter(s, b)
+
+ // copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ...
+ // if frag != 0, move the 1 to the end to cause fragmentation.
+ if frag == 0 {
+ _, err := io.Copyn(w, r, 1)
+ if err != nil {
+ t.Errorf("%s: first Copyn: %s", test, err)
+ continue
+ }
+ }
+ for n := 1; n <= len(plain)/2; n *= 2 {
+ _, err := io.Copyn(w, r, int64(n))
+ if err != nil {
+ t.Errorf("%s: Copyn %d: %s", test, n, err)
+ }
+ }
+
+ // check output
+ crypt := crypt[0 : len(crypt)-frag]
+ data := b.Bytes()
+ if len(data) != len(crypt) {
+ t.Errorf("%s: want %d bytes, got %d", test, len(crypt), len(data))
+ continue
+ }
+
+ if string(data) != string(crypt) {
+ t.Errorf("%s: want %x got %x", test, data, crypt)
+ }
+ }
+ }
+}
+
+
+func TestXorWriter(t *testing.T) {
+ // Do shorter I/O sizes first; they're easier to debug.
+ for n := 1; n <= 256 && !t.Failed(); n *= 2 {
+ testXorWriter(t, n)
+ }
+}
+
+func testXorReader(t *testing.T, maxio int) {
+ var readers = []func(io.Reader) io.Reader{
+ func(r io.Reader) io.Reader { return r },
+ iotest.OneByteReader,
+ iotest.HalfReader,
+ }
+ var plain, crypt [256]byte
+ for i := 0; i < len(plain); i++ {
+ plain[i] = byte(255 - i)
+ }
+ b := new(bytes.Buffer)
+ for block := 1; block <= 64 && block <= maxio; block *= 2 {
+ // compute encrypted version
+ n := byte(0)
+ for i := 0; i < len(crypt); i++ {
+ if i%block == 0 {
+ n++
+ }
+ crypt[i] = plain[i] ^ n
+ n++
+ }
+
+ for mode := 0; mode < len(readers); mode++ {
+ for frag := 0; frag < 2; frag++ {
+ test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio)
+ s := newIncStream(block)
+ b.Reset()
+ r := newXorReader(s, readers[mode](bytes.NewBuffer(crypt[0:maxio])))
+
+ // read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ...
+ // if frag == 1, move the 1 to the end to cause fragmentation.
+ if frag == 0 {
+ _, err := io.Copyn(b, r, 1)
+ if err != nil {
+ t.Errorf("%s: first Copyn: %s", test, err)
+ continue
+ }
+ }
+ for n := 1; n <= maxio/2; n *= 2 {
+ _, err := io.Copyn(b, r, int64(n))
+ if err != nil {
+ t.Errorf("%s: Copyn %d: %s", test, n, err)
+ }
+ }
+
+ // check output
+ data := b.Bytes()
+ crypt := crypt[0 : maxio-frag]
+ plain := plain[0 : maxio-frag]
+ if len(data) != len(plain) {
+ t.Errorf("%s: want %d bytes, got %d", test, len(plain), len(data))
+ continue
+ }
+
+ if string(data) != string(plain) {
+ t.Errorf("%s: input=%x want %x got %x", test, crypt, plain, data)
+ }
+ }
+ }
+ }
+}
+
+func TestXorReader(t *testing.T) {
+ // Do shorter I/O sizes first; they're easier to debug.
+ for n := 1; n <= 256 && !t.Failed(); n *= 2 {
+ testXorReader(t, n)
+ }
+}
+
+// TODO(rsc): Test handling of writes after write errors.
diff --git a/libgo/go/crypto/blowfish/block.go b/libgo/go/crypto/blowfish/block.go
new file mode 100644
index 000000000..7fbe7eefb
--- /dev/null
+++ b/libgo/go/crypto/blowfish/block.go
@@ -0,0 +1,101 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+func expandKey(key []byte, c *Cipher) {
+ copy(c.p[0:], p[0:])
+ copy(c.s0[0:], s0[0:])
+ copy(c.s1[0:], s1[0:])
+ copy(c.s2[0:], s2[0:])
+ copy(c.s3[0:], s3[0:])
+
+ j := 0
+ for i := 0; i < 18; i++ {
+ var d uint32
+ for k := 0; k < 4; k++ {
+ d = d<<8 | uint32(key[j])&0x000000FF
+ j++
+ if j >= len(key) {
+ j = 0
+ }
+ }
+ c.p[i] ^= d
+ }
+
+ var l, r uint32
+ for i := 0; i < 18; i += 2 {
+ l, r = encryptBlock(l, r, c)
+ c.p[i], c.p[i+1] = l, r
+ }
+
+ for i := 0; i < 256; i += 2 {
+ l, r = encryptBlock(l, r, c)
+ c.s0[i], c.s0[i+1] = l, r
+ }
+ for i := 0; i < 256; i += 2 {
+ l, r = encryptBlock(l, r, c)
+ c.s1[i], c.s1[i+1] = l, r
+ }
+ for i := 0; i < 256; i += 2 {
+ l, r = encryptBlock(l, r, c)
+ c.s2[i], c.s2[i+1] = l, r
+ }
+ for i := 0; i < 256; i += 2 {
+ l, r = encryptBlock(l, r, c)
+ c.s3[i], c.s3[i+1] = l, r
+ }
+}
+
+func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+ xl, xr := l, r
+ xl ^= c.p[0]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
+ xr ^= c.p[17]
+ return xr, xl
+}
+
+func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+ xl, xr := l, r
+ xl ^= c.p[17]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
+ xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
+ xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
+ xr ^= c.p[0]
+ return xr, xl
+}
+
+func zero(x []uint32) {
+ for i := range x {
+ x[i] = 0
+ }
+}
diff --git a/libgo/go/crypto/blowfish/blowfish_test.go b/libgo/go/crypto/blowfish/blowfish_test.go
new file mode 100644
index 000000000..3a7ab6c2a
--- /dev/null
+++ b/libgo/go/crypto/blowfish/blowfish_test.go
@@ -0,0 +1,192 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+import (
+ "testing"
+)
+
+type CryptTest struct {
+ key []byte
+ in []byte
+ out []byte
+}
+
+// Test vector values are from http://www.schneier.com/code/vectors.txt.
+var encryptTests = []CryptTest{
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
+ {
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x51, 0x86, 0x6F, 0xD5, 0xB8, 0x5E, 0xCB, 0x8A}},
+ {
+ []byte{0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ []byte{0x7D, 0x85, 0x6F, 0x9A, 0x61, 0x30, 0x63, 0xF2}},
+ {
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x24, 0x66, 0xDD, 0x87, 0x8B, 0x96, 0x3C, 0x9D}},
+
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x61, 0xF9, 0xC3, 0x80, 0x22, 0x81, 0xB0, 0x96}},
+ {
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x7D, 0x0C, 0xC6, 0x30, 0xAF, 0xDA, 0x1E, 0xC7}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
+ {
+ []byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x0A, 0xCE, 0xAB, 0x0F, 0xC6, 0xA0, 0xA2, 0x8D}},
+ {
+ []byte{0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57},
+ []byte{0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42},
+ []byte{0x59, 0xC6, 0x82, 0x45, 0xEB, 0x05, 0x28, 0x2B}},
+ {
+ []byte{0x01, 0x31, 0xD9, 0x61, 0x9D, 0xC1, 0x37, 0x6E},
+ []byte{0x5C, 0xD5, 0x4C, 0xA8, 0x3D, 0xEF, 0x57, 0xDA},
+ []byte{0xB1, 0xB8, 0xCC, 0x0B, 0x25, 0x0F, 0x09, 0xA0}},
+ {
+ []byte{0x07, 0xA1, 0x13, 0x3E, 0x4A, 0x0B, 0x26, 0x86},
+ []byte{0x02, 0x48, 0xD4, 0x38, 0x06, 0xF6, 0x71, 0x72},
+ []byte{0x17, 0x30, 0xE5, 0x77, 0x8B, 0xEA, 0x1D, 0xA4}},
+ {
+ []byte{0x38, 0x49, 0x67, 0x4C, 0x26, 0x02, 0x31, 0x9E},
+ []byte{0x51, 0x45, 0x4B, 0x58, 0x2D, 0xDF, 0x44, 0x0A},
+ []byte{0xA2, 0x5E, 0x78, 0x56, 0xCF, 0x26, 0x51, 0xEB}},
+ {
+ []byte{0x04, 0xB9, 0x15, 0xBA, 0x43, 0xFE, 0xB5, 0xB6},
+ []byte{0x42, 0xFD, 0x44, 0x30, 0x59, 0x57, 0x7F, 0xA2},
+ []byte{0x35, 0x38, 0x82, 0xB1, 0x09, 0xCE, 0x8F, 0x1A}},
+ {
+ []byte{0x01, 0x13, 0xB9, 0x70, 0xFD, 0x34, 0xF2, 0xCE},
+ []byte{0x05, 0x9B, 0x5E, 0x08, 0x51, 0xCF, 0x14, 0x3A},
+ []byte{0x48, 0xF4, 0xD0, 0x88, 0x4C, 0x37, 0x99, 0x18}},
+ {
+ []byte{0x01, 0x70, 0xF1, 0x75, 0x46, 0x8F, 0xB5, 0xE6},
+ []byte{0x07, 0x56, 0xD8, 0xE0, 0x77, 0x47, 0x61, 0xD2},
+ []byte{0x43, 0x21, 0x93, 0xB7, 0x89, 0x51, 0xFC, 0x98}},
+ {
+ []byte{0x43, 0x29, 0x7F, 0xAD, 0x38, 0xE3, 0x73, 0xFE},
+ []byte{0x76, 0x25, 0x14, 0xB8, 0x29, 0xBF, 0x48, 0x6A},
+ []byte{0x13, 0xF0, 0x41, 0x54, 0xD6, 0x9D, 0x1A, 0xE5}},
+ {
+ []byte{0x07, 0xA7, 0x13, 0x70, 0x45, 0xDA, 0x2A, 0x16},
+ []byte{0x3B, 0xDD, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02},
+ []byte{0x2E, 0xED, 0xDA, 0x93, 0xFF, 0xD3, 0x9C, 0x79}},
+ {
+ []byte{0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F},
+ []byte{0x26, 0x95, 0x5F, 0x68, 0x35, 0xAF, 0x60, 0x9A},
+ []byte{0xD8, 0x87, 0xE0, 0x39, 0x3C, 0x2D, 0xA6, 0xE3}},
+ {
+ []byte{0x37, 0xD0, 0x6B, 0xB5, 0x16, 0xCB, 0x75, 0x46},
+ []byte{0x16, 0x4D, 0x5E, 0x40, 0x4F, 0x27, 0x52, 0x32},
+ []byte{0x5F, 0x99, 0xD0, 0x4F, 0x5B, 0x16, 0x39, 0x69}},
+ {
+ []byte{0x1F, 0x08, 0x26, 0x0D, 0x1A, 0xC2, 0x46, 0x5E},
+ []byte{0x6B, 0x05, 0x6E, 0x18, 0x75, 0x9F, 0x5C, 0xCA},
+ []byte{0x4A, 0x05, 0x7A, 0x3B, 0x24, 0xD3, 0x97, 0x7B}},
+ {
+ []byte{0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76},
+ []byte{0x00, 0x4B, 0xD6, 0xEF, 0x09, 0x17, 0x60, 0x62},
+ []byte{0x45, 0x20, 0x31, 0xC1, 0xE4, 0xFA, 0xDA, 0x8E}},
+ {
+ []byte{0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xB0, 0x07},
+ []byte{0x48, 0x0D, 0x39, 0x00, 0x6E, 0xE7, 0x62, 0xF2},
+ []byte{0x75, 0x55, 0xAE, 0x39, 0xF5, 0x9B, 0x87, 0xBD}},
+ {
+ []byte{0x49, 0x79, 0x3E, 0xBC, 0x79, 0xB3, 0x25, 0x8F},
+ []byte{0x43, 0x75, 0x40, 0xC8, 0x69, 0x8F, 0x3C, 0xFA},
+ []byte{0x53, 0xC5, 0x5F, 0x9C, 0xB4, 0x9F, 0xC0, 0x19}},
+ {
+ []byte{0x4F, 0xB0, 0x5E, 0x15, 0x15, 0xAB, 0x73, 0xA7},
+ []byte{0x07, 0x2D, 0x43, 0xA0, 0x77, 0x07, 0x52, 0x92},
+ []byte{0x7A, 0x8E, 0x7B, 0xFA, 0x93, 0x7E, 0x89, 0xA3}},
+ {
+ []byte{0x49, 0xE9, 0x5D, 0x6D, 0x4C, 0xA2, 0x29, 0xBF},
+ []byte{0x02, 0xFE, 0x55, 0x77, 0x81, 0x17, 0xF1, 0x2A},
+ []byte{0xCF, 0x9C, 0x5D, 0x7A, 0x49, 0x86, 0xAD, 0xB5}},
+ {
+ []byte{0x01, 0x83, 0x10, 0xDC, 0x40, 0x9B, 0x26, 0xD6},
+ []byte{0x1D, 0x9D, 0x5C, 0x50, 0x18, 0xF7, 0x28, 0xC2},
+ []byte{0xD1, 0xAB, 0xB2, 0x90, 0x65, 0x8B, 0xC7, 0x78}},
+ {
+ []byte{0x1C, 0x58, 0x7F, 0x1C, 0x13, 0x92, 0x4F, 0xEF},
+ []byte{0x30, 0x55, 0x32, 0x28, 0x6D, 0x6F, 0x29, 0x5A},
+ []byte{0x55, 0xCB, 0x37, 0x74, 0xD1, 0x3E, 0xF2, 0x01}},
+ {
+ []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0xFA, 0x34, 0xEC, 0x48, 0x47, 0xB2, 0x68, 0xB2}},
+ {
+ []byte{0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE}},
+ {
+ []byte{0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0xC3, 0x9E, 0x07, 0x2D, 0x9F, 0xAC, 0x63, 0x1D}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x01, 0x49, 0x33, 0xE0, 0xCD, 0xAF, 0xF6, 0xE4}},
+ {
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xF2, 0x1E, 0x9A, 0x77, 0xB7, 0x1C, 0x49, 0xBC}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x24, 0x59, 0x46, 0x88, 0x57, 0x54, 0x36, 0x9A}},
+ {
+ []byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x6B, 0x5C, 0x5A, 0x9C, 0x5D, 0x9E, 0x0A, 0x5A}},
+}
+
+func TestCipherEncrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ ct := make([]byte, len(tt.out))
+ c.Encrypt(ct, tt.in)
+ for j, v := range ct {
+ if v != tt.out[j] {
+ t.Errorf("Cipher.Encrypt, test vector #%d: cipher-text[%d] = %#x, expected %#x", i, j, v, tt.out[j])
+ break
+ }
+ }
+ }
+}
+
+func TestCipherDecrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ pt := make([]byte, len(tt.in))
+ c.Decrypt(pt, tt.out)
+ for j, v := range pt {
+ if v != tt.in[j] {
+ t.Errorf("Cipher.Decrypt, test vector #%d: plain-text[%d] = %#x, expected %#x", i, j, v, tt.in[j])
+ break
+ }
+ }
+ }
+}
diff --git a/libgo/go/crypto/blowfish/cipher.go b/libgo/go/crypto/blowfish/cipher.go
new file mode 100644
index 000000000..947f762d8
--- /dev/null
+++ b/libgo/go/crypto/blowfish/cipher.go
@@ -0,0 +1,79 @@
+// 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.
+
+// This package implements Bruce Schneier's Blowfish encryption algorithm.
+package blowfish
+
+// The code is a port of Bruce Schneier's C implementation.
+// See http://www.schneier.com/blowfish.html.
+
+import (
+ "os"
+ "strconv"
+)
+
+// The Blowfish block size in bytes.
+const BlockSize = 8
+
+// A Cipher is an instance of Blowfish encryption using a particular key.
+type Cipher struct {
+ p [18]uint32
+ s0, s1, s2, s3 [256]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a Cipher.
+// The key argument should be the Blowfish key, 4 to 56 bytes.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ k := len(key)
+ if k < 4 || k > 56 {
+ return nil, KeySizeError(k)
+ }
+ var result Cipher
+ expandKey(key, &result)
+ return &result, nil
+}
+
+// BlockSize returns the Blowfish block size, 8 bytes.
+// It is necessary to satisfy the Cipher interface in the
+// package "crypto/block".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+ l, r = encryptBlock(l, r, c)
+ dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+ dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+// Decrypt decrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+ l, r = decryptBlock(l, r, c)
+ dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+ dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+// Reset zeros the key data, so that it will no longer
+// appear in the process's memory.
+func (c *Cipher) Reset() {
+ zero(c.p[0:])
+ zero(c.s0[0:])
+ zero(c.s1[0:])
+ zero(c.s2[0:])
+ zero(c.s3[0:])
+}
diff --git a/libgo/go/crypto/blowfish/const.go b/libgo/go/crypto/blowfish/const.go
new file mode 100644
index 000000000..8c5ee4cb0
--- /dev/null
+++ b/libgo/go/crypto/blowfish/const.go
@@ -0,0 +1,199 @@
+// 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.
+
+// The startup permutation array and substitution boxes.
+// They are the hexadecimal digits of PI; see:
+// http://www.schneier.com/code/constants.txt.
+
+package blowfish
+
+var s0 = [256]uint32{
+ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
+ 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
+ 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
+ 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
+ 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
+ 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
+ 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
+ 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
+ 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
+ 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
+ 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
+ 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
+ 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
+ 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
+ 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
+ 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
+ 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
+ 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
+ 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
+ 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
+ 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
+ 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+}
+
+var s1 = [256]uint32{
+ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
+ 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
+ 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
+ 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
+ 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
+ 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
+ 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
+ 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
+ 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
+ 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
+ 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
+ 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
+ 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
+ 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
+ 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
+ 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
+ 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
+ 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
+ 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
+ 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
+ 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
+ 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+}
+
+var s2 = [256]uint32{
+ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
+ 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
+ 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
+ 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
+ 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
+ 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
+ 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
+ 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
+ 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
+ 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
+ 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
+ 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
+ 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
+ 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
+ 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
+ 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
+ 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
+ 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
+ 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
+ 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
+ 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
+ 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+}
+
+var s3 = [256]uint32{
+ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
+ 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
+ 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
+ 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
+ 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
+ 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
+ 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
+ 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
+ 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
+ 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
+ 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
+ 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
+ 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
+ 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
+ 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
+ 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
+ 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
+ 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
+ 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
+ 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
+ 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
+ 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+}
+
+var p = [18]uint32{
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
+ 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
+}
diff --git a/libgo/go/crypto/cast5/cast5.go b/libgo/go/crypto/cast5/cast5.go
new file mode 100644
index 000000000..35f3e64b6
--- /dev/null
+++ b/libgo/go/crypto/cast5/cast5.go
@@ -0,0 +1,536 @@
+// 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.
+
+// This package implements CAST5, as defined in RFC 2144. CAST5 is a common
+// OpenPGP cipher.
+package cast5
+
+import (
+ "os"
+)
+
+const BlockSize = 8
+const KeySize = 16
+
+type Cipher struct {
+ masking [16]uint32
+ rotate [16]uint8
+}
+
+func NewCipher(key []byte) (c *Cipher, err os.Error) {
+ if len(key) != KeySize {
+ return nil, os.ErrorString("CAST5: keys must be 16 bytes")
+ }
+
+ c = new(Cipher)
+ c.keySchedule(key)
+ return
+}
+
+func (c *Cipher) BlockSize() int {
+ return BlockSize
+}
+
+// Reset zeros the key material in memory.
+func (c *Cipher) Reset() {
+ for i := 0; i < 16; i++ {
+ c.masking[i] = 0
+ c.rotate[i] = 0
+ }
+}
+
+func (c *Cipher) Encrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+ l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+ l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+ l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+ l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+
+ l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+ l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+ l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+ l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+
+ l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+ l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+ l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+ l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+
+ l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+ l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+ l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+ l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+
+ dst[0] = uint8(r >> 24)
+ dst[1] = uint8(r >> 16)
+ dst[2] = uint8(r >> 8)
+ dst[3] = uint8(r)
+ dst[4] = uint8(l >> 24)
+ dst[5] = uint8(l >> 16)
+ dst[6] = uint8(l >> 8)
+ dst[7] = uint8(l)
+}
+
+func (c *Cipher) Decrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+ l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+ l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+ l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+ l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+
+ l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+ l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+ l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+ l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+
+ l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+ l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+ l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+ l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+
+ l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+ l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+ l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+ l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+
+ dst[0] = uint8(r >> 24)
+ dst[1] = uint8(r >> 16)
+ dst[2] = uint8(r >> 8)
+ dst[3] = uint8(r)
+ dst[4] = uint8(l >> 24)
+ dst[5] = uint8(l >> 16)
+ dst[6] = uint8(l >> 8)
+ dst[7] = uint8(l)
+}
+
+type keyScheduleA [4][7]uint8
+type keyScheduleB [4][5]uint8
+
+// keyScheduleRound contains the magic values for a round of the key schedule.
+// The keyScheduleA deals with the lines like:
+// z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]
+// Conceptually, both x and z are in the same array, x first. The first
+// element describes which word of this array gets written to and the
+// second, which word gets read. So, for the line above, it's "4, 0", because
+// it's writing to the first word of z, which, being after x, is word 4, and
+// reading from the first word of x: word 0.
+//
+// Next are the indexes into the S-boxes. Now the array is treated as bytes. So
+// "xD" is 0xd. The first byte of z is written as "16 + 0", just to be clear
+// that it's z that we're indexing.
+//
+// keyScheduleB deals with lines like:
+// K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]
+// "K1" is ignored because key words are always written in order. So the five
+// elements are the S-box indexes. They use the same form as in keyScheduleA,
+// above.
+
+type keyScheduleRound struct{}
+type keySchedule []keyScheduleRound
+
+var schedule = []struct {
+ a keyScheduleA
+ b keyScheduleB
+}{
+ {
+ keyScheduleA{
+ {4, 0, 0xd, 0xf, 0xc, 0xe, 0x8},
+ {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+ {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+ {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+ },
+ keyScheduleB{
+ {16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2},
+ {16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6},
+ {16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9},
+ {16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc},
+ },
+ },
+ {
+ keyScheduleA{
+ {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+ {1, 4, 0, 2, 1, 3, 16 + 2},
+ {2, 5, 7, 6, 5, 4, 16 + 1},
+ {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+ },
+ keyScheduleB{
+ {3, 2, 0xc, 0xd, 8},
+ {1, 0, 0xe, 0xf, 0xd},
+ {7, 6, 8, 9, 3},
+ {5, 4, 0xa, 0xb, 7},
+ },
+ },
+ {
+ keyScheduleA{
+ {4, 0, 0xd, 0xf, 0xc, 0xe, 8},
+ {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+ {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+ {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+ },
+ keyScheduleB{
+ {16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9},
+ {16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc},
+ {16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2},
+ {16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6},
+ },
+ },
+ {
+ keyScheduleA{
+ {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+ {1, 4, 0, 2, 1, 3, 16 + 2},
+ {2, 5, 7, 6, 5, 4, 16 + 1},
+ {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+ },
+ keyScheduleB{
+ {8, 9, 7, 6, 3},
+ {0xa, 0xb, 5, 4, 7},
+ {0xc, 0xd, 3, 2, 8},
+ {0xe, 0xf, 1, 0, 0xd},
+ },
+ },
+}
+
+func (c *Cipher) keySchedule(in []byte) {
+ var t [8]uint32
+ var k [32]uint32
+
+ for i := 0; i < 4; i++ {
+ j := i * 4
+ t[i] = uint32(in[j])<<24 | uint32(in[j+1])<<16 | uint32(in[j+2])<<8 | uint32(in[j+3])
+ }
+
+ x := []byte{6, 7, 4, 5}
+ ki := 0
+
+ for half := 0; half < 2; half++ {
+ for _, round := range schedule {
+ for j := 0; j < 4; j++ {
+ var a [7]uint8
+ copy(a[:], round.a[j][:])
+ w := t[a[1]]
+ w ^= sBox[4][(t[a[2]>>2]>>(24-8*(a[2]&3)))&0xff]
+ w ^= sBox[5][(t[a[3]>>2]>>(24-8*(a[3]&3)))&0xff]
+ w ^= sBox[6][(t[a[4]>>2]>>(24-8*(a[4]&3)))&0xff]
+ w ^= sBox[7][(t[a[5]>>2]>>(24-8*(a[5]&3)))&0xff]
+ w ^= sBox[x[j]][(t[a[6]>>2]>>(24-8*(a[6]&3)))&0xff]
+ t[a[0]] = w
+ }
+
+ for j := 0; j < 4; j++ {
+ var b [5]uint8
+ copy(b[:], round.b[j][:])
+ w := sBox[4][(t[b[0]>>2]>>(24-8*(b[0]&3)))&0xff]
+ w ^= sBox[5][(t[b[1]>>2]>>(24-8*(b[1]&3)))&0xff]
+ w ^= sBox[6][(t[b[2]>>2]>>(24-8*(b[2]&3)))&0xff]
+ w ^= sBox[7][(t[b[3]>>2]>>(24-8*(b[3]&3)))&0xff]
+ w ^= sBox[4+j][(t[b[4]>>2]>>(24-8*(b[4]&3)))&0xff]
+ k[ki] = w
+ ki++
+ }
+ }
+ }
+
+ for i := 0; i < 16; i++ {
+ c.masking[i] = k[i]
+ c.rotate[i] = uint8(k[16+i] & 0x1f)
+ }
+}
+
+// These are the three 'f' functions. See RFC 2144, section 2.2.
+func f1(d, m uint32, r uint8) uint32 {
+ t := m + d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] ^ sBox[1][(I>>16)&0xff]) - sBox[2][(I>>8)&0xff]) + sBox[3][I&0xff]
+}
+
+func f2(d, m uint32, r uint8) uint32 {
+ t := m ^ d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] - sBox[1][(I>>16)&0xff]) + sBox[2][(I>>8)&0xff]) ^ sBox[3][I&0xff]
+}
+
+func f3(d, m uint32, r uint8) uint32 {
+ t := m - d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] + sBox[1][(I>>16)&0xff]) ^ sBox[2][(I>>8)&0xff]) - sBox[3][I&0xff]
+}
+
+var sBox = [8][256]uint32{
+ {
+ 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
+ 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+ 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+ 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
+ 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+ 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+ 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
+ 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+ 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+ 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+ 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
+ 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+ 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
+ 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+ 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+ 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
+ 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
+ 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+ 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+ 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+ 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+ 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
+ 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+ 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+ 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+ 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
+ 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+ 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
+ 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
+ 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+ 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+ 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf,
+ },
+ {
+ 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
+ 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+ 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+ 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+ 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
+ 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+ 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
+ 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+ 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+ 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
+ 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+ 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+ 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+ 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+ 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+ 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+ 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
+ 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+ 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
+ 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+ 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+ 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
+ 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+ 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+ 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
+ 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+ 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+ 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
+ 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+ 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+ 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
+ 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1,
+ },
+ {
+ 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
+ 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
+ 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+ 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
+ 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+ 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+ 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
+ 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+ 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+ 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
+ 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
+ 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+ 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
+ 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+ 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+ 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
+ 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+ 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+ 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
+ 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
+ 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+ 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+ 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+ 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+ 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+ 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+ 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+ 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+ 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
+ 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+ 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
+ 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783,
+ },
+ {
+ 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
+ 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
+ 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+ 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
+ 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+ 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+ 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
+ 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
+ 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+ 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
+ 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
+ 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+ 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+ 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
+ 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+ 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
+ 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+ 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+ 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+ 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+ 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+ 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+ 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+ 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+ 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+ 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
+ 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+ 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+ 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
+ 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+ 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
+ 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2,
+ },
+ {
+ 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
+ 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
+ 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+ 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+ 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+ 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+ 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
+ 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
+ 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+ 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
+ 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
+ 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+ 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
+ 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
+ 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+ 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
+ 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
+ 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+ 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
+ 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
+ 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+ 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
+ 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
+ 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+ 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+ 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
+ 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+ 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+ 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+ 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+ 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
+ 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4,
+ },
+ {
+ 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
+ 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
+ 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+ 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
+ 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+ 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+ 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+ 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
+ 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+ 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
+ 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+ 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+ 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
+ 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+ 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+ 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
+ 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
+ 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+ 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
+ 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
+ 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+ 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+ 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+ 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+ 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
+ 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
+ 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+ 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+ 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
+ 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+ 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+ 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f,
+ },
+ {
+ 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
+ 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
+ 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+ 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+ 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+ 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+ 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+ 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
+ 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+ 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+ 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+ 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+ 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
+ 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
+ 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+ 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+ 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+ 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+ 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
+ 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+ 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+ 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+ 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
+ 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+ 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+ 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
+ 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+ 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
+ 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
+ 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+ 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+ 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3,
+ },
+ {
+ 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
+ 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
+ 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+ 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
+ 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+ 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+ 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+ 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
+ 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+ 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
+ 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+ 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+ 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
+ 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
+ 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+ 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
+ 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
+ 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+ 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+ 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+ 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+ 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
+ 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+ 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+ 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
+ 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
+ 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+ 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
+ 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
+ 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+ 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+ 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e,
+ },
+}
diff --git a/libgo/go/crypto/cast5/cast5_test.go b/libgo/go/crypto/cast5/cast5_test.go
new file mode 100644
index 000000000..5f7025ff2
--- /dev/null
+++ b/libgo/go/crypto/cast5/cast5_test.go
@@ -0,0 +1,104 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cast5
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+)
+
+// This test vector is taken from RFC 2144, App B.1.
+// Since the other two test vectors are for reduced-round variants, we can't
+// use them.
+var basicTests = []struct {
+ key, plainText, cipherText string
+}{
+ {
+ "0123456712345678234567893456789a",
+ "0123456789abcdef",
+ "238b4fe5847e44b2",
+ },
+}
+
+func TestBasic(t *testing.T) {
+ for i, test := range basicTests {
+ key, _ := hex.DecodeString(test.key)
+ plainText, _ := hex.DecodeString(test.plainText)
+ expected, _ := hex.DecodeString(test.cipherText)
+
+ c, err := NewCipher(key)
+ if err != nil {
+ t.Errorf("#%d: failed to create Cipher: %s", i, err)
+ continue
+ }
+ var cipherText [BlockSize]byte
+ c.Encrypt(cipherText[:], plainText)
+ if !bytes.Equal(cipherText[:], expected) {
+ t.Errorf("#%d: got:%x want:%x", i, cipherText, expected)
+ }
+
+ var plainTextAgain [BlockSize]byte
+ c.Decrypt(plainTextAgain[:], cipherText[:])
+ if !bytes.Equal(plainTextAgain[:], plainText) {
+ t.Errorf("#%d: got:%x want:%x", i, plainTextAgain, plainText)
+ }
+ }
+}
+
+// TestFull performs the test specified in RFC 2144, App B.2.
+// However, due to the length of time taken, it's disabled here and a more
+// limited version is included, below.
+func TestFull(t *testing.T) {
+ // This is too slow for normal testing
+ return
+
+ a, b := iterate(1000000)
+
+ const expectedA = "eea9d0a249fd3ba6b3436fb89d6dca92"
+ const expectedB = "b2c95eb00c31ad7180ac05b8e83d696e"
+
+ if hex.EncodeToString(a) != expectedA {
+ t.Errorf("a: got:%x want:%s", a, expectedA)
+ }
+ if hex.EncodeToString(b) != expectedB {
+ t.Errorf("b: got:%x want:%s", b, expectedB)
+ }
+}
+
+func iterate(iterations int) ([]byte, []byte) {
+ const initValueHex = "0123456712345678234567893456789a"
+
+ initValue, _ := hex.DecodeString(initValueHex)
+
+ var a, b [16]byte
+ copy(a[:], initValue)
+ copy(b[:], initValue)
+
+ for i := 0; i < iterations; i++ {
+ c, _ := NewCipher(b[:])
+ c.Encrypt(a[:8], a[:8])
+ c.Encrypt(a[8:], a[8:])
+ c, _ = NewCipher(a[:])
+ c.Encrypt(b[:8], b[:8])
+ c.Encrypt(b[8:], b[8:])
+ }
+
+ return a[:], b[:]
+}
+
+func TestLimited(t *testing.T) {
+ a, b := iterate(1000)
+
+ const expectedA = "23f73b14b02a2ad7dfb9f2c35644798d"
+ const expectedB = "e5bf37eff14c456a40b21ce369370a9f"
+
+ if hex.EncodeToString(a) != expectedA {
+ t.Errorf("a: got:%x want:%s", a, expectedA)
+ }
+ if hex.EncodeToString(b) != expectedB {
+ t.Errorf("b: got:%x want:%s", b, expectedB)
+ }
+}
diff --git a/libgo/go/crypto/cipher/cbc.go b/libgo/go/crypto/cipher/cbc.go
new file mode 100644
index 000000000..4632f882a
--- /dev/null
+++ b/libgo/go/crypto/cipher/cbc.go
@@ -0,0 +1,78 @@
+// 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.
+
+// Cipher block chaining (CBC) mode.
+
+// CBC provides confidentiality by xoring (chaining) each plaintext block
+// with the previous ciphertext block before applying the block cipher.
+
+// See NIST SP 800-38A, pp 10-11
+
+package cipher
+
+type cbc struct {
+ b Block
+ blockSize int
+ iv []byte
+ tmp []byte
+}
+
+func newCBC(b Block, iv []byte) *cbc {
+ return &cbc{
+ b: b,
+ blockSize: b.BlockSize(),
+ iv: dup(iv),
+ tmp: make([]byte, b.BlockSize()),
+ }
+}
+
+type cbcEncrypter cbc
+
+// NewCBCEncrypter returns a BlockMode which encrypts in cipher block chaining
+// mode, using the given Block. The length of iv must be the same as the
+// Block's block size.
+func NewCBCEncrypter(b Block, iv []byte) BlockMode {
+ return (*cbcEncrypter)(newCBC(b, iv))
+}
+
+func (x *cbcEncrypter) BlockSize() int { return x.blockSize }
+
+func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
+ for len(src) > 0 {
+ for i := 0; i < x.blockSize; i++ {
+ x.iv[i] ^= src[i]
+ }
+ x.b.Encrypt(x.iv, x.iv)
+ for i := 0; i < x.blockSize; i++ {
+ dst[i] = x.iv[i]
+ }
+ src = src[x.blockSize:]
+ dst = dst[x.blockSize:]
+ }
+}
+
+type cbcDecrypter cbc
+
+// NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining
+// mode, using the given Block. The length of iv must be the same as the
+// Block's block size as must match the iv used to encrypt the data.
+func NewCBCDecrypter(b Block, iv []byte) BlockMode {
+ return (*cbcDecrypter)(newCBC(b, iv))
+}
+
+func (x *cbcDecrypter) BlockSize() int { return x.blockSize }
+
+func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
+ for len(src) > 0 {
+ x.b.Decrypt(x.tmp, src[:x.blockSize])
+ for i := 0; i < x.blockSize; i++ {
+ x.tmp[i] ^= x.iv[i]
+ x.iv[i] = src[i]
+ dst[i] = x.tmp[i]
+ }
+
+ src = src[x.blockSize:]
+ dst = dst[x.blockSize:]
+ }
+}
diff --git a/libgo/go/crypto/cipher/cbc_aes_test.go b/libgo/go/crypto/cipher/cbc_aes_test.go
new file mode 100644
index 000000000..944ca1ba8
--- /dev/null
+++ b/libgo/go/crypto/cipher/cbc_aes_test.go
@@ -0,0 +1,89 @@
+// 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.
+
+// CBC AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 24-29.
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/aes"
+ "testing"
+)
+
+var cbcAESTests = []struct {
+ name string
+ key []byte
+ iv []byte
+ in []byte
+ out []byte
+}{
+ // NIST SP 800-38A pp 27-29
+ {
+ "CBC-AES128",
+ commonKey128,
+ commonIV,
+ commonInput,
+ []byte{
+ 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
+ 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
+ 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
+ 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7,
+ },
+ },
+ {
+ "CBC-AES192",
+ commonKey192,
+ commonIV,
+ commonInput,
+ []byte{
+ 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8,
+ 0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, 0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a,
+ 0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0,
+ 0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd,
+ },
+ },
+ {
+ "CBC-AES256",
+ commonKey256,
+ commonIV,
+ commonInput,
+ []byte{
+ 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
+ 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
+ 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
+ 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b,
+ },
+ },
+}
+
+func TestCBC_AES(t *testing.T) {
+ for _, tt := range cbcAESTests {
+ test := tt.name
+
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ continue
+ }
+
+ encrypter := NewCBCEncrypter(c, tt.iv)
+ d := make([]byte, len(tt.in))
+ encrypter.CryptBlocks(d, tt.in)
+ if !bytes.Equal(tt.out, d) {
+ t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out)
+ }
+
+ decrypter := NewCBCDecrypter(c, tt.iv)
+ p := make([]byte, len(d))
+ decrypter.CryptBlocks(p, d)
+ if !bytes.Equal(tt.in, p) {
+ t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test, d, tt.in)
+ }
+ }
+}
diff --git a/libgo/go/crypto/cipher/cfb.go b/libgo/go/crypto/cipher/cfb.go
new file mode 100644
index 000000000..d14165a86
--- /dev/null
+++ b/libgo/go/crypto/cipher/cfb.go
@@ -0,0 +1,64 @@
+// 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.
+
+// CFB (Cipher Feedback) Mode.
+
+package cipher
+
+type cfb struct {
+ b Block
+ out []byte
+ outUsed int
+ decrypt bool
+}
+
+// NewCFBEncrypter returns a Stream which encrypts with cipher feedback mode,
+// using the given Block. The iv must be the same length as the Block's block
+// size.
+func NewCFBEncrypter(block Block, iv []byte) Stream {
+ return newCFB(block, iv, false)
+}
+
+// NewCFBDecrypter returns a Stream which decrypts with cipher feedback mode,
+// using the given Block. The iv must be the same length as the Block's block
+// size.
+func NewCFBDecrypter(block Block, iv []byte) Stream {
+ return newCFB(block, iv, true)
+}
+
+func newCFB(block Block, iv []byte, decrypt bool) Stream {
+ blockSize := block.BlockSize()
+ if len(iv) != blockSize {
+ return nil
+ }
+
+ x := &cfb{
+ b: block,
+ out: make([]byte, blockSize),
+ outUsed: 0,
+ decrypt: decrypt,
+ }
+ block.Encrypt(x.out, iv)
+
+ return x
+}
+
+func (x *cfb) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.out) {
+ x.b.Encrypt(x.out, x.out)
+ x.outUsed = 0
+ }
+
+ if x.decrypt {
+ t := src[i]
+ dst[i] = src[i] ^ x.out[x.outUsed]
+ x.out[x.outUsed] = t
+ } else {
+ x.out[x.outUsed] ^= src[i]
+ dst[i] = x.out[x.outUsed]
+ }
+ x.outUsed++
+ }
+}
diff --git a/libgo/go/crypto/cipher/cfb_test.go b/libgo/go/crypto/cipher/cfb_test.go
new file mode 100644
index 000000000..9547bfceb
--- /dev/null
+++ b/libgo/go/crypto/cipher/cfb_test.go
@@ -0,0 +1,35 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/rand"
+ "testing"
+)
+
+func TestCFB(t *testing.T) {
+ block, err := aes.NewCipher(commonKey128)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ plaintext := []byte("this is the plaintext")
+ iv := make([]byte, block.BlockSize())
+ rand.Reader.Read(iv)
+ cfb := NewCFBEncrypter(block, iv)
+ ciphertext := make([]byte, len(plaintext))
+ cfb.XORKeyStream(ciphertext, plaintext)
+
+ cfbdec := NewCFBDecrypter(block, iv)
+ plaintextCopy := make([]byte, len(plaintext))
+ cfbdec.XORKeyStream(plaintextCopy, ciphertext)
+
+ if !bytes.Equal(plaintextCopy, plaintext) {
+ t.Errorf("got: %x, want: %x", plaintextCopy, plaintext)
+ }
+}
diff --git a/libgo/go/crypto/cipher/cipher.go b/libgo/go/crypto/cipher/cipher.go
new file mode 100644
index 000000000..50516b23a
--- /dev/null
+++ b/libgo/go/crypto/cipher/cipher.go
@@ -0,0 +1,63 @@
+// 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.
+
+// The cipher package implements standard block cipher modes
+// that can be wrapped around low-level block cipher implementations.
+// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html
+// and NIST Special Publication 800-38A.
+package cipher
+
+// A Block represents an implementation of block cipher
+// using a given key. It provides the capability to encrypt
+// or decrypt individual blocks. The mode implementations
+// extend that capability to streams of blocks.
+type Block interface {
+ // BlockSize returns the cipher's block size.
+ BlockSize() int
+
+ // Encrypt encrypts the first block in src into dst.
+ // Dst and src may point at the same memory.
+ Encrypt(dst, src []byte)
+
+ // Decrypt decrypts the first block in src into dst.
+ // Dst and src may point at the same memory.
+ Decrypt(dst, src []byte)
+}
+
+// A Stream represents a stream cipher.
+type Stream interface {
+ // XORKeyStream XORs each byte in the given slice with a byte from the
+ // cipher's key stream. Dst and src may point to the same memory.
+ XORKeyStream(dst, src []byte)
+}
+
+// A BlockMode represents a block cipher running in a block-based mode (CBC,
+// ECB etc).
+type BlockMode interface {
+ // BlockSize returns the mode's block size.
+ BlockSize() int
+
+ // CryptBlocks encrypts or decrypts a number of blocks. The length of
+ // src must be a multiple of the block size. Dst and src may point to
+ // the same memory.
+ CryptBlocks(dst, src []byte)
+}
+
+// Utility routines
+
+func shift1(dst, src []byte) byte {
+ var b byte
+ for i := len(src) - 1; i >= 0; i-- {
+ bb := src[i] >> 7
+ dst[i] = src[i]<<1 | b
+ b = bb
+ }
+ return b
+}
+
+func dup(p []byte) []byte {
+ q := make([]byte, len(p))
+ copy(q, p)
+ return q
+}
diff --git a/libgo/go/crypto/cipher/common_test.go b/libgo/go/crypto/cipher/common_test.go
new file mode 100644
index 000000000..fb755757c
--- /dev/null
+++ b/libgo/go/crypto/cipher/common_test.go
@@ -0,0 +1,28 @@
+// 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 cipher
+
+// Common values for tests.
+
+var commonInput = []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+}
+
+var commonKey128 = []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
+
+var commonKey192 = []byte{
+ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
+}
+
+var commonKey256 = []byte{
+ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
+}
+
+var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
diff --git a/libgo/go/crypto/cipher/ctr.go b/libgo/go/crypto/cipher/ctr.go
new file mode 100644
index 000000000..04436ec23
--- /dev/null
+++ b/libgo/go/crypto/cipher/ctr.go
@@ -0,0 +1,51 @@
+// 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.
+
+// Counter (CTR) mode.
+
+// CTR converts a block cipher into a stream cipher by
+// repeatedly encrypting an incrementing counter and
+// xoring the resulting stream of data with the input.
+
+// See NIST SP 800-38A, pp 13-15
+
+package cipher
+
+type ctr struct {
+ b Block
+ ctr []byte
+ out []byte
+ outUsed int
+}
+
+// NewCTR returns a Stream which encrypts/decrypts using the given Block in
+// counter mode. The length of iv must be the same as the Block's block size.
+func NewCTR(block Block, iv []byte) Stream {
+ return &ctr{
+ b: block,
+ ctr: dup(iv),
+ out: make([]byte, len(iv)),
+ outUsed: len(iv),
+ }
+}
+
+func (x *ctr) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.ctr) {
+ x.b.Encrypt(x.out, x.ctr)
+ x.outUsed = 0
+
+ // Increment counter
+ for i := len(x.ctr) - 1; i >= 0; i-- {
+ x.ctr[i]++
+ if x.ctr[i] != 0 {
+ break
+ }
+ }
+ }
+
+ dst[i] = src[i] ^ x.out[x.outUsed]
+ x.outUsed++
+ }
+}
diff --git a/libgo/go/crypto/cipher/ctr_aes_test.go b/libgo/go/crypto/cipher/ctr_aes_test.go
new file mode 100644
index 000000000..8dca9968c
--- /dev/null
+++ b/libgo/go/crypto/cipher/ctr_aes_test.go
@@ -0,0 +1,101 @@
+// 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.
+
+// CTR AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 55-58.
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/aes"
+ "testing"
+)
+
+var commonCounter = []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}
+
+var ctrAESTests = []struct {
+ name string
+ key []byte
+ iv []byte
+ in []byte
+ out []byte
+}{
+ // NIST SP 800-38A pp 55-58
+ {
+ "CTR-AES128",
+ commonKey128,
+ commonCounter,
+ commonInput,
+ []byte{
+ 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+ 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+ 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+ 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee,
+ },
+ },
+ {
+ "CTR-AES192",
+ commonKey192,
+ commonCounter,
+ commonInput,
+ []byte{
+ 0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2, 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b,
+ 0x09, 0x03, 0x39, 0xec, 0x0a, 0xa6, 0xfa, 0xef, 0xd5, 0xcc, 0xc2, 0xc6, 0xf4, 0xce, 0x8e, 0x94,
+ 0x1e, 0x36, 0xb2, 0x6b, 0xd1, 0xeb, 0xc6, 0x70, 0xd1, 0xbd, 0x1d, 0x66, 0x56, 0x20, 0xab, 0xf7,
+ 0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58, 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50,
+ },
+ },
+ {
+ "CTR-AES256",
+ commonKey256,
+ commonCounter,
+ commonInput,
+ []byte{
+ 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
+ 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a, 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
+ 0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
+ 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6, 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6,
+ },
+ },
+}
+
+func TestCTR_AES(t *testing.T) {
+ for _, tt := range ctrAESTests {
+ test := tt.name
+
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ continue
+ }
+
+ for j := 0; j <= 5; j += 5 {
+ in := tt.in[0 : len(tt.in)-j]
+ ctr := NewCTR(c, tt.iv)
+ encrypted := make([]byte, len(in))
+ ctr.XORKeyStream(encrypted, in)
+ if out := tt.out[0:len(in)]; !bytes.Equal(out, encrypted) {
+ t.Errorf("%s/%d: CTR\ninpt %x\nhave %x\nwant %x", test, len(in), in, encrypted, out)
+ }
+ }
+
+ for j := 0; j <= 7; j += 7 {
+ in := tt.out[0 : len(tt.out)-j]
+ ctr := NewCTR(c, tt.iv)
+ plain := make([]byte, len(in))
+ ctr.XORKeyStream(plain, in)
+ if out := tt.in[0:len(in)]; !bytes.Equal(out, plain) {
+ t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), plain, out)
+ }
+ }
+
+ if t.Failed() {
+ break
+ }
+ }
+}
diff --git a/libgo/go/crypto/cipher/io.go b/libgo/go/crypto/cipher/io.go
new file mode 100644
index 000000000..97f40b8e7
--- /dev/null
+++ b/libgo/go/crypto/cipher/io.go
@@ -0,0 +1,57 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher
+
+import (
+ "os"
+ "io"
+)
+
+// The Stream* objects are so simple that all their members are public. Users
+// can create them themselves.
+
+// StreamReader wraps a Stream into an io.Reader. It simply calls XORKeyStream
+// to process each slice of data which passes through.
+type StreamReader struct {
+ S Stream
+ R io.Reader
+}
+
+func (r StreamReader) Read(dst []byte) (n int, err os.Error) {
+ n, err = r.R.Read(dst)
+ r.S.XORKeyStream(dst[:n], dst[:n])
+ return
+}
+
+// StreamWriter wraps a Stream into an io.Writer. It simply calls XORKeyStream
+// to process each slice of data which passes through. If any Write call
+// returns short then the StreamWriter is out of sync and must be discarded.
+type StreamWriter struct {
+ S Stream
+ W io.Writer
+ Err os.Error
+}
+
+func (w StreamWriter) Write(src []byte) (n int, err os.Error) {
+ if w.Err != nil {
+ return 0, w.Err
+ }
+ c := make([]byte, len(src))
+ w.S.XORKeyStream(c, src)
+ n, err = w.W.Write(c)
+ if n != len(src) {
+ if err == nil { // should never happen
+ err = io.ErrShortWrite
+ }
+ w.Err = err
+ }
+ return
+}
+
+func (w StreamWriter) Close() os.Error {
+ // This saves us from either requiring a WriteCloser or having a
+ // StreamWriterCloser.
+ return w.W.(io.Closer).Close()
+}
diff --git a/libgo/go/crypto/cipher/ocfb.go b/libgo/go/crypto/cipher/ocfb.go
new file mode 100644
index 000000000..43cb5a531
--- /dev/null
+++ b/libgo/go/crypto/cipher/ocfb.go
@@ -0,0 +1,112 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9
+
+package cipher
+
+type ocfbEncrypter struct {
+ b Block
+ fre []byte
+ outUsed int
+}
+
+// NewOCFBEncrypter returns a Stream which encrypts data with OpenPGP's cipher
+// feedback mode using the given Block, and an initial amount of ciphertext.
+// randData must be random bytes and be the same length as the Block's block
+// size.
+func NewOCFBEncrypter(block Block, randData []byte) (Stream, []byte) {
+ blockSize := block.BlockSize()
+ if len(randData) != blockSize {
+ return nil, nil
+ }
+
+ x := &ocfbEncrypter{
+ b: block,
+ fre: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ prefix := make([]byte, blockSize+2)
+
+ block.Encrypt(x.fre, x.fre)
+ for i := 0; i < blockSize; i++ {
+ prefix[i] = randData[i] ^ x.fre[i]
+ }
+
+ block.Encrypt(x.fre, prefix[:blockSize])
+ prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
+ prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
+
+ block.Encrypt(x.fre, prefix[2:])
+ return x, prefix
+}
+
+func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.fre) {
+ x.b.Encrypt(x.fre, x.fre)
+ x.outUsed = 0
+ }
+
+ x.fre[x.outUsed] ^= src[i]
+ dst[i] = x.fre[x.outUsed]
+ x.outUsed++
+ }
+}
+
+type ocfbDecrypter struct {
+ b Block
+ fre []byte
+ outUsed int
+}
+
+// NewOCFBDecrypter returns a Stream which decrypts data with OpenPGP's cipher
+// feedback mode using the given Block. Prefix must be the first blockSize + 2
+// bytes of the ciphertext, where blockSize is the Block's block size. If an
+// incorrect key is detected then nil is returned.
+func NewOCFBDecrypter(block Block, prefix []byte) Stream {
+ blockSize := block.BlockSize()
+ if len(prefix) != blockSize+2 {
+ return nil
+ }
+
+ x := &ocfbDecrypter{
+ b: block,
+ fre: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ prefixCopy := make([]byte, len(prefix))
+ copy(prefixCopy, prefix)
+
+ block.Encrypt(x.fre, x.fre)
+ for i := 0; i < blockSize; i++ {
+ prefixCopy[i] ^= x.fre[i]
+ }
+
+ block.Encrypt(x.fre, prefix[:blockSize])
+ prefixCopy[blockSize] ^= x.fre[0]
+ prefixCopy[blockSize+1] ^= x.fre[1]
+
+ if prefixCopy[blockSize-2] != prefixCopy[blockSize] ||
+ prefixCopy[blockSize-1] != prefixCopy[blockSize+1] {
+ return nil
+ }
+
+ block.Encrypt(x.fre, prefix[2:])
+ return x
+}
+
+func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.fre) {
+ x.b.Encrypt(x.fre, x.fre)
+ x.outUsed = 0
+ }
+
+ c := src[i]
+ dst[i] = x.fre[x.outUsed] ^ src[i]
+ x.fre[x.outUsed] = c
+ x.outUsed++
+ }
+}
diff --git a/libgo/go/crypto/cipher/ocfb_test.go b/libgo/go/crypto/cipher/ocfb_test.go
new file mode 100644
index 000000000..289bb7c91
--- /dev/null
+++ b/libgo/go/crypto/cipher/ocfb_test.go
@@ -0,0 +1,39 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/rand"
+ "testing"
+)
+
+func TestOCFB(t *testing.T) {
+ block, err := aes.NewCipher(commonKey128)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ plaintext := []byte("this is the plaintext")
+ randData := make([]byte, block.BlockSize())
+ rand.Reader.Read(randData)
+ ocfb, prefix := NewOCFBEncrypter(block, randData)
+ ciphertext := make([]byte, len(plaintext))
+ ocfb.XORKeyStream(ciphertext, plaintext)
+
+ ocfbdec := NewOCFBDecrypter(block, prefix)
+ if ocfbdec == nil {
+ t.Error("NewOCFBDecrypter failed")
+ return
+ }
+ plaintextCopy := make([]byte, len(plaintext))
+ ocfbdec.XORKeyStream(plaintextCopy, ciphertext)
+
+ if !bytes.Equal(plaintextCopy, plaintext) {
+ t.Errorf("got: %x, want: %x", plaintextCopy, plaintext)
+ }
+}
diff --git a/libgo/go/crypto/cipher/ofb.go b/libgo/go/crypto/cipher/ofb.go
new file mode 100644
index 000000000..85e5f02b0
--- /dev/null
+++ b/libgo/go/crypto/cipher/ofb.go
@@ -0,0 +1,44 @@
+// 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.
+
+// OFB (Output Feedback) Mode.
+
+package cipher
+
+type ofb struct {
+ b Block
+ out []byte
+ outUsed int
+}
+
+// NewOFB returns a Stream that encrypts or decrypts using the block cipher b
+// in output feedback mode. The initialization vector iv's length must be equal
+// to b's block size.
+func NewOFB(b Block, iv []byte) Stream {
+ blockSize := b.BlockSize()
+ if len(iv) != blockSize {
+ return nil
+ }
+
+ x := &ofb{
+ b: b,
+ out: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ b.Encrypt(x.out, iv)
+
+ return x
+}
+
+func (x *ofb) XORKeyStream(dst, src []byte) {
+ for i, s := range src {
+ if x.outUsed == len(x.out) {
+ x.b.Encrypt(x.out, x.out)
+ x.outUsed = 0
+ }
+
+ dst[i] = s ^ x.out[x.outUsed]
+ x.outUsed++
+ }
+}
diff --git a/libgo/go/crypto/cipher/ofb_test.go b/libgo/go/crypto/cipher/ofb_test.go
new file mode 100644
index 000000000..9b4495c88
--- /dev/null
+++ b/libgo/go/crypto/cipher/ofb_test.go
@@ -0,0 +1,101 @@
+// 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.
+
+// OFB AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 52-55.
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/aes"
+ "testing"
+)
+
+type ofbTest struct {
+ name string
+ key []byte
+ iv []byte
+ in []byte
+ out []byte
+}
+
+var ofbTests = []ofbTest{
+ // NIST SP 800-38A pp 52-55
+ {
+ "OFB-AES128",
+ commonKey128,
+ commonIV,
+ commonInput,
+ []byte{
+ 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
+ 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25,
+ 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc,
+ 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e,
+ },
+ },
+ {
+ "OFB-AES192",
+ commonKey192,
+ commonIV,
+ commonInput,
+ []byte{
+ 0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
+ 0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01,
+ 0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2,
+ 0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a,
+ },
+ },
+ {
+ "OFB-AES256",
+ commonKey256,
+ commonIV,
+ commonInput,
+ []byte{
+ 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
+ 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d,
+ 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08,
+ 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84,
+ },
+ },
+}
+
+func TestOFB(t *testing.T) {
+ for _, tt := range ofbTests {
+ test := tt.name
+
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ continue
+ }
+
+ for j := 0; j <= 5; j += 5 {
+ plaintext := tt.in[0 : len(tt.in)-j]
+ ofb := NewOFB(c, tt.iv)
+ ciphertext := make([]byte, len(plaintext))
+ ofb.XORKeyStream(ciphertext, plaintext)
+ if !bytes.Equal(ciphertext, tt.out[:len(plaintext)]) {
+ t.Errorf("%s/%d: encrypting\ninput % x\nhave % x\nwant % x", test, len(plaintext), plaintext, ciphertext, tt.out)
+ }
+ }
+
+ for j := 0; j <= 5; j += 5 {
+ ciphertext := tt.out[0 : len(tt.in)-j]
+ ofb := NewOFB(c, tt.iv)
+ plaintext := make([]byte, len(ciphertext))
+ ofb.XORKeyStream(plaintext, ciphertext)
+ if !bytes.Equal(plaintext, tt.in[:len(ciphertext)]) {
+ t.Errorf("%s/%d: decrypting\nhave % x\nwant % x", test, len(ciphertext), plaintext, tt.in)
+ }
+ }
+
+ if t.Failed() {
+ break
+ }
+ }
+}
diff --git a/libgo/go/crypto/elliptic/elliptic.go b/libgo/go/crypto/elliptic/elliptic.go
new file mode 100644
index 000000000..beac45ca0
--- /dev/null
+++ b/libgo/go/crypto/elliptic/elliptic.go
@@ -0,0 +1,376 @@
+// 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.
+
+// The elliptic package implements several standard elliptic curves over prime
+// fields
+package elliptic
+
+// This package operates, internally, on Jacobian coordinates. For a given
+// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
+// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
+// calculation can be performed within the transform (as in ScalarMult and
+// ScalarBaseMult). But even for Add and Double, it's faster to apply and
+// reverse the transform than to operate in affine coordinates.
+
+import (
+ "big"
+ "io"
+ "os"
+ "sync"
+)
+
+// A Curve represents a short-form Weierstrass curve with a=-3.
+// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
+type Curve struct {
+ P *big.Int // the order of the underlying field
+ B *big.Int // the constant of the curve equation
+ Gx, Gy *big.Int // (x,y) of the base point
+ BitSize int // the size of the underlying field
+}
+
+// IsOnCurve returns true if the given (x,y) lies on the curve.
+func (curve *Curve) IsOnCurve(x, y *big.Int) bool {
+ // y² = x³ - 3x + b
+ y2 := new(big.Int).Mul(y, y)
+ y2.Mod(y2, curve.P)
+
+ x3 := new(big.Int).Mul(x, x)
+ x3.Mul(x3, x)
+
+ threeX := new(big.Int).Lsh(x, 1)
+ threeX.Add(threeX, x)
+
+ x3.Sub(x3, threeX)
+ x3.Add(x3, curve.B)
+ x3.Mod(x3, curve.P)
+
+ return x3.Cmp(y2) == 0
+}
+
+// affineFromJacobian reverses the Jacobian transform. See the comment at the
+// top of the file.
+func (curve *Curve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
+ zinv := new(big.Int).ModInverse(z, curve.P)
+ zinvsq := new(big.Int).Mul(zinv, zinv)
+
+ xOut = new(big.Int).Mul(x, zinvsq)
+ xOut.Mod(xOut, curve.P)
+ zinvsq.Mul(zinvsq, zinv)
+ yOut = new(big.Int).Mul(y, zinvsq)
+ yOut.Mod(yOut, curve.P)
+ return
+}
+
+// Add returns the sum of (x1,y1) and (x2,y2)
+func (curve *Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
+ z := new(big.Int).SetInt64(1)
+ return curve.affineFromJacobian(curve.addJacobian(x1, y1, z, x2, y2, z))
+}
+
+// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
+// (x2, y2, z2) and returns their sum, also in Jacobian form.
+func (curve *Curve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
+ z1z1 := new(big.Int).Mul(z1, z1)
+ z1z1.Mod(z1z1, curve.P)
+ z2z2 := new(big.Int).Mul(z2, z2)
+ z2z2.Mod(z2z2, curve.P)
+
+ u1 := new(big.Int).Mul(x1, z2z2)
+ u1.Mod(u1, curve.P)
+ u2 := new(big.Int).Mul(x2, z1z1)
+ u2.Mod(u2, curve.P)
+ h := new(big.Int).Sub(u2, u1)
+ if h.Sign() == -1 {
+ h.Add(h, curve.P)
+ }
+ i := new(big.Int).Lsh(h, 1)
+ i.Mul(i, i)
+ j := new(big.Int).Mul(h, i)
+
+ s1 := new(big.Int).Mul(y1, z2)
+ s1.Mul(s1, z2z2)
+ s1.Mod(s1, curve.P)
+ s2 := new(big.Int).Mul(y2, z1)
+ s2.Mul(s2, z1z1)
+ s2.Mod(s2, curve.P)
+ r := new(big.Int).Sub(s2, s1)
+ if r.Sign() == -1 {
+ r.Add(r, curve.P)
+ }
+ r.Lsh(r, 1)
+ v := new(big.Int).Mul(u1, i)
+
+ x3 := new(big.Int).Set(r)
+ x3.Mul(x3, x3)
+ x3.Sub(x3, j)
+ x3.Sub(x3, v)
+ x3.Sub(x3, v)
+ x3.Mod(x3, curve.P)
+
+ y3 := new(big.Int).Set(r)
+ v.Sub(v, x3)
+ y3.Mul(y3, v)
+ s1.Mul(s1, j)
+ s1.Lsh(s1, 1)
+ y3.Sub(y3, s1)
+ y3.Mod(y3, curve.P)
+
+ z3 := new(big.Int).Add(z1, z2)
+ z3.Mul(z3, z3)
+ z3.Sub(z3, z1z1)
+ if z3.Sign() == -1 {
+ z3.Add(z3, curve.P)
+ }
+ z3.Sub(z3, z2z2)
+ if z3.Sign() == -1 {
+ z3.Add(z3, curve.P)
+ }
+ z3.Mul(z3, h)
+ z3.Mod(z3, curve.P)
+
+ return x3, y3, z3
+}
+
+// Double returns 2*(x,y)
+func (curve *Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
+ z1 := new(big.Int).SetInt64(1)
+ return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
+}
+
+// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
+// returns its double, also in Jacobian form.
+func (curve *Curve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
+ delta := new(big.Int).Mul(z, z)
+ delta.Mod(delta, curve.P)
+ gamma := new(big.Int).Mul(y, y)
+ gamma.Mod(gamma, curve.P)
+ alpha := new(big.Int).Sub(x, delta)
+ if alpha.Sign() == -1 {
+ alpha.Add(alpha, curve.P)
+ }
+ alpha2 := new(big.Int).Add(x, delta)
+ alpha.Mul(alpha, alpha2)
+ alpha2.Set(alpha)
+ alpha.Lsh(alpha, 1)
+ alpha.Add(alpha, alpha2)
+
+ beta := alpha2.Mul(x, gamma)
+
+ x3 := new(big.Int).Mul(alpha, alpha)
+ beta8 := new(big.Int).Lsh(beta, 3)
+ x3.Sub(x3, beta8)
+ for x3.Sign() == -1 {
+ x3.Add(x3, curve.P)
+ }
+ x3.Mod(x3, curve.P)
+
+ z3 := new(big.Int).Add(y, z)
+ z3.Mul(z3, z3)
+ z3.Sub(z3, gamma)
+ if z3.Sign() == -1 {
+ z3.Add(z3, curve.P)
+ }
+ z3.Sub(z3, delta)
+ if z3.Sign() == -1 {
+ z3.Add(z3, curve.P)
+ }
+ z3.Mod(z3, curve.P)
+
+ beta.Lsh(beta, 2)
+ beta.Sub(beta, x3)
+ if beta.Sign() == -1 {
+ beta.Add(beta, curve.P)
+ }
+ y3 := alpha.Mul(alpha, beta)
+
+ gamma.Mul(gamma, gamma)
+ gamma.Lsh(gamma, 3)
+ gamma.Mod(gamma, curve.P)
+
+ y3.Sub(y3, gamma)
+ if y3.Sign() == -1 {
+ y3.Add(y3, curve.P)
+ }
+ y3.Mod(y3, curve.P)
+
+ return x3, y3, z3
+}
+
+// ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
+func (curve *Curve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
+ // We have a slight problem in that the identity of the group (the
+ // point at infinity) cannot be represented in (x, y) form on a finite
+ // machine. Thus the standard add/double algorithm has to be tweaked
+ // slightly: our initial state is not the identity, but x, and we
+ // ignore the first true bit in |k|. If we don't find any true bits in
+ // |k|, then we return nil, nil, because we cannot return the identity
+ // element.
+
+ Bz := new(big.Int).SetInt64(1)
+ x := Bx
+ y := By
+ z := Bz
+
+ seenFirstTrue := false
+ for _, byte := range k {
+ for bitNum := 0; bitNum < 8; bitNum++ {
+ if seenFirstTrue {
+ x, y, z = curve.doubleJacobian(x, y, z)
+ }
+ if byte&0x80 == 0x80 {
+ if !seenFirstTrue {
+ seenFirstTrue = true
+ } else {
+ x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z)
+ }
+ }
+ byte <<= 1
+ }
+ }
+
+ if !seenFirstTrue {
+ return nil, nil
+ }
+
+ return curve.affineFromJacobian(x, y, z)
+}
+
+// ScalarBaseMult returns k*G, where G is the base point of the group and k is
+// an integer in big-endian form.
+func (curve *Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
+ return curve.ScalarMult(curve.Gx, curve.Gy, k)
+}
+
+var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
+
+// GenerateKey returns a public/private key pair. The private key is generated
+// using the given reader, which must return random data.
+func (curve *Curve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err os.Error) {
+ byteLen := (curve.BitSize + 7) >> 3
+ priv = make([]byte, byteLen)
+
+ for x == nil {
+ _, err = io.ReadFull(rand, priv)
+ if err != nil {
+ return
+ }
+ // We have to mask off any excess bits in the case that the size of the
+ // underlying field is not a whole number of bytes.
+ priv[0] &= mask[curve.BitSize%8]
+ // This is because, in tests, rand will return all zeros and we don't
+ // want to get the point at infinity and loop forever.
+ priv[1] ^= 0x42
+ x, y = curve.ScalarBaseMult(priv)
+ }
+ return
+}
+
+// Marshal converts a point into the form specified in section 4.3.6 of ANSI
+// X9.62.
+func (curve *Curve) Marshal(x, y *big.Int) []byte {
+ byteLen := (curve.BitSize + 7) >> 3
+
+ ret := make([]byte, 1+2*byteLen)
+ ret[0] = 4 // uncompressed point
+
+ xBytes := x.Bytes()
+ copy(ret[1+byteLen-len(xBytes):], xBytes)
+ yBytes := y.Bytes()
+ copy(ret[1+2*byteLen-len(yBytes):], yBytes)
+ return ret
+}
+
+// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On
+// error, x = nil.
+func (curve *Curve) Unmarshal(data []byte) (x, y *big.Int) {
+ byteLen := (curve.BitSize + 7) >> 3
+ if len(data) != 1+2*byteLen {
+ return
+ }
+ if data[0] != 4 { // uncompressed form
+ return
+ }
+ x = new(big.Int).SetBytes(data[1 : 1+byteLen])
+ y = new(big.Int).SetBytes(data[1+byteLen:])
+ return
+}
+
+var initonce sync.Once
+var p224 *Curve
+var p256 *Curve
+var p384 *Curve
+var p521 *Curve
+
+func initAll() {
+ initP224()
+ initP256()
+ initP384()
+ initP521()
+}
+
+func initP224() {
+ // See FIPS 186-3, section D.2.2
+ p224 = new(Curve)
+ p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10)
+ p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)
+ p224.Gx, _ = new(big.Int).SetString("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 16)
+ p224.Gy, _ = new(big.Int).SetString("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", 16)
+ p224.BitSize = 224
+}
+
+func initP256() {
+ // See FIPS 186-3, section D.2.3
+ p256 = new(Curve)
+ p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
+ p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
+ p256.Gx, _ = new(big.Int).SetString("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16)
+ p256.Gy, _ = new(big.Int).SetString("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16)
+ p256.BitSize = 256
+}
+
+func initP384() {
+ // See FIPS 186-3, section D.2.4
+ p384 = new(Curve)
+ p384.P, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319", 10)
+ p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16)
+ p384.Gx, _ = new(big.Int).SetString("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", 16)
+ p384.Gy, _ = new(big.Int).SetString("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", 16)
+ p384.BitSize = 384
+}
+
+func initP521() {
+ // See FIPS 186-3, section D.2.5
+ p521 = new(Curve)
+ p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10)
+ p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16)
+ p521.Gx, _ = new(big.Int).SetString("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16)
+ p521.Gy, _ = new(big.Int).SetString("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16)
+ p521.BitSize = 521
+}
+
+// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2)
+func P224() *Curve {
+ initonce.Do(initAll)
+ return p224
+}
+
+// P256 returns a Curve which implements P-256 (see FIPS 186-3, section D.2.3)
+func P256() *Curve {
+ initonce.Do(initAll)
+ return p256
+}
+
+// P384 returns a Curve which implements P-384 (see FIPS 186-3, section D.2.4)
+func P384() *Curve {
+ initonce.Do(initAll)
+ return p384
+}
+
+// P256 returns a Curve which implements P-521 (see FIPS 186-3, section D.2.5)
+func P521() *Curve {
+ initonce.Do(initAll)
+ return p521
+}
diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go
new file mode 100644
index 000000000..6ae6fb96d
--- /dev/null
+++ b/libgo/go/crypto/elliptic/elliptic_test.go
@@ -0,0 +1,331 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elliptic
+
+import (
+ "big"
+ "crypto/rand"
+ "fmt"
+ "testing"
+)
+
+func TestOnCurve(t *testing.T) {
+ p224 := P224()
+ if !p224.IsOnCurve(p224.Gx, p224.Gy) {
+ t.Errorf("FAIL")
+ }
+}
+
+type baseMultTest struct {
+ k string
+ x, y string
+}
+
+var p224BaseMultTests = []baseMultTest{
+ {
+ "1",
+ "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+ "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
+ },
+ {
+ "2",
+ "706a46dc76dcb76798e60e6d89474788d16dc18032d268fd1a704fa6",
+ "1c2b76a7bc25e7702a704fa986892849fca629487acf3709d2e4e8bb",
+ },
+ {
+ "3",
+ "df1b1d66a551d0d31eff822558b9d2cc75c2180279fe0d08fd896d04",
+ "a3f7f03cadd0be444c0aa56830130ddf77d317344e1af3591981a925",
+ },
+ {
+ "4",
+ "ae99feebb5d26945b54892092a8aee02912930fa41cd114e40447301",
+ "482580a0ec5bc47e88bc8c378632cd196cb3fa058a7114eb03054c9",
+ },
+ {
+ "5",
+ "31c49ae75bce7807cdff22055d94ee9021fedbb5ab51c57526f011aa",
+ "27e8bff1745635ec5ba0c9f1c2ede15414c6507d29ffe37e790a079b",
+ },
+ {
+ "6",
+ "1f2483f82572251fca975fea40db821df8ad82a3c002ee6c57112408",
+ "89faf0ccb750d99b553c574fad7ecfb0438586eb3952af5b4b153c7e",
+ },
+ {
+ "7",
+ "db2f6be630e246a5cf7d99b85194b123d487e2d466b94b24a03c3e28",
+ "f3a30085497f2f611ee2517b163ef8c53b715d18bb4e4808d02b963",
+ },
+ {
+ "8",
+ "858e6f9cc6c12c31f5df124aa77767b05c8bc021bd683d2b55571550",
+ "46dcd3ea5c43898c5c5fc4fdac7db39c2f02ebee4e3541d1e78047a",
+ },
+ {
+ "9",
+ "2fdcccfee720a77ef6cb3bfbb447f9383117e3daa4a07e36ed15f78d",
+ "371732e4f41bf4f7883035e6a79fcedc0e196eb07b48171697517463",
+ },
+ {
+ "10",
+ "aea9e17a306517eb89152aa7096d2c381ec813c51aa880e7bee2c0fd",
+ "39bb30eab337e0a521b6cba1abe4b2b3a3e524c14a3fe3eb116b655f",
+ },
+ {
+ "11",
+ "ef53b6294aca431f0f3c22dc82eb9050324f1d88d377e716448e507c",
+ "20b510004092e96636cfb7e32efded8265c266dfb754fa6d6491a6da",
+ },
+ {
+ "12",
+ "6e31ee1dc137f81b056752e4deab1443a481033e9b4c93a3044f4f7a",
+ "207dddf0385bfdeab6e9acda8da06b3bbef224a93ab1e9e036109d13",
+ },
+ {
+ "13",
+ "34e8e17a430e43289793c383fac9774247b40e9ebd3366981fcfaeca",
+ "252819f71c7fb7fbcb159be337d37d3336d7feb963724fdfb0ecb767",
+ },
+ {
+ "14",
+ "a53640c83dc208603ded83e4ecf758f24c357d7cf48088b2ce01e9fa",
+ "d5814cd724199c4a5b974a43685fbf5b8bac69459c9469bc8f23ccaf",
+ },
+ {
+ "15",
+ "baa4d8635511a7d288aebeedd12ce529ff102c91f97f867e21916bf9",
+ "979a5f4759f80f4fb4ec2e34f5566d595680a11735e7b61046127989",
+ },
+ {
+ "16",
+ "b6ec4fe1777382404ef679997ba8d1cc5cd8e85349259f590c4c66d",
+ "3399d464345906b11b00e363ef429221f2ec720d2f665d7dead5b482",
+ },
+ {
+ "17",
+ "b8357c3a6ceef288310e17b8bfeff9200846ca8c1942497c484403bc",
+ "ff149efa6606a6bd20ef7d1b06bd92f6904639dce5174db6cc554a26",
+ },
+ {
+ "18",
+ "c9ff61b040874c0568479216824a15eab1a838a797d189746226e4cc",
+ "ea98d60e5ffc9b8fcf999fab1df7e7ef7084f20ddb61bb045a6ce002",
+ },
+ {
+ "19",
+ "a1e81c04f30ce201c7c9ace785ed44cc33b455a022f2acdbc6cae83c",
+ "dcf1f6c3db09c70acc25391d492fe25b4a180babd6cea356c04719cd",
+ },
+ {
+ "20",
+ "fcc7f2b45df1cd5a3c0c0731ca47a8af75cfb0347e8354eefe782455",
+ "d5d7110274cba7cdee90e1a8b0d394c376a5573db6be0bf2747f530",
+ },
+ {
+ "112233445566778899",
+ "61f077c6f62ed802dad7c2f38f5c67f2cc453601e61bd076bb46179e",
+ "2272f9e9f5933e70388ee652513443b5e289dd135dcc0d0299b225e4",
+ },
+ {
+ "112233445566778899112233445566778899",
+ "29895f0af496bfc62b6ef8d8a65c88c613949b03668aab4f0429e35",
+ "3ea6e53f9a841f2019ec24bde1a75677aa9b5902e61081c01064de93",
+ },
+ {
+ "6950511619965839450988900688150712778015737983940691968051900319680",
+ "ab689930bcae4a4aa5f5cb085e823e8ae30fd365eb1da4aba9cf0379",
+ "3345a121bbd233548af0d210654eb40bab788a03666419be6fbd34e7",
+ },
+ {
+ "13479972933410060327035789020509431695094902435494295338570602119423",
+ "bdb6a8817c1f89da1c2f3dd8e97feb4494f2ed302a4ce2bc7f5f4025",
+ "4c7020d57c00411889462d77a5438bb4e97d177700bf7243a07f1680",
+ },
+ {
+ "13479971751745682581351455311314208093898607229429740618390390702079",
+ "d58b61aa41c32dd5eba462647dba75c5d67c83606c0af2bd928446a9",
+ "d24ba6a837be0460dd107ae77725696d211446c5609b4595976b16bd",
+ },
+ {
+ "13479972931865328106486971546324465392952975980343228160962702868479",
+ "dc9fa77978a005510980e929a1485f63716df695d7a0c18bb518df03",
+ "ede2b016f2ddffc2a8c015b134928275ce09e5661b7ab14ce0d1d403",
+ },
+ {
+ "11795773708834916026404142434151065506931607341523388140225443265536",
+ "499d8b2829cfb879c901f7d85d357045edab55028824d0f05ba279ba",
+ "bf929537b06e4015919639d94f57838fa33fc3d952598dcdbb44d638",
+ },
+ {
+ "784254593043826236572847595991346435467177662189391577090",
+ "8246c999137186632c5f9eddf3b1b0e1764c5e8bd0e0d8a554b9cb77",
+ "e80ed8660bc1cb17ac7d845be40a7a022d3306f116ae9f81fea65947",
+ },
+ {
+ "13479767645505654746623887797783387853576174193480695826442858012671",
+ "6670c20afcceaea672c97f75e2e9dd5c8460e54bb38538ebb4bd30eb",
+ "f280d8008d07a4caf54271f993527d46ff3ff46fd1190a3f1faa4f74",
+ },
+ {
+ "205688069665150753842126177372015544874550518966168735589597183",
+ "eca934247425cfd949b795cb5ce1eff401550386e28d1a4c5a8eb",
+ "d4c01040dba19628931bc8855370317c722cbd9ca6156985f1c2e9ce",
+ },
+ {
+ "13479966930919337728895168462090683249159702977113823384618282123295",
+ "ef353bf5c73cd551b96d596fbc9a67f16d61dd9fe56af19de1fba9cd",
+ "21771b9cdce3e8430c09b3838be70b48c21e15bc09ee1f2d7945b91f",
+ },
+ {
+ "50210731791415612487756441341851895584393717453129007497216",
+ "4036052a3091eb481046ad3289c95d3ac905ca0023de2c03ecd451cf",
+ "d768165a38a2b96f812586a9d59d4136035d9c853a5bf2e1c86a4993",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368041",
+ "fcc7f2b45df1cd5a3c0c0731ca47a8af75cfb0347e8354eefe782455",
+ "f2a28eefd8b345832116f1e574f2c6b2c895aa8c24941f40d8b80ad1",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368042",
+ "a1e81c04f30ce201c7c9ace785ed44cc33b455a022f2acdbc6cae83c",
+ "230e093c24f638f533dac6e2b6d01da3b5e7f45429315ca93fb8e634",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368043",
+ "c9ff61b040874c0568479216824a15eab1a838a797d189746226e4cc",
+ "156729f1a003647030666054e208180f8f7b0df2249e44fba5931fff",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368044",
+ "b8357c3a6ceef288310e17b8bfeff9200846ca8c1942497c484403bc",
+ "eb610599f95942df1082e4f9426d086fb9c6231ae8b24933aab5db",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368045",
+ "b6ec4fe1777382404ef679997ba8d1cc5cd8e85349259f590c4c66d",
+ "cc662b9bcba6f94ee4ff1c9c10bd6ddd0d138df2d099a282152a4b7f",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368046",
+ "baa4d8635511a7d288aebeedd12ce529ff102c91f97f867e21916bf9",
+ "6865a0b8a607f0b04b13d1cb0aa992a5a97f5ee8ca1849efb9ed8678",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368047",
+ "a53640c83dc208603ded83e4ecf758f24c357d7cf48088b2ce01e9fa",
+ "2a7eb328dbe663b5a468b5bc97a040a3745396ba636b964370dc3352",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368048",
+ "34e8e17a430e43289793c383fac9774247b40e9ebd3366981fcfaeca",
+ "dad7e608e380480434ea641cc82c82cbc92801469c8db0204f13489a",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368049",
+ "6e31ee1dc137f81b056752e4deab1443a481033e9b4c93a3044f4f7a",
+ "df82220fc7a4021549165325725f94c3410ddb56c54e161fc9ef62ee",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368050",
+ "ef53b6294aca431f0f3c22dc82eb9050324f1d88d377e716448e507c",
+ "df4aefffbf6d1699c930481cd102127c9a3d992048ab05929b6e5927",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368051",
+ "aea9e17a306517eb89152aa7096d2c381ec813c51aa880e7bee2c0fd",
+ "c644cf154cc81f5ade49345e541b4d4b5c1adb3eb5c01c14ee949aa2",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368052",
+ "2fdcccfee720a77ef6cb3bfbb447f9383117e3daa4a07e36ed15f78d",
+ "c8e8cd1b0be40b0877cfca1958603122f1e6914f84b7e8e968ae8b9e",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368053",
+ "858e6f9cc6c12c31f5df124aa77767b05c8bc021bd683d2b55571550",
+ "fb9232c15a3bc7673a3a03b0253824c53d0fd1411b1cabe2e187fb87",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368054",
+ "db2f6be630e246a5cf7d99b85194b123d487e2d466b94b24a03c3e28",
+ "f0c5cff7ab680d09ee11dae84e9c1072ac48ea2e744b1b7f72fd469e",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368055",
+ "1f2483f82572251fca975fea40db821df8ad82a3c002ee6c57112408",
+ "76050f3348af2664aac3a8b05281304ebc7a7914c6ad50a4b4eac383",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368056",
+ "31c49ae75bce7807cdff22055d94ee9021fedbb5ab51c57526f011aa",
+ "d817400e8ba9ca13a45f360e3d121eaaeb39af82d6001c8186f5f866",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368057",
+ "ae99feebb5d26945b54892092a8aee02912930fa41cd114e40447301",
+ "fb7da7f5f13a43b81774373c879cd32d6934c05fa758eeb14fcfab38",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368058",
+ "df1b1d66a551d0d31eff822558b9d2cc75c2180279fe0d08fd896d04",
+ "5c080fc3522f41bbb3f55a97cfecf21f882ce8cbb1e50ca6e67e56dc",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368059",
+ "706a46dc76dcb76798e60e6d89474788d16dc18032d268fd1a704fa6",
+ "e3d4895843da188fd58fb0567976d7b50359d6b78530c8f62d1b1746",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368060",
+ "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+ "42c89c774a08dc04b3dd201932bc8a5ea5f8b89bbb2a7e667aff81cd",
+ },
+}
+
+func TestBaseMult(t *testing.T) {
+ p224 := P224()
+ for i, e := range p224BaseMultTests {
+ k, ok := new(big.Int).SetString(e.k, 10)
+ if !ok {
+ t.Errorf("%d: bad value for k: %s", i, e.k)
+ }
+ x, y := p224.ScalarBaseMult(k.Bytes())
+ if fmt.Sprintf("%x", x) != e.x || fmt.Sprintf("%x", y) != e.y {
+ t.Errorf("%d: bad output for k=%s: got (%x, %s), want (%s, %s)", i, e.k, x, y, e.x, e.y)
+ }
+ }
+}
+
+func BenchmarkBaseMult(b *testing.B) {
+ b.ResetTimer()
+ p224 := P224()
+ e := p224BaseMultTests[25]
+ k, _ := new(big.Int).SetString(e.k, 10)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ p224.ScalarBaseMult(k.Bytes())
+ }
+}
+
+func TestMarshal(t *testing.T) {
+ p224 := P224()
+ _, x, y, err := p224.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ serialised := p224.Marshal(x, y)
+ xx, yy := p224.Unmarshal(serialised)
+ if xx == nil {
+ t.Error("failed to unmarshal")
+ return
+ }
+ if xx.Cmp(x) != 0 || yy.Cmp(y) != 0 {
+ t.Error("unmarshal returned different values")
+ return
+ }
+}
diff --git a/libgo/go/crypto/hmac/hmac.go b/libgo/go/crypto/hmac/hmac.go
new file mode 100644
index 000000000..298fb2c06
--- /dev/null
+++ b/libgo/go/crypto/hmac/hmac.go
@@ -0,0 +1,100 @@
+// 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.
+
+// The hmac package implements the Keyed-Hash Message Authentication Code (HMAC)
+// as defined in U.S. Federal Information Processing Standards Publication 198.
+// An HMAC is a cryptographic hash that uses a key to sign a message.
+// The receiver verifies the hash by recomputing it using the same key.
+package hmac
+
+import (
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "hash"
+ "os"
+)
+
+// FIPS 198:
+// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
+
+// key is zero padded to 64 bytes
+// ipad = 0x36 byte repeated to 64 bytes
+// opad = 0x5c byte repeated to 64 bytes
+// hmac = H([key ^ opad] H([key ^ ipad] text))
+
+const (
+ // NOTE(rsc): This constant is actually the
+ // underlying hash function's block size.
+ // HMAC is only conventionally used with
+ // MD5 and SHA1, and both use 64-byte blocks.
+ // The hash.Hash interface doesn't provide a
+ // way to find out the block size.
+ padSize = 64
+)
+
+type hmac struct {
+ size int
+ key, tmp []byte
+ outer, inner hash.Hash
+}
+
+func (h *hmac) tmpPad(xor byte) {
+ for i, k := range h.key {
+ h.tmp[i] = xor ^ k
+ }
+ for i := len(h.key); i < padSize; i++ {
+ h.tmp[i] = xor
+ }
+}
+
+func (h *hmac) Sum() []byte {
+ sum := h.inner.Sum()
+ h.tmpPad(0x5c)
+ for i, b := range sum {
+ h.tmp[padSize+i] = b
+ }
+ h.outer.Reset()
+ h.outer.Write(h.tmp)
+ return h.outer.Sum()
+}
+
+func (h *hmac) Write(p []byte) (n int, err os.Error) {
+ return h.inner.Write(p)
+}
+
+func (h *hmac) Size() int { return h.size }
+
+func (h *hmac) Reset() {
+ h.inner.Reset()
+ h.tmpPad(0x36)
+ h.inner.Write(h.tmp[0:padSize])
+}
+
+// New returns a new HMAC hash using the given hash generator and key.
+func New(h func() hash.Hash, key []byte) hash.Hash {
+ hm := new(hmac)
+ hm.outer = h()
+ hm.inner = h()
+ hm.size = hm.inner.Size()
+ hm.tmp = make([]byte, padSize+hm.size)
+ if len(key) > padSize {
+ // If key is too big, hash it.
+ hm.outer.Write(key)
+ key = hm.outer.Sum()
+ }
+ hm.key = make([]byte, len(key))
+ copy(hm.key, key)
+ hm.Reset()
+ return hm
+}
+
+// NewMD5 returns a new HMAC-MD5 hash using the given key.
+func NewMD5(key []byte) hash.Hash { return New(md5.New, key) }
+
+// NewSHA1 returns a new HMAC-SHA1 hash using the given key.
+func NewSHA1(key []byte) hash.Hash { return New(sha1.New, key) }
+
+// NewSHA256 returns a new HMAC-SHA256 hash using the given key.
+func NewSHA256(key []byte) hash.Hash { return New(sha256.New, key) }
diff --git a/libgo/go/crypto/hmac/hmac_test.go b/libgo/go/crypto/hmac/hmac_test.go
new file mode 100644
index 000000000..40adbad04
--- /dev/null
+++ b/libgo/go/crypto/hmac/hmac_test.go
@@ -0,0 +1,205 @@
+// 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 hmac
+
+import (
+ "hash"
+ "fmt"
+ "testing"
+)
+
+type hmacTest struct {
+ hash func([]byte) hash.Hash
+ key []byte
+ in []byte
+ out string
+}
+
+var hmacTests = []hmacTest{
+ // Tests from US FIPS 198
+ // http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
+ {
+ NewSHA1,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ []byte("Sample #1"),
+ "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a",
+ },
+ {
+ NewSHA1,
+ []byte{
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43,
+ },
+ []byte("Sample #2"),
+ "0922d3405faa3d194f82a45830737d5cc6c75d24",
+ },
+ {
+ NewSHA1,
+ []byte{
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ },
+ []byte("Sample #3"),
+ "bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa",
+ },
+
+ // Test from Plan 9.
+ {
+ NewMD5,
+ []byte("Jefe"),
+ []byte("what do ya want for nothing?"),
+ "750c783e6ab0b503eaa86e310a5db738",
+ },
+
+ // Tests from RFC 4231
+ {
+ NewSHA256,
+ []byte{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ []byte("Hi There"),
+ "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
+ },
+ {
+ NewSHA256,
+ []byte("Jefe"),
+ []byte("what do ya want for nothing?"),
+ "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ []byte{
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd,
+ },
+ "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19,
+ },
+ []byte{
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd,
+ },
+ "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa,
+ },
+ []byte("Test Using Larger Than Block-Size Key - Hash Key First"),
+ "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa,
+ },
+ []byte("This is a test using a larger than block-size key " +
+ "and a larger than block-size data. The key needs to " +
+ "be hashed before being used by the HMAC algorithm."),
+ "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
+ },
+}
+
+func TestHMAC(t *testing.T) {
+ for i, tt := range hmacTests {
+ h := tt.hash(tt.key)
+ for j := 0; j < 2; j++ {
+ n, err := h.Write(tt.in)
+ if n != len(tt.in) || err != nil {
+ t.Errorf("test %d.%d: Write(%d) = %d, %v", i, j, len(tt.in), n, err)
+ continue
+ }
+
+ // Repetive Sum() calls should return the same value
+ for k := 0; k < 2; k++ {
+ sum := fmt.Sprintf("%x", h.Sum())
+ if sum != tt.out {
+ t.Errorf("test %d.%d.%d: have %s want %s\n", i, j, k, sum, tt.out)
+ }
+ }
+
+ // Second iteration: make sure reset works.
+ h.Reset()
+ }
+ }
+}
diff --git a/libgo/go/crypto/md4/md4.go b/libgo/go/crypto/md4/md4.go
new file mode 100644
index 000000000..e13c986e6
--- /dev/null
+++ b/libgo/go/crypto/md4/md4.go
@@ -0,0 +1,112 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the MD4 hash algorithm as defined in RFC 1320.
+package md4
+
+import (
+ "hash"
+ "os"
+)
+
+// The size of an MD4 checksum in bytes.
+const Size = 16
+
+const (
+ _Chunk = 64
+ _Init0 = 0x67452301
+ _Init1 = 0xEFCDAB89
+ _Init2 = 0x98BADCFE
+ _Init3 = 0x10325476
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ s [4]uint32
+ x [_Chunk]byte
+ nx int
+ len uint64
+}
+
+func (d *digest) Reset() {
+ d.s[0] = _Init0
+ d.s[1] = _Init1
+ d.s[2] = _Init2
+ d.s[3] = _Init3
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the MD4 checksum.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > _Chunk-d.nx {
+ n = _Chunk - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == _Chunk {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0, so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ len := d.len
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if len%64 < 56 {
+ d.Write(tmp[0 : 56-len%64])
+ } else {
+ d.Write(tmp[0 : 64+56-len%64])
+ }
+
+ // Length in bits.
+ len <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(len >> (8 * i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 16)
+ j := 0
+ for _, s := range d.s {
+ p[j+0] = byte(s >> 0)
+ p[j+1] = byte(s >> 8)
+ p[j+2] = byte(s >> 16)
+ p[j+3] = byte(s >> 24)
+ j += 4
+ }
+ return p
+}
diff --git a/libgo/go/crypto/md4/md4_test.go b/libgo/go/crypto/md4/md4_test.go
new file mode 100644
index 000000000..721bd4cbc
--- /dev/null
+++ b/libgo/go/crypto/md4/md4_test.go
@@ -0,0 +1,71 @@
+// 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 md4
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type md4Test struct {
+ out string
+ in string
+}
+
+var golden = []md4Test{
+ {"31d6cfe0d16ae931b73c59d7e0c089c0", ""},
+ {"bde52cb31de33e46245e05fbdbd6fb24", "a"},
+ {"ec388dd78999dfc7cf4632465693b6bf", "ab"},
+ {"a448017aaf21d8525fc10ae87aa6729d", "abc"},
+ {"41decd8f579255c5200f86a4bb3ba740", "abcd"},
+ {"9803f4a34e8eb14f96adba49064a0c41", "abcde"},
+ {"804e7f1c2586e50b49ac65db5b645131", "abcdef"},
+ {"752f4adfe53d1da0241b5bc216d098fc", "abcdefg"},
+ {"ad9daf8d49d81988590a6f0e745d15dd", "abcdefgh"},
+ {"1e4e28b05464316b56402b3815ed2dfd", "abcdefghi"},
+ {"dc959c6f5d6f9e04e4380777cc964b3d", "abcdefghij"},
+ {"1b5701e265778898ef7de5623bbe7cc0", "Discard medicine more than two years old."},
+ {"d7f087e090fe7ad4a01cb59dacc9a572", "He who has a shady past knows that nice guys finish last."},
+ {"a6f8fd6df617c72837592fc3570595c9", "I wouldn't marry him with a ten foot pole."},
+ {"c92a84a9526da8abc240c05d6b1a1ce0", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"f6013160c4dcb00847069fee3bb09803", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"2c3bb64f50b9107ed57640fe94bec09f", "Nepal premier won't resign."},
+ {"45b7d8a32c7806f2f7f897332774d6e4", "For every action there is an equal and opposite government program."},
+ {"b5b4f9026b175c62d7654bdc3a1cd438", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"caf44e80f2c20ce19b5ba1cab766e7bd", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"191fae6707f496aa54a6bce9f2ecf74d", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"9ddc753e7a4ccee6081cd1b45b23a834", "size: a.out: bad magic"},
+ {"8d050f55b1cadb9323474564be08a521", "The major problem is with sendmail. -Mark Horton"},
+ {"ad6e2587f74c3e3cc19146f6127fa2e3", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"1d616d60a5fabe85589c3f1566ca7fca", "If the enemy is within range, then so are you."},
+ {"aec3326a4f496a2ced65a1963f84577f", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"77b4fd762d6b9245e61c50bf6ebf118b", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"e8f48c726bae5e516f6ddb1a4fe62438", "C is as portable as Stonehedge!!"},
+ {"a3a84366e7219e887423b01f9be7166e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"a6b7aa35157e984ef5d9b7f32e5fbb52", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"75661f0545955f8f9abeeb17845f3fd6", "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("md4[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
diff --git a/libgo/go/crypto/md4/md4block.go b/libgo/go/crypto/md4/md4block.go
new file mode 100644
index 000000000..3fed475f3
--- /dev/null
+++ b/libgo/go/crypto/md4/md4block.go
@@ -0,0 +1,89 @@
+// 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.
+
+// MD4 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package md4
+
+var shift1 = []uint{3, 7, 11, 19}
+var shift2 = []uint{3, 5, 9, 13}
+var shift3 = []uint{3, 9, 11, 15}
+
+var xIndex2 = []uint{0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}
+var xIndex3 = []uint{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}
+
+func _Block(dig *digest, p []byte) int {
+ a := dig.s[0]
+ b := dig.s[1]
+ c := dig.s[2]
+ d := dig.s[3]
+ n := 0
+ var X [16]uint32
+ for len(p) >= _Chunk {
+ aa, bb, cc, dd := a, b, c, d
+
+ j := 0
+ for i := 0; i < 16; i++ {
+ X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
+ j += 4
+ }
+
+ // If this needs to be made faster in the future,
+ // the usual trick is to unroll each of these
+ // loops by a factor of 4; that lets you replace
+ // the shift[] lookups with constants and,
+ // with suitable variable renaming in each
+ // unrolled body, delete the a, b, c, d = d, a, b, c
+ // (or you can let the optimizer do the renaming).
+ //
+ // The index variables are uint so that % by a power
+ // of two can be optimized easily by a compiler.
+
+ // Round 1.
+ for i := uint(0); i < 16; i++ {
+ x := i
+ s := shift1[i%4]
+ f := ((c ^ d) & b) ^ d
+ a += f + X[x]
+ a = a<<s | a>>(32-s)
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 2.
+ for i := uint(0); i < 16; i++ {
+ x := xIndex2[i]
+ s := shift2[i%4]
+ g := (b & c) | (b & d) | (c & d)
+ a += g + X[x] + 0x5a827999
+ a = a<<s | a>>(32-s)
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 3.
+ for i := uint(0); i < 16; i++ {
+ x := xIndex3[i]
+ s := shift3[i%4]
+ h := b ^ c ^ d
+ a += h + X[x] + 0x6ed9eba1
+ a = a<<s | a>>(32-s)
+ a, b, c, d = d, a, b, c
+ }
+
+ a += aa
+ b += bb
+ c += cc
+ d += dd
+
+ p = p[_Chunk:]
+ n += _Chunk
+ }
+
+ dig.s[0] = a
+ dig.s[1] = b
+ dig.s[2] = c
+ dig.s[3] = d
+ return n
+}
diff --git a/libgo/go/crypto/md5/md5.go b/libgo/go/crypto/md5/md5.go
new file mode 100644
index 000000000..54fddb63b
--- /dev/null
+++ b/libgo/go/crypto/md5/md5.go
@@ -0,0 +1,112 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the MD5 hash algorithm as defined in RFC 1321.
+package md5
+
+import (
+ "hash"
+ "os"
+)
+
+// The size of an MD5 checksum in bytes.
+const Size = 16
+
+const (
+ _Chunk = 64
+ _Init0 = 0x67452301
+ _Init1 = 0xEFCDAB89
+ _Init2 = 0x98BADCFE
+ _Init3 = 0x10325476
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ s [4]uint32
+ x [_Chunk]byte
+ nx int
+ len uint64
+}
+
+func (d *digest) Reset() {
+ d.s[0] = _Init0
+ d.s[1] = _Init1
+ d.s[2] = _Init2
+ d.s[3] = _Init3
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the MD5 checksum.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > _Chunk-d.nx {
+ n = _Chunk - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == _Chunk {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0 so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ len := d.len
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if len%64 < 56 {
+ d.Write(tmp[0 : 56-len%64])
+ } else {
+ d.Write(tmp[0 : 64+56-len%64])
+ }
+
+ // Length in bits.
+ len <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(len >> (8 * i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 16)
+ j := 0
+ for _, s := range d.s {
+ p[j+0] = byte(s >> 0)
+ p[j+1] = byte(s >> 8)
+ p[j+2] = byte(s >> 16)
+ p[j+3] = byte(s >> 24)
+ j += 4
+ }
+ return p
+}
diff --git a/libgo/go/crypto/md5/md5_test.go b/libgo/go/crypto/md5/md5_test.go
new file mode 100644
index 000000000..857002b70
--- /dev/null
+++ b/libgo/go/crypto/md5/md5_test.go
@@ -0,0 +1,71 @@
+// 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 md5
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type md5Test struct {
+ out string
+ in string
+}
+
+var golden = []md5Test{
+ {"d41d8cd98f00b204e9800998ecf8427e", ""},
+ {"0cc175b9c0f1b6a831c399e269772661", "a"},
+ {"187ef4436122d1cc2f40dc2b92f0eba0", "ab"},
+ {"900150983cd24fb0d6963f7d28e17f72", "abc"},
+ {"e2fc714c4727ee9395f324cd2e7f331f", "abcd"},
+ {"ab56b4d92b40713acc5af89985d4b786", "abcde"},
+ {"e80b5017098950fc58aad83c8c14978e", "abcdef"},
+ {"7ac66c0f148de9519b8bd264312c4d64", "abcdefg"},
+ {"e8dc4081b13434b45189a720b77b6818", "abcdefgh"},
+ {"8aa99b1f439ff71293e95357bac6fd94", "abcdefghi"},
+ {"a925576942e94b2ef57a066101b48876", "abcdefghij"},
+ {"d747fc1719c7eacb84058196cfe56d57", "Discard medicine more than two years old."},
+ {"bff2dcb37ef3a44ba43ab144768ca837", "He who has a shady past knows that nice guys finish last."},
+ {"0441015ecb54a7342d017ed1bcfdbea5", "I wouldn't marry him with a ten foot pole."},
+ {"9e3cac8e9e9757a60c3ea391130d3689", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"a0f04459b031f916a59a35cc482dc039", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"e7a48e0fe884faf31475d2a04b1362cc", "Nepal premier won't resign."},
+ {"637d2fe925c07c113800509964fb0e06", "For every action there is an equal and opposite government program."},
+ {"834a8d18d5c6562119cf4c7f5086cb71", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"de3a4d2fd6c73ec2db2abad23b444281", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"acf203f997e2cf74ea3aff86985aefaf", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"e1c1384cb4d2221dfdd7c795a4222c9a", "size: a.out: bad magic"},
+ {"c90f3ddecc54f34228c063d7525bf644", "The major problem is with sendmail. -Mark Horton"},
+ {"cdf7ab6c1fd49bd9933c43f3ea5af185", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"83bc85234942fc883c063cbd7f0ad5d0", "If the enemy is within range, then so are you."},
+ {"277cbe255686b48dd7e8f389394d9299", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"fd3fb0a7ffb8af16603f3d3af98f8e1f", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"469b13a78ebf297ecda64d4723655154", "C is as portable as Stonehedge!!"},
+ {"63eb3a2f466410104731c4b037600110", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"72c2ed7592debca1c90fc0100f931a2f", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"132f7619d33b523b1d9e5bd8e0928355", "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("md5[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
diff --git a/libgo/go/crypto/md5/md5block.go b/libgo/go/crypto/md5/md5block.go
new file mode 100644
index 000000000..a887e2e05
--- /dev/null
+++ b/libgo/go/crypto/md5/md5block.go
@@ -0,0 +1,172 @@
+// 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.
+
+// MD5 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package md5
+
+// table[i] = int((1<<32) * abs(sin(i+1 radians))).
+var table = []uint32{
+ // round 1
+ 0xd76aa478,
+ 0xe8c7b756,
+ 0x242070db,
+ 0xc1bdceee,
+ 0xf57c0faf,
+ 0x4787c62a,
+ 0xa8304613,
+ 0xfd469501,
+ 0x698098d8,
+ 0x8b44f7af,
+ 0xffff5bb1,
+ 0x895cd7be,
+ 0x6b901122,
+ 0xfd987193,
+ 0xa679438e,
+ 0x49b40821,
+
+ // round 2
+ 0xf61e2562,
+ 0xc040b340,
+ 0x265e5a51,
+ 0xe9b6c7aa,
+ 0xd62f105d,
+ 0x2441453,
+ 0xd8a1e681,
+ 0xe7d3fbc8,
+ 0x21e1cde6,
+ 0xc33707d6,
+ 0xf4d50d87,
+ 0x455a14ed,
+ 0xa9e3e905,
+ 0xfcefa3f8,
+ 0x676f02d9,
+ 0x8d2a4c8a,
+
+ // round3
+ 0xfffa3942,
+ 0x8771f681,
+ 0x6d9d6122,
+ 0xfde5380c,
+ 0xa4beea44,
+ 0x4bdecfa9,
+ 0xf6bb4b60,
+ 0xbebfbc70,
+ 0x289b7ec6,
+ 0xeaa127fa,
+ 0xd4ef3085,
+ 0x4881d05,
+ 0xd9d4d039,
+ 0xe6db99e5,
+ 0x1fa27cf8,
+ 0xc4ac5665,
+
+ // round 4
+ 0xf4292244,
+ 0x432aff97,
+ 0xab9423a7,
+ 0xfc93a039,
+ 0x655b59c3,
+ 0x8f0ccc92,
+ 0xffeff47d,
+ 0x85845dd1,
+ 0x6fa87e4f,
+ 0xfe2ce6e0,
+ 0xa3014314,
+ 0x4e0811a1,
+ 0xf7537e82,
+ 0xbd3af235,
+ 0x2ad7d2bb,
+ 0xeb86d391,
+}
+
+var shift1 = []uint{7, 12, 17, 22}
+var shift2 = []uint{5, 9, 14, 20}
+var shift3 = []uint{4, 11, 16, 23}
+var shift4 = []uint{6, 10, 15, 21}
+
+func _Block(dig *digest, p []byte) int {
+ a := dig.s[0]
+ b := dig.s[1]
+ c := dig.s[2]
+ d := dig.s[3]
+ n := 0
+ var X [16]uint32
+ for len(p) >= _Chunk {
+ aa, bb, cc, dd := a, b, c, d
+
+ j := 0
+ for i := 0; i < 16; i++ {
+ X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
+ j += 4
+ }
+
+ // If this needs to be made faster in the future,
+ // the usual trick is to unroll each of these
+ // loops by a factor of 4; that lets you replace
+ // the shift[] lookups with constants and,
+ // with suitable variable renaming in each
+ // unrolled body, delete the a, b, c, d = d, a, b, c
+ // (or you can let the optimizer do the renaming).
+ //
+ // The index variables are uint so that % by a power
+ // of two can be optimized easily by a compiler.
+
+ // Round 1.
+ for i := uint(0); i < 16; i++ {
+ x := i
+ s := shift1[i%4]
+ f := ((c ^ d) & b) ^ d
+ a += f + X[x] + table[i]
+ a = a<<s | a>>(32-s) + b
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 2.
+ for i := uint(0); i < 16; i++ {
+ x := (1 + 5*i) % 16
+ s := shift2[i%4]
+ g := ((b ^ c) & d) ^ c
+ a += g + X[x] + table[i+16]
+ a = a<<s | a>>(32-s) + b
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 3.
+ for i := uint(0); i < 16; i++ {
+ x := (5 + 3*i) % 16
+ s := shift3[i%4]
+ h := b ^ c ^ d
+ a += h + X[x] + table[i+32]
+ a = a<<s | a>>(32-s) + b
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 4.
+ for i := uint(0); i < 16; i++ {
+ x := (7 * i) % 16
+ s := shift4[i%4]
+ j := c ^ (b | ^d)
+ a += j + X[x] + table[i+48]
+ a = a<<s | a>>(32-s) + b
+ a, b, c, d = d, a, b, c
+ }
+
+ a += aa
+ b += bb
+ c += cc
+ d += dd
+
+ p = p[_Chunk:]
+ n += _Chunk
+ }
+
+ dig.s[0] = a
+ dig.s[1] = b
+ dig.s[2] = c
+ dig.s[3] = d
+ return n
+}
diff --git a/libgo/go/crypto/ocsp/ocsp.go b/libgo/go/crypto/ocsp/ocsp.go
new file mode 100644
index 000000000..f3fa3bc83
--- /dev/null
+++ b/libgo/go/crypto/ocsp/ocsp.go
@@ -0,0 +1,203 @@
+// 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.
+
+// This package parses OCSP responses as specified in RFC 2560. OCSP responses
+// are signed messages attesting to the validity of a certificate for a small
+// period of time. This is used to manage revocation for X.509 certificates.
+package ocsp
+
+import (
+ "asn1"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/x509"
+ "os"
+ "time"
+)
+
+var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
+var idSHA1WithRSA = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 1, 5})
+
+// These are internal structures that reflect the ASN.1 structure of an OCSP
+// response. See RFC 2560, section 4.2.
+
+const (
+ ocspSuccess = 0
+ ocspMalformed = 1
+ ocspInternalError = 2
+ ocspTryLater = 3
+ ocspSigRequired = 4
+ ocspUnauthorized = 5
+)
+
+type rdnSequence []relativeDistinguishedNameSET
+
+type relativeDistinguishedNameSET []attributeTypeAndValue
+
+type attributeTypeAndValue struct {
+ Type asn1.ObjectIdentifier
+ Value interface{}
+}
+
+type algorithmIdentifier struct {
+ Algorithm asn1.ObjectIdentifier
+}
+
+type certID struct {
+ HashAlgorithm algorithmIdentifier
+ NameHash []byte
+ IssuerKeyHash []byte
+ SerialNumber asn1.RawValue
+}
+
+type responseASN1 struct {
+ Status asn1.Enumerated
+ Response responseBytes "explicit,tag:0"
+}
+
+type responseBytes struct {
+ ResponseType asn1.ObjectIdentifier
+ Response []byte
+}
+
+type basicResponse struct {
+ TBSResponseData responseData
+ SignatureAlgorithm algorithmIdentifier
+ Signature asn1.BitString
+ Certificates []asn1.RawValue "explicit,tag:0,optional"
+}
+
+type responseData struct {
+ Raw asn1.RawContent
+ Version int "optional,default:1,explicit,tag:0"
+ RequestorName rdnSequence "optional,explicit,tag:1"
+ KeyHash []byte "optional,explicit,tag:2"
+ ProducedAt *time.Time
+ Responses []singleResponse
+}
+
+type singleResponse struct {
+ CertID certID
+ Good asn1.Flag "explicit,tag:0,optional"
+ Revoked revokedInfo "explicit,tag:1,optional"
+ Unknown asn1.Flag "explicit,tag:2,optional"
+ ThisUpdate *time.Time
+ NextUpdate *time.Time "explicit,tag:0,optional"
+}
+
+type revokedInfo struct {
+ RevocationTime *time.Time
+ Reason int "explicit,tag:0,optional"
+}
+
+// This is the exposed reflection of the internal OCSP structures.
+
+const (
+ // Good means that the certificate is valid.
+ Good = iota
+ // Revoked means that the certificate has been deliberately revoked.
+ Revoked = iota
+ // Unknown means that the OCSP responder doesn't know about the certificate.
+ Unknown = iota
+ // ServerFailed means that the OCSP responder failed to process the request.
+ ServerFailed = iota
+)
+
+// Response represents an OCSP response. See RFC 2560.
+type Response struct {
+ // Status is one of {Good, Revoked, Unknown, ServerFailed}
+ Status int
+ SerialNumber []byte
+ ProducedAt, ThisUpdate, NextUpdate, RevokedAt *time.Time
+ RevocationReason int
+ Certificate *x509.Certificate
+}
+
+// ParseError results from an invalid OCSP response.
+type ParseError string
+
+func (p ParseError) String() string {
+ return string(p)
+}
+
+// ParseResponse parses an OCSP response in DER form. It only supports
+// responses for a single certificate and only those using RSA signatures.
+// Non-RSA responses will result in an x509.UnsupportedAlgorithmError.
+// Signature errors or parse failures will result in a ParseError.
+func ParseResponse(bytes []byte) (*Response, os.Error) {
+ var resp responseASN1
+ rest, err := asn1.Unmarshal(bytes, &resp)
+ if err != nil {
+ return nil, err
+ }
+ if len(rest) > 0 {
+ return nil, ParseError("trailing data in OCSP response")
+ }
+
+ ret := new(Response)
+ if resp.Status != ocspSuccess {
+ ret.Status = ServerFailed
+ return ret, nil
+ }
+
+ if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) {
+ return nil, ParseError("bad OCSP response type")
+ }
+
+ var basicResp basicResponse
+ rest, err = asn1.Unmarshal(resp.Response.Response, &basicResp)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(basicResp.Certificates) != 1 {
+ return nil, ParseError("OCSP response contains bad number of certificates")
+ }
+
+ if len(basicResp.TBSResponseData.Responses) != 1 {
+ return nil, ParseError("OCSP response contains bad number of responses")
+ }
+
+ ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ if ret.Certificate.PublicKeyAlgorithm != x509.RSA || !basicResp.SignatureAlgorithm.Algorithm.Equal(idSHA1WithRSA) {
+ return nil, x509.UnsupportedAlgorithmError{}
+ }
+
+ h := sha1.New()
+ hashType := rsa.HashSHA1
+
+ pub := ret.Certificate.PublicKey.(*rsa.PublicKey)
+ h.Write(basicResp.TBSResponseData.Raw)
+ digest := h.Sum()
+ signature := basicResp.Signature.RightAlign()
+
+ if rsa.VerifyPKCS1v15(pub, hashType, digest, signature) != nil {
+ return nil, ParseError("bad OCSP signature")
+ }
+
+ r := basicResp.TBSResponseData.Responses[0]
+
+ ret.SerialNumber = r.CertID.SerialNumber.Bytes
+
+ switch {
+ case bool(r.Good):
+ ret.Status = Good
+ case bool(r.Unknown):
+ ret.Status = Unknown
+ default:
+ ret.Status = Revoked
+ ret.RevokedAt = r.Revoked.RevocationTime
+ ret.RevocationReason = r.Revoked.Reason
+ }
+
+ ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
+ ret.ThisUpdate = r.ThisUpdate
+ ret.NextUpdate = r.NextUpdate
+
+ return ret, nil
+}
diff --git a/libgo/go/crypto/ocsp/ocsp_test.go b/libgo/go/crypto/ocsp/ocsp_test.go
new file mode 100644
index 000000000..f9889790f
--- /dev/null
+++ b/libgo/go/crypto/ocsp/ocsp_test.go
@@ -0,0 +1,97 @@
+package ocsp
+
+import (
+ "bytes"
+ "encoding/hex"
+ "reflect"
+ "testing"
+ "time"
+)
+
+func TestOCSPDecode(t *testing.T) {
+ responseBytes, _ := hex.DecodeString(ocspResponseHex)
+ resp, err := ParseResponse(responseBytes)
+ if err != nil {
+ t.Error(err)
+ }
+
+ expected := Response{Status: 0, SerialNumber: []byte{0x1, 0xd0, 0xfa}, RevocationReason: 0, ThisUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 15, Minute: 1, Second: 5, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}, NextUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 18, Minute: 35, Second: 17, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}}
+
+ if !reflect.DeepEqual(resp.ThisUpdate, resp.ThisUpdate) {
+ t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate)
+ }
+
+ if !reflect.DeepEqual(resp.NextUpdate, resp.NextUpdate) {
+ t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, expected.NextUpdate)
+ }
+
+ if resp.Status != expected.Status {
+ t.Errorf("resp.Status: got %d, want %d", resp.Status, expected.Status)
+ }
+
+ if !bytes.Equal(resp.SerialNumber, expected.SerialNumber) {
+ t.Errorf("resp.SerialNumber: got %x, want %x", resp.SerialNumber, expected.SerialNumber)
+ }
+
+ if resp.RevocationReason != expected.RevocationReason {
+ t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, expected.RevocationReason)
+ }
+}
+
+// This OCSP response was taken from Thawte's public OCSP responder.
+// To recreate:
+// $ openssl s_client -tls1 -showcerts -servername www.google.com -connect www.google.com:443
+// Copy and paste the first certificate into /tmp/cert.crt and the second into
+// /tmp/intermediate.crt
+// $ openssl ocsp -issuer /tmp/intermediate.crt -cert /tmp/cert.crt -url http://ocsp.thawte.com -resp_text -respout /tmp/ocsp.der
+// Then hex encode the result:
+// $ python -c 'print file("/tmp/ocsp.der", "r").read().encode("hex")'
+
+const ocspResponseHex = "308206bc0a0100a08206b5308206b106092b0601050507300101048206a23082069e3081" +
+ "c9a14e304c310b300906035504061302494c31163014060355040a130d5374617274436f" +
+ "6d204c74642e312530230603550403131c5374617274436f6d20436c6173732031204f43" +
+ "5350205369676e6572180f32303130303730373137333531375a30663064303c30090605" +
+ "2b0e03021a050004146568874f40750f016a3475625e1f5c93e5a26d580414eb4234d098" +
+ "b0ab9ff41b6b08f7cc642eef0e2c45020301d0fa8000180f323031303037303731353031" +
+ "30355aa011180f32303130303730373138333531375a300d06092a864886f70d01010505" +
+ "000382010100ab557ff070d1d7cebbb5f0ec91a15c3fed22eb2e1b8244f1b84545f013a4" +
+ "fb46214c5e3fbfbebb8a56acc2b9db19f68fd3c3201046b3824d5ba689f99864328710cb" +
+ "467195eb37d84f539e49f859316b32964dc3e47e36814ce94d6c56dd02733b1d0802f7ff" +
+ "4eebdbbd2927dcf580f16cbc290f91e81b53cb365e7223f1d6e20a88ea064104875e0145" +
+ "672b20fc14829d51ca122f5f5d77d3ad6c83889c55c7dc43680ba2fe3cef8b05dbcabdc0" +
+ "d3e09aaf9725597f8c858c2fa38c0d6aed2e6318194420dd1a1137445d13e1c97ab47896" +
+ "17a4e08925f46f867b72e3a4dc1f08cb870b2b0717f7207faa0ac512e628a029aba7457a" +
+ "e63dcf3281e2162d9349a08204ba308204b6308204b23082039aa003020102020101300d" +
+ "06092a864886f70d010105050030818c310b300906035504061302494c31163014060355" +
+ "040a130d5374617274436f6d204c74642e312b3029060355040b13225365637572652044" +
+ "69676974616c204365727469666963617465205369676e696e6731383036060355040313" +
+ "2f5374617274436f6d20436c6173732031205072696d61727920496e7465726d65646961" +
+ "746520536572766572204341301e170d3037313032353030323330365a170d3132313032" +
+ "333030323330365a304c310b300906035504061302494c31163014060355040a130d5374" +
+ "617274436f6d204c74642e312530230603550403131c5374617274436f6d20436c617373" +
+ "2031204f435350205369676e657230820122300d06092a864886f70d0101010500038201" +
+ "0f003082010a0282010100b9561b4c45318717178084e96e178df2255e18ed8d8ecc7c2b" +
+ "7b51a6c1c2e6bf0aa3603066f132fe10ae97b50e99fa24b83fc53dd2777496387d14e1c3" +
+ "a9b6a4933e2ac12413d085570a95b8147414a0bc007c7bcf222446ef7f1a156d7ea1c577" +
+ "fc5f0facdfd42eb0f5974990cb2f5cefebceef4d1bdc7ae5c1075c5a99a93171f2b0845b" +
+ "4ff0864e973fcfe32f9d7511ff87a3e943410c90a4493a306b6944359340a9ca96f02b66" +
+ "ce67f028df2980a6aaee8d5d5d452b8b0eb93f923cc1e23fcccbdbe7ffcb114d08fa7a6a" +
+ "3c404f825d1a0e715935cf623a8c7b59670014ed0622f6089a9447a7a19010f7fe58f841" +
+ "29a2765ea367824d1c3bb2fda308530203010001a382015c30820158300c0603551d1301" +
+ "01ff04023000300b0603551d0f0404030203a8301e0603551d250417301506082b060105" +
+ "0507030906092b0601050507300105301d0603551d0e0416041445e0a36695414c5dd449" +
+ "bc00e33cdcdbd2343e173081a80603551d230481a030819d8014eb4234d098b0ab9ff41b" +
+ "6b08f7cc642eef0e2c45a18181a47f307d310b300906035504061302494c311630140603" +
+ "55040a130d5374617274436f6d204c74642e312b3029060355040b132253656375726520" +
+ "4469676974616c204365727469666963617465205369676e696e67312930270603550403" +
+ "13205374617274436f6d2043657274696669636174696f6e20417574686f726974798201" +
+ "0a30230603551d12041c301a8618687474703a2f2f7777772e737461727473736c2e636f" +
+ "6d2f302c06096086480186f842010d041f161d5374617274436f6d205265766f63617469" +
+ "6f6e20417574686f72697479300d06092a864886f70d01010505000382010100182d2215" +
+ "8f0fc0291324fa8574c49bb8ff2835085adcbf7b7fc4191c397ab6951328253fffe1e5ec" +
+ "2a7da0d50fca1a404e6968481366939e666c0a6209073eca57973e2fefa9ed1718e8176f" +
+ "1d85527ff522c08db702e3b2b180f1cbff05d98128252cf0f450f7dd2772f4188047f19d" +
+ "c85317366f94bc52d60f453a550af58e308aaab00ced33040b62bf37f5b1ab2a4f7f0f80" +
+ "f763bf4d707bc8841d7ad9385ee2a4244469260b6f2bf085977af9074796048ecc2f9d48" +
+ "a1d24ce16e41a9941568fec5b42771e118f16c106a54ccc339a4b02166445a167902e75e" +
+ "6d8620b0825dcd18a069b90fd851d10fa8effd409deec02860d26d8d833f304b10669b42"
diff --git a/libgo/go/crypto/openpgp/armor/armor.go b/libgo/go/crypto/openpgp/armor/armor.go
new file mode 100644
index 000000000..97080f6c6
--- /dev/null
+++ b/libgo/go/crypto/openpgp/armor/armor.go
@@ -0,0 +1,220 @@
+// 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.
+
+// This package implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
+// very similar to PEM except that it has an additional CRC checksum.
+package armor
+
+import (
+ "bytes"
+ "crypto/openpgp/error"
+ "encoding/base64"
+ "encoding/line"
+ "io"
+ "os"
+)
+
+// A Block represents an OpenPGP armored structure.
+//
+// The encoded form is:
+// -----BEGIN Type-----
+// Headers
+//
+// base64-encoded Bytes
+// '=' base64 encoded checksum
+// -----END Type-----
+// where Headers is a possibly empty sequence of Key: Value lines.
+//
+// Since the armored data can be very large, this package presents a streaming
+// interface.
+type Block struct {
+ Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE").
+ Header map[string]string // Optional headers.
+ Body io.Reader // A Reader from which the contents can be read
+ lReader lineReader
+ oReader openpgpReader
+}
+
+var ArmorCorrupt os.Error = error.StructuralError("armor invalid")
+
+const crc24Init = 0xb704ce
+const crc24Poly = 0x1864cfb
+const crc24Mask = 0xffffff
+
+// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
+func crc24(crc uint32, d []byte) uint32 {
+ for _, b := range d {
+ crc ^= uint32(b) << 16
+ for i := 0; i < 8; i++ {
+ crc <<= 1
+ if crc&0x1000000 != 0 {
+ crc ^= crc24Poly
+ }
+ }
+ }
+ return crc
+}
+
+var armorStart = []byte("-----BEGIN ")
+var armorEnd = []byte("-----END ")
+var armorEndOfLine = []byte("-----")
+
+// lineReader wraps a line based reader. It watches for the end of an armor
+// block and records the expected CRC value.
+type lineReader struct {
+ in *line.Reader
+ buf []byte
+ eof bool
+ crc uint32
+}
+
+func (l *lineReader) Read(p []byte) (n int, err os.Error) {
+ if l.eof {
+ return 0, os.EOF
+ }
+
+ if len(l.buf) > 0 {
+ n = copy(p, l.buf)
+ l.buf = l.buf[n:]
+ return
+ }
+
+ line, isPrefix, err := l.in.ReadLine()
+ if err != nil {
+ return
+ }
+ if isPrefix {
+ return 0, ArmorCorrupt
+ }
+
+ if len(line) == 5 && line[0] == '=' {
+ // This is the checksum line
+ var expectedBytes [3]byte
+ var m int
+ m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:])
+ if m != 3 || err != nil {
+ return
+ }
+ l.crc = uint32(expectedBytes[0])<<16 |
+ uint32(expectedBytes[1])<<8 |
+ uint32(expectedBytes[2])
+
+ line, _, err = l.in.ReadLine()
+ if err != nil && err != os.EOF {
+ return
+ }
+ if !bytes.HasPrefix(line, armorEnd) {
+ return 0, ArmorCorrupt
+ }
+
+ l.eof = true
+ return 0, os.EOF
+ }
+
+ if len(line) != 64 {
+ return 0, ArmorCorrupt
+ }
+
+ n = copy(p, line)
+ bytesToSave := len(line) - n
+ if bytesToSave > 0 {
+ if cap(l.buf) < bytesToSave {
+ l.buf = make([]byte, 0, bytesToSave)
+ }
+ l.buf = l.buf[0:bytesToSave]
+ copy(l.buf, line[n:])
+ }
+
+ return
+}
+
+// openpgpReader passes Read calls to the underlying base64 decoder, but keeps
+// a running CRC of the resulting data and checks the CRC against the value
+// found by the lineReader at EOF.
+type openpgpReader struct {
+ lReader *lineReader
+ b64Reader io.Reader
+ currentCRC uint32
+}
+
+func (r *openpgpReader) Read(p []byte) (n int, err os.Error) {
+ n, err = r.b64Reader.Read(p)
+ r.currentCRC = crc24(r.currentCRC, p[:n])
+
+ if err == os.EOF {
+ if r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
+ return 0, ArmorCorrupt
+ }
+ }
+
+ return
+}
+
+// Decode reads a PGP armored block from the given Reader. It will ignore
+// leading garbage. If it doesn't find a block, it will return nil, os.EOF. The
+// given Reader is not usable after calling this function: an arbitary amount
+// of data may have been read past the end of the block.
+func Decode(in io.Reader) (p *Block, err os.Error) {
+ r := line.NewReader(in, 100)
+ var line []byte
+ ignoreNext := false
+
+TryNextBlock:
+ p = nil
+
+ // Skip leading garbage
+ for {
+ ignoreThis := ignoreNext
+ line, ignoreNext, err = r.ReadLine()
+ if err != nil {
+ return
+ }
+ if ignoreNext || ignoreThis {
+ continue
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) {
+ break
+ }
+ }
+
+ p = new(Block)
+ p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)])
+ p.Header = make(map[string]string)
+ nextIsContinuation := false
+ var lastKey string
+
+ // Read headers
+ for {
+ isContinuation := nextIsContinuation
+ line, nextIsContinuation, err = r.ReadLine()
+ if err != nil {
+ p = nil
+ return
+ }
+ if isContinuation {
+ p.Header[lastKey] += string(line)
+ continue
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) == 0 {
+ break
+ }
+
+ i := bytes.Index(line, []byte(": "))
+ if i == -1 {
+ goto TryNextBlock
+ }
+ lastKey = string(line[:i])
+ p.Header[lastKey] = string(line[i+2:])
+ }
+
+ p.lReader.in = r
+ p.oReader.currentCRC = crc24Init
+ p.oReader.lReader = &p.lReader
+ p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
+ p.Body = &p.oReader
+
+ return
+}
diff --git a/libgo/go/crypto/openpgp/armor/armor_test.go b/libgo/go/crypto/openpgp/armor/armor_test.go
new file mode 100644
index 000000000..e4ffd414b
--- /dev/null
+++ b/libgo/go/crypto/openpgp/armor/armor_test.go
@@ -0,0 +1,97 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package armor
+
+import (
+ "bytes"
+ "hash/adler32"
+ "io/ioutil"
+ "testing"
+)
+
+func TestDecodeEncode(t *testing.T) {
+ buf := bytes.NewBuffer([]byte(armorExample1))
+ result, err := Decode(buf)
+ if err != nil {
+ t.Error(err)
+ }
+ expectedType := "PGP SIGNATURE"
+ if result.Type != expectedType {
+ t.Errorf("result.Type: got:%s want:%s", result.Type, expectedType)
+ }
+ if len(result.Header) != 1 {
+ t.Errorf("len(result.Header): got:%d want:1", len(result.Header))
+ }
+ v, ok := result.Header["Version"]
+ if !ok || v != "GnuPG v1.4.10 (GNU/Linux)" {
+ t.Errorf("result.Header: got:%#v", result.Header)
+ }
+
+ contents, err := ioutil.ReadAll(result.Body)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if adler32.Checksum(contents) != 0x789d7f00 {
+ t.Errorf("contents: got: %x", contents)
+ }
+
+ buf = bytes.NewBuffer(nil)
+ w, err := Encode(buf, result.Type, result.Header)
+ if err != nil {
+ t.Error(err)
+ }
+ _, err = w.Write(contents)
+ if err != nil {
+ t.Error(err)
+ }
+ w.Close()
+
+ if !bytes.Equal(buf.Bytes(), []byte(armorExample1)) {
+ t.Errorf("got: %s\nwant: %s", string(buf.Bytes()), armorExample1)
+ }
+}
+
+func TestLongHeader(t *testing.T) {
+ buf := bytes.NewBuffer([]byte(armorLongLine))
+ result, err := Decode(buf)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ value, ok := result.Header["Version"]
+ if !ok {
+ t.Errorf("missing Version header")
+ }
+ if value != longValueExpected {
+ t.Errorf("got: %s want: %s", value, longValueExpected)
+ }
+}
+
+const armorExample1 = `-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+iQEcBAABAgAGBQJMtFESAAoJEKsQXJGvOPsVj40H/1WW6jaMXv4BW+1ueDSMDwM8
+kx1fLOXbVM5/Kn5LStZNt1jWWnpxdz7eq3uiqeCQjmqUoRde3YbB2EMnnwRbAhpp
+cacnAvy9ZQ78OTxUdNW1mhX5bS6q1MTEJnl+DcyigD70HG/yNNQD7sOPMdYQw0TA
+byQBwmLwmTsuZsrYqB68QyLHI+DUugn+kX6Hd2WDB62DKa2suoIUIHQQCd/ofwB3
+WfCYInXQKKOSxu2YOg2Eb4kLNhSMc1i9uKUWAH+sdgJh7NBgdoE4MaNtBFkHXRvv
+okWuf3+xA9ksp1npSY/mDvgHijmjvtpRDe6iUeqfCn8N9u9CBg8geANgaG8+QA4=
+=wfQG
+-----END PGP SIGNATURE-----`
+
+const armorLongLine = `-----BEGIN PGP SIGNATURE-----
+Version: 0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz
+
+iQEcBAABAgAGBQJMtFESAAoJEKsQXJGvOPsVj40H/1WW6jaMXv4BW+1ueDSMDwM8
+kx1fLOXbVM5/Kn5LStZNt1jWWnpxdz7eq3uiqeCQjmqUoRde3YbB2EMnnwRbAhpp
+cacnAvy9ZQ78OTxUdNW1mhX5bS6q1MTEJnl+DcyigD70HG/yNNQD7sOPMdYQw0TA
+byQBwmLwmTsuZsrYqB68QyLHI+DUugn+kX6Hd2WDB62DKa2suoIUIHQQCd/ofwB3
+WfCYInXQKKOSxu2YOg2Eb4kLNhSMc1i9uKUWAH+sdgJh7NBgdoE4MaNtBFkHXRvv
+okWuf3+xA9ksp1npSY/mDvgHijmjvtpRDe6iUeqfCn8N9u9CBg8geANgaG8+QA4=
+=wfQG
+-----END PGP SIGNATURE-----`
+
+const longValueExpected = "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
diff --git a/libgo/go/crypto/openpgp/armor/encode.go b/libgo/go/crypto/openpgp/armor/encode.go
new file mode 100644
index 000000000..410e73460
--- /dev/null
+++ b/libgo/go/crypto/openpgp/armor/encode.go
@@ -0,0 +1,162 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package armor
+
+import (
+ "encoding/base64"
+ "io"
+ "os"
+)
+
+var armorHeaderSep = []byte(": ")
+var blockEnd = []byte("\n=")
+var newline = []byte("\n")
+var armorEndOfLineOut = []byte("-----\n")
+
+// writeSlices writes its arguments to the given Writer.
+func writeSlices(out io.Writer, slices ...[]byte) (err os.Error) {
+ for _, s := range slices {
+ _, err := out.Write(s)
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// lineBreaker breaks data across several lines, all of the same byte length
+// (except possibly the last). Lines are broken with a single '\n'.
+type lineBreaker struct {
+ lineLength int
+ line []byte
+ used int
+ out io.Writer
+ haveWritten bool
+}
+
+func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
+ return &lineBreaker{
+ lineLength: lineLength,
+ line: make([]byte, lineLength),
+ used: 0,
+ out: out,
+ }
+}
+
+func (l *lineBreaker) Write(b []byte) (n int, err os.Error) {
+ n = len(b)
+
+ if n == 0 {
+ return
+ }
+
+ if l.used == 0 && l.haveWritten {
+ _, err = l.out.Write([]byte{'\n'})
+ if err != nil {
+ return
+ }
+ }
+
+ if l.used+len(b) < l.lineLength {
+ l.used += copy(l.line[l.used:], b)
+ return
+ }
+
+ l.haveWritten = true
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ excess := l.lineLength - l.used
+ l.used = 0
+
+ _, err = l.out.Write(b[0:excess])
+ if err != nil {
+ return
+ }
+
+ _, err = l.Write(b[excess:])
+ return
+}
+
+func (l *lineBreaker) Close() (err os.Error) {
+ if l.used > 0 {
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+// encoding keeps track of a running CRC24 over the data which has been written
+// to it and outputs a OpenPGP checksum when closed, followed by an armor
+// trailer.
+//
+// It's built into a stack of io.Writers:
+// encoding -> base64 encoder -> lineBreaker -> out
+type encoding struct {
+ out io.Writer
+ breaker *lineBreaker
+ b64 io.WriteCloser
+ crc uint32
+ blockType []byte
+}
+
+func (e *encoding) Write(data []byte) (n int, err os.Error) {
+ e.crc = crc24(e.crc, data)
+ return e.b64.Write(data)
+}
+
+func (e *encoding) Close() (err os.Error) {
+ err = e.b64.Close()
+ if err != nil {
+ return
+ }
+
+ var checksumBytes [3]byte
+ checksumBytes[0] = byte(e.crc >> 16)
+ checksumBytes[1] = byte(e.crc >> 8)
+ checksumBytes[2] = byte(e.crc)
+
+ var b64ChecksumBytes [4]byte
+ base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
+
+ return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
+}
+
+// Encode returns a WriteCloser which will encode the data written to it in
+// OpenPGP armor.
+func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err os.Error) {
+ bType := []byte(blockType)
+ err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
+ if err != nil {
+ return
+ }
+
+ for k, v := range headers {
+ err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
+ if err != nil {
+ return
+ }
+ }
+
+ if len(headers) > 0 {
+ _, err := out.Write(newline)
+ if err != nil {
+ return
+ }
+ }
+
+ e := &encoding{
+ out: out,
+ breaker: newLineBreaker(out, 64),
+ crc: crc24Init,
+ blockType: bType,
+ }
+ e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
+ return e, nil
+}
diff --git a/libgo/go/crypto/openpgp/error/error.go b/libgo/go/crypto/openpgp/error/error.go
new file mode 100644
index 000000000..2d80ce373
--- /dev/null
+++ b/libgo/go/crypto/openpgp/error/error.go
@@ -0,0 +1,46 @@
+// 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.
+
+// This package contains common error types for the OpenPGP packages.
+package error
+
+// A StructuralError is returned when OpenPGP data is found to be syntactically
+// invalid.
+type StructuralError string
+
+func (s StructuralError) String() string {
+ return "OpenPGP data invalid: " + string(s)
+}
+
+// UnsupportedError indicates that, although the OpenPGP data is valid, it
+// makes use of currently unimplemented features.
+type UnsupportedError string
+
+func (s UnsupportedError) String() string {
+ return "OpenPGP feature unsupported: " + string(s)
+}
+
+// InvalidArgumentError indicates that the caller is in error and passed an
+// incorrect value.
+type InvalidArgumentError string
+
+func (i InvalidArgumentError) String() string {
+ return "OpenPGP argument invalid: " + string(i)
+}
+
+// SignatureError indicates that a syntactically valid signature failed to
+// validate.
+type SignatureError string
+
+func (b SignatureError) String() string {
+ return "OpenPGP signature invalid: " + string(b)
+}
+
+type keyIncorrect int
+
+func (ki keyIncorrect) String() string {
+ return "the given key was incorrect"
+}
+
+var KeyIncorrectError = keyIncorrect(0)
diff --git a/libgo/go/crypto/openpgp/s2k/s2k.go b/libgo/go/crypto/openpgp/s2k/s2k.go
new file mode 100644
index 000000000..f369d7ed4
--- /dev/null
+++ b/libgo/go/crypto/openpgp/s2k/s2k.go
@@ -0,0 +1,146 @@
+// 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 package implements the various OpenPGP string-to-key transforms as
+// specified in RFC 4800 section 3.7.1.
+package s2k
+
+import (
+ "crypto/md5"
+ "crypto/openpgp/error"
+ "crypto/ripemd160"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "hash"
+ "io"
+ "os"
+)
+
+// Simple writes to out the result of computing the Simple S2K function (RFC
+// 4880, section 3.7.1.1) using the given hash and input passphrase.
+func Simple(out []byte, h hash.Hash, in []byte) {
+ Salted(out, h, in, nil)
+}
+
+var zero [1]byte
+
+// Salted writes to out the result of computing the Salted S2K function (RFC
+// 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
+func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
+ done := 0
+
+ for i := 0; done < len(out); i++ {
+ h.Reset()
+ for j := 0; j < i; j++ {
+ h.Write(zero[:])
+ }
+ h.Write(salt)
+ h.Write(in)
+ n := copy(out[done:], h.Sum())
+ done += n
+ }
+}
+
+// Iterated writes to out the result of computing the Iterated and Salted S2K
+// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
+// salt and iteration count.
+func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
+ combined := make([]byte, len(in)+len(salt))
+ copy(combined, salt)
+ copy(combined[len(salt):], in)
+
+ if count < len(combined) {
+ count = len(combined)
+ }
+
+ done := 0
+ for i := 0; done < len(out); i++ {
+ h.Reset()
+ for j := 0; j < i; j++ {
+ h.Write(zero[:])
+ }
+ written := 0
+ for written < count {
+ if written+len(combined) > count {
+ todo := count - written
+ h.Write(combined[:todo])
+ written = count
+ } else {
+ h.Write(combined)
+ written += len(combined)
+ }
+ }
+ n := copy(out[done:], h.Sum())
+ done += n
+ }
+}
+
+// Parse reads a binary specification for a string-to-key transformation from r
+// and returns a function which performs that transform.
+func Parse(r io.Reader) (f func(out, in []byte), err os.Error) {
+ var buf [9]byte
+
+ _, err = io.ReadFull(r, buf[:2])
+ if err != nil {
+ return
+ }
+
+ h := hashFuncFromType(buf[1])
+ if h == nil {
+ return nil, error.UnsupportedError("hash for S2K function")
+ }
+
+ switch buf[0] {
+ case 1:
+ f := func(out, in []byte) {
+ Simple(out, h, in)
+ }
+ return f, nil
+ case 2:
+ _, err := io.ReadFull(r, buf[:8])
+ if err != nil {
+ return
+ }
+ f := func(out, in []byte) {
+ Salted(out, h, in, buf[:8])
+ }
+ return f, nil
+ case 3:
+ _, err := io.ReadFull(r, buf[:9])
+ if err != nil {
+ return
+ }
+ count := (16 + int(buf[8]&15)) << (uint32(buf[8]>>4) + 6)
+ f := func(out, in []byte) {
+ Iterated(out, h, in, buf[:8], count)
+ }
+ return f, nil
+ }
+
+ return nil, error.UnsupportedError("S2K function")
+}
+
+// hashFuncFromType returns a hash.Hash which corresponds to the given hash
+// type byte. See RFC 4880, section 9.4.
+func hashFuncFromType(hashType byte) hash.Hash {
+ switch hashType {
+ case 1:
+ return md5.New()
+ case 2:
+ return sha1.New()
+ case 3:
+ return ripemd160.New()
+ case 8:
+ return sha256.New()
+ case 9:
+ return sha512.New384()
+ case 10:
+ return sha512.New()
+ case 11:
+ return sha256.New224()
+ }
+
+ return nil
+}
diff --git a/libgo/go/crypto/openpgp/s2k/s2k_test.go b/libgo/go/crypto/openpgp/s2k/s2k_test.go
new file mode 100644
index 000000000..814b78627
--- /dev/null
+++ b/libgo/go/crypto/openpgp/s2k/s2k_test.go
@@ -0,0 +1,94 @@
+// 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 s2k
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "encoding/hex"
+ "testing"
+)
+
+var saltedTests = []struct {
+ in, out string
+}{
+ {"hello", "10295ac1"},
+ {"world", "ac587a5e"},
+ {"foo", "4dda8077"},
+ {"bar", "bd8aac6b9ea9cae04eae6a91c6133b58b5d9a61c14f355516ed9370456"},
+ {"x", "f1d3f289"},
+ {"xxxxxxxxxxxxxxxxxxxxxxx", "e00d7b45"},
+}
+
+func TestSalted(t *testing.T) {
+ h := sha1.New()
+ salt := [4]byte{1, 2, 3, 4}
+
+ for i, test := range saltedTests {
+ expected, _ := hex.DecodeString(test.out)
+ out := make([]byte, len(expected))
+ Salted(out, h, []byte(test.in), salt[:])
+ if !bytes.Equal(expected, out) {
+ t.Errorf("#%d, got: %x want: %x", i, out, expected)
+ }
+ }
+}
+
+
+var iteratedTests = []struct {
+ in, out string
+}{
+ {"hello", "83126105"},
+ {"world", "6fa317f9"},
+ {"foo", "8fbc35b9"},
+ {"bar", "2af5a99b54f093789fd657f19bd245af7604d0f6ae06f66602a46a08ae"},
+ {"x", "5a684dfe"},
+ {"xxxxxxxxxxxxxxxxxxxxxxx", "18955174"},
+}
+
+func TestIterated(t *testing.T) {
+ h := sha1.New()
+ salt := [4]byte{4, 3, 2, 1}
+
+ for i, test := range iteratedTests {
+ expected, _ := hex.DecodeString(test.out)
+ out := make([]byte, len(expected))
+ Iterated(out, h, []byte(test.in), salt[:], 31)
+ if !bytes.Equal(expected, out) {
+ t.Errorf("#%d, got: %x want: %x", i, out, expected)
+ }
+ }
+}
+
+
+var parseTests = []struct {
+ spec, in, out string
+}{
+ /* Simple with SHA1 */
+ {"0102", "hello", "aaf4c61d"},
+ /* Salted with SHA1 */
+ {"02020102030405060708", "hello", "f4f7d67e"},
+ /* Iterated with SHA1 */
+ {"03020102030405060708f1", "hello", "f2a57b7c"},
+}
+
+func TestParse(t *testing.T) {
+ for i, test := range parseTests {
+ spec, _ := hex.DecodeString(test.spec)
+ buf := bytes.NewBuffer(spec)
+ f, err := Parse(buf)
+ if err != nil {
+ t.Errorf("%d: Parse returned error: %s", i, err)
+ continue
+ }
+
+ expected, _ := hex.DecodeString(test.out)
+ out := make([]byte, len(expected))
+ f(out, []byte(test.in))
+ if !bytes.Equal(out, expected) {
+ t.Errorf("%d: output got: %x want: %x", i, out, expected)
+ }
+ }
+}
diff --git a/libgo/go/crypto/rand/rand.go b/libgo/go/crypto/rand/rand.go
new file mode 100644
index 000000000..42d9da0ef
--- /dev/null
+++ b/libgo/go/crypto/rand/rand.go
@@ -0,0 +1,21 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rand implements a cryptographically secure
+// pseudorandom number generator.
+package rand
+
+import (
+ "io"
+ "os"
+)
+
+// Reader is a global, shared instance of a cryptographically
+// strong pseudo-random generator.
+// On Unix-like systems, Reader reads from /dev/urandom.
+// On Windows systems, Reader uses the CryptGenRandom API.
+var Reader io.Reader
+
+// Read is a helper function that calls Reader.Read.
+func Read(b []byte) (n int, err os.Error) { return Reader.Read(b) }
diff --git a/libgo/go/crypto/rand/rand_test.go b/libgo/go/crypto/rand/rand_test.go
new file mode 100644
index 000000000..f64ead4ca
--- /dev/null
+++ b/libgo/go/crypto/rand/rand_test.go
@@ -0,0 +1,27 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+ "bytes"
+ "compress/flate"
+ "testing"
+)
+
+func TestRead(t *testing.T) {
+ b := make([]byte, 4e6)
+ n, err := Read(b)
+ if n != len(b) || err != nil {
+ t.Fatalf("Read(buf) = %d, %s", n, err)
+ }
+
+ var z bytes.Buffer
+ f := flate.NewWriter(&z, 5)
+ f.Write(b)
+ f.Close()
+ if z.Len() < len(b)*99/100 {
+ t.Fatalf("Compressed %d -> %d", len(b), z.Len())
+ }
+}
diff --git a/libgo/go/crypto/rand/rand_unix.go b/libgo/go/crypto/rand/rand_unix.go
new file mode 100644
index 000000000..ff16f2554
--- /dev/null
+++ b/libgo/go/crypto/rand/rand_unix.go
@@ -0,0 +1,125 @@
+// 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.
+
+// Unix cryptographically secure pseudorandom number
+// generator.
+
+package rand
+
+import (
+ "crypto/aes"
+ "io"
+ "os"
+ "sync"
+ "time"
+)
+
+// Easy implementation: read from /dev/urandom.
+// This is sufficient on Linux, OS X, and FreeBSD.
+
+func init() { Reader = &devReader{name: "/dev/urandom"} }
+
+// A devReader satisfies reads by reading the file named name.
+type devReader struct {
+ name string
+ f *os.File
+ mu sync.Mutex
+}
+
+func (r *devReader) Read(b []byte) (n int, err os.Error) {
+ r.mu.Lock()
+ if r.f == nil {
+ f, err := os.Open(r.name, os.O_RDONLY, 0)
+ if f == nil {
+ r.mu.Unlock()
+ return 0, err
+ }
+ r.f = f
+ }
+ r.mu.Unlock()
+ return r.f.Read(b)
+}
+
+// Alternate pseudo-random implementation for use on
+// systems without a reliable /dev/urandom. So far we
+// haven't needed it.
+
+// newReader returns a new pseudorandom generator that
+// seeds itself by reading from entropy. If entropy == nil,
+// the generator seeds itself by reading from the system's
+// random number generator, typically /dev/random.
+// The Read method on the returned reader always returns
+// the full amount asked for, or else it returns an error.
+//
+// The generator uses the X9.31 algorithm with AES-128,
+// reseeding after every 1 MB of generated data.
+func newReader(entropy io.Reader) io.Reader {
+ if entropy == nil {
+ entropy = &devReader{name: "/dev/random"}
+ }
+ return &reader{entropy: entropy}
+}
+
+type reader struct {
+ mu sync.Mutex
+ budget int // number of bytes that can be generated
+ cipher *aes.Cipher
+ entropy io.Reader
+ time, seed, dst, key [aes.BlockSize]byte
+}
+
+func (r *reader) Read(b []byte) (n int, err os.Error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ n = len(b)
+
+ for len(b) > 0 {
+ if r.budget == 0 {
+ _, err := io.ReadFull(r.entropy, r.seed[0:])
+ if err != nil {
+ return n - len(b), err
+ }
+ _, err = io.ReadFull(r.entropy, r.key[0:])
+ if err != nil {
+ return n - len(b), err
+ }
+ r.cipher, err = aes.NewCipher(r.key[0:])
+ if err != nil {
+ return n - len(b), err
+ }
+ r.budget = 1 << 20 // reseed after generating 1MB
+ }
+ r.budget -= aes.BlockSize
+
+ // ANSI X9.31 (== X9.17) algorithm, but using AES in place of 3DES.
+ //
+ // single block:
+ // t = encrypt(time)
+ // dst = encrypt(t^seed)
+ // seed = encrypt(t^dst)
+ ns := time.Nanoseconds()
+ r.time[0] = byte(ns >> 56)
+ r.time[1] = byte(ns >> 48)
+ r.time[2] = byte(ns >> 40)
+ r.time[3] = byte(ns >> 32)
+ r.time[4] = byte(ns >> 24)
+ r.time[5] = byte(ns >> 16)
+ r.time[6] = byte(ns >> 8)
+ r.time[7] = byte(ns)
+ r.cipher.Encrypt(r.time[0:], r.time[0:])
+ for i := 0; i < aes.BlockSize; i++ {
+ r.dst[i] = r.time[i] ^ r.seed[i]
+ }
+ r.cipher.Encrypt(r.dst[0:], r.dst[0:])
+ for i := 0; i < aes.BlockSize; i++ {
+ r.seed[i] = r.time[i] ^ r.dst[i]
+ }
+ r.cipher.Encrypt(r.seed[0:], r.seed[0:])
+
+ m := copy(b, r.dst[0:])
+ b = b[m:]
+ }
+
+ return n, nil
+}
diff --git a/libgo/go/crypto/rand/rand_windows.go b/libgo/go/crypto/rand/rand_windows.go
new file mode 100644
index 000000000..4b2b7a26f
--- /dev/null
+++ b/libgo/go/crypto/rand/rand_windows.go
@@ -0,0 +1,43 @@
+// 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.
+
+// Windows cryptographically secure pseudorandom number
+// generator.
+
+package rand
+
+import (
+ "os"
+ "sync"
+ "syscall"
+)
+
+// Implemented by using Windows CryptoAPI 2.0.
+
+func init() { Reader = &rngReader{} }
+
+// A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
+type rngReader struct {
+ prov uint32
+ mu sync.Mutex
+}
+
+func (r *rngReader) Read(b []byte) (n int, err os.Error) {
+ r.mu.Lock()
+ if r.prov == 0 {
+ const provType = syscall.PROV_RSA_FULL
+ const flags = syscall.CRYPT_VERIFYCONTEXT | syscall.CRYPT_SILENT
+ ok, errno := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
+ if !ok {
+ r.mu.Unlock()
+ return 0, os.NewSyscallError("CryptAcquireContext", errno)
+ }
+ }
+ r.mu.Unlock()
+ ok, errno := syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
+ if !ok {
+ return 0, os.NewSyscallError("CryptGenRandom", errno)
+ }
+ return len(b), nil
+}
diff --git a/libgo/go/crypto/rc4/rc4.go b/libgo/go/crypto/rc4/rc4.go
new file mode 100644
index 000000000..65fd195f3
--- /dev/null
+++ b/libgo/go/crypto/rc4/rc4.go
@@ -0,0 +1,66 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements RC4 encryption, as defined in Bruce Schneier's
+// Applied Cryptography.
+package rc4
+
+// BUG(agl): RC4 is in common use but has design weaknesses that make
+// it a poor choice for new protocols.
+
+import (
+ "os"
+ "strconv"
+)
+
+// A Cipher is an instance of RC4 using a particular key.
+type Cipher struct {
+ s [256]byte
+ i, j uint8
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/rc4: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new Cipher. The key argument should be the
+// RC4 key, at least 1 byte and at most 256 bytes.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ k := len(key)
+ if k < 1 || k > 256 {
+ return nil, KeySizeError(k)
+ }
+ var c Cipher
+ for i := 0; i < 256; i++ {
+ c.s[i] = uint8(i)
+ }
+ var j uint8 = 0
+ for i := 0; i < 256; i++ {
+ j += c.s[i] + key[i%k]
+ c.s[i], c.s[j] = c.s[j], c.s[i]
+ }
+ return &c, nil
+}
+
+// XORKeyStream sets dst to the result of XORing src with the key stream.
+// Dst and src may be the same slice but otherwise should not overlap.
+func (c *Cipher) XORKeyStream(dst, src []byte) {
+ for i := range src {
+ c.i += 1
+ c.j += c.s[c.i]
+ c.s[c.i], c.s[c.j] = c.s[c.j], c.s[c.i]
+ dst[i] = src[i] ^ c.s[c.s[c.i]+c.s[c.j]]
+ }
+}
+
+// Reset zeros the key data so that it will no longer appear in the
+// process's memory.
+func (c *Cipher) Reset() {
+ for i := range c.s {
+ c.s[i] = 0
+ }
+ c.i, c.j = 0, 0
+}
diff --git a/libgo/go/crypto/rc4/rc4_test.go b/libgo/go/crypto/rc4/rc4_test.go
new file mode 100644
index 000000000..6265d9408
--- /dev/null
+++ b/libgo/go/crypto/rc4/rc4_test.go
@@ -0,0 +1,59 @@
+// 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 rc4
+
+import (
+ "testing"
+)
+
+type rc4Test struct {
+ key, keystream []byte
+}
+
+var golden = []rc4Test{
+ // Test vectors from the original cypherpunk posting of ARC4:
+ // http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0?pli=1
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a},
+ },
+ {
+ []byte{0xef, 0x01, 0x23, 0x45},
+ []byte{0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, 0xbd, 0x61},
+ },
+
+ // Test vectors from the Wikipedia page: http://en.wikipedia.org/wiki/RC4
+ {
+ []byte{0x4b, 0x65, 0x79},
+ []byte{0xeb, 0x9f, 0x77, 0x81, 0xb7, 0x34, 0xca, 0x72, 0xa7, 0x19},
+ },
+ {
+ []byte{0x57, 0x69, 0x6b, 0x69},
+ []byte{0x60, 0x44, 0xdb, 0x6d, 0x41, 0xb7},
+ },
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c, err := NewCipher(g.key)
+ if err != nil {
+ t.Errorf("Failed to create cipher at golden index %d", i)
+ return
+ }
+ keystream := make([]byte, len(g.keystream))
+ c.XORKeyStream(keystream, keystream)
+ for j, v := range keystream {
+ if g.keystream[j] != v {
+ t.Errorf("Failed at golden index %d", i)
+ break
+ }
+ }
+ }
+}
diff --git a/libgo/go/crypto/ripemd160/ripemd160.go b/libgo/go/crypto/ripemd160/ripemd160.go
new file mode 100644
index 000000000..5614f1360
--- /dev/null
+++ b/libgo/go/crypto/ripemd160/ripemd160.go
@@ -0,0 +1,113 @@
+// 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.
+
+// This package implements the RIPEMD-160 hash algorithm.
+package ripemd160
+
+// RIPEMD-160 is designed by by Hans Dobbertin, Antoon Bosselaers, and Bart
+// Preneel with specifications available at:
+// http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf.
+
+import (
+ "hash"
+ "os"
+)
+
+// The size of the checksum in bytes.
+const Size = 20
+
+// The block size of the hash algorithm in bytes.
+const BlockSize = 64
+
+const (
+ _s0 = 0x67452301
+ _s1 = 0xefcdab89
+ _s2 = 0x98badcfe
+ _s3 = 0x10325476
+ _s4 = 0xc3d2e1f0
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ s [5]uint32 // running context
+ x [BlockSize]byte // temporary buffer
+ nx int // index into x
+ tc uint64 // total count of bytes processed
+}
+
+func (d *digest) Reset() {
+ d.s[0], d.s[1], d.s[2], d.s[3], d.s[4] = _s0, _s1, _s2, _s3, _s4
+ d.nx = 0
+ d.tc = 0
+}
+
+// New returns a new hash.Hash computing the checksum.
+func New() hash.Hash {
+ result := new(digest)
+ result.Reset()
+ return result
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.tc += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > BlockSize-d.nx {
+ n = BlockSize - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == BlockSize {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0 so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ tc := d.tc
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if tc%64 < 56 {
+ d.Write(tmp[0 : 56-tc%64])
+ } else {
+ d.Write(tmp[0 : 64+56-tc%64])
+ }
+
+ // Length in bits.
+ tc <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(tc >> (8 * i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 20)
+ j := 0
+ for _, s := range d.s {
+ p[j], p[j+1], p[j+2], p[j+3] = byte(s), byte(s>>8), byte(s>>16), byte(s>>24)
+ j += 4
+ }
+ return p
+}
diff --git a/libgo/go/crypto/ripemd160/ripemd160_test.go b/libgo/go/crypto/ripemd160/ripemd160_test.go
new file mode 100644
index 000000000..f4135f5cf
--- /dev/null
+++ b/libgo/go/crypto/ripemd160/ripemd160_test.go
@@ -0,0 +1,64 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ripemd160
+
+// Test vectors are from:
+// http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type mdTest struct {
+ out string
+ in string
+}
+
+var vectors = [...]mdTest{
+ {"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""},
+ {"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"},
+ {"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"},
+ {"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"},
+ {"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"},
+ {"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
+ {"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
+ {"9b752e45573d4b39f4dbd3323cab82bf63326bfb", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
+}
+
+func TestVectors(t *testing.T) {
+ for i := 0; i < len(vectors); i++ {
+ tv := vectors[i]
+ md := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(md, tv.in)
+ } else {
+ io.WriteString(md, tv.in[0:len(tv.in)/2])
+ md.Sum()
+ io.WriteString(md, tv.in[len(tv.in)/2:])
+ }
+ s := fmt.Sprintf("%x", md.Sum())
+ if s != tv.out {
+ t.Fatalf("RIPEMD-160[%d](%s) = %s, expected %s", j, tv.in, s, tv.out)
+ }
+ md.Reset()
+ }
+ }
+}
+
+func TestMillionA(t *testing.T) {
+ md := New()
+ for i := 0; i < 100000; i++ {
+ io.WriteString(md, "aaaaaaaaaa")
+ }
+ out := "52783243c1697bdbe16d37f97f68f08325dc1528"
+ s := fmt.Sprintf("%x", md.Sum())
+ if s != out {
+ t.Fatalf("RIPEMD-160 (1 million 'a') = %s, expected %s", s, out)
+ }
+ md.Reset()
+}
diff --git a/libgo/go/crypto/ripemd160/ripemd160block.go b/libgo/go/crypto/ripemd160/ripemd160block.go
new file mode 100644
index 000000000..7bc8e6c48
--- /dev/null
+++ b/libgo/go/crypto/ripemd160/ripemd160block.go
@@ -0,0 +1,161 @@
+// 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.
+
+// RIPEMD-160 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package ripemd160
+
+// work buffer indices and roll amounts for one line
+var _n = [80]uint{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
+ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
+ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
+ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13,
+}
+
+var _r = [80]uint{
+ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
+ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
+ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
+ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
+ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6,
+}
+
+// same for the other parallel one
+var n_ = [80]uint{
+ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
+ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
+ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
+ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
+ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11,
+}
+
+var r_ = [80]uint{
+ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
+ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
+ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
+ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
+ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11,
+}
+
+func _Block(md *digest, p []byte) int {
+ n := 0
+ var x [16]uint32
+ var alpha, beta uint32
+ for len(p) >= BlockSize {
+ a, b, c, d, e := md.s[0], md.s[1], md.s[2], md.s[3], md.s[4]
+ aa, bb, cc, dd, ee := a, b, c, d, e
+ j := 0
+ for i := 0; i < 16; i++ {
+ x[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
+ j += 4
+ }
+
+ // round 1
+ i := 0
+ for i < 16 {
+ alpha = a + (b ^ c ^ d) + x[_n[i]]
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb ^ (cc | ^dd)) + x[n_[i]] + 0x50a28be6
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 2
+ for i < 32 {
+ alpha = a + (b&c | ^b&d) + x[_n[i]] + 0x5a827999
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb&dd | cc&^dd) + x[n_[i]] + 0x5c4dd124
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 3
+ for i < 48 {
+ alpha = a + (b | ^c ^ d) + x[_n[i]] + 0x6ed9eba1
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb | ^cc ^ dd) + x[n_[i]] + 0x6d703ef3
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 4
+ for i < 64 {
+ alpha = a + (b&d | c&^d) + x[_n[i]] + 0x8f1bbcdc
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb&cc | ^bb&dd) + x[n_[i]] + 0x7a6d76e9
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 5
+ for i < 80 {
+ alpha = a + (b ^ (c | ^d)) + x[_n[i]] + 0xa953fd4e
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb ^ cc ^ dd) + x[n_[i]]
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // combine results
+ dd += c + md.s[1]
+ md.s[1] = md.s[2] + d + ee
+ md.s[2] = md.s[3] + e + aa
+ md.s[3] = md.s[4] + a + bb
+ md.s[4] = md.s[0] + b + cc
+ md.s[0] = dd
+
+ p = p[BlockSize:]
+ n += BlockSize
+ }
+ return n
+}
diff --git a/libgo/go/crypto/rsa/pkcs1v15.go b/libgo/go/crypto/rsa/pkcs1v15.go
new file mode 100644
index 000000000..714046250
--- /dev/null
+++ b/libgo/go/crypto/rsa/pkcs1v15.go
@@ -0,0 +1,273 @@
+// 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 rsa
+
+import (
+ "big"
+ "crypto/subtle"
+ "io"
+ "os"
+)
+
+// This file implements encryption and decryption using PKCS#1 v1.5 padding.
+
+// EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5.
+// The message must be no longer than the length of the public modulus minus 11 bytes.
+// WARNING: use of this function to encrypt plaintexts other than session keys
+// is dangerous. Use RSA OAEP in new protocols.
+func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err os.Error) {
+ k := (pub.N.BitLen() + 7) / 8
+ if len(msg) > k-11 {
+ err = MessageTooLongError{}
+ return
+ }
+
+ // EM = 0x02 || PS || 0x00 || M
+ em := make([]byte, k-1)
+ em[0] = 2
+ ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
+ err = nonZeroRandomBytes(ps, rand)
+ if err != nil {
+ return
+ }
+ em[len(em)-len(msg)-1] = 0
+ copy(mm, msg)
+
+ m := new(big.Int).SetBytes(em)
+ c := encrypt(new(big.Int), pub, m)
+ out = c.Bytes()
+ return
+}
+
+// DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
+// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks.
+func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err os.Error) {
+ valid, out, err := decryptPKCS1v15(rand, priv, ciphertext)
+ if err == nil && valid == 0 {
+ err = DecryptionError{}
+ }
+
+ return
+}
+
+// DecryptPKCS1v15SessionKey decrypts a session key using RSA and the padding scheme from PKCS#1 v1.5.
+// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks.
+// It returns an error if the ciphertext is the wrong length or if the
+// ciphertext is greater than the public modulus. Otherwise, no error is
+// returned. If the padding is valid, the resulting plaintext message is copied
+// into key. Otherwise, key is unchanged. These alternatives occur in constant
+// time. It is intended that the user of this function generate a random
+// session key beforehand and continue the protocol with the resulting value.
+// This will remove any possibility that an attacker can learn any information
+// about the plaintext.
+// See ``Chosen Ciphertext Attacks Against Protocols Based on the RSA
+// Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology
+// (Crypto '98),
+func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err os.Error) {
+ k := (priv.N.BitLen() + 7) / 8
+ if k-(len(key)+3+8) < 0 {
+ err = DecryptionError{}
+ return
+ }
+
+ valid, msg, err := decryptPKCS1v15(rand, priv, ciphertext)
+ if err != nil {
+ return
+ }
+
+ valid &= subtle.ConstantTimeEq(int32(len(msg)), int32(len(key)))
+ subtle.ConstantTimeCopy(valid, key, msg)
+ return
+}
+
+func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, msg []byte, err os.Error) {
+ k := (priv.N.BitLen() + 7) / 8
+ if k < 11 {
+ err = DecryptionError{}
+ return
+ }
+
+ c := new(big.Int).SetBytes(ciphertext)
+ m, err := decrypt(rand, priv, c)
+ if err != nil {
+ return
+ }
+
+ em := leftPad(m.Bytes(), k)
+ firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
+ secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 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 := 2; i < len(em); i++ {
+ equals0 := subtle.ConstantTimeByteEq(em[i], 0)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
+ }
+
+ valid = firstByteIsZero & secondByteIsTwo & (^lookingForIndex & 1)
+ msg = em[index+1:]
+ return
+}
+
+// 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 = rand.Read(s[i : i+1])
+ if err != nil {
+ return
+ }
+ // In tests, the PRNG may return all zeros so we do
+ // this to break the loop.
+ s[i] ^= 0x42
+ }
+ }
+
+ return
+}
+
+// Due to the design of PKCS#1 v1.5, we need to know the exact hash function in
+// use. A generic hash.Hash will not do.
+type PKCS1v15Hash int
+
+const (
+ HashMD5 PKCS1v15Hash = iota
+ HashSHA1
+ HashSHA256
+ HashSHA384
+ HashSHA512
+ HashMD5SHA1 // combined MD5 and SHA1 hash used for RSA signing in TLS.
+)
+
+// These are ASN1 DER structures:
+// DigestInfo ::= SEQUENCE {
+// digestAlgorithm AlgorithmIdentifier,
+// digest OCTET STRING
+// }
+// For performance, we don't use the generic ASN1 encoder. Rather, we
+// precompute a prefix of the digest value that makes a valid ASN1 DER string
+// with the correct contents.
+var hashPrefixes = [][]byte{
+ // HashMD5
+ {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
+ // HashSHA1
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
+ // HashSHA256
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
+ // HashSHA384
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
+ // HashSHA512
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
+ // HashMD5SHA1
+ {}, // A special TLS case which doesn't use an ASN1 prefix.
+}
+
+// SignPKCS1v15 calcuates the signature of hashed using RSASSA-PSS-SIGN from RSA PKCS#1 v1.5.
+// Note that hashed must be the result of hashing the input message using the
+// given hash function.
+func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash PKCS1v15Hash, hashed []byte) (s []byte, err os.Error) {
+ hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
+ if err != nil {
+ return
+ }
+
+ tLen := len(prefix) + hashLen
+ k := (priv.N.BitLen() + 7) / 8
+ if k < tLen+11 {
+ return nil, MessageTooLongError{}
+ }
+
+ // EM = 0x00 || 0x01 || PS || 0x00 || T
+ em := make([]byte, k)
+ em[1] = 1
+ for i := 2; i < k-tLen-1; i++ {
+ em[i] = 0xff
+ }
+ copy(em[k-tLen:k-hashLen], prefix)
+ copy(em[k-hashLen:k], hashed)
+
+ m := new(big.Int).SetBytes(em)
+ c, err := decrypt(rand, priv, m)
+ if err == nil {
+ s = c.Bytes()
+ }
+ return
+}
+
+// VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
+// hashed is the result of hashing the input message using the given hash
+// function and sig is the signature. A valid signature is indicated by
+// returning a nil error.
+func VerifyPKCS1v15(pub *PublicKey, hash PKCS1v15Hash, hashed []byte, sig []byte) (err os.Error) {
+ hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
+ if err != nil {
+ return
+ }
+
+ tLen := len(prefix) + hashLen
+ k := (pub.N.BitLen() + 7) / 8
+ if k < tLen+11 {
+ err = VerificationError{}
+ return
+ }
+
+ c := new(big.Int).SetBytes(sig)
+ m := encrypt(new(big.Int), pub, c)
+ em := leftPad(m.Bytes(), k)
+ // EM = 0x00 || 0x01 || PS || 0x00 || T
+
+ ok := subtle.ConstantTimeByteEq(em[0], 0)
+ ok &= subtle.ConstantTimeByteEq(em[1], 1)
+ ok &= subtle.ConstantTimeCompare(em[k-hashLen:k], hashed)
+ ok &= subtle.ConstantTimeCompare(em[k-tLen:k-hashLen], prefix)
+ ok &= subtle.ConstantTimeByteEq(em[k-tLen-1], 0)
+
+ for i := 2; i < k-tLen-1; i++ {
+ ok &= subtle.ConstantTimeByteEq(em[i], 0xff)
+ }
+
+ if ok != 1 {
+ return VerificationError{}
+ }
+
+ return nil
+}
+
+func pkcs1v15HashInfo(hash PKCS1v15Hash, inLen int) (hashLen int, prefix []byte, err os.Error) {
+ switch hash {
+ case HashMD5:
+ hashLen = 16
+ case HashSHA1:
+ hashLen = 20
+ case HashSHA256:
+ hashLen = 32
+ case HashSHA384:
+ hashLen = 48
+ case HashSHA512:
+ hashLen = 64
+ case HashMD5SHA1:
+ hashLen = 36
+ default:
+ return 0, nil, os.ErrorString("unknown hash function")
+ }
+
+ if inLen != hashLen {
+ return 0, nil, os.ErrorString("input must be hashed message")
+ }
+
+ prefix = hashPrefixes[int(hash)]
+ return
+}
diff --git a/libgo/go/crypto/rsa/pkcs1v15_test.go b/libgo/go/crypto/rsa/pkcs1v15_test.go
new file mode 100644
index 000000000..bf6306dc2
--- /dev/null
+++ b/libgo/go/crypto/rsa/pkcs1v15_test.go
@@ -0,0 +1,220 @@
+// 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 rsa
+
+import (
+ "big"
+ "bytes"
+ "crypto/rand"
+ "crypto/sha1"
+ "encoding/base64"
+ "encoding/hex"
+ "io"
+ "testing"
+ "testing/quick"
+)
+
+func decodeBase64(in string) []byte {
+ out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
+ n, err := base64.StdEncoding.Decode(out, []byte(in))
+ if err != nil {
+ return nil
+ }
+ return out[0:n]
+}
+
+type DecryptPKCS1v15Test struct {
+ in, out string
+}
+
+// These test vectors were generated with `openssl rsautl -pkcs -encrypt`
+var decryptPKCS1v15Tests = []DecryptPKCS1v15Test{
+ {
+ "gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==",
+ "x",
+ },
+ {
+ "Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==",
+ "testing.",
+ },
+ {
+ "arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==",
+ "testing.\n",
+ },
+ {
+ "WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==",
+ "01234567890123456789012345678901234567890123456789012",
+ },
+}
+
+func TestDecryptPKCS1v15(t *testing.T) {
+ for i, test := range decryptPKCS1v15Tests {
+ out, err := DecryptPKCS1v15(nil, rsaPrivateKey, decodeBase64(test.in))
+ if err != nil {
+ t.Errorf("#%d error decrypting", i)
+ }
+ want := []byte(test.out)
+ if bytes.Compare(out, want) != 0 {
+ t.Errorf("#%d got:%#v want:%#v", i, out, want)
+ }
+ }
+}
+
+func TestEncryptPKCS1v15(t *testing.T) {
+ random := rand.Reader
+ k := (rsaPrivateKey.N.BitLen() + 7) / 8
+
+ tryEncryptDecrypt := func(in []byte, blind bool) bool {
+ if len(in) > k-11 {
+ in = in[0 : k-11]
+ }
+
+ ciphertext, err := EncryptPKCS1v15(random, &rsaPrivateKey.PublicKey, in)
+ if err != nil {
+ t.Errorf("error encrypting: %s", err)
+ return false
+ }
+
+ var rand io.Reader
+ if !blind {
+ rand = nil
+ } else {
+ rand = random
+ }
+ plaintext, err := DecryptPKCS1v15(rand, rsaPrivateKey, ciphertext)
+ if err != nil {
+ t.Errorf("error decrypting: %s", err)
+ return false
+ }
+
+ if bytes.Compare(plaintext, in) != 0 {
+ t.Errorf("output mismatch: %#v %#v", plaintext, in)
+ return false
+ }
+ return true
+ }
+
+ quick.Check(tryEncryptDecrypt, nil)
+}
+
+// These test vectors were generated with `openssl rsautl -pkcs -encrypt`
+var decryptPKCS1v15SessionKeyTests = []DecryptPKCS1v15Test{
+ {
+ "e6ukkae6Gykq0fKzYwULpZehX+UPXYzMoB5mHQUDEiclRbOTqas4Y0E6nwns1BBpdvEJcilhl5zsox/6DtGsYg==",
+ "1234",
+ },
+ {
+ "Dtis4uk/q/LQGGqGk97P59K03hkCIVFMEFZRgVWOAAhxgYpCRG0MX2adptt92l67IqMki6iVQyyt0TtX3IdtEw==",
+ "FAIL",
+ },
+ {
+ "LIyFyCYCptPxrvTxpol8F3M7ZivlMsf53zs0vHRAv+rDIh2YsHS69ePMoPMe3TkOMZ3NupiL3takPxIs1sK+dw==",
+ "abcd",
+ },
+ {
+ "bafnobel46bKy76JzqU/RIVOH0uAYvzUtauKmIidKgM0sMlvobYVAVQPeUQ/oTGjbIZ1v/6Gyi5AO4DtHruGdw==",
+ "FAIL",
+ },
+}
+
+func TestEncryptPKCS1v15SessionKey(t *testing.T) {
+ for i, test := range decryptPKCS1v15SessionKeyTests {
+ key := []byte("FAIL")
+ err := DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, decodeBase64(test.in), key)
+ if err != nil {
+ t.Errorf("#%d error decrypting", i)
+ }
+ want := []byte(test.out)
+ if bytes.Compare(key, want) != 0 {
+ t.Errorf("#%d got:%#v want:%#v", i, key, want)
+ }
+ }
+}
+
+func TestNonZeroRandomBytes(t *testing.T) {
+ random := rand.Reader
+
+ b := make([]byte, 512)
+ err := nonZeroRandomBytes(b, random)
+ if err != nil {
+ t.Errorf("returned error: %s", err)
+ }
+ for _, b := range b {
+ if b == 0 {
+ t.Errorf("Zero octet found")
+ return
+ }
+ }
+}
+
+type signPKCS1v15Test struct {
+ in, out string
+}
+
+// These vectors have been tested with
+// `openssl rsautl -verify -inkey pk -in signature | hexdump -C`
+var signPKCS1v15Tests = []signPKCS1v15Test{
+ {"Test.\n", "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e336ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"},
+}
+
+func TestSignPKCS1v15(t *testing.T) {
+ for i, test := range signPKCS1v15Tests {
+ h := sha1.New()
+ h.Write([]byte(test.in))
+ digest := h.Sum()
+
+ s, err := SignPKCS1v15(nil, rsaPrivateKey, HashSHA1, digest)
+ if err != nil {
+ t.Errorf("#%d %s", i, err)
+ }
+
+ expected, _ := hex.DecodeString(test.out)
+ if bytes.Compare(s, expected) != 0 {
+ t.Errorf("#%d got: %x want: %x", i, s, expected)
+ }
+ }
+}
+
+func TestVerifyPKCS1v15(t *testing.T) {
+ for i, test := range signPKCS1v15Tests {
+ h := sha1.New()
+ h.Write([]byte(test.in))
+ digest := h.Sum()
+
+ sig, _ := hex.DecodeString(test.out)
+
+ err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, HashSHA1, digest, sig)
+ if err != nil {
+ t.Errorf("#%d %s", i, err)
+ }
+ }
+}
+
+func bigFromString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 10)
+ return ret
+}
+
+// In order to generate new test vectors you'll need the PEM form of this key:
+// -----BEGIN RSA PRIVATE KEY-----
+// MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+// fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+// /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+// RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+// EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+// IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+// tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+// -----END RSA PRIVATE KEY-----
+
+var rsaPrivateKey = &PrivateKey{
+ PublicKey: PublicKey{
+ N: bigFromString("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"),
+ E: 65537,
+ },
+ D: bigFromString("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861"),
+ P: bigFromString("98920366548084643601728869055592650835572950932266967461790948584315647051443"),
+ Q: bigFromString("94560208308847015747498523884063394671606671904944666360068158221458669711639"),
+}
diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go
new file mode 100644
index 000000000..c7a8d2053
--- /dev/null
+++ b/libgo/go/crypto/rsa/rsa.go
@@ -0,0 +1,445 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements RSA encryption as specified in PKCS#1.
+package rsa
+
+// TODO(agl): Add support for PSS padding.
+
+import (
+ "big"
+ "crypto/subtle"
+ "hash"
+ "io"
+ "os"
+)
+
+var bigZero = big.NewInt(0)
+var bigOne = big.NewInt(1)
+
+// randomPrime returns a number, p, of the given size, such that p is prime
+// with high probability.
+func randomPrime(rand io.Reader, bits int) (p *big.Int, err os.Error) {
+ if bits < 1 {
+ err = os.EINVAL
+ }
+
+ bytes := make([]byte, (bits+7)/8)
+ p = new(big.Int)
+
+ for {
+ _, err = io.ReadFull(rand, bytes)
+ if err != nil {
+ return
+ }
+
+ // Don't let the value be too small.
+ bytes[0] |= 0x80
+ // Make the value odd since an even number this large certainly isn't prime.
+ bytes[len(bytes)-1] |= 1
+
+ p.SetBytes(bytes)
+ if big.ProbablyPrime(p, 20) {
+ return
+ }
+ }
+
+ return
+}
+
+// randomNumber returns a uniform random value in [0, max).
+func randomNumber(rand io.Reader, max *big.Int) (n *big.Int, err os.Error) {
+ k := (max.BitLen() + 7) / 8
+
+ // r is the number of bits in the used in the most significant byte of
+ // max.
+ r := uint(max.BitLen() % 8)
+ if r == 0 {
+ r = 8
+ }
+
+ bytes := make([]byte, k)
+ n = new(big.Int)
+
+ for {
+ _, err = io.ReadFull(rand, bytes)
+ if err != nil {
+ return
+ }
+
+ // Clear bits in the first byte to increase the probability
+ // that the candidate is < max.
+ bytes[0] &= uint8(int(1<<r) - 1)
+
+ n.SetBytes(bytes)
+ if n.Cmp(max) < 0 {
+ return
+ }
+ }
+
+ return
+}
+
+// A PublicKey represents the public part of an RSA key.
+type PublicKey struct {
+ N *big.Int // modulus
+ E int // public exponent
+}
+
+// A PrivateKey represents an RSA key
+type PrivateKey struct {
+ PublicKey // public part.
+ D *big.Int // private exponent
+ P, Q *big.Int // prime factors of N
+}
+
+// Validate performs basic sanity checks on the key.
+// It returns nil if the key is valid, or else an os.Error describing a problem.
+
+func (priv PrivateKey) Validate() os.Error {
+ // Check that p and q are prime. Note that this is just a sanity
+ // check. Since the random witnesses chosen by ProbablyPrime are
+ // deterministic, given the candidate number, it's easy for an attack
+ // to generate composites that pass this test.
+ if !big.ProbablyPrime(priv.P, 20) {
+ return os.ErrorString("P is composite")
+ }
+ if !big.ProbablyPrime(priv.Q, 20) {
+ return os.ErrorString("Q is composite")
+ }
+
+ // Check that p*q == n.
+ modulus := new(big.Int).Mul(priv.P, priv.Q)
+ if modulus.Cmp(priv.N) != 0 {
+ return os.ErrorString("invalid modulus")
+ }
+ // Check that e and totient(p, q) are coprime.
+ pminus1 := new(big.Int).Sub(priv.P, bigOne)
+ qminus1 := new(big.Int).Sub(priv.Q, bigOne)
+ totient := new(big.Int).Mul(pminus1, qminus1)
+ e := big.NewInt(int64(priv.E))
+ gcd := new(big.Int)
+ x := new(big.Int)
+ y := new(big.Int)
+ big.GcdInt(gcd, x, y, totient, e)
+ if gcd.Cmp(bigOne) != 0 {
+ return os.ErrorString("invalid public exponent E")
+ }
+ // Check that de ≡ 1 (mod totient(p, q))
+ 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 nil
+}
+
+// GenerateKeyPair generates an RSA keypair of the given bit size.
+func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
+ priv = new(PrivateKey)
+ // Smaller public exponents lead to faster public key
+ // operations. Since the exponent must be coprime to
+ // (p-1)(q-1), the smallest possible value is 3. Some have
+ // suggested that a larger exponent (often 2**16+1) be used
+ // since previous implementation bugs[1] were avoided when this
+ // was the case. However, there are no current reasons not to use
+ // small exponents.
+ // [1] http://marc.info/?l=cryptography&m=115694833312008&w=2
+ priv.E = 3
+
+ pminus1 := new(big.Int)
+ qminus1 := new(big.Int)
+ totient := new(big.Int)
+
+ for {
+ p, err := randomPrime(rand, bits/2)
+ if err != nil {
+ return nil, err
+ }
+
+ q, err := randomPrime(rand, bits/2)
+ if err != nil {
+ return nil, err
+ }
+
+ if p.Cmp(q) == 0 {
+ continue
+ }
+
+ n := new(big.Int).Mul(p, q)
+ pminus1.Sub(p, bigOne)
+ qminus1.Sub(q, bigOne)
+ totient.Mul(pminus1, qminus1)
+
+ g := new(big.Int)
+ priv.D = new(big.Int)
+ y := new(big.Int)
+ e := big.NewInt(int64(priv.E))
+ big.GcdInt(g, priv.D, y, e, totient)
+
+ if g.Cmp(bigOne) == 0 {
+ priv.D.Add(priv.D, totient)
+ priv.P = p
+ priv.Q = q
+ priv.N = n
+
+ break
+ }
+ }
+
+ return
+}
+
+// incCounter increments a four byte, big-endian counter.
+func incCounter(c *[4]byte) {
+ if c[3]++; c[3] != 0 {
+ return
+ }
+ if c[2]++; c[2] != 0 {
+ return
+ }
+ if c[1]++; c[1] != 0 {
+ return
+ }
+ c[0]++
+}
+
+// mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function
+// specified in PKCS#1 v2.1.
+func mgf1XOR(out []byte, hash hash.Hash, seed []byte) {
+ var counter [4]byte
+
+ done := 0
+ for done < len(out) {
+ hash.Write(seed)
+ hash.Write(counter[0:4])
+ digest := hash.Sum()
+ hash.Reset()
+
+ for i := 0; i < len(digest) && done < len(out); i++ {
+ out[done] ^= digest[i]
+ done++
+ }
+ incCounter(&counter)
+ }
+}
+
+// MessageTooLongError is returned when attempting to encrypt a message which
+// is too large for the size of the public key.
+type MessageTooLongError struct{}
+
+func (MessageTooLongError) String() string {
+ return "message too long for RSA public key size"
+}
+
+func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
+ e := big.NewInt(int64(pub.E))
+ c.Exp(m, e, pub.N)
+ return c
+}
+
+// EncryptOAEP encrypts the given message with RSA-OAEP.
+// The message must be no longer than the length of the public modulus less
+// twice the hash length plus 2.
+func EncryptOAEP(hash hash.Hash, rand io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err os.Error) {
+ hash.Reset()
+ k := (pub.N.BitLen() + 7) / 8
+ if len(msg) > k-2*hash.Size()-2 {
+ err = MessageTooLongError{}
+ return
+ }
+
+ hash.Write(label)
+ lHash := hash.Sum()
+ hash.Reset()
+
+ em := make([]byte, k)
+ seed := em[1 : 1+hash.Size()]
+ db := em[1+hash.Size():]
+
+ copy(db[0:hash.Size()], lHash)
+ db[len(db)-len(msg)-1] = 1
+ copy(db[len(db)-len(msg):], msg)
+
+ _, err = io.ReadFull(rand, seed)
+ if err != nil {
+ return
+ }
+
+ mgf1XOR(db, hash, seed)
+ mgf1XOR(seed, hash, db)
+
+ m := new(big.Int)
+ m.SetBytes(em)
+ c := encrypt(new(big.Int), pub, m)
+ out = c.Bytes()
+ return
+}
+
+// A DecryptionError represents a failure to decrypt a message.
+// It is deliberately vague to avoid adaptive attacks.
+type DecryptionError struct{}
+
+func (DecryptionError) String() string { return "RSA decryption error" }
+
+// A VerificationError represents a failure to verify a signature.
+// It is deliberately vague to avoid adaptive attacks.
+type VerificationError struct{}
+
+func (VerificationError) String() string { return "RSA verification error" }
+
+// modInverse returns ia, the inverse of a in the multiplicative group of prime
+// order n. It requires that a be a member of the group (i.e. less than n).
+func modInverse(a, n *big.Int) (ia *big.Int, ok bool) {
+ g := new(big.Int)
+ x := new(big.Int)
+ y := new(big.Int)
+ big.GcdInt(g, x, y, a, n)
+ if g.Cmp(bigOne) != 0 {
+ // In this case, a and n aren't coprime and we cannot calculate
+ // the inverse. This happens because the values of n are nearly
+ // prime (being the product of two primes) rather than truly
+ // prime.
+ return
+ }
+
+ if x.Cmp(bigOne) < 0 {
+ // 0 is not the multiplicative inverse of any element so, if x
+ // < 1, then x is negative.
+ x.Add(x, n)
+ }
+
+ return x, true
+}
+
+// decrypt performs an RSA decryption, resulting in a plaintext integer. If a
+// random source is given, RSA blinding is used.
+func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.Error) {
+ // TODO(agl): can we get away with reusing blinds?
+ if c.Cmp(priv.N) > 0 {
+ err = DecryptionError{}
+ return
+ }
+
+ var ir *big.Int
+ if rand != nil {
+ // Blinding enabled. Blinding involves multiplying c by r^e.
+ // Then the decryption operation performs (m^e * r^e)^d mod n
+ // which equals mr mod n. The factor of r can then be removed
+ // by multipling by the multiplicative inverse of r.
+
+ var r *big.Int
+
+ for {
+ r, err = randomNumber(rand, priv.N)
+ if err != nil {
+ return
+ }
+ if r.Cmp(bigZero) == 0 {
+ r = bigOne
+ }
+ var ok bool
+ ir, ok = modInverse(r, priv.N)
+ if ok {
+ break
+ }
+ }
+ bigE := big.NewInt(int64(priv.E))
+ rpowe := new(big.Int).Exp(r, bigE, priv.N)
+ c.Mul(c, rpowe)
+ c.Mod(c, priv.N)
+ }
+
+ m = new(big.Int).Exp(c, priv.D, priv.N)
+
+ if ir != nil {
+ // Unblind.
+ m.Mul(m, ir)
+ m.Mod(m, priv.N)
+ }
+
+ return
+}
+
+// DecryptOAEP decrypts ciphertext using RSA-OAEP.
+// If rand != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.
+func DecryptOAEP(hash hash.Hash, rand io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err os.Error) {
+ k := (priv.N.BitLen() + 7) / 8
+ if len(ciphertext) > k ||
+ k < hash.Size()*2+2 {
+ err = DecryptionError{}
+ return
+ }
+
+ c := new(big.Int).SetBytes(ciphertext)
+
+ m, err := decrypt(rand, priv, c)
+ if err != nil {
+ return
+ }
+
+ hash.Write(label)
+ lHash := hash.Sum()
+ hash.Reset()
+
+ // Converting the plaintext number to bytes will strip any
+ // leading zeros so we may have to left pad. We do this unconditionally
+ // to avoid leaking timing information. (Although we still probably
+ // leak the number of leading zeros. It's not clear that we can do
+ // anything about this.)
+ em := leftPad(m.Bytes(), k)
+
+ firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
+
+ seed := em[1 : hash.Size()+1]
+ db := em[hash.Size()+1:]
+
+ mgf1XOR(seed, hash, db)
+ mgf1XOR(db, hash, seed)
+
+ lHash2 := db[0:hash.Size()]
+
+ // We have to validate the plaintext in constant time in order to avoid
+ // attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal
+ // Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1
+ // v2.0. In J. Kilian, editor, Advances in Cryptology.
+ lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2)
+
+ // The remainder of the plaintext must be zero or more 0x00, followed
+ // by 0x01, followed by the message.
+ // lookingForIndex: 1 iff we are still looking for the 0x01
+ // index: the offset of the first 0x01 byte
+ // invalid: 1 iff we saw a non-zero byte before the 0x01.
+ var lookingForIndex, index, invalid int
+ lookingForIndex = 1
+ rest := db[hash.Size():]
+
+ for i := 0; i < len(rest); i++ {
+ equals0 := subtle.ConstantTimeByteEq(rest[i], 0)
+ equals1 := subtle.ConstantTimeByteEq(rest[i], 1)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals1, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals1, 0, lookingForIndex)
+ invalid = subtle.ConstantTimeSelect(lookingForIndex&^equals0, 1, invalid)
+ }
+
+ if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 {
+ err = DecryptionError{}
+ return
+ }
+
+ msg = rest[index+1:]
+ return
+}
+
+// leftPad returns a new slice of length size. The contents of input are right
+// aligned in the new slice.
+func leftPad(input []byte, size int) (out []byte) {
+ n := len(input)
+ if n > size {
+ n = size
+ }
+ out = make([]byte, size)
+ copy(out[len(out)-n:], input)
+ return
+}
diff --git a/libgo/go/crypto/rsa/rsa_test.go b/libgo/go/crypto/rsa/rsa_test.go
new file mode 100644
index 000000000..df1f17f17
--- /dev/null
+++ b/libgo/go/crypto/rsa/rsa_test.go
@@ -0,0 +1,250 @@
+// 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 rsa
+
+import (
+ "big"
+ "bytes"
+ "crypto/rand"
+ "crypto/sha1"
+ "testing"
+)
+
+func TestKeyGeneration(t *testing.T) {
+ random := rand.Reader
+
+ priv, err := GenerateKey(random, 1024)
+ if err != nil {
+ t.Errorf("failed to generate key")
+ }
+ pub := &priv.PublicKey
+ m := big.NewInt(42)
+ c := encrypt(new(big.Int), pub, m)
+ m2, err := decrypt(nil, priv, c)
+ if err != nil {
+ t.Errorf("error while decrypting: %s", err)
+ }
+ if m.Cmp(m2) != 0 {
+ t.Errorf("got:%v, want:%v (%s)", m2, m, priv)
+ }
+
+ m3, err := decrypt(random, priv, c)
+ if err != nil {
+ t.Errorf("error while decrypting (blind): %s", err)
+ }
+ if m.Cmp(m3) != 0 {
+ t.Errorf("(blind) got:%v, want:%v", m3, m)
+ }
+}
+
+type testEncryptOAEPMessage struct {
+ in []byte
+ seed []byte
+ out []byte
+}
+
+type testEncryptOAEPStruct struct {
+ modulus string
+ e int
+ d string
+ msgs []testEncryptOAEPMessage
+}
+
+func TestEncryptOAEP(t *testing.T) {
+ sha1 := sha1.New()
+ n := new(big.Int)
+ for i, test := range testEncryptOAEPData {
+ n.SetString(test.modulus, 16)
+ public := PublicKey{n, test.e}
+
+ for j, message := range test.msgs {
+ randomSource := bytes.NewBuffer(message.seed)
+ out, err := EncryptOAEP(sha1, randomSource, &public, message.in, nil)
+ if err != nil {
+ t.Errorf("#%d,%d error: %s", i, j, err)
+ }
+ if bytes.Compare(out, message.out) != 0 {
+ t.Errorf("#%d,%d bad result: %s (want %s)", i, j, out, message.out)
+ }
+ }
+ }
+}
+
+func TestDecryptOAEP(t *testing.T) {
+ random := rand.Reader
+
+ sha1 := sha1.New()
+ n := new(big.Int)
+ d := new(big.Int)
+ for i, test := range testEncryptOAEPData {
+ n.SetString(test.modulus, 16)
+ d.SetString(test.d, 16)
+ private := PrivateKey{PublicKey{n, test.e}, d, nil, nil}
+
+ for j, message := range test.msgs {
+ out, err := DecryptOAEP(sha1, nil, &private, message.out, nil)
+ if err != nil {
+ t.Errorf("#%d,%d error: %s", i, j, err)
+ } else if bytes.Compare(out, message.in) != 0 {
+ t.Errorf("#%d,%d bad result: %#v (want %#v)", i, j, out, message.in)
+ }
+
+ // Decrypt with blinding.
+ out, err = DecryptOAEP(sha1, random, &private, message.out, nil)
+ if err != nil {
+ t.Errorf("#%d,%d (blind) error: %s", i, j, err)
+ } else if bytes.Compare(out, message.in) != 0 {
+ t.Errorf("#%d,%d (blind) bad result: %#v (want %#v)", i, j, out, message.in)
+ }
+ }
+ }
+}
+
+// testEncryptOAEPData contains a subset of the vectors from RSA's "Test vectors for RSA-OAEP".
+var testEncryptOAEPData = []testEncryptOAEPStruct{
+ // Key 1
+ {"a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb",
+ 65537,
+ "53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1",
+ []testEncryptOAEPMessage{
+ // Example 1.1
+ {
+ []byte{0x66, 0x28, 0x19, 0x4e, 0x12, 0x07, 0x3d, 0xb0,
+ 0x3b, 0xa9, 0x4c, 0xda, 0x9e, 0xf9, 0x53, 0x23, 0x97,
+ 0xd5, 0x0d, 0xba, 0x79, 0xb9, 0x87, 0x00, 0x4a, 0xfe,
+ 0xfe, 0x34,
+ },
+ []byte{0x18, 0xb7, 0x76, 0xea, 0x21, 0x06, 0x9d, 0x69,
+ 0x77, 0x6a, 0x33, 0xe9, 0x6b, 0xad, 0x48, 0xe1, 0xdd,
+ 0xa0, 0xa5, 0xef,
+ },
+ []byte{0x35, 0x4f, 0xe6, 0x7b, 0x4a, 0x12, 0x6d, 0x5d,
+ 0x35, 0xfe, 0x36, 0xc7, 0x77, 0x79, 0x1a, 0x3f, 0x7b,
+ 0xa1, 0x3d, 0xef, 0x48, 0x4e, 0x2d, 0x39, 0x08, 0xaf,
+ 0xf7, 0x22, 0xfa, 0xd4, 0x68, 0xfb, 0x21, 0x69, 0x6d,
+ 0xe9, 0x5d, 0x0b, 0xe9, 0x11, 0xc2, 0xd3, 0x17, 0x4f,
+ 0x8a, 0xfc, 0xc2, 0x01, 0x03, 0x5f, 0x7b, 0x6d, 0x8e,
+ 0x69, 0x40, 0x2d, 0xe5, 0x45, 0x16, 0x18, 0xc2, 0x1a,
+ 0x53, 0x5f, 0xa9, 0xd7, 0xbf, 0xc5, 0xb8, 0xdd, 0x9f,
+ 0xc2, 0x43, 0xf8, 0xcf, 0x92, 0x7d, 0xb3, 0x13, 0x22,
+ 0xd6, 0xe8, 0x81, 0xea, 0xa9, 0x1a, 0x99, 0x61, 0x70,
+ 0xe6, 0x57, 0xa0, 0x5a, 0x26, 0x64, 0x26, 0xd9, 0x8c,
+ 0x88, 0x00, 0x3f, 0x84, 0x77, 0xc1, 0x22, 0x70, 0x94,
+ 0xa0, 0xd9, 0xfa, 0x1e, 0x8c, 0x40, 0x24, 0x30, 0x9c,
+ 0xe1, 0xec, 0xcc, 0xb5, 0x21, 0x00, 0x35, 0xd4, 0x7a,
+ 0xc7, 0x2e, 0x8a,
+ },
+ },
+ // Example 1.2
+ {
+ []byte{0x75, 0x0c, 0x40, 0x47, 0xf5, 0x47, 0xe8, 0xe4,
+ 0x14, 0x11, 0x85, 0x65, 0x23, 0x29, 0x8a, 0xc9, 0xba,
+ 0xe2, 0x45, 0xef, 0xaf, 0x13, 0x97, 0xfb, 0xe5, 0x6f,
+ 0x9d, 0xd5,
+ },
+ []byte{0x0c, 0xc7, 0x42, 0xce, 0x4a, 0x9b, 0x7f, 0x32,
+ 0xf9, 0x51, 0xbc, 0xb2, 0x51, 0xef, 0xd9, 0x25, 0xfe,
+ 0x4f, 0xe3, 0x5f,
+ },
+ []byte{0x64, 0x0d, 0xb1, 0xac, 0xc5, 0x8e, 0x05, 0x68,
+ 0xfe, 0x54, 0x07, 0xe5, 0xf9, 0xb7, 0x01, 0xdf, 0xf8,
+ 0xc3, 0xc9, 0x1e, 0x71, 0x6c, 0x53, 0x6f, 0xc7, 0xfc,
+ 0xec, 0x6c, 0xb5, 0xb7, 0x1c, 0x11, 0x65, 0x98, 0x8d,
+ 0x4a, 0x27, 0x9e, 0x15, 0x77, 0xd7, 0x30, 0xfc, 0x7a,
+ 0x29, 0x93, 0x2e, 0x3f, 0x00, 0xc8, 0x15, 0x15, 0x23,
+ 0x6d, 0x8d, 0x8e, 0x31, 0x01, 0x7a, 0x7a, 0x09, 0xdf,
+ 0x43, 0x52, 0xd9, 0x04, 0xcd, 0xeb, 0x79, 0xaa, 0x58,
+ 0x3a, 0xdc, 0xc3, 0x1e, 0xa6, 0x98, 0xa4, 0xc0, 0x52,
+ 0x83, 0xda, 0xba, 0x90, 0x89, 0xbe, 0x54, 0x91, 0xf6,
+ 0x7c, 0x1a, 0x4e, 0xe4, 0x8d, 0xc7, 0x4b, 0xbb, 0xe6,
+ 0x64, 0x3a, 0xef, 0x84, 0x66, 0x79, 0xb4, 0xcb, 0x39,
+ 0x5a, 0x35, 0x2d, 0x5e, 0xd1, 0x15, 0x91, 0x2d, 0xf6,
+ 0x96, 0xff, 0xe0, 0x70, 0x29, 0x32, 0x94, 0x6d, 0x71,
+ 0x49, 0x2b, 0x44,
+ },
+ },
+ // Example 1.3
+ {
+ []byte{0xd9, 0x4a, 0xe0, 0x83, 0x2e, 0x64, 0x45, 0xce,
+ 0x42, 0x33, 0x1c, 0xb0, 0x6d, 0x53, 0x1a, 0x82, 0xb1,
+ 0xdb, 0x4b, 0xaa, 0xd3, 0x0f, 0x74, 0x6d, 0xc9, 0x16,
+ 0xdf, 0x24, 0xd4, 0xe3, 0xc2, 0x45, 0x1f, 0xff, 0x59,
+ 0xa6, 0x42, 0x3e, 0xb0, 0xe1, 0xd0, 0x2d, 0x4f, 0xe6,
+ 0x46, 0xcf, 0x69, 0x9d, 0xfd, 0x81, 0x8c, 0x6e, 0x97,
+ 0xb0, 0x51,
+ },
+ []byte{0x25, 0x14, 0xdf, 0x46, 0x95, 0x75, 0x5a, 0x67,
+ 0xb2, 0x88, 0xea, 0xf4, 0x90, 0x5c, 0x36, 0xee, 0xc6,
+ 0x6f, 0xd2, 0xfd,
+ },
+ []byte{0x42, 0x37, 0x36, 0xed, 0x03, 0x5f, 0x60, 0x26,
+ 0xaf, 0x27, 0x6c, 0x35, 0xc0, 0xb3, 0x74, 0x1b, 0x36,
+ 0x5e, 0x5f, 0x76, 0xca, 0x09, 0x1b, 0x4e, 0x8c, 0x29,
+ 0xe2, 0xf0, 0xbe, 0xfe, 0xe6, 0x03, 0x59, 0x5a, 0xa8,
+ 0x32, 0x2d, 0x60, 0x2d, 0x2e, 0x62, 0x5e, 0x95, 0xeb,
+ 0x81, 0xb2, 0xf1, 0xc9, 0x72, 0x4e, 0x82, 0x2e, 0xca,
+ 0x76, 0xdb, 0x86, 0x18, 0xcf, 0x09, 0xc5, 0x34, 0x35,
+ 0x03, 0xa4, 0x36, 0x08, 0x35, 0xb5, 0x90, 0x3b, 0xc6,
+ 0x37, 0xe3, 0x87, 0x9f, 0xb0, 0x5e, 0x0e, 0xf3, 0x26,
+ 0x85, 0xd5, 0xae, 0xc5, 0x06, 0x7c, 0xd7, 0xcc, 0x96,
+ 0xfe, 0x4b, 0x26, 0x70, 0xb6, 0xea, 0xc3, 0x06, 0x6b,
+ 0x1f, 0xcf, 0x56, 0x86, 0xb6, 0x85, 0x89, 0xaa, 0xfb,
+ 0x7d, 0x62, 0x9b, 0x02, 0xd8, 0xf8, 0x62, 0x5c, 0xa3,
+ 0x83, 0x36, 0x24, 0xd4, 0x80, 0x0f, 0xb0, 0x81, 0xb1,
+ 0xcf, 0x94, 0xeb,
+ },
+ },
+ },
+ },
+ // Key 10
+ {"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb",
+ 65537,
+ "056b04216fe5f354ac77250a4b6b0c8525a85c59b0bd80c56450a22d5f438e596a333aa875e291dd43f48cb88b9d5fc0d499f9fcd1c397f9afc070cd9e398c8d19e61db7c7410a6b2675dfbf5d345b804d201add502d5ce2dfcb091ce9997bbebe57306f383e4d588103f036f7e85d1934d152a323e4a8db451d6f4a5b1b0f102cc150e02feee2b88dea4ad4c1baccb24d84072d14e1d24a6771f7408ee30564fb86d4393a34bcf0b788501d193303f13a2284b001f0f649eaf79328d4ac5c430ab4414920a9460ed1b7bc40ec653e876d09abc509ae45b525190116a0c26101848298509c1c3bf3a483e7274054e15e97075036e989f60932807b5257751e79",
+ []testEncryptOAEPMessage{
+ // Example 10.1
+ {
+ []byte{0x8b, 0xba, 0x6b, 0xf8, 0x2a, 0x6c, 0x0f, 0x86,
+ 0xd5, 0xf1, 0x75, 0x6e, 0x97, 0x95, 0x68, 0x70, 0xb0,
+ 0x89, 0x53, 0xb0, 0x6b, 0x4e, 0xb2, 0x05, 0xbc, 0x16,
+ 0x94, 0xee,
+ },
+ []byte{0x47, 0xe1, 0xab, 0x71, 0x19, 0xfe, 0xe5, 0x6c,
+ 0x95, 0xee, 0x5e, 0xaa, 0xd8, 0x6f, 0x40, 0xd0, 0xaa,
+ 0x63, 0xbd, 0x33,
+ },
+ []byte{0x53, 0xea, 0x5d, 0xc0, 0x8c, 0xd2, 0x60, 0xfb,
+ 0x3b, 0x85, 0x85, 0x67, 0x28, 0x7f, 0xa9, 0x15, 0x52,
+ 0xc3, 0x0b, 0x2f, 0xeb, 0xfb, 0xa2, 0x13, 0xf0, 0xae,
+ 0x87, 0x70, 0x2d, 0x06, 0x8d, 0x19, 0xba, 0xb0, 0x7f,
+ 0xe5, 0x74, 0x52, 0x3d, 0xfb, 0x42, 0x13, 0x9d, 0x68,
+ 0xc3, 0xc5, 0xaf, 0xee, 0xe0, 0xbf, 0xe4, 0xcb, 0x79,
+ 0x69, 0xcb, 0xf3, 0x82, 0xb8, 0x04, 0xd6, 0xe6, 0x13,
+ 0x96, 0x14, 0x4e, 0x2d, 0x0e, 0x60, 0x74, 0x1f, 0x89,
+ 0x93, 0xc3, 0x01, 0x4b, 0x58, 0xb9, 0xb1, 0x95, 0x7a,
+ 0x8b, 0xab, 0xcd, 0x23, 0xaf, 0x85, 0x4f, 0x4c, 0x35,
+ 0x6f, 0xb1, 0x66, 0x2a, 0xa7, 0x2b, 0xfc, 0xc7, 0xe5,
+ 0x86, 0x55, 0x9d, 0xc4, 0x28, 0x0d, 0x16, 0x0c, 0x12,
+ 0x67, 0x85, 0xa7, 0x23, 0xeb, 0xee, 0xbe, 0xff, 0x71,
+ 0xf1, 0x15, 0x94, 0x44, 0x0a, 0xae, 0xf8, 0x7d, 0x10,
+ 0x79, 0x3a, 0x87, 0x74, 0xa2, 0x39, 0xd4, 0xa0, 0x4c,
+ 0x87, 0xfe, 0x14, 0x67, 0xb9, 0xda, 0xf8, 0x52, 0x08,
+ 0xec, 0x6c, 0x72, 0x55, 0x79, 0x4a, 0x96, 0xcc, 0x29,
+ 0x14, 0x2f, 0x9a, 0x8b, 0xd4, 0x18, 0xe3, 0xc1, 0xfd,
+ 0x67, 0x34, 0x4b, 0x0c, 0xd0, 0x82, 0x9d, 0xf3, 0xb2,
+ 0xbe, 0xc6, 0x02, 0x53, 0x19, 0x62, 0x93, 0xc6, 0xb3,
+ 0x4d, 0x3f, 0x75, 0xd3, 0x2f, 0x21, 0x3d, 0xd4, 0x5c,
+ 0x62, 0x73, 0xd5, 0x05, 0xad, 0xf4, 0xcc, 0xed, 0x10,
+ 0x57, 0xcb, 0x75, 0x8f, 0xc2, 0x6a, 0xee, 0xfa, 0x44,
+ 0x12, 0x55, 0xed, 0x4e, 0x64, 0xc1, 0x99, 0xee, 0x07,
+ 0x5e, 0x7f, 0x16, 0x64, 0x61, 0x82, 0xfd, 0xb4, 0x64,
+ 0x73, 0x9b, 0x68, 0xab, 0x5d, 0xaf, 0xf0, 0xe6, 0x3e,
+ 0x95, 0x52, 0x01, 0x68, 0x24, 0xf0, 0x54, 0xbf, 0x4d,
+ 0x3c, 0x8c, 0x90, 0xa9, 0x7b, 0xb6, 0xb6, 0x55, 0x32,
+ 0x84, 0xeb, 0x42, 0x9f, 0xcc,
+ },
+ },
+ },
+ },
+}
diff --git a/libgo/go/crypto/sha1/sha1.go b/libgo/go/crypto/sha1/sha1.go
new file mode 100644
index 000000000..8716c3591
--- /dev/null
+++ b/libgo/go/crypto/sha1/sha1.go
@@ -0,0 +1,114 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the SHA1 hash algorithm as defined in RFC 3174.
+package sha1
+
+import (
+ "hash"
+ "os"
+)
+
+// The size of a SHA1 checksum in bytes.
+const Size = 20
+
+const (
+ _Chunk = 64
+ _Init0 = 0x67452301
+ _Init1 = 0xEFCDAB89
+ _Init2 = 0x98BADCFE
+ _Init3 = 0x10325476
+ _Init4 = 0xC3D2E1F0
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ h [5]uint32
+ x [_Chunk]byte
+ nx int
+ len uint64
+}
+
+func (d *digest) Reset() {
+ d.h[0] = _Init0
+ d.h[1] = _Init1
+ d.h[2] = _Init2
+ d.h[3] = _Init3
+ d.h[4] = _Init4
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the SHA1 checksum.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > _Chunk-d.nx {
+ n = _Chunk - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == _Chunk {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0 so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ len := d.len
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if len%64 < 56 {
+ d.Write(tmp[0 : 56-len%64])
+ } else {
+ d.Write(tmp[0 : 64+56-len%64])
+ }
+
+ // Length in bits.
+ len <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(len >> (56 - 8*i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 20)
+ j := 0
+ for _, s := range d.h {
+ p[j+0] = byte(s >> 24)
+ p[j+1] = byte(s >> 16)
+ p[j+2] = byte(s >> 8)
+ p[j+3] = byte(s >> 0)
+ j += 4
+ }
+ return p
+}
diff --git a/libgo/go/crypto/sha1/sha1_test.go b/libgo/go/crypto/sha1/sha1_test.go
new file mode 100644
index 000000000..2712fe35e
--- /dev/null
+++ b/libgo/go/crypto/sha1/sha1_test.go
@@ -0,0 +1,73 @@
+// 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.
+
+// SHA1 hash algorithm. See RFC 3174.
+
+package sha1
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type sha1Test struct {
+ out string
+ in string
+}
+
+var golden = []sha1Test{
+ {"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""},
+ {"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"},
+ {"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"},
+ {"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"},
+ {"81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd"},
+ {"03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde"},
+ {"1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef"},
+ {"2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg"},
+ {"425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh"},
+ {"c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi"},
+ {"d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij"},
+ {"ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old."},
+ {"e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last."},
+ {"45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole."},
+ {"55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign."},
+ {"6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program."},
+ {"597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size: a.out: bad magic"},
+ {"74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail. -Mark Horton"},
+ {"0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you."},
+ {"410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!"},
+ {"32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
diff --git a/libgo/go/crypto/sha1/sha1block.go b/libgo/go/crypto/sha1/sha1block.go
new file mode 100644
index 000000000..b5d32af70
--- /dev/null
+++ b/libgo/go/crypto/sha1/sha1block.go
@@ -0,0 +1,81 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA1 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package sha1
+
+const (
+ _K0 = 0x5A827999
+ _K1 = 0x6ED9EBA1
+ _K2 = 0x8F1BBCDC
+ _K3 = 0xCA62C1D6
+)
+
+func _Block(dig *digest, p []byte) int {
+ var w [80]uint32
+
+ n := 0
+ h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4]
+ for len(p) >= _Chunk {
+ // Can interlace the computation of w with the
+ // rounds below if needed for speed.
+ for i := 0; i < 16; i++ {
+ j := i * 4
+ w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
+ }
+ for i := 16; i < 80; i++ {
+ tmp := w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]
+ w[i] = tmp<<1 | tmp>>(32-1)
+ }
+
+ a, b, c, d, e := h0, h1, h2, h3, h4
+
+ // Each of the four 20-iteration rounds
+ // differs only in the computation of f and
+ // the choice of K (_K0, _K1, etc).
+ for i := 0; i < 20; i++ {
+ f := b&c | (^b)&d
+ a5 := a<<5 | a>>(32-5)
+ b30 := b<<30 | b>>(32-30)
+ t := a5 + f + e + w[i] + _K0
+ a, b, c, d, e = t, a, b30, c, d
+ }
+ for i := 20; i < 40; i++ {
+ f := b ^ c ^ d
+ a5 := a<<5 | a>>(32-5)
+ b30 := b<<30 | b>>(32-30)
+ t := a5 + f + e + w[i] + _K1
+ a, b, c, d, e = t, a, b30, c, d
+ }
+ for i := 40; i < 60; i++ {
+ f := b&c | b&d | c&d
+ a5 := a<<5 | a>>(32-5)
+ b30 := b<<30 | b>>(32-30)
+ t := a5 + f + e + w[i] + _K2
+ a, b, c, d, e = t, a, b30, c, d
+ }
+ for i := 60; i < 80; i++ {
+ f := b ^ c ^ d
+ a5 := a<<5 | a>>(32-5)
+ b30 := b<<30 | b>>(32-30)
+ t := a5 + f + e + w[i] + _K3
+ a, b, c, d, e = t, a, b30, c, d
+ }
+
+ h0 += a
+ h1 += b
+ h2 += c
+ h3 += d
+ h4 += e
+
+ p = p[_Chunk:]
+ n += _Chunk
+ }
+
+ dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4] = h0, h1, h2, h3, h4
+ return n
+}
diff --git a/libgo/go/crypto/sha256/sha256.go b/libgo/go/crypto/sha256/sha256.go
new file mode 100644
index 000000000..57a8ffa0d
--- /dev/null
+++ b/libgo/go/crypto/sha256/sha256.go
@@ -0,0 +1,159 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the SHA224 and SHA256 hash algorithms as defined in FIPS 180-2.
+package sha256
+
+import (
+ "hash"
+ "os"
+)
+
+// The size of a SHA256 checksum in bytes.
+const Size = 32
+
+// The size of a SHA224 checksum in bytes.
+const Size224 = 28
+
+const (
+ _Chunk = 64
+ _Init0 = 0x6A09E667
+ _Init1 = 0xBB67AE85
+ _Init2 = 0x3C6EF372
+ _Init3 = 0xA54FF53A
+ _Init4 = 0x510E527F
+ _Init5 = 0x9B05688C
+ _Init6 = 0x1F83D9AB
+ _Init7 = 0x5BE0CD19
+ _Init0_224 = 0xC1059ED8
+ _Init1_224 = 0x367CD507
+ _Init2_224 = 0x3070DD17
+ _Init3_224 = 0xF70E5939
+ _Init4_224 = 0xFFC00B31
+ _Init5_224 = 0x68581511
+ _Init6_224 = 0x64F98FA7
+ _Init7_224 = 0xBEFA4FA4
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ h [8]uint32
+ x [_Chunk]byte
+ nx int
+ len uint64
+ is224 bool // mark if this digest is SHA-224
+}
+
+func (d *digest) Reset() {
+ if !d.is224 {
+ d.h[0] = _Init0
+ d.h[1] = _Init1
+ d.h[2] = _Init2
+ d.h[3] = _Init3
+ d.h[4] = _Init4
+ d.h[5] = _Init5
+ d.h[6] = _Init6
+ d.h[7] = _Init7
+ } else {
+ d.h[0] = _Init0_224
+ d.h[1] = _Init1_224
+ d.h[2] = _Init2_224
+ d.h[3] = _Init3_224
+ d.h[4] = _Init4_224
+ d.h[5] = _Init5_224
+ d.h[6] = _Init6_224
+ d.h[7] = _Init7_224
+ }
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the SHA256 checksum.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+// New224 returns a new hash.Hash computing the SHA224 checksum.
+func New224() hash.Hash {
+ d := new(digest)
+ d.is224 = true
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int {
+ if !d.is224 {
+ return Size
+ }
+ return Size224
+}
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > _Chunk-d.nx {
+ n = _Chunk - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == _Chunk {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0 so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ len := d.len
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if len%64 < 56 {
+ d.Write(tmp[0 : 56-len%64])
+ } else {
+ d.Write(tmp[0 : 64+56-len%64])
+ }
+
+ // Length in bits.
+ len <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(len >> (56 - 8*i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 32)
+ j := 0
+ for _, s := range d.h {
+ p[j+0] = byte(s >> 24)
+ p[j+1] = byte(s >> 16)
+ p[j+2] = byte(s >> 8)
+ p[j+3] = byte(s >> 0)
+ j += 4
+ }
+ if d.is224 {
+ return p[0:28]
+ }
+ return p
+}
diff --git a/libgo/go/crypto/sha256/sha256_test.go b/libgo/go/crypto/sha256/sha256_test.go
new file mode 100644
index 000000000..42a3fa7a0
--- /dev/null
+++ b/libgo/go/crypto/sha256/sha256_test.go
@@ -0,0 +1,125 @@
+// 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.
+
+// SHA256 hash algorithm. See FIPS 180-2.
+
+package sha256
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type sha256Test struct {
+ out string
+ in string
+}
+
+var golden = []sha256Test{
+ {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""},
+ {"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a"},
+ {"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab"},
+ {"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"},
+ {"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", "abcd"},
+ {"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", "abcde"},
+ {"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", "abcdef"},
+ {"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", "abcdefg"},
+ {"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", "abcdefgh"},
+ {"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", "abcdefghi"},
+ {"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", "abcdefghij"},
+ {"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", "Discard medicine more than two years old."},
+ {"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", "He who has a shady past knows that nice guys finish last."},
+ {"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", "I wouldn't marry him with a ten foot pole."},
+ {"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", "Nepal premier won't resign."},
+ {"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", "For every action there is an equal and opposite government program."},
+ {"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", "size: a.out: bad magic"},
+ {"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", "The major problem is with sendmail. -Mark Horton"},
+ {"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", "If the enemy is within range, then so are you."},
+ {"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", "C is as portable as Stonehedge!!"},
+ {"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++? -Paul Glick"},
+}
+
+var golden224 = []sha256Test{
+ {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""},
+ {"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", "a"},
+ {"db3cda86d4429a1d39c148989566b38f7bda0156296bd364ba2f878b", "ab"},
+ {"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"},
+ {"a76654d8e3550e9a2d67a0eeb6c67b220e5885eddd3fde135806e601", "abcd"},
+ {"bdd03d560993e675516ba5a50638b6531ac2ac3d5847c61916cfced6", "abcde"},
+ {"7043631cb415556a275a4ebecb802c74ee9f6153908e1792a90b6a98", "abcdef"},
+ {"d1884e711701ad81abe0c77a3b0ea12e19ba9af64077286c72fc602d", "abcdefg"},
+ {"17eb7d40f0356f8598e89eafad5f6c759b1f822975d9c9b737c8a517", "abcdefgh"},
+ {"aeb35915346c584db820d2de7af3929ffafef9222a9bcb26516c7334", "abcdefghi"},
+ {"d35e1e5af29ddb0d7e154357df4ad9842afee527c689ee547f753188", "abcdefghij"},
+ {"19297f1cef7ddc8a7e947f5c5a341e10f7245045e425db67043988d7", "Discard medicine more than two years old."},
+ {"0f10c2eb436251f777fbbd125e260d36aecf180411726c7c885f599a", "He who has a shady past knows that nice guys finish last."},
+ {"4d1842104919f314cad8a3cd20b3cba7e8ed3e7abed62b57441358f6", "I wouldn't marry him with a ten foot pole."},
+ {"a8ba85c6fe0c48fbffc72bbb2f03fcdbc87ae2dc7a56804d1590fb3b", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"5543fbab26e67e8885b1a852d567d1cb8b9bfe42e0899584c50449a9", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"65ca107390f5da9efa05d28e57b221657edc7e43a9a18fb15b053ddb", "Nepal premier won't resign."},
+ {"84953962be366305a9cc9b5cd16ed019edc37ac96c0deb3e12cca116", "For every action there is an equal and opposite government program."},
+ {"35a189ce987151dfd00b3577583cc6a74b9869eecf894459cb52038d", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"2fc333713983edfd4ef2c0da6fb6d6415afb94987c91e4069eb063e6", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"cbe32d38d577a1b355960a4bc3c659c2dc4670859a19777a875842c4", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"a2dc118ce959e027576413a7b440c875cdc8d40df9141d6ef78a57e1", "size: a.out: bad magic"},
+ {"d10787e24052bcff26dc484787a54ed819e4e4511c54890ee977bf81", "The major problem is with sendmail. -Mark Horton"},
+ {"62efcf16ab8a893acdf2f348aaf06b63039ff1bf55508c830532c9fb", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"3e9b7e4613c59f58665104c5fa86c272db5d3a2ff30df5bb194a5c99", "If the enemy is within range, then so are you."},
+ {"5999c208b8bdf6d471bb7c359ac5b829e73a8211dff686143a4e7f18", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"3b2d67ff54eabc4ef737b14edf87c64280ef582bcdf2a6d56908b405", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"d0733595d20e4d3d6b5c565a445814d1bbb2fd08b9a3b8ffb97930c6", "C is as portable as Stonehedge!!"},
+ {"43fb8aeed8a833175c9295c1165415f98c866ef08a4922959d673507", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"ec18e66e93afc4fb1604bc2baedbfd20b44c43d76e65c0996d7851c6", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"86ed2eaa9c75ba98396e5c9fb2f679ecf0ea2ed1e0ee9ceecb4a9332", "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("sha256[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+ for i := 0; i < len(golden224); i++ {
+ g := golden224[i]
+ c := New224()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("sha224[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
diff --git a/libgo/go/crypto/sha256/sha256block.go b/libgo/go/crypto/sha256/sha256block.go
new file mode 100644
index 000000000..7b0f55444
--- /dev/null
+++ b/libgo/go/crypto/sha256/sha256block.go
@@ -0,0 +1,129 @@
+// 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.
+
+// SHA256 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package sha256
+
+var _K = []uint32{
+ 0x428a2f98,
+ 0x71374491,
+ 0xb5c0fbcf,
+ 0xe9b5dba5,
+ 0x3956c25b,
+ 0x59f111f1,
+ 0x923f82a4,
+ 0xab1c5ed5,
+ 0xd807aa98,
+ 0x12835b01,
+ 0x243185be,
+ 0x550c7dc3,
+ 0x72be5d74,
+ 0x80deb1fe,
+ 0x9bdc06a7,
+ 0xc19bf174,
+ 0xe49b69c1,
+ 0xefbe4786,
+ 0x0fc19dc6,
+ 0x240ca1cc,
+ 0x2de92c6f,
+ 0x4a7484aa,
+ 0x5cb0a9dc,
+ 0x76f988da,
+ 0x983e5152,
+ 0xa831c66d,
+ 0xb00327c8,
+ 0xbf597fc7,
+ 0xc6e00bf3,
+ 0xd5a79147,
+ 0x06ca6351,
+ 0x14292967,
+ 0x27b70a85,
+ 0x2e1b2138,
+ 0x4d2c6dfc,
+ 0x53380d13,
+ 0x650a7354,
+ 0x766a0abb,
+ 0x81c2c92e,
+ 0x92722c85,
+ 0xa2bfe8a1,
+ 0xa81a664b,
+ 0xc24b8b70,
+ 0xc76c51a3,
+ 0xd192e819,
+ 0xd6990624,
+ 0xf40e3585,
+ 0x106aa070,
+ 0x19a4c116,
+ 0x1e376c08,
+ 0x2748774c,
+ 0x34b0bcb5,
+ 0x391c0cb3,
+ 0x4ed8aa4a,
+ 0x5b9cca4f,
+ 0x682e6ff3,
+ 0x748f82ee,
+ 0x78a5636f,
+ 0x84c87814,
+ 0x8cc70208,
+ 0x90befffa,
+ 0xa4506ceb,
+ 0xbef9a3f7,
+ 0xc67178f2,
+}
+
+func _Block(dig *digest, p []byte) int {
+ var w [64]uint32
+ n := 0
+ h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
+ for len(p) >= _Chunk {
+ // Can interlace the computation of w with the
+ // rounds below if needed for speed.
+ for i := 0; i < 16; i++ {
+ j := i * 4
+ w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
+ }
+ for i := 16; i < 64; i++ {
+ t1 := (w[i-2]>>17 | w[i-2]<<(32-17)) ^ (w[i-2]>>19 | w[i-2]<<(32-19)) ^ (w[i-2] >> 10)
+
+ t2 := (w[i-15]>>7 | w[i-15]<<(32-7)) ^ (w[i-15]>>18 | w[i-15]<<(32-18)) ^ (w[i-15] >> 3)
+
+ w[i] = t1 + w[i-7] + t2 + w[i-16]
+ }
+
+ a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7
+
+ for i := 0; i < 64; i++ {
+ t1 := h + ((e>>6 | e<<(32-6)) ^ (e>>11 | e<<(32-11)) ^ (e>>25 | e<<(32-25))) + ((e & f) ^ (^e & g)) + _K[i] + w[i]
+
+ t2 := ((a>>2 | a<<(32-2)) ^ (a>>13 | a<<(32-13)) ^ (a>>22 | a<<(32-22))) + ((a & b) ^ (a & c) ^ (b & c))
+
+ h = g
+ g = f
+ f = e
+ e = d + t1
+ d = c
+ c = b
+ b = a
+ a = t1 + t2
+ }
+
+ h0 += a
+ h1 += b
+ h2 += c
+ h3 += d
+ h4 += e
+ h5 += f
+ h6 += g
+ h7 += h
+
+ p = p[_Chunk:]
+ n += _Chunk
+ }
+
+ dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
+ return n
+}
diff --git a/libgo/go/crypto/sha512/sha512.go b/libgo/go/crypto/sha512/sha512.go
new file mode 100644
index 000000000..c3cda97d9
--- /dev/null
+++ b/libgo/go/crypto/sha512/sha512.go
@@ -0,0 +1,163 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the SHA384 and SHA512 hash algorithms as defined in FIPS 180-2.
+package sha512
+
+import (
+ "hash"
+ "os"
+)
+
+// The size of a SHA512 checksum in bytes.
+const Size = 64
+
+// The size of a SHA384 checksum in bytes.
+const Size384 = 48
+
+const (
+ _Chunk = 128
+ _Init0 = 0x6a09e667f3bcc908
+ _Init1 = 0xbb67ae8584caa73b
+ _Init2 = 0x3c6ef372fe94f82b
+ _Init3 = 0xa54ff53a5f1d36f1
+ _Init4 = 0x510e527fade682d1
+ _Init5 = 0x9b05688c2b3e6c1f
+ _Init6 = 0x1f83d9abfb41bd6b
+ _Init7 = 0x5be0cd19137e2179
+ _Init0_384 = 0xcbbb9d5dc1059ed8
+ _Init1_384 = 0x629a292a367cd507
+ _Init2_384 = 0x9159015a3070dd17
+ _Init3_384 = 0x152fecd8f70e5939
+ _Init4_384 = 0x67332667ffc00b31
+ _Init5_384 = 0x8eb44a8768581511
+ _Init6_384 = 0xdb0c2e0d64f98fa7
+ _Init7_384 = 0x47b5481dbefa4fa4
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ h [8]uint64
+ x [_Chunk]byte
+ nx int
+ len uint64
+ is384 bool // mark if this digest is SHA-384
+}
+
+func (d *digest) Reset() {
+ if !d.is384 {
+ d.h[0] = _Init0
+ d.h[1] = _Init1
+ d.h[2] = _Init2
+ d.h[3] = _Init3
+ d.h[4] = _Init4
+ d.h[5] = _Init5
+ d.h[6] = _Init6
+ d.h[7] = _Init7
+ } else {
+ d.h[0] = _Init0_384
+ d.h[1] = _Init1_384
+ d.h[2] = _Init2_384
+ d.h[3] = _Init3_384
+ d.h[4] = _Init4_384
+ d.h[5] = _Init5_384
+ d.h[6] = _Init6_384
+ d.h[7] = _Init7_384
+ }
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the SHA512 checksum.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+// New384 returns a new hash.Hash computing the SHA384 checksum.
+func New384() hash.Hash {
+ d := new(digest)
+ d.is384 = true
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int {
+ if !d.is384 {
+ return Size
+ }
+ return Size384
+}
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > _Chunk-d.nx {
+ n = _Chunk - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == _Chunk {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum() []byte {
+ // Make a copy of d0 so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 112 bytes mod 128.
+ len := d.len
+ var tmp [128]byte
+ tmp[0] = 0x80
+ if len%128 < 112 {
+ d.Write(tmp[0 : 112-len%128])
+ } else {
+ d.Write(tmp[0 : 128+112-len%128])
+ }
+
+ // Length in bits.
+ len <<= 3
+ for i := uint(0); i < 16; i++ {
+ tmp[i] = byte(len >> (120 - 8*i))
+ }
+ d.Write(tmp[0:16])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ p := make([]byte, 64)
+ j := 0
+ for _, s := range d.h {
+ p[j+0] = byte(s >> 56)
+ p[j+1] = byte(s >> 48)
+ p[j+2] = byte(s >> 40)
+ p[j+3] = byte(s >> 32)
+ p[j+4] = byte(s >> 24)
+ p[j+5] = byte(s >> 16)
+ p[j+6] = byte(s >> 8)
+ p[j+7] = byte(s >> 0)
+ j += 8
+ }
+ if d.is384 {
+ return p[0:48]
+ }
+ return p
+}
diff --git a/libgo/go/crypto/sha512/sha512_test.go b/libgo/go/crypto/sha512/sha512_test.go
new file mode 100644
index 000000000..dd116dc17
--- /dev/null
+++ b/libgo/go/crypto/sha512/sha512_test.go
@@ -0,0 +1,125 @@
+// 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.
+
+// SHA512 hash algorithm. See FIPS 180-2.
+
+package sha512
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type sha512Test struct {
+ out string
+ in string
+}
+
+var golden = []sha512Test{
+ {"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""},
+ {"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", "a"},
+ {"2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d", "ab"},
+ {"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"},
+ {"d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f", "abcd"},
+ {"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1", "abcde"},
+ {"e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7", "abcdef"},
+ {"d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c", "abcdefg"},
+ {"a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce", "abcdefgh"},
+ {"f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe", "abcdefghi"},
+ {"ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745", "abcdefghij"},
+ {"2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d", "Discard medicine more than two years old."},
+ {"a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce", "He who has a shady past knows that nice guys finish last."},
+ {"8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8", "I wouldn't marry him with a ten foot pole."},
+ {"26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015", "Nepal premier won't resign."},
+ {"d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe", "For every action there is an equal and opposite government program."},
+ {"9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311", "size: a.out: bad magic"},
+ {"b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7", "The major problem is with sendmail. -Mark Horton"},
+ {"d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e", "If the enemy is within range, then so are you."},
+ {"00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7", "C is as portable as Stonehedge!!"},
+ {"2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0", "How can you write a big system without C++? -Paul Glick"},
+}
+
+var golden384 = []sha512Test{
+ {"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""},
+ {"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", "a"},
+ {"c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", "ab"},
+ {"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"},
+ {"1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", "abcd"},
+ {"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", "abcde"},
+ {"c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", "abcdef"},
+ {"9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", "abcdefg"},
+ {"9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", "abcdefgh"},
+ {"ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", "abcdefghi"},
+ {"a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", "abcdefghij"},
+ {"86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", "Discard medicine more than two years old."},
+ {"ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", "He who has a shady past knows that nice guys finish last."},
+ {"40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", "I wouldn't marry him with a ten foot pole."},
+ {"e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", "Nepal premier won't resign."},
+ {"5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", "For every action there is an equal and opposite government program."},
+ {"ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", "size: a.out: bad magic"},
+ {"5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", "The major problem is with sendmail. -Mark Horton"},
+ {"5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", "If the enemy is within range, then so are you."},
+ {"76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", "C is as portable as Stonehedge!!"},
+ {"bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("sha512[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+ for i := 0; i < len(golden384); i++ {
+ g := golden384[i]
+ c := New384()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum()
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum())
+ if s != g.out {
+ t.Fatalf("sha384[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
diff --git a/libgo/go/crypto/sha512/sha512block.go b/libgo/go/crypto/sha512/sha512block.go
new file mode 100644
index 000000000..6b7506287
--- /dev/null
+++ b/libgo/go/crypto/sha512/sha512block.go
@@ -0,0 +1,144 @@
+// 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.
+
+// SHA512 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package sha512
+
+var _K = []uint64{
+ 0x428a2f98d728ae22,
+ 0x7137449123ef65cd,
+ 0xb5c0fbcfec4d3b2f,
+ 0xe9b5dba58189dbbc,
+ 0x3956c25bf348b538,
+ 0x59f111f1b605d019,
+ 0x923f82a4af194f9b,
+ 0xab1c5ed5da6d8118,
+ 0xd807aa98a3030242,
+ 0x12835b0145706fbe,
+ 0x243185be4ee4b28c,
+ 0x550c7dc3d5ffb4e2,
+ 0x72be5d74f27b896f,
+ 0x80deb1fe3b1696b1,
+ 0x9bdc06a725c71235,
+ 0xc19bf174cf692694,
+ 0xe49b69c19ef14ad2,
+ 0xefbe4786384f25e3,
+ 0x0fc19dc68b8cd5b5,
+ 0x240ca1cc77ac9c65,
+ 0x2de92c6f592b0275,
+ 0x4a7484aa6ea6e483,
+ 0x5cb0a9dcbd41fbd4,
+ 0x76f988da831153b5,
+ 0x983e5152ee66dfab,
+ 0xa831c66d2db43210,
+ 0xb00327c898fb213f,
+ 0xbf597fc7beef0ee4,
+ 0xc6e00bf33da88fc2,
+ 0xd5a79147930aa725,
+ 0x06ca6351e003826f,
+ 0x142929670a0e6e70,
+ 0x27b70a8546d22ffc,
+ 0x2e1b21385c26c926,
+ 0x4d2c6dfc5ac42aed,
+ 0x53380d139d95b3df,
+ 0x650a73548baf63de,
+ 0x766a0abb3c77b2a8,
+ 0x81c2c92e47edaee6,
+ 0x92722c851482353b,
+ 0xa2bfe8a14cf10364,
+ 0xa81a664bbc423001,
+ 0xc24b8b70d0f89791,
+ 0xc76c51a30654be30,
+ 0xd192e819d6ef5218,
+ 0xd69906245565a910,
+ 0xf40e35855771202a,
+ 0x106aa07032bbd1b8,
+ 0x19a4c116b8d2d0c8,
+ 0x1e376c085141ab53,
+ 0x2748774cdf8eeb99,
+ 0x34b0bcb5e19b48a8,
+ 0x391c0cb3c5c95a63,
+ 0x4ed8aa4ae3418acb,
+ 0x5b9cca4f7763e373,
+ 0x682e6ff3d6b2b8a3,
+ 0x748f82ee5defb2fc,
+ 0x78a5636f43172f60,
+ 0x84c87814a1f0ab72,
+ 0x8cc702081a6439ec,
+ 0x90befffa23631e28,
+ 0xa4506cebde82bde9,
+ 0xbef9a3f7b2c67915,
+ 0xc67178f2e372532b,
+ 0xca273eceea26619c,
+ 0xd186b8c721c0c207,
+ 0xeada7dd6cde0eb1e,
+ 0xf57d4f7fee6ed178,
+ 0x06f067aa72176fba,
+ 0x0a637dc5a2c898a6,
+ 0x113f9804bef90dae,
+ 0x1b710b35131c471b,
+ 0x28db77f523047d84,
+ 0x32caab7b40c72493,
+ 0x3c9ebe0a15c9bebc,
+ 0x431d67c49c100d4c,
+ 0x4cc5d4becb3e42b6,
+ 0x597f299cfc657e2a,
+ 0x5fcb6fab3ad6faec,
+ 0x6c44198c4a475817,
+}
+
+func _Block(dig *digest, p []byte) int {
+ var w [80]uint64
+ n := 0
+ h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
+ for len(p) >= _Chunk {
+ for i := 0; i < 16; i++ {
+ j := i * 8
+ w[i] = uint64(p[j])<<56 | uint64(p[j+1])<<48 | uint64(p[j+2])<<40 | uint64(p[j+3])<<32 |
+ uint64(p[j+4])<<24 | uint64(p[j+5])<<16 | uint64(p[j+6])<<8 | uint64(p[j+7])
+ }
+ for i := 16; i < 80; i++ {
+ t1 := (w[i-2]>>19 | w[i-2]<<(64-19)) ^ (w[i-2]>>61 | w[i-2]<<(64-61)) ^ (w[i-2] >> 6)
+
+ t2 := (w[i-15]>>1 | w[i-15]<<(64-1)) ^ (w[i-15]>>8 | w[i-15]<<(64-8)) ^ (w[i-15] >> 7)
+
+ w[i] = t1 + w[i-7] + t2 + w[i-16]
+ }
+
+ a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7
+
+ for i := 0; i < 80; i++ {
+ t1 := h + ((e>>14 | e<<(64-14)) ^ (e>>18 | e<<(64-18)) ^ (e>>41 | e<<(64-41))) + ((e & f) ^ (^e & g)) + _K[i] + w[i]
+
+ t2 := ((a>>28 | a<<(64-28)) ^ (a>>34 | a<<(64-34)) ^ (a>>39 | a<<(64-39))) + ((a & b) ^ (a & c) ^ (b & c))
+
+ h = g
+ g = f
+ f = e
+ e = d + t1
+ d = c
+ c = b
+ b = a
+ a = t1 + t2
+ }
+
+ h0 += a
+ h1 += b
+ h2 += c
+ h3 += d
+ h4 += e
+ h5 += f
+ h6 += g
+ h7 += h
+
+ p = p[_Chunk:]
+ n += _Chunk
+ }
+
+ dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
+ return n
+}
diff --git a/libgo/go/crypto/subtle/constant_time.go b/libgo/go/crypto/subtle/constant_time.go
new file mode 100644
index 000000000..a3d70b9c9
--- /dev/null
+++ b/libgo/go/crypto/subtle/constant_time.go
@@ -0,0 +1,57 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements functions that are often useful in cryptographic
+// code but require careful thought to use correctly.
+package subtle
+
+// ConstantTimeCompare returns 1 iff the two equal length slices, x
+// and y, have equal contents. The time taken is a function of the length of
+// the slices and is independent of the contents.
+func ConstantTimeCompare(x, y []byte) int {
+ var v byte
+
+ for i := 0; i < len(x); i++ {
+ v |= x[i] ^ y[i]
+ }
+
+ return ConstantTimeByteEq(v, 0)
+}
+
+// ConstantTimeSelect returns x if v is 1 and y if v is 0.
+// Its behavior is undefined if v takes any other value.
+func ConstantTimeSelect(v, x, y int) int { return ^(v-1)&x | (v-1)&y }
+
+// ConstantTimeByteEq returns 1 if x == y and 0 otherwise.
+func ConstantTimeByteEq(x, y uint8) int {
+ z := ^(x ^ y)
+ z &= z >> 4
+ z &= z >> 2
+ z &= z >> 1
+
+ return int(z)
+}
+
+// ConstantTimeEq returns 1 if x == y and 0 otherwise.
+func ConstantTimeEq(x, y int32) int {
+ z := ^(x ^ y)
+ z &= z >> 16
+ z &= z >> 8
+ z &= z >> 4
+ z &= z >> 2
+ z &= z >> 1
+
+ return int(z & 1)
+}
+
+// ConstantTimeCopy copies the contents of y into x iff v == 1. If v == 0, x is left unchanged.
+// Its behavior is undefined if v takes any other value.
+func ConstantTimeCopy(v int, x, y []byte) {
+ xmask := byte(v - 1)
+ ymask := byte(^(v - 1))
+ for i := 0; i < len(x); i++ {
+ x[i] = x[i]&xmask | y[i]&ymask
+ }
+ return
+}
diff --git a/libgo/go/crypto/subtle/constant_time_test.go b/libgo/go/crypto/subtle/constant_time_test.go
new file mode 100644
index 000000000..b28b73581
--- /dev/null
+++ b/libgo/go/crypto/subtle/constant_time_test.go
@@ -0,0 +1,105 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package subtle
+
+import (
+ "testing"
+ "testing/quick"
+)
+
+type TestConstantTimeCompareStruct struct {
+ a, b []byte
+ out int
+}
+
+var testConstandTimeCompareData = []TestConstantTimeCompareStruct{
+ {[]byte{}, []byte{}, 1},
+ {[]byte{0x11}, []byte{0x11}, 1},
+ {[]byte{0x12}, []byte{0x11}, 0},
+}
+
+func TestConstantTimeCompare(t *testing.T) {
+ for i, test := range testConstandTimeCompareData {
+ if r := ConstantTimeCompare(test.a, test.b); r != test.out {
+ t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out)
+ }
+ }
+}
+
+type TestConstantTimeByteEqStruct struct {
+ a, b uint8
+ out int
+}
+
+var testConstandTimeByteEqData = []TestConstantTimeByteEqStruct{
+ {0, 0, 1},
+ {0, 1, 0},
+ {1, 0, 0},
+ {0xff, 0xff, 1},
+ {0xff, 0xfe, 0},
+}
+
+func byteEq(a, b uint8) int {
+ if a == b {
+ return 1
+ }
+ return 0
+}
+
+func TestConstantTimeByteEq(t *testing.T) {
+ for i, test := range testConstandTimeByteEqData {
+ if r := ConstantTimeByteEq(test.a, test.b); r != test.out {
+ t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out)
+ }
+ }
+ err := quick.CheckEqual(ConstantTimeByteEq, byteEq, nil)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func eq(a, b int32) int {
+ if a == b {
+ return 1
+ }
+ return 0
+}
+
+func TestConstantTimeEq(t *testing.T) {
+ err := quick.CheckEqual(ConstantTimeEq, eq, nil)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func makeCopy(v int, x, y []byte) []byte {
+ if len(x) > len(y) {
+ x = x[0:len(y)]
+ } else {
+ y = y[0:len(x)]
+ }
+ if v == 1 {
+ copy(x, y)
+ }
+ return x
+}
+
+func constantTimeCopyWrapper(v int, x, y []byte) []byte {
+ if len(x) > len(y) {
+ x = x[0:len(y)]
+ } else {
+ y = y[0:len(x)]
+ }
+ v &= 1
+ ConstantTimeCopy(v, x, y)
+ return x
+}
+
+func TestConstantTimeCopy(t *testing.T) {
+ err := quick.CheckEqual(constantTimeCopyWrapper, makeCopy, nil)
+ if err != nil {
+ t.Error(err)
+ }
+}
diff --git a/libgo/go/crypto/tls/alert.go b/libgo/go/crypto/tls/alert.go
new file mode 100644
index 000000000..3b9e0e241
--- /dev/null
+++ b/libgo/go/crypto/tls/alert.go
@@ -0,0 +1,73 @@
+// 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 tls
+
+import "strconv"
+
+type alert uint8
+
+const (
+ // alert level
+ alertLevelWarning = 1
+ alertLevelError = 2
+)
+
+const (
+ alertCloseNotify alert = 0
+ alertUnexpectedMessage alert = 10
+ alertBadRecordMAC alert = 20
+ alertDecryptionFailed alert = 21
+ alertRecordOverflow alert = 22
+ alertDecompressionFailure alert = 30
+ alertHandshakeFailure alert = 40
+ alertBadCertificate alert = 42
+ alertUnsupportedCertificate alert = 43
+ alertCertificateRevoked alert = 44
+ alertCertificateExpired alert = 45
+ alertCertificateUnknown alert = 46
+ alertIllegalParameter alert = 47
+ alertUnknownCA alert = 48
+ alertAccessDenied alert = 49
+ alertDecodeError alert = 50
+ alertDecryptError alert = 51
+ alertProtocolVersion alert = 70
+ alertInsufficientSecurity alert = 71
+ alertInternalError alert = 80
+ alertUserCanceled alert = 90
+ alertNoRenegotiation alert = 100
+)
+
+var alertText = map[alert]string{
+ alertCloseNotify: "close notify",
+ alertUnexpectedMessage: "unexpected message",
+ alertBadRecordMAC: "bad record MAC",
+ alertDecryptionFailed: "decryption failed",
+ alertRecordOverflow: "record overflow",
+ alertDecompressionFailure: "decompression failure",
+ alertHandshakeFailure: "handshake failure",
+ alertBadCertificate: "bad certificate",
+ alertUnsupportedCertificate: "unsupported certificate",
+ alertCertificateRevoked: "revoked certificate",
+ alertCertificateExpired: "expired certificate",
+ alertCertificateUnknown: "unknown certificate",
+ alertIllegalParameter: "illegal parameter",
+ alertUnknownCA: "unknown certificate authority",
+ alertAccessDenied: "access denied",
+ alertDecodeError: "error decoding message",
+ alertDecryptError: "error decrypting message",
+ alertProtocolVersion: "protocol version not supported",
+ alertInsufficientSecurity: "insufficient security level",
+ alertInternalError: "internal error",
+ alertUserCanceled: "user canceled",
+ alertNoRenegotiation: "no renegotiation",
+}
+
+func (e alert) String() string {
+ s, ok := alertText[e]
+ if ok {
+ return s
+ }
+ return "alert(" + strconv.Itoa(int(e)) + ")"
+}
diff --git a/libgo/go/crypto/tls/ca_set.go b/libgo/go/crypto/tls/ca_set.go
new file mode 100644
index 000000000..ae00ac558
--- /dev/null
+++ b/libgo/go/crypto/tls/ca_set.go
@@ -0,0 +1,89 @@
+// 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 tls
+
+import (
+ "crypto/x509"
+ "encoding/pem"
+ "strings"
+)
+
+// A CASet is a set of certificates.
+type CASet struct {
+ bySubjectKeyId map[string][]*x509.Certificate
+ byName map[string][]*x509.Certificate
+}
+
+// NewCASet returns a new, empty CASet.
+func NewCASet() *CASet {
+ return &CASet{
+ make(map[string][]*x509.Certificate),
+ make(map[string][]*x509.Certificate),
+ }
+}
+
+func nameToKey(name *x509.Name) string {
+ return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
+}
+
+// FindVerifiedParent attempts to find the certificate in s which has signed
+// the given certificate. If no such certificate can be found or the signature
+// doesn't match, it returns nil.
+func (s *CASet) FindVerifiedParent(cert *x509.Certificate) (parent *x509.Certificate) {
+ var candidates []*x509.Certificate
+
+ if len(cert.AuthorityKeyId) > 0 {
+ candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
+ }
+ if len(candidates) == 0 {
+ candidates = s.byName[nameToKey(&cert.Issuer)]
+ }
+
+ for _, c := range candidates {
+ if cert.CheckSignatureFrom(c) == nil {
+ return c
+ }
+ }
+
+ return nil
+}
+
+// AddCert adds a certificate to the set
+func (s *CASet) AddCert(cert *x509.Certificate) {
+ if len(cert.SubjectKeyId) > 0 {
+ keyId := string(cert.SubjectKeyId)
+ s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], cert)
+ }
+ name := nameToKey(&cert.Subject)
+ s.byName[name] = append(s.byName[name], cert)
+}
+
+// SetFromPEM attempts to parse a series of PEM encoded root certificates. It
+// appends any certificates found to s and returns true if any certificates
+// were successfully parsed. On many Linux systems, /etc/ssl/cert.pem will
+// contains the system wide set of root CAs in a format suitable for this
+// function.
+func (s *CASet) SetFromPEM(pemCerts []byte) (ok bool) {
+ for len(pemCerts) > 0 {
+ var block *pem.Block
+ block, pemCerts = pem.Decode(pemCerts)
+ if block == nil {
+ break
+ }
+ if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
+ continue
+ }
+
+ cert, err := x509.ParseCertificate(block.Bytes)
+ if err != nil {
+ continue
+ }
+
+ s.AddCert(cert)
+ ok = true
+ }
+
+ return
+}
diff --git a/libgo/go/crypto/tls/cipher_suites.go b/libgo/go/crypto/tls/cipher_suites.go
new file mode 100644
index 000000000..bc7b0d32f
--- /dev/null
+++ b/libgo/go/crypto/tls/cipher_suites.go
@@ -0,0 +1,102 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hmac"
+ "crypto/rc4"
+ "crypto/x509"
+ "hash"
+ "os"
+)
+
+// a keyAgreement implements the client and server side of a TLS key agreement
+// protocol by generating and processing key exchange messages.
+type keyAgreement interface {
+ // On the server side, the first two methods are called in order.
+
+ // In the case that the key agreement protocol doesn't use a
+ // ServerKeyExchange message, generateServerKeyExchange can return nil,
+ // nil.
+ generateServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, os.Error)
+ processClientKeyExchange(*Config, *clientKeyExchangeMsg) ([]byte, os.Error)
+
+ // On the client side, the next two methods are called in order.
+
+ // This method may not be called if the server doesn't send a
+ // ServerKeyExchange message.
+ processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) os.Error
+ generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error)
+}
+
+// A cipherSuite is a specific combination of key agreement, cipher and MAC
+// function. All cipher suites currently assume RSA key agreement.
+type cipherSuite struct {
+ // the lengths, in bytes, of the key material needed for each component.
+ keyLen int
+ macLen int
+ ivLen int
+ ka func() keyAgreement
+ // If elliptic is set, a server will only consider this ciphersuite if
+ // the ClientHello indicated that the client supports an elliptic curve
+ // and point format that we can handle.
+ elliptic bool
+ cipher func(key, iv []byte, isRead bool) interface{}
+ mac func(macKey []byte) hash.Hash
+}
+
+var cipherSuites = map[uint16]*cipherSuite{
+ TLS_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, rsaKA, false, cipherRC4, hmacSHA1},
+ TLS_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, rsaKA, false, cipherAES, hmacSHA1},
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, ecdheRSAKA, true, cipherRC4, hmacSHA1},
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, ecdheRSAKA, true, cipherAES, hmacSHA1},
+}
+
+func cipherRC4(key, iv []byte, isRead bool) interface{} {
+ cipher, _ := rc4.NewCipher(key)
+ return cipher
+}
+
+func cipherAES(key, iv []byte, isRead bool) interface{} {
+ block, _ := aes.NewCipher(key)
+ if isRead {
+ return cipher.NewCBCDecrypter(block, iv)
+ }
+ return cipher.NewCBCEncrypter(block, iv)
+}
+
+func hmacSHA1(key []byte) hash.Hash {
+ return hmac.NewSHA1(key)
+}
+
+func rsaKA() keyAgreement {
+ return rsaKeyAgreement{}
+}
+
+func ecdheRSAKA() keyAgreement {
+ return new(ecdheRSAKeyAgreement)
+}
+
+// mutualCipherSuite returns a cipherSuite and its id given a list of supported
+// ciphersuites and the id requested by the peer.
+func mutualCipherSuite(have []uint16, want uint16) (suite *cipherSuite, id uint16) {
+ for _, id := range have {
+ if id == want {
+ return cipherSuites[id], id
+ }
+ }
+ return
+}
+
+// A list of the possible cipher suite ids. Taken from
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+const (
+ TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
+ TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
+)
diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go
new file mode 100644
index 000000000..7135f3d0f
--- /dev/null
+++ b/libgo/go/crypto/tls/common.go
@@ -0,0 +1,258 @@
+// 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 tls
+
+import (
+ "crypto/rand"
+ "crypto/rsa"
+ "io"
+ "io/ioutil"
+ "sync"
+ "time"
+)
+
+const (
+ maxPlaintext = 16384 // maximum plaintext payload length
+ maxCiphertext = 16384 + 2048 // maximum ciphertext payload length
+ recordHeaderLen = 5 // record header length
+ maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
+
+ minVersion = 0x0301 // minimum supported version - TLS 1.0
+ maxVersion = 0x0301 // maximum supported version - TLS 1.0
+)
+
+// TLS record types.
+type recordType uint8
+
+const (
+ recordTypeChangeCipherSpec recordType = 20
+ recordTypeAlert recordType = 21
+ recordTypeHandshake recordType = 22
+ recordTypeApplicationData recordType = 23
+)
+
+// TLS handshake message types.
+const (
+ typeClientHello uint8 = 1
+ typeServerHello uint8 = 2
+ typeCertificate uint8 = 11
+ typeServerKeyExchange uint8 = 12
+ typeCertificateRequest uint8 = 13
+ typeServerHelloDone uint8 = 14
+ typeCertificateVerify uint8 = 15
+ typeClientKeyExchange uint8 = 16
+ typeFinished uint8 = 20
+ typeCertificateStatus uint8 = 22
+ typeNextProtocol uint8 = 67 // Not IANA assigned
+)
+
+// TLS compression types.
+const (
+ compressionNone uint8 = 0
+)
+
+// TLS extension numbers
+var (
+ extensionServerName uint16 = 0
+ extensionStatusRequest uint16 = 5
+ extensionSupportedCurves uint16 = 10
+ extensionSupportedPoints uint16 = 11
+ extensionNextProtoNeg uint16 = 13172 // not IANA assigned
+)
+
+// TLS Elliptic Curves
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
+var (
+ curveP256 uint16 = 23
+ curveP384 uint16 = 24
+ curveP521 uint16 = 25
+)
+
+// TLS Elliptic Curve Point Formats
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
+var (
+ pointFormatUncompressed uint8 = 0
+)
+
+// TLS CertificateStatusType (RFC 3546)
+const (
+ statusTypeOCSP uint8 = 1
+)
+
+// Certificate types (for certificateRequestMsg)
+const (
+ certTypeRSASign = 1 // A certificate containing an RSA key
+ certTypeDSSSign = 2 // A certificate containing a DSA key
+ certTypeRSAFixedDH = 3 // A certificate containing a static DH key
+ certTypeDSSFixedDH = 4 // A certficiate containing a static DH key
+ // Rest of these are reserved by the TLS spec
+)
+
+// ConnectionState records basic TLS details about the connection.
+type ConnectionState struct {
+ HandshakeComplete bool
+ CipherSuite uint16
+ NegotiatedProtocol string
+}
+
+// A Config structure is used to configure a TLS client or server. After one
+// has been passed to a TLS function it must not be modified.
+type Config struct {
+ // Rand provides the source of entropy for nonces and RSA blinding.
+ // If Rand is nil, TLS uses the cryptographic random reader in package
+ // crypto/rand.
+ Rand io.Reader
+
+ // Time returns the current time as the number of seconds since the epoch.
+ // If Time is nil, TLS uses the system time.Seconds.
+ Time func() int64
+
+ // Certificates contains one or more certificate chains
+ // to present to the other side of the connection.
+ // Server configurations must include at least one certificate.
+ Certificates []Certificate
+
+ // RootCAs defines the set of root certificate authorities
+ // that clients use when verifying server certificates.
+ // If RootCAs is nil, TLS uses the host's root CA set.
+ RootCAs *CASet
+
+ // NextProtos is a list of supported, application level protocols.
+ // Currently only server-side handling is supported.
+ NextProtos []string
+
+ // ServerName is included in the client's handshake to support virtual
+ // hosting.
+ ServerName string
+
+ // AuthenticateClient controls whether a server will request a certificate
+ // from the client. It does not require that the client send a
+ // certificate nor does it require that the certificate sent be
+ // anything more than self-signed.
+ AuthenticateClient bool
+
+ // CipherSuites is a list of supported cipher suites. If CipherSuites
+ // is nil, TLS uses a list of suites supported by the implementation.
+ CipherSuites []uint16
+}
+
+func (c *Config) rand() io.Reader {
+ r := c.Rand
+ if r == nil {
+ return rand.Reader
+ }
+ return r
+}
+
+func (c *Config) time() int64 {
+ t := c.Time
+ if t == nil {
+ t = time.Seconds
+ }
+ return t()
+}
+
+func (c *Config) rootCAs() *CASet {
+ s := c.RootCAs
+ if s == nil {
+ s = defaultRoots()
+ }
+ return s
+}
+
+func (c *Config) cipherSuites() []uint16 {
+ s := c.CipherSuites
+ if s == nil {
+ s = defaultCipherSuites()
+ }
+ return s
+}
+
+// A Certificate is a chain of one or more certificates, leaf first.
+type Certificate struct {
+ Certificate [][]byte
+ PrivateKey *rsa.PrivateKey
+}
+
+// A TLS record.
+type record struct {
+ contentType recordType
+ major, minor uint8
+ payload []byte
+}
+
+type handshakeMessage interface {
+ marshal() []byte
+ unmarshal([]byte) bool
+}
+
+// mutualVersion returns the protocol version to use given the advertised
+// version of the peer.
+func mutualVersion(vers uint16) (uint16, bool) {
+ if vers < minVersion {
+ return 0, false
+ }
+ if vers > maxVersion {
+ vers = maxVersion
+ }
+ return vers, true
+}
+
+var emptyConfig Config
+
+func defaultConfig() *Config {
+ return &emptyConfig
+}
+
+// Possible certificate files; stop after finding one.
+// On OS X we should really be using the Directory Services keychain
+// but that requires a lot of Mach goo to get at. Instead we use
+// the same root set that curl uses.
+var certFiles = []string{
+ "/etc/ssl/certs/ca-certificates.crt", // Linux etc
+ "/usr/share/curl/curl-ca-bundle.crt", // OS X
+}
+
+var once sync.Once
+
+func defaultRoots() *CASet {
+ once.Do(initDefaults)
+ return varDefaultRoots
+}
+
+func defaultCipherSuites() []uint16 {
+ once.Do(initDefaults)
+ return varDefaultCipherSuites
+}
+
+func initDefaults() {
+ initDefaultRoots()
+ initDefaultCipherSuites()
+}
+
+var varDefaultRoots *CASet
+
+func initDefaultRoots() {
+ roots := NewCASet()
+ for _, file := range certFiles {
+ data, err := ioutil.ReadFile(file)
+ if err == nil {
+ roots.SetFromPEM(data)
+ break
+ }
+ }
+ varDefaultRoots = roots
+}
+
+var varDefaultCipherSuites []uint16
+
+func initDefaultCipherSuites() {
+ varDefaultCipherSuites = make([]uint16, len(cipherSuites))
+ i := 0
+ for id, _ := range cipherSuites {
+ varDefaultCipherSuites[i] = id
+ i++
+ }
+}
diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go
new file mode 100644
index 000000000..d203e8d51
--- /dev/null
+++ b/libgo/go/crypto/tls/conn.go
@@ -0,0 +1,801 @@
+// 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.
+
+// TLS low level connection and record layer
+
+package tls
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/subtle"
+ "crypto/x509"
+ "hash"
+ "io"
+ "net"
+ "os"
+ "sync"
+)
+
+// A Conn represents a secured connection.
+// It implements the net.Conn interface.
+type Conn struct {
+ // constant
+ conn net.Conn
+ isClient bool
+
+ // constant after handshake; protected by handshakeMutex
+ handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+ vers uint16 // TLS version
+ haveVers bool // version has been negotiated
+ config *Config // configuration passed to constructor
+ handshakeComplete bool
+ cipherSuite uint16
+ ocspResponse []byte // stapled OCSP response
+ peerCertificates []*x509.Certificate
+
+ clientProtocol string
+
+ // first permanent error
+ errMutex sync.Mutex
+ err os.Error
+
+ // input/output
+ in, out halfConn // in.Mutex < out.Mutex
+ rawInput *block // raw input, right off the wire
+ input *block // application data waiting to be read
+ hand bytes.Buffer // handshake data waiting to be read
+
+ tmp [16]byte
+}
+
+func (c *Conn) setError(err os.Error) os.Error {
+ c.errMutex.Lock()
+ defer c.errMutex.Unlock()
+
+ if c.err == nil {
+ c.err = err
+ }
+ return err
+}
+
+func (c *Conn) error() os.Error {
+ c.errMutex.Lock()
+ defer c.errMutex.Unlock()
+
+ return c.err
+}
+
+// Access to net.Conn methods.
+// Cannot just embed net.Conn because that would
+// export the struct field too.
+
+// LocalAddr returns the local network address.
+func (c *Conn) LocalAddr() net.Addr {
+ return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (c *Conn) RemoteAddr() net.Addr {
+ return c.conn.RemoteAddr()
+}
+
+// SetTimeout sets the read deadline associated with the connection.
+// There is no write deadline.
+func (c *Conn) SetTimeout(nsec int64) os.Error {
+ return c.conn.SetTimeout(nsec)
+}
+
+// SetReadTimeout sets the time (in nanoseconds) that
+// Read will wait for data before returning os.EAGAIN.
+// Setting nsec == 0 (the default) disables the deadline.
+func (c *Conn) SetReadTimeout(nsec int64) os.Error {
+ return c.conn.SetReadTimeout(nsec)
+}
+
+// SetWriteTimeout exists to satisfy the net.Conn interface
+// but is not implemented by TLS. It always returns an error.
+func (c *Conn) SetWriteTimeout(nsec int64) os.Error {
+ return os.NewError("TLS does not support SetWriteTimeout")
+}
+
+// A halfConn represents one direction of the record layer
+// connection, either sending or receiving.
+type halfConn struct {
+ sync.Mutex
+ cipher interface{} // cipher algorithm
+ mac hash.Hash // MAC algorithm
+ seq [8]byte // 64-bit sequence number
+ bfree *block // list of free blocks
+
+ nextCipher interface{} // next encryption state
+ nextMac hash.Hash // next MAC algorithm
+}
+
+// prepareCipherSpec sets the encryption and MAC states
+// that a subsequent changeCipherSpec will use.
+func (hc *halfConn) prepareCipherSpec(cipher interface{}, mac hash.Hash) {
+ hc.nextCipher = cipher
+ hc.nextMac = mac
+}
+
+// changeCipherSpec changes the encryption and MAC states
+// to the ones previously passed to prepareCipherSpec.
+func (hc *halfConn) changeCipherSpec() os.Error {
+ if hc.nextCipher == nil {
+ return alertInternalError
+ }
+ hc.cipher = hc.nextCipher
+ hc.mac = hc.nextMac
+ hc.nextCipher = nil
+ hc.nextMac = nil
+ return nil
+}
+
+// incSeq increments the sequence number.
+func (hc *halfConn) incSeq() {
+ for i := 7; i >= 0; i-- {
+ hc.seq[i]++
+ if hc.seq[i] != 0 {
+ return
+ }
+ }
+
+ // Not allowed to let sequence number wrap.
+ // Instead, must renegotiate before it does.
+ // Not likely enough to bother.
+ panic("TLS: sequence number wraparound")
+}
+
+// resetSeq resets the sequence number to zero.
+func (hc *halfConn) resetSeq() {
+ for i := range hc.seq {
+ hc.seq[i] = 0
+ }
+}
+
+// removePadding returns an unpadded slice, in constant time, which is a prefix
+// of the input. It also returns a byte which is equal to 255 if the padding
+// was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
+func removePadding(payload []byte) ([]byte, byte) {
+ if len(payload) < 1 {
+ return payload, 0
+ }
+
+ paddingLen := payload[len(payload)-1]
+ t := uint(len(payload)-1) - uint(paddingLen)
+ // if len(payload) >= (paddingLen - 1) then the MSB of t is zero
+ good := byte(int32(^t) >> 31)
+
+ toCheck := 255 // the maximum possible padding length
+ // The length of the padded data is public, so we can use an if here
+ if toCheck+1 > len(payload) {
+ toCheck = len(payload) - 1
+ }
+
+ for i := 0; i < toCheck; i++ {
+ t := uint(paddingLen) - uint(i)
+ // if i <= paddingLen then the MSB of t is zero
+ mask := byte(int32(^t) >> 31)
+ b := payload[len(payload)-1-i]
+ good &^= mask&paddingLen ^ mask&b
+ }
+
+ // We AND together the bits of good and replicate the result across
+ // all the bits.
+ good &= good << 4
+ good &= good << 2
+ good &= good << 1
+ good = uint8(int8(good) >> 7)
+
+ toRemove := good&paddingLen + 1
+ return payload[:len(payload)-int(toRemove)], good
+}
+
+func roundUp(a, b int) int {
+ return a + (b-a%b)%b
+}
+
+// decrypt checks and strips the mac and decrypts the data in b.
+func (hc *halfConn) decrypt(b *block) (bool, alert) {
+ // pull out payload
+ payload := b.data[recordHeaderLen:]
+
+ macSize := 0
+ if hc.mac != nil {
+ macSize = hc.mac.Size()
+ }
+
+ paddingGood := byte(255)
+
+ // decrypt
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case cipher.BlockMode:
+ blockSize := c.BlockSize()
+
+ if len(payload)%blockSize != 0 || len(payload) < roundUp(macSize+1, blockSize) {
+ return false, alertBadRecordMAC
+ }
+
+ c.CryptBlocks(payload, payload)
+ payload, paddingGood = removePadding(payload)
+ b.resize(recordHeaderLen + len(payload))
+
+ // note that we still have a timing side-channel in the
+ // MAC check, below. An attacker can align the record
+ // so that a correct padding will cause one less hash
+ // block to be calculated. Then they can iteratively
+ // decrypt a record by breaking each byte. See
+ // "Password Interception in a SSL/TLS Channel", Brice
+ // Canvel et al.
+ //
+ // However, our behaviour matches OpenSSL, so we leak
+ // only as much as they do.
+ default:
+ panic("unknown cipher type")
+ }
+ }
+
+ // check, strip mac
+ if hc.mac != nil {
+ if len(payload) < macSize {
+ return false, alertBadRecordMAC
+ }
+
+ // strip mac off payload, b.data
+ n := len(payload) - macSize
+ b.data[3] = byte(n >> 8)
+ b.data[4] = byte(n)
+ b.resize(recordHeaderLen + n)
+ remoteMAC := payload[n:]
+
+ hc.mac.Reset()
+ hc.mac.Write(hc.seq[0:])
+ hc.incSeq()
+ hc.mac.Write(b.data)
+
+ if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 || paddingGood != 255 {
+ return false, alertBadRecordMAC
+ }
+ }
+
+ return true, 0
+}
+
+// padToBlockSize calculates the needed padding block, if any, for a payload.
+// On exit, prefix aliases payload and extends to the end of the last full
+// block of payload. finalBlock is a fresh slice which contains the contents of
+// any suffix of payload as well as the needed padding to make finalBlock a
+// full block.
+func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) {
+ overrun := len(payload) % blockSize
+ paddingLen := blockSize - overrun
+ prefix = payload[:len(payload)-overrun]
+ finalBlock = make([]byte, blockSize)
+ copy(finalBlock, payload[len(payload)-overrun:])
+ for i := overrun; i < blockSize; i++ {
+ finalBlock[i] = byte(paddingLen - 1)
+ }
+ return
+}
+
+// encrypt encrypts and macs the data in b.
+func (hc *halfConn) encrypt(b *block) (bool, alert) {
+ // mac
+ if hc.mac != nil {
+ hc.mac.Reset()
+ hc.mac.Write(hc.seq[0:])
+ hc.incSeq()
+ hc.mac.Write(b.data)
+ mac := hc.mac.Sum()
+ n := len(b.data)
+ b.resize(n + len(mac))
+ copy(b.data[n:], mac)
+ }
+
+ payload := b.data[recordHeaderLen:]
+
+ // encrypt
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case cipher.BlockMode:
+ prefix, finalBlock := padToBlockSize(payload, c.BlockSize())
+ b.resize(recordHeaderLen + len(prefix) + len(finalBlock))
+ c.CryptBlocks(b.data[recordHeaderLen:], prefix)
+ c.CryptBlocks(b.data[recordHeaderLen+len(prefix):], finalBlock)
+ default:
+ panic("unknown cipher type")
+ }
+ }
+
+ // update length to include MAC and any block padding needed.
+ n := len(b.data) - recordHeaderLen
+ b.data[3] = byte(n >> 8)
+ b.data[4] = byte(n)
+
+ return true, 0
+}
+
+// A block is a simple data buffer.
+type block struct {
+ data []byte
+ off int // index for Read
+ link *block
+}
+
+// resize resizes block to be n bytes, growing if necessary.
+func (b *block) resize(n int) {
+ if n > cap(b.data) {
+ b.reserve(n)
+ }
+ b.data = b.data[0:n]
+}
+
+// reserve makes sure that block contains a capacity of at least n bytes.
+func (b *block) reserve(n int) {
+ if cap(b.data) >= n {
+ return
+ }
+ m := cap(b.data)
+ if m == 0 {
+ m = 1024
+ }
+ for m < n {
+ m *= 2
+ }
+ data := make([]byte, len(b.data), m)
+ copy(data, b.data)
+ b.data = data
+}
+
+// readFromUntil reads from r into b until b contains at least n bytes
+// or else returns an error.
+func (b *block) readFromUntil(r io.Reader, n int) os.Error {
+ // quick case
+ if len(b.data) >= n {
+ return nil
+ }
+
+ // read until have enough.
+ b.reserve(n)
+ for {
+ m, err := r.Read(b.data[len(b.data):cap(b.data)])
+ b.data = b.data[0 : len(b.data)+m]
+ if len(b.data) >= n {
+ break
+ }
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (b *block) Read(p []byte) (n int, err os.Error) {
+ n = copy(p, b.data[b.off:])
+ b.off += n
+ return
+}
+
+// newBlock allocates a new block, from hc's free list if possible.
+func (hc *halfConn) newBlock() *block {
+ b := hc.bfree
+ if b == nil {
+ return new(block)
+ }
+ hc.bfree = b.link
+ b.link = nil
+ b.resize(0)
+ return b
+}
+
+// freeBlock returns a block to hc's free list.
+// The protocol is such that each side only has a block or two on
+// its free list at a time, so there's no need to worry about
+// trimming the list, etc.
+func (hc *halfConn) freeBlock(b *block) {
+ b.link = hc.bfree
+ hc.bfree = b
+}
+
+// splitBlock splits a block after the first n bytes,
+// returning a block with those n bytes and a
+// block with the remaindec. the latter may be nil.
+func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
+ if len(b.data) <= n {
+ return b, nil
+ }
+ bb := hc.newBlock()
+ bb.resize(len(b.data) - n)
+ copy(bb.data, b.data[n:])
+ b.data = b.data[0:n]
+ return b, bb
+}
+
+// readRecord reads the next TLS record from the connection
+// and updates the record layer state.
+// c.in.Mutex <= L; c.input == nil.
+func (c *Conn) readRecord(want recordType) os.Error {
+ // Caller must be in sync with connection:
+ // handshake data if handshake not yet completed,
+ // else application data. (We don't support renegotiation.)
+ switch want {
+ default:
+ return c.sendAlert(alertInternalError)
+ case recordTypeHandshake, recordTypeChangeCipherSpec:
+ if c.handshakeComplete {
+ return c.sendAlert(alertInternalError)
+ }
+ case recordTypeApplicationData:
+ if !c.handshakeComplete {
+ return c.sendAlert(alertInternalError)
+ }
+ }
+
+Again:
+ if c.rawInput == nil {
+ c.rawInput = c.in.newBlock()
+ }
+ b := c.rawInput
+
+ // Read header, payload.
+ if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil {
+ // RFC suggests that EOF without an alertCloseNotify is
+ // an error, but popular web sites seem to do this,
+ // so we can't make it an error.
+ // if err == os.EOF {
+ // err = io.ErrUnexpectedEOF
+ // }
+ if e, ok := err.(net.Error); !ok || !e.Temporary() {
+ c.setError(err)
+ }
+ return err
+ }
+ typ := recordType(b.data[0])
+ vers := uint16(b.data[1])<<8 | uint16(b.data[2])
+ n := int(b.data[3])<<8 | int(b.data[4])
+ if c.haveVers && vers != c.vers {
+ return c.sendAlert(alertProtocolVersion)
+ }
+ if n > maxCiphertext {
+ return c.sendAlert(alertRecordOverflow)
+ }
+ if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ if e, ok := err.(net.Error); !ok || !e.Temporary() {
+ c.setError(err)
+ }
+ return err
+ }
+
+ // Process message.
+ b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
+ b.off = recordHeaderLen
+ if ok, err := c.in.decrypt(b); !ok {
+ return c.sendAlert(err)
+ }
+ data := b.data[b.off:]
+ if len(data) > maxPlaintext {
+ c.sendAlert(alertRecordOverflow)
+ c.in.freeBlock(b)
+ return c.error()
+ }
+
+ switch typ {
+ default:
+ c.sendAlert(alertUnexpectedMessage)
+
+ case recordTypeAlert:
+ if len(data) != 2 {
+ c.sendAlert(alertUnexpectedMessage)
+ break
+ }
+ if alert(data[1]) == alertCloseNotify {
+ c.setError(os.EOF)
+ break
+ }
+ switch data[0] {
+ case alertLevelWarning:
+ // drop on the floor
+ c.in.freeBlock(b)
+ goto Again
+ case alertLevelError:
+ c.setError(&net.OpError{Op: "remote error", Error: alert(data[1])})
+ default:
+ c.sendAlert(alertUnexpectedMessage)
+ }
+
+ case recordTypeChangeCipherSpec:
+ if typ != want || len(data) != 1 || data[0] != 1 {
+ c.sendAlert(alertUnexpectedMessage)
+ break
+ }
+ err := c.in.changeCipherSpec()
+ if err != nil {
+ c.sendAlert(err.(alert))
+ }
+
+ case recordTypeApplicationData:
+ if typ != want {
+ c.sendAlert(alertUnexpectedMessage)
+ break
+ }
+ c.input = b
+ b = nil
+
+ case recordTypeHandshake:
+ // TODO(rsc): Should at least pick off connection close.
+ if typ != want {
+ return c.sendAlert(alertNoRenegotiation)
+ }
+ c.hand.Write(data)
+ }
+
+ if b != nil {
+ c.in.freeBlock(b)
+ }
+ return c.error()
+}
+
+// sendAlert sends a TLS alert message.
+// c.out.Mutex <= L.
+func (c *Conn) sendAlertLocked(err alert) os.Error {
+ c.tmp[0] = alertLevelError
+ if err == alertNoRenegotiation {
+ c.tmp[0] = alertLevelWarning
+ }
+ c.tmp[1] = byte(err)
+ c.writeRecord(recordTypeAlert, c.tmp[0:2])
+ // closeNotify is a special case in that it isn't an error:
+ if err != alertCloseNotify {
+ return c.setError(&net.OpError{Op: "local error", Error: err})
+ }
+ return nil
+}
+
+// sendAlert sends a TLS alert message.
+// L < c.out.Mutex.
+func (c *Conn) sendAlert(err alert) os.Error {
+ c.out.Lock()
+ defer c.out.Unlock()
+ return c.sendAlertLocked(err)
+}
+
+// writeRecord writes a TLS record with the given type and payload
+// to the connection and updates the record layer state.
+// c.out.Mutex <= L.
+func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err os.Error) {
+ b := c.out.newBlock()
+ for len(data) > 0 {
+ m := len(data)
+ if m > maxPlaintext {
+ m = maxPlaintext
+ }
+ b.resize(recordHeaderLen + m)
+ b.data[0] = byte(typ)
+ vers := c.vers
+ if vers == 0 {
+ vers = maxVersion
+ }
+ b.data[1] = byte(vers >> 8)
+ b.data[2] = byte(vers)
+ b.data[3] = byte(m >> 8)
+ b.data[4] = byte(m)
+ copy(b.data[recordHeaderLen:], data)
+ c.out.encrypt(b)
+ _, err = c.conn.Write(b.data)
+ if err != nil {
+ break
+ }
+ n += m
+ data = data[m:]
+ }
+ c.out.freeBlock(b)
+
+ if typ == recordTypeChangeCipherSpec {
+ err = c.out.changeCipherSpec()
+ if err != nil {
+ // Cannot call sendAlert directly,
+ // because we already hold c.out.Mutex.
+ c.tmp[0] = alertLevelError
+ c.tmp[1] = byte(err.(alert))
+ c.writeRecord(recordTypeAlert, c.tmp[0:2])
+ c.err = &net.OpError{Op: "local error", Error: err}
+ return n, c.err
+ }
+ }
+ return
+}
+
+// readHandshake reads the next handshake message from
+// the record layer.
+// c.in.Mutex < L; c.out.Mutex < L.
+func (c *Conn) readHandshake() (interface{}, os.Error) {
+ for c.hand.Len() < 4 {
+ if c.err != nil {
+ return nil, c.err
+ }
+ c.readRecord(recordTypeHandshake)
+ }
+
+ data := c.hand.Bytes()
+ n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if n > maxHandshake {
+ c.sendAlert(alertInternalError)
+ return nil, c.err
+ }
+ for c.hand.Len() < 4+n {
+ if c.err != nil {
+ return nil, c.err
+ }
+ c.readRecord(recordTypeHandshake)
+ }
+ data = c.hand.Next(4 + n)
+ var m handshakeMessage
+ switch data[0] {
+ case typeClientHello:
+ m = new(clientHelloMsg)
+ case typeServerHello:
+ m = new(serverHelloMsg)
+ case typeCertificate:
+ m = new(certificateMsg)
+ case typeCertificateRequest:
+ m = new(certificateRequestMsg)
+ case typeCertificateStatus:
+ m = new(certificateStatusMsg)
+ case typeServerKeyExchange:
+ m = new(serverKeyExchangeMsg)
+ case typeServerHelloDone:
+ m = new(serverHelloDoneMsg)
+ case typeClientKeyExchange:
+ m = new(clientKeyExchangeMsg)
+ case typeCertificateVerify:
+ m = new(certificateVerifyMsg)
+ case typeNextProtocol:
+ m = new(nextProtoMsg)
+ case typeFinished:
+ m = new(finishedMsg)
+ default:
+ c.sendAlert(alertUnexpectedMessage)
+ return nil, alertUnexpectedMessage
+ }
+
+ // The handshake message unmarshallers
+ // expect to be able to keep references to data,
+ // so pass in a fresh copy that won't be overwritten.
+ data = append([]byte(nil), data...)
+
+ if !m.unmarshal(data) {
+ c.sendAlert(alertUnexpectedMessage)
+ return nil, alertUnexpectedMessage
+ }
+ return m, nil
+}
+
+// Write writes data to the connection.
+func (c *Conn) Write(b []byte) (n int, err os.Error) {
+ if err = c.Handshake(); err != nil {
+ return
+ }
+
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ if !c.handshakeComplete {
+ return 0, alertInternalError
+ }
+ if c.err != nil {
+ return 0, c.err
+ }
+ return c.writeRecord(recordTypeApplicationData, b)
+}
+
+// Read can be made to time out and return err == os.EAGAIN
+// after a fixed time limit; see SetTimeout and SetReadTimeout.
+func (c *Conn) Read(b []byte) (n int, err os.Error) {
+ if err = c.Handshake(); err != nil {
+ return
+ }
+
+ c.in.Lock()
+ defer c.in.Unlock()
+
+ for c.input == nil && c.err == nil {
+ if err := c.readRecord(recordTypeApplicationData); err != nil {
+ // Soft error, like EAGAIN
+ return 0, err
+ }
+ }
+ if c.err != nil {
+ return 0, c.err
+ }
+ n, err = c.input.Read(b)
+ if c.input.off >= len(c.input.data) {
+ c.in.freeBlock(c.input)
+ c.input = nil
+ }
+ return n, nil
+}
+
+// Close closes the connection.
+func (c *Conn) Close() os.Error {
+ if err := c.Handshake(); err != nil {
+ return err
+ }
+ return c.sendAlert(alertCloseNotify)
+}
+
+// Handshake runs the client or server handshake
+// protocol if it has not yet been run.
+// Most uses of this package need not call Handshake
+// explicitly: the first Read or Write will call it automatically.
+func (c *Conn) Handshake() os.Error {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if err := c.error(); err != nil {
+ return err
+ }
+ if c.handshakeComplete {
+ return nil
+ }
+ if c.isClient {
+ return c.clientHandshake()
+ }
+ return c.serverHandshake()
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (c *Conn) ConnectionState() ConnectionState {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ var state ConnectionState
+ state.HandshakeComplete = c.handshakeComplete
+ if c.handshakeComplete {
+ state.NegotiatedProtocol = c.clientProtocol
+ state.CipherSuite = c.cipherSuite
+ }
+
+ return state
+}
+
+// OCSPResponse returns the stapled OCSP response from the TLS server, if
+// any. (Only valid for client connections.)
+func (c *Conn) OCSPResponse() []byte {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ return c.ocspResponse
+}
+
+// PeerCertificates returns the certificate chain that was presented by the
+// other side.
+func (c *Conn) PeerCertificates() []*x509.Certificate {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ return c.peerCertificates
+}
+
+// VerifyHostname checks that the peer certificate chain is valid for
+// connecting to host. If so, it returns nil; if not, it returns an os.Error
+// describing the problem.
+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")
+ }
+ if !c.handshakeComplete {
+ return os.ErrorString("TLS handshake has not yet been performed")
+ }
+ return c.peerCertificates[0].VerifyHostname(host)
+}
diff --git a/libgo/go/crypto/tls/conn_test.go b/libgo/go/crypto/tls/conn_test.go
new file mode 100644
index 000000000..f44a50bed
--- /dev/null
+++ b/libgo/go/crypto/tls/conn_test.go
@@ -0,0 +1,52 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "testing"
+)
+
+func TestRoundUp(t *testing.T) {
+ if roundUp(0, 16) != 0 ||
+ roundUp(1, 16) != 16 ||
+ roundUp(15, 16) != 16 ||
+ roundUp(16, 16) != 16 ||
+ roundUp(17, 16) != 32 {
+ t.Error("roundUp broken")
+ }
+}
+
+var paddingTests = []struct {
+ in []byte
+ good bool
+ expectedLen int
+}{
+ {[]byte{1, 2, 3, 4, 0}, true, 4},
+ {[]byte{1, 2, 3, 4, 0, 1}, false, 0},
+ {[]byte{1, 2, 3, 4, 99, 99}, false, 0},
+ {[]byte{1, 2, 3, 4, 1, 1}, true, 4},
+ {[]byte{1, 2, 3, 2, 2, 2}, true, 3},
+ {[]byte{1, 2, 3, 3, 3, 3}, true, 2},
+ {[]byte{1, 2, 3, 4, 3, 3}, false, 0},
+ {[]byte{1, 4, 4, 4, 4, 4}, true, 1},
+ {[]byte{5, 5, 5, 5, 5, 5}, true, 0},
+ {[]byte{6, 6, 6, 6, 6, 6}, false, 0},
+}
+
+func TestRemovePadding(t *testing.T) {
+ for i, test := range paddingTests {
+ payload, good := removePadding(test.in)
+ expectedGood := byte(255)
+ if !test.good {
+ expectedGood = 0
+ }
+ if good != expectedGood {
+ t.Errorf("#%d: wrong validity, want:%d got:%d", i, expectedGood, good)
+ }
+ if good == 255 && len(payload) != test.expectedLen {
+ t.Errorf("#%d: got %d, want %d", i, len(payload), test.expectedLen)
+ }
+ }
+}
diff --git a/libgo/go/crypto/tls/generate_cert.go b/libgo/go/crypto/tls/generate_cert.go
new file mode 100644
index 000000000..3e0c63938
--- /dev/null
+++ b/libgo/go/crypto/tls/generate_cert.go
@@ -0,0 +1,70 @@
+// 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.
+
+// Generate a self-signed X.509 certificate for a TLS server. Outputs to
+// 'cert.pem' and 'key.pem' and will overwrite existing files.
+
+package main
+
+import (
+ "crypto/rsa"
+ "crypto/rand"
+ "crypto/x509"
+ "encoding/pem"
+ "flag"
+ "log"
+ "os"
+ "time"
+)
+
+var hostName *string = flag.String("host", "127.0.0.1", "Hostname to generate a certificate for")
+
+func main() {
+ flag.Parse()
+
+ priv, err := rsa.GenerateKey(rand.Reader, 1024)
+ if err != nil {
+ log.Exitf("failed to generate private key: %s", err)
+ return
+ }
+
+ now := time.Seconds()
+
+ template := x509.Certificate{
+ SerialNumber: []byte{0},
+ Subject: x509.Name{
+ CommonName: *hostName,
+ Organization: []string{"Acme Co"},
+ },
+ NotBefore: time.SecondsToUTC(now - 300),
+ NotAfter: time.SecondsToUTC(now + 60*60*24*365), // valid for 1 year.
+
+ SubjectKeyId: []byte{1, 2, 3, 4},
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ }
+
+ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
+ if err != nil {
+ log.Exitf("Failed to create certificate: %s", err)
+ return
+ }
+
+ certOut, err := os.Open("cert.pem", os.O_WRONLY|os.O_CREAT, 0644)
+ if err != nil {
+ log.Exitf("failed to open cert.pem for writing: %s", err)
+ return
+ }
+ pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
+ certOut.Close()
+ log.Print("written cert.pem\n")
+
+ keyOut, err := os.Open("key.pem", os.O_WRONLY|os.O_CREAT, 0600)
+ if err != nil {
+ log.Print("failed to open key.pem for writing:", err)
+ return
+ }
+ pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
+ keyOut.Close()
+ log.Print("written key.pem\n")
+}
diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go
new file mode 100644
index 000000000..1ca33f59d
--- /dev/null
+++ b/libgo/go/crypto/tls/handshake_client.go
@@ -0,0 +1,300 @@
+// 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 tls
+
+import (
+ "crypto/rsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "io"
+ "os"
+)
+
+func (c *Conn) clientHandshake() os.Error {
+ finishedHash := newFinishedHash()
+
+ if c.config == nil {
+ c.config = defaultConfig()
+ }
+
+ hello := &clientHelloMsg{
+ vers: maxVersion,
+ cipherSuites: c.config.cipherSuites(),
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ ocspStapling: true,
+ serverName: c.config.ServerName,
+ supportedCurves: []uint16{curveP256, curveP384, curveP521},
+ supportedPoints: []uint8{pointFormatUncompressed},
+ }
+
+ t := uint32(c.config.time())
+ hello.random[0] = byte(t >> 24)
+ hello.random[1] = byte(t >> 16)
+ hello.random[2] = byte(t >> 8)
+ hello.random[3] = byte(t)
+ _, err := io.ReadFull(c.config.rand(), hello.random[4:])
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return os.ErrorString("short read from Rand")
+ }
+
+ finishedHash.Write(hello.marshal())
+ c.writeRecord(recordTypeHandshake, hello.marshal())
+
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ serverHello, ok := msg.(*serverHelloMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(serverHello.marshal())
+
+ vers, ok := mutualVersion(serverHello.vers)
+ if !ok {
+ c.sendAlert(alertProtocolVersion)
+ }
+ c.vers = vers
+ c.haveVers = true
+
+ if serverHello.compressionMethod != compressionNone {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+
+ suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
+ if suite == nil {
+ return c.sendAlert(alertHandshakeFailure)
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ certMsg, ok := msg.(*certificateMsg)
+ if !ok || len(certMsg.certificates) == 0 {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(certMsg.marshal())
+
+ certs := make([]*x509.Certificate, len(certMsg.certificates))
+ chain := NewCASet()
+ for i, asn1Data := range certMsg.certificates {
+ cert, err := x509.ParseCertificate(asn1Data)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return os.ErrorString("failed to parse certificate from server: " + err.String())
+ }
+ certs[i] = cert
+ chain.AddCert(cert)
+ }
+
+ // If we don't have a root CA set configured then anything is accepted.
+ // TODO(rsc): Find certificates for OS X 10.6.
+ for cur := certs[0]; c.config.RootCAs != nil; {
+ parent := c.config.RootCAs.FindVerifiedParent(cur)
+ if parent != nil {
+ break
+ }
+
+ parent = chain.FindVerifiedParent(cur)
+ if parent == nil {
+ c.sendAlert(alertBadCertificate)
+ return os.ErrorString("could not find root certificate for chain")
+ }
+
+ if !parent.BasicConstraintsValid || !parent.IsCA {
+ c.sendAlert(alertBadCertificate)
+ return os.ErrorString("intermediate certificate does not have CA bit set")
+ }
+ // KeyUsage status flags are ignored. From Engineering
+ // Security, Peter Gutmann: A European government CA marked its
+ // signing certificates as being valid for encryption only, but
+ // no-one noticed. Another European CA marked its signature
+ // keys as not being valid for signatures. A different CA
+ // marked its own trusted root certificate as being invalid for
+ // certificate signing. Another national CA distributed a
+ // certificate to be used to encrypt data for the country’s tax
+ // authority that was marked as only being usable for digital
+ // signatures but not for encryption. Yet another CA reversed
+ // the order of the bit flags in the keyUsage due to confusion
+ // over encoding endianness, essentially setting a random
+ // keyUsage in certificates that it issued. Another CA created
+ // a self-invalidating certificate by adding a certificate
+ // policy statement stipulating that the certificate had to be
+ // used strictly as specified in the keyUsage, and a keyUsage
+ // containing a flag indicating that the RSA encryption key
+ // could only be used for Diffie-Hellman key agreement.
+
+ cur = parent
+ }
+
+ if _, ok := certs[0].PublicKey.(*rsa.PublicKey); !ok {
+ return c.sendAlert(alertUnsupportedCertificate)
+ }
+
+ c.peerCertificates = certs
+
+ if serverHello.certStatus {
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ cs, ok := msg.(*certificateStatusMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(cs.marshal())
+
+ if cs.statusType == statusTypeOCSP {
+ c.ocspResponse = cs.response
+ }
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ keyAgreement := suite.ka()
+
+ skx, ok := msg.(*serverKeyExchangeMsg)
+ if ok {
+ finishedHash.Write(skx.marshal())
+ err = keyAgreement.processServerKeyExchange(c.config, hello, serverHello, certs[0], skx)
+ if err != nil {
+ c.sendAlert(alertUnexpectedMessage)
+ return err
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+
+ transmitCert := false
+ certReq, ok := msg.(*certificateRequestMsg)
+ if ok {
+ // We only accept certificates with RSA keys.
+ rsaAvail := false
+ for _, certType := range certReq.certificateTypes {
+ if certType == certTypeRSASign {
+ rsaAvail = true
+ break
+ }
+ }
+
+ // For now, only send a certificate back if the server gives us an
+ // empty list of certificateAuthorities.
+ //
+ // RFC 4346 on the certificateAuthorities field:
+ // A list of the distinguished names of acceptable certificate
+ // authorities. These distinguished names may specify a desired
+ // distinguished name for a root CA or for a subordinate CA; thus,
+ // this message can be used to describe both known roots and a
+ // desired authorization space. If the certificate_authorities
+ // list is empty then the client MAY send any certificate of the
+ // appropriate ClientCertificateType, unless there is some
+ // external arrangement to the contrary.
+ if rsaAvail && len(certReq.certificateAuthorities) == 0 {
+ transmitCert = true
+ }
+
+ finishedHash.Write(certReq.marshal())
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+
+ shd, ok := msg.(*serverHelloDoneMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(shd.marshal())
+
+ var cert *x509.Certificate
+ if transmitCert {
+ certMsg = new(certificateMsg)
+ if len(c.config.Certificates) > 0 {
+ cert, err = x509.ParseCertificate(c.config.Certificates[0].Certificate[0])
+ if err == nil && cert.PublicKeyAlgorithm == x509.RSA {
+ certMsg.certificates = c.config.Certificates[0].Certificate
+ } else {
+ cert = nil
+ }
+ }
+ finishedHash.Write(certMsg.marshal())
+ c.writeRecord(recordTypeHandshake, certMsg.marshal())
+ }
+
+ preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hello, certs[0])
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ if ckx != nil {
+ finishedHash.Write(ckx.marshal())
+ c.writeRecord(recordTypeHandshake, ckx.marshal())
+ }
+
+ if cert != nil {
+ certVerify := new(certificateVerifyMsg)
+ var digest [36]byte
+ copy(digest[0:16], finishedHash.serverMD5.Sum())
+ copy(digest[16:36], finishedHash.serverSHA1.Sum())
+ signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, rsa.HashMD5SHA1, digest[0:])
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ certVerify.signature = signed
+
+ finishedHash.Write(certVerify.marshal())
+ c.writeRecord(recordTypeHandshake, certVerify.marshal())
+ }
+
+ masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromPreMasterSecret10(preMasterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
+
+ clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */ )
+ clientHash := suite.mac(clientMAC)
+ c.out.prepareCipherSpec(clientCipher, clientHash)
+ c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+
+ finished := new(finishedMsg)
+ finished.verifyData = finishedHash.clientSum(masterSecret)
+ finishedHash.Write(finished.marshal())
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+
+ serverCipher := suite.cipher(serverKey, serverIV, true /* for reading */ )
+ serverHash := suite.mac(serverMAC)
+ c.in.prepareCipherSpec(serverCipher, serverHash)
+ c.readRecord(recordTypeChangeCipherSpec)
+ if c.err != nil {
+ return c.err
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ serverFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+
+ verify := finishedHash.serverSum(masterSecret)
+ if len(verify) != len(serverFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
+ return c.sendAlert(alertHandshakeFailure)
+ }
+
+ c.handshakeComplete = true
+ c.cipherSuite = suiteId
+ return nil
+}
diff --git a/libgo/go/crypto/tls/handshake_client_test.go b/libgo/go/crypto/tls/handshake_client_test.go
new file mode 100644
index 000000000..e5c9684b9
--- /dev/null
+++ b/libgo/go/crypto/tls/handshake_client_test.go
@@ -0,0 +1,211 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "flag"
+ "io"
+ "net"
+ "testing"
+)
+
+func testClientScript(t *testing.T, name string, clientScript [][]byte, config *Config) {
+ c, s := net.Pipe()
+ cli := Client(c, config)
+ go func() {
+ cli.Write([]byte("hello\n"))
+ cli.Close()
+ }()
+
+ defer c.Close()
+ for i, b := range clientScript {
+ if i%2 == 1 {
+ s.Write(b)
+ continue
+ }
+ bb := make([]byte, len(b))
+ _, err := io.ReadFull(s, bb)
+ if err != nil {
+ t.Fatalf("%s #%d: %s", name, i, err)
+ }
+ if !bytes.Equal(b, bb) {
+ t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
+ }
+ }
+}
+
+func TestHandshakeClientRC4(t *testing.T) {
+ testClientScript(t, "RC4", rc4ClientScript, testConfig)
+}
+
+var connect = flag.Bool("connect", false, "connect to a TLS server on :10443")
+
+func TestRunClient(t *testing.T) {
+ if !*connect {
+ return
+ }
+
+ testConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
+
+ conn, err := Dial("tcp", "", "127.0.0.1:10443", testConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ conn.Write([]byte("hello\n"))
+ conn.Close()
+}
+
+// Script of interaction with gnutls implementation.
+// The values for this test are obtained by building and running in client mode:
+// % gotest -match "TestRunClient" -connect
+// and then:
+// % gnutls-serv -p 10443 --debug 100 --x509keyfile key.pem --x509certfile cert.pem -a > /tmp/log 2>&1
+// % python parse-gnutls-cli-debug-log.py < /tmp/log
+//
+// Where key.pem is:
+// -----BEGIN RSA PRIVATE KEY-----
+// MIIBPAIBAAJBAJ+zw4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVD
+// TGiXav6ooKXfX3j/7tdkuD8Ey2//Kv7+ue0CAwEAAQJAN6W31vDEP2DjdqhzCDDu
+// OA4NACqoiFqyblo7yc2tM4h4xMbC3Yx5UKMN9ZkCtX0gzrz6DyF47bdKcWBzNWCj
+// gQIhANEoojVt7hq+SQ6MCN6FTAysGgQf56Q3TYoJMoWvdiXVAiEAw3e3rc+VJpOz
+// rHuDo6bgpjUAAXM+v3fcpsfZSNO6V7kCIQCtbVjanpUwvZkMI9by02oUk9taki3b
+// PzPfAfNPYAbCJQIhAJXNQDWyqwn/lGmR11cqY2y9nZ1+5w3yHGatLrcDnQHxAiEA
+// vnlEGo8K85u+KwIOimM48ZG8oTk7iFdkqLJR1utT3aU=
+// -----END RSA PRIVATE KEY-----
+//
+// and cert.pem is:
+// -----BEGIN CERTIFICATE-----
+// MIIBoDCCAUoCAQAwDQYJKoZIhvcNAQEEBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV
+// BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD
+// VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw05NzA5MDkwMzQxMjZa
+// Fw05NzEwMDkwMzQxMjZaMF4xCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
+// YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFzAVBgNVBAMT
+// DkVyaWMgdGhlIFlvdW5nMFEwCQYFKw4DAgwFAANEAAJBALVEqPODnpI4rShlY8S7
+// tB713JNvabvn6Gned7zylwLLiXQAo/PAT6mfdWPTyCX9RlId/Aroh1ou893BA32Q
+// sggwDQYJKoZIhvcNAQEEBQADQQCU5SSgapJSdRXJoX+CpCvFy+JVh9HpSjCpSNKO
+// 19raHv98hKAUJuP9HyM+SUsffO6mAIgitUaqW8/wDMePhEC3
+// -----END CERTIFICATE-----
+var rc4ClientScript = [][]byte{
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
+ 0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05,
+ 0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
+ 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
+ 0x46, 0x03, 0x01, 0x4d, 0x0a, 0x56, 0x16, 0xb5,
+ 0x91, 0xd1, 0xcb, 0x80, 0x4d, 0xc7, 0x46, 0xf3,
+ 0x37, 0x0c, 0xef, 0xea, 0x64, 0x11, 0x14, 0x56,
+ 0x97, 0x9b, 0xc5, 0x67, 0x08, 0xb7, 0x13, 0xea,
+ 0xf8, 0xc9, 0xb3, 0x20, 0xe2, 0xfc, 0x41, 0xf6,
+ 0x96, 0x90, 0x9d, 0x43, 0x9b, 0xe9, 0x6e, 0xf8,
+ 0x41, 0x16, 0xcc, 0xf3, 0xc7, 0xde, 0xda, 0x5a,
+ 0xa1, 0x33, 0x69, 0xe2, 0xde, 0x5b, 0xaf, 0x2a,
+ 0x92, 0xe7, 0xd4, 0xa0, 0x00, 0x05, 0x00, 0x16,
+ 0x03, 0x01, 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xf3,
+ 0x00, 0x01, 0xf0, 0x00, 0x01, 0xed, 0x30, 0x82,
+ 0x01, 0xe9, 0x30, 0x82, 0x01, 0x52, 0x02, 0x01,
+ 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00,
+ 0x30, 0x5b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
+ 0x13, 0x0a, 0x51, 0x75, 0x65, 0x65, 0x6e, 0x73,
+ 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x1a, 0x30, 0x18,
+ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43,
+ 0x72, 0x79, 0x70, 0x74, 0x53, 0x6f, 0x66, 0x74,
+ 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
+ 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x12, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x43, 0x41, 0x20, 0x28, 0x31, 0x30, 0x32, 0x34,
+ 0x20, 0x62, 0x69, 0x74, 0x29, 0x30, 0x1e, 0x17,
+ 0x0d, 0x30, 0x30, 0x31, 0x30, 0x31, 0x36, 0x32,
+ 0x32, 0x33, 0x31, 0x30, 0x33, 0x5a, 0x17, 0x0d,
+ 0x30, 0x33, 0x30, 0x31, 0x31, 0x34, 0x32, 0x32,
+ 0x33, 0x31, 0x30, 0x33, 0x5a, 0x30, 0x63, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x51,
+ 0x75, 0x65, 0x65, 0x6e, 0x73, 0x6c, 0x61, 0x6e,
+ 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x11, 0x43, 0x72, 0x79, 0x70,
+ 0x74, 0x53, 0x6f, 0x66, 0x74, 0x20, 0x50, 0x74,
+ 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x23, 0x30,
+ 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a,
+ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74,
+ 0x65, 0x73, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74,
+ 0x20, 0x28, 0x35, 0x31, 0x32, 0x20, 0x62, 0x69,
+ 0x74, 0x29, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48,
+ 0x02, 0x41, 0x00, 0x9f, 0xb3, 0xc3, 0x84, 0x27,
+ 0x95, 0xff, 0x12, 0x31, 0x52, 0x0f, 0x15, 0xef,
+ 0x46, 0x11, 0xc4, 0xad, 0x80, 0xe6, 0x36, 0x5b,
+ 0x0f, 0xdd, 0x80, 0xd7, 0x61, 0x8d, 0xe0, 0xfc,
+ 0x72, 0x45, 0x09, 0x34, 0xfe, 0x55, 0x66, 0x45,
+ 0x43, 0x4c, 0x68, 0x97, 0x6a, 0xfe, 0xa8, 0xa0,
+ 0xa5, 0xdf, 0x5f, 0x78, 0xff, 0xee, 0xd7, 0x64,
+ 0xb8, 0x3f, 0x04, 0xcb, 0x6f, 0xff, 0x2a, 0xfe,
+ 0xfe, 0xb9, 0xed, 0x02, 0x03, 0x01, 0x00, 0x01,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03,
+ 0x81, 0x81, 0x00, 0x93, 0xd2, 0x0a, 0xc5, 0x41,
+ 0xe6, 0x5a, 0xa9, 0x86, 0xf9, 0x11, 0x87, 0xe4,
+ 0xdb, 0x45, 0xe2, 0xc5, 0x95, 0x78, 0x1a, 0x6c,
+ 0x80, 0x6d, 0x73, 0x1f, 0xb4, 0x6d, 0x44, 0xa3,
+ 0xba, 0x86, 0x88, 0xc8, 0x58, 0xcd, 0x1c, 0x06,
+ 0x35, 0x6c, 0x44, 0x62, 0x88, 0xdf, 0xe4, 0xf6,
+ 0x64, 0x61, 0x95, 0xef, 0x4a, 0xa6, 0x7f, 0x65,
+ 0x71, 0xd7, 0x6b, 0x88, 0x39, 0xf6, 0x32, 0xbf,
+ 0xac, 0x93, 0x67, 0x69, 0x51, 0x8c, 0x93, 0xec,
+ 0x48, 0x5f, 0xc9, 0xb1, 0x42, 0xf9, 0x55, 0xd2,
+ 0x7e, 0x4e, 0xf4, 0xf2, 0x21, 0x6b, 0x90, 0x57,
+ 0xe6, 0xd7, 0x99, 0x9e, 0x41, 0xca, 0x80, 0xbf,
+ 0x1a, 0x28, 0xa2, 0xca, 0x5b, 0x50, 0x4a, 0xed,
+ 0x84, 0xe7, 0x82, 0xc7, 0xd2, 0xcf, 0x36, 0x9e,
+ 0x6a, 0x67, 0xb9, 0x88, 0xa7, 0xf3, 0x8a, 0xd0,
+ 0x04, 0xf8, 0xe8, 0xc6, 0x17, 0xe3, 0xc5, 0x29,
+ 0xbc, 0x17, 0xf1, 0x16, 0x03, 0x01, 0x00, 0x04,
+ 0x0e, 0x00, 0x00, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
+ 0x42, 0x00, 0x40, 0x87, 0xa1, 0x1f, 0x14, 0xe1,
+ 0xfb, 0x91, 0xac, 0x58, 0x2e, 0xf3, 0x71, 0xce,
+ 0x01, 0x85, 0x2c, 0xc7, 0xfe, 0x84, 0x87, 0x82,
+ 0xb7, 0x57, 0xdb, 0x37, 0x4d, 0x46, 0x83, 0x67,
+ 0x52, 0x82, 0x51, 0x01, 0x95, 0x23, 0x68, 0x69,
+ 0x6b, 0xd0, 0xa7, 0xa7, 0xe5, 0x88, 0xd0, 0x47,
+ 0x71, 0xb8, 0xd2, 0x03, 0x05, 0x25, 0x56, 0x5c,
+ 0x10, 0x08, 0xc6, 0x9b, 0xd4, 0x67, 0xcd, 0x28,
+ 0xbe, 0x9c, 0x48, 0x14, 0x03, 0x01, 0x00, 0x01,
+ 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc1, 0xb8,
+ 0xd3, 0x7f, 0xc5, 0xc2, 0x5a, 0x1d, 0x6d, 0x5b,
+ 0x2d, 0x5c, 0x82, 0x87, 0xc2, 0x6f, 0x0d, 0x63,
+ 0x7b, 0x72, 0x2b, 0xda, 0x69, 0xc4, 0xfe, 0x3c,
+ 0x84, 0xa1, 0x5a, 0x62, 0x38, 0x37, 0xc6, 0x54,
+ 0x25, 0x2a,
+ },
+
+ {
+ 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x01, 0x00, 0x24, 0xea, 0x88, 0x9c, 0x00, 0xf6,
+ 0x35, 0xb8, 0x42, 0x7f, 0x15, 0x17, 0x76, 0x5e,
+ 0x4b, 0x24, 0xcb, 0x7e, 0xa0, 0x7b, 0xc3, 0x70,
+ 0x52, 0x0a, 0x88, 0x2a, 0x7a, 0x45, 0x59, 0x90,
+ 0x59, 0xac, 0xc6, 0xb5, 0x56, 0x55, 0x96,
+ },
+}
diff --git a/libgo/go/crypto/tls/handshake_messages.go b/libgo/go/crypto/tls/handshake_messages.go
new file mode 100644
index 000000000..e5e856271
--- /dev/null
+++ b/libgo/go/crypto/tls/handshake_messages.go
@@ -0,0 +1,904 @@
+// 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 tls
+
+type clientHelloMsg struct {
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuites []uint16
+ compressionMethods []uint8
+ nextProtoNeg bool
+ serverName string
+ ocspStapling bool
+ supportedCurves []uint16
+ supportedPoints []uint8
+}
+
+func (m *clientHelloMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods)
+ numExtensions := 0
+ extensionsLength := 0
+ if m.nextProtoNeg {
+ numExtensions++
+ }
+ if m.ocspStapling {
+ extensionsLength += 1 + 2 + 2
+ numExtensions++
+ }
+ if len(m.serverName) > 0 {
+ extensionsLength += 5 + len(m.serverName)
+ numExtensions++
+ }
+ if len(m.supportedCurves) > 0 {
+ extensionsLength += 2 + 2*len(m.supportedCurves)
+ numExtensions++
+ }
+ if len(m.supportedPoints) > 0 {
+ extensionsLength += 1 + len(m.supportedPoints)
+ numExtensions++
+ }
+ if numExtensions > 0 {
+ extensionsLength += 4 * numExtensions
+ length += 2 + extensionsLength
+ }
+
+ x := make([]byte, 4+length)
+ x[0] = typeClientHello
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ x[4] = uint8(m.vers >> 8)
+ x[5] = uint8(m.vers)
+ copy(x[6:38], m.random)
+ x[38] = uint8(len(m.sessionId))
+ copy(x[39:39+len(m.sessionId)], m.sessionId)
+ y := x[39+len(m.sessionId):]
+ y[0] = uint8(len(m.cipherSuites) >> 7)
+ y[1] = uint8(len(m.cipherSuites) << 1)
+ for i, suite := range m.cipherSuites {
+ y[2+i*2] = uint8(suite >> 8)
+ y[3+i*2] = uint8(suite)
+ }
+ z := y[2+len(m.cipherSuites)*2:]
+ z[0] = uint8(len(m.compressionMethods))
+ copy(z[1:], m.compressionMethods)
+
+ z = z[1+len(m.compressionMethods):]
+ if numExtensions > 0 {
+ z[0] = byte(extensionsLength >> 8)
+ z[1] = byte(extensionsLength)
+ z = z[2:]
+ }
+ if m.nextProtoNeg {
+ z[0] = byte(extensionNextProtoNeg >> 8)
+ z[1] = byte(extensionNextProtoNeg)
+ // The length is always 0
+ z = z[4:]
+ }
+ if len(m.serverName) > 0 {
+ z[0] = byte(extensionServerName >> 8)
+ z[1] = byte(extensionServerName)
+ l := len(m.serverName) + 5
+ z[2] = byte(l >> 8)
+ z[3] = byte(l)
+ z = z[4:]
+
+ // RFC 3546, section 3.1
+ //
+ // struct {
+ // NameType name_type;
+ // select (name_type) {
+ // case host_name: HostName;
+ // } name;
+ // } ServerName;
+ //
+ // enum {
+ // host_name(0), (255)
+ // } NameType;
+ //
+ // opaque HostName<1..2^16-1>;
+ //
+ // struct {
+ // ServerName server_name_list<1..2^16-1>
+ // } ServerNameList;
+
+ z[0] = byte((len(m.serverName) + 3) >> 8)
+ z[1] = byte(len(m.serverName) + 3)
+ z[3] = byte(len(m.serverName) >> 8)
+ z[4] = byte(len(m.serverName))
+ copy(z[5:], []byte(m.serverName))
+ z = z[l:]
+ }
+ if m.ocspStapling {
+ // RFC 4366, section 3.6
+ z[0] = byte(extensionStatusRequest >> 8)
+ z[1] = byte(extensionStatusRequest)
+ z[2] = 0
+ z[3] = 5
+ z[4] = 1 // OCSP type
+ // Two zero valued uint16s for the two lengths.
+ z = z[9:]
+ }
+ if len(m.supportedCurves) > 0 {
+ // http://tools.ietf.org/html/rfc4492#section-5.5.1
+ z[0] = byte(extensionSupportedCurves >> 8)
+ z[1] = byte(extensionSupportedCurves)
+ l := 2 + 2*len(m.supportedCurves)
+ z[2] = byte(l >> 8)
+ z[3] = byte(l)
+ l -= 2
+ z[4] = byte(l >> 8)
+ z[5] = byte(l)
+ z = z[6:]
+ for _, curve := range m.supportedCurves {
+ z[0] = byte(curve >> 8)
+ z[1] = byte(curve)
+ z = z[2:]
+ }
+ }
+ if len(m.supportedPoints) > 0 {
+ // http://tools.ietf.org/html/rfc4492#section-5.5.2
+ z[0] = byte(extensionSupportedPoints >> 8)
+ z[1] = byte(extensionSupportedPoints)
+ l := 1 + len(m.supportedPoints)
+ z[2] = byte(l >> 8)
+ z[3] = byte(l)
+ l--
+ z[4] = byte(l)
+ z = z[5:]
+ for _, pointFormat := range m.supportedPoints {
+ z[0] = byte(pointFormat)
+ z = z[1:]
+ }
+ }
+
+ m.raw = x
+
+ return x
+}
+
+func (m *clientHelloMsg) unmarshal(data []byte) bool {
+ if len(data) < 42 {
+ return false
+ }
+ m.raw = data
+ m.vers = uint16(data[4])<<8 | uint16(data[5])
+ m.random = data[6:38]
+ sessionIdLen := int(data[38])
+ if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+ return false
+ }
+ m.sessionId = data[39 : 39+sessionIdLen]
+ data = data[39+sessionIdLen:]
+ if len(data) < 2 {
+ return false
+ }
+ // cipherSuiteLen is the number of bytes of cipher suite numbers. Since
+ // they are uint16s, the number must be even.
+ cipherSuiteLen := int(data[0])<<8 | int(data[1])
+ if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen {
+ return false
+ }
+ numCipherSuites := cipherSuiteLen / 2
+ m.cipherSuites = make([]uint16, numCipherSuites)
+ for i := 0; i < numCipherSuites; i++ {
+ m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
+ }
+ data = data[2+cipherSuiteLen:]
+ if len(data) < 1 {
+ return false
+ }
+ compressionMethodsLen := int(data[0])
+ if len(data) < 1+compressionMethodsLen {
+ return false
+ }
+ m.compressionMethods = data[1 : 1+compressionMethodsLen]
+
+ data = data[1+compressionMethodsLen:]
+
+ m.nextProtoNeg = false
+ m.serverName = ""
+ m.ocspStapling = false
+
+ if len(data) == 0 {
+ // ClientHello is optionally followed by extension data
+ return true
+ }
+ if len(data) < 2 {
+ return false
+ }
+
+ extensionsLength := int(data[0])<<8 | int(data[1])
+ data = data[2:]
+ if extensionsLength != len(data) {
+ return false
+ }
+
+ for len(data) != 0 {
+ if len(data) < 4 {
+ return false
+ }
+ extension := uint16(data[0])<<8 | uint16(data[1])
+ length := int(data[2])<<8 | int(data[3])
+ data = data[4:]
+ if len(data) < length {
+ return false
+ }
+
+ switch extension {
+ case extensionServerName:
+ if length < 2 {
+ return false
+ }
+ numNames := int(data[0])<<8 | int(data[1])
+ d := data[2:]
+ for i := 0; i < numNames; i++ {
+ if len(d) < 3 {
+ return false
+ }
+ nameType := d[0]
+ nameLen := int(d[1])<<8 | int(d[2])
+ d = d[3:]
+ if len(d) < nameLen {
+ return false
+ }
+ if nameType == 0 {
+ m.serverName = string(d[0:nameLen])
+ break
+ }
+ d = d[nameLen:]
+ }
+ case extensionNextProtoNeg:
+ if length > 0 {
+ return false
+ }
+ m.nextProtoNeg = true
+ case extensionStatusRequest:
+ m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
+ case extensionSupportedCurves:
+ // http://tools.ietf.org/html/rfc4492#section-5.5.1
+ if length < 2 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ if l%2 == 1 || length != l+2 {
+ return false
+ }
+ numCurves := l / 2
+ m.supportedCurves = make([]uint16, numCurves)
+ d := data[2:]
+ for i := 0; i < numCurves; i++ {
+ m.supportedCurves[i] = uint16(d[0])<<8 | uint16(d[1])
+ d = d[2:]
+ }
+ case extensionSupportedPoints:
+ // http://tools.ietf.org/html/rfc4492#section-5.5.2
+ if length < 1 {
+ return false
+ }
+ l := int(data[0])
+ if length != l+1 {
+ return false
+ }
+ m.supportedPoints = make([]uint8, l)
+ copy(m.supportedPoints, data[1:])
+ }
+ data = data[length:]
+ }
+
+ return true
+}
+
+type serverHelloMsg struct {
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ compressionMethod uint8
+ nextProtoNeg bool
+ nextProtos []string
+ certStatus bool
+}
+
+func (m *serverHelloMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ length := 38 + len(m.sessionId)
+ numExtensions := 0
+ extensionsLength := 0
+
+ nextProtoLen := 0
+ if m.nextProtoNeg {
+ numExtensions++
+ for _, v := range m.nextProtos {
+ nextProtoLen += len(v)
+ }
+ nextProtoLen += len(m.nextProtos)
+ extensionsLength += nextProtoLen
+ }
+ if m.certStatus {
+ numExtensions++
+ }
+ if numExtensions > 0 {
+ extensionsLength += 4 * numExtensions
+ length += 2 + extensionsLength
+ }
+
+ x := make([]byte, 4+length)
+ x[0] = typeServerHello
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ x[4] = uint8(m.vers >> 8)
+ x[5] = uint8(m.vers)
+ copy(x[6:38], m.random)
+ x[38] = uint8(len(m.sessionId))
+ copy(x[39:39+len(m.sessionId)], m.sessionId)
+ z := x[39+len(m.sessionId):]
+ z[0] = uint8(m.cipherSuite >> 8)
+ z[1] = uint8(m.cipherSuite)
+ z[2] = uint8(m.compressionMethod)
+
+ z = z[3:]
+ if numExtensions > 0 {
+ z[0] = byte(extensionsLength >> 8)
+ z[1] = byte(extensionsLength)
+ z = z[2:]
+ }
+ if m.nextProtoNeg {
+ z[0] = byte(extensionNextProtoNeg >> 8)
+ z[1] = byte(extensionNextProtoNeg)
+ z[2] = byte(nextProtoLen >> 8)
+ z[3] = byte(nextProtoLen)
+ z = z[4:]
+
+ for _, v := range m.nextProtos {
+ l := len(v)
+ if l > 255 {
+ l = 255
+ }
+ z[0] = byte(l)
+ copy(z[1:], []byte(v[0:l]))
+ z = z[1+l:]
+ }
+ }
+ if m.certStatus {
+ z[0] = byte(extensionStatusRequest >> 8)
+ z[1] = byte(extensionStatusRequest)
+ z = z[4:]
+ }
+
+ m.raw = x
+
+ return x
+}
+
+func (m *serverHelloMsg) unmarshal(data []byte) bool {
+ if len(data) < 42 {
+ return false
+ }
+ m.raw = data
+ m.vers = uint16(data[4])<<8 | uint16(data[5])
+ m.random = data[6:38]
+ sessionIdLen := int(data[38])
+ if sessionIdLen > 32 || len(data) < 39+sessionIdLen {
+ return false
+ }
+ m.sessionId = data[39 : 39+sessionIdLen]
+ data = data[39+sessionIdLen:]
+ if len(data) < 3 {
+ return false
+ }
+ m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
+ m.compressionMethod = data[2]
+ data = data[3:]
+
+ m.nextProtoNeg = false
+ m.nextProtos = nil
+ m.certStatus = false
+
+ if len(data) == 0 {
+ // ServerHello is optionally followed by extension data
+ return true
+ }
+ if len(data) < 2 {
+ return false
+ }
+
+ extensionsLength := int(data[0])<<8 | int(data[1])
+ data = data[2:]
+ if len(data) != extensionsLength {
+ return false
+ }
+
+ for len(data) != 0 {
+ if len(data) < 4 {
+ return false
+ }
+ extension := uint16(data[0])<<8 | uint16(data[1])
+ length := int(data[2])<<8 | int(data[3])
+ data = data[4:]
+ if len(data) < length {
+ return false
+ }
+
+ switch extension {
+ case extensionNextProtoNeg:
+ m.nextProtoNeg = true
+ d := data
+ for len(d) > 0 {
+ l := int(d[0])
+ d = d[1:]
+ if l == 0 || l > len(d) {
+ return false
+ }
+ m.nextProtos = append(m.nextProtos, string(d[0:l]))
+ d = d[l:]
+ }
+ case extensionStatusRequest:
+ if length > 0 {
+ return false
+ }
+ m.certStatus = true
+ }
+ data = data[length:]
+ }
+
+ return true
+}
+
+type certificateMsg struct {
+ raw []byte
+ certificates [][]byte
+}
+
+func (m *certificateMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ var i int
+ for _, slice := range m.certificates {
+ i += len(slice)
+ }
+
+ length := 3 + 3*len(m.certificates) + i
+ x = make([]byte, 4+length)
+ x[0] = typeCertificate
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ certificateOctets := length - 3
+ x[4] = uint8(certificateOctets >> 16)
+ x[5] = uint8(certificateOctets >> 8)
+ x[6] = uint8(certificateOctets)
+
+ y := x[7:]
+ for _, slice := range m.certificates {
+ y[0] = uint8(len(slice) >> 16)
+ y[1] = uint8(len(slice) >> 8)
+ y[2] = uint8(len(slice))
+ copy(y[3:], slice)
+ y = y[3+len(slice):]
+ }
+
+ m.raw = x
+ return
+}
+
+func (m *certificateMsg) unmarshal(data []byte) bool {
+ if len(data) < 7 {
+ return false
+ }
+
+ m.raw = data
+ certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6])
+ if uint32(len(data)) != certsLen+7 {
+ return false
+ }
+
+ numCerts := 0
+ d := data[7:]
+ for certsLen > 0 {
+ if len(d) < 4 {
+ return false
+ }
+ certLen := uint32(d[0])<<24 | uint32(d[1])<<8 | uint32(d[2])
+ if uint32(len(d)) < 3+certLen {
+ return false
+ }
+ d = d[3+certLen:]
+ certsLen -= 3 + certLen
+ numCerts++
+ }
+
+ m.certificates = make([][]byte, numCerts)
+ d = data[7:]
+ for i := 0; i < numCerts; i++ {
+ certLen := uint32(d[0])<<24 | uint32(d[1])<<8 | uint32(d[2])
+ m.certificates[i] = d[3 : 3+certLen]
+ d = d[3+certLen:]
+ }
+
+ return true
+}
+
+type serverKeyExchangeMsg struct {
+ raw []byte
+ key []byte
+}
+
+func (m *serverKeyExchangeMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+ length := len(m.key)
+ x := make([]byte, length+4)
+ x[0] = typeServerKeyExchange
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ copy(x[4:], m.key)
+
+ m.raw = x
+ return x
+}
+
+func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 4 {
+ return false
+ }
+ m.key = data[4:]
+ return true
+}
+
+type certificateStatusMsg struct {
+ raw []byte
+ statusType uint8
+ response []byte
+}
+
+func (m *certificateStatusMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ var x []byte
+ if m.statusType == statusTypeOCSP {
+ x = make([]byte, 4+4+len(m.response))
+ x[0] = typeCertificateStatus
+ l := len(m.response) + 4
+ x[1] = byte(l >> 16)
+ x[2] = byte(l >> 8)
+ x[3] = byte(l)
+ x[4] = statusTypeOCSP
+
+ l -= 4
+ x[5] = byte(l >> 16)
+ x[6] = byte(l >> 8)
+ x[7] = byte(l)
+ copy(x[8:], m.response)
+ } else {
+ x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType}
+ }
+
+ m.raw = x
+ return x
+}
+
+func (m *certificateStatusMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 5 {
+ return false
+ }
+ m.statusType = data[4]
+
+ m.response = nil
+ if m.statusType == statusTypeOCSP {
+ if len(data) < 8 {
+ return false
+ }
+ respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
+ if uint32(len(data)) != 4+4+respLen {
+ return false
+ }
+ m.response = data[8:]
+ }
+ return true
+}
+
+type serverHelloDoneMsg struct{}
+
+func (m *serverHelloDoneMsg) marshal() []byte {
+ x := make([]byte, 4)
+ x[0] = typeServerHelloDone
+ return x
+}
+
+func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
+ return len(data) == 4
+}
+
+type clientKeyExchangeMsg struct {
+ raw []byte
+ ciphertext []byte
+}
+
+func (m *clientKeyExchangeMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+ length := len(m.ciphertext)
+ x := make([]byte, length+4)
+ x[0] = typeClientKeyExchange
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ copy(x[4:], m.ciphertext)
+
+ m.raw = x
+ return x
+}
+
+func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 4 {
+ return false
+ }
+ l := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if l != len(data)-4 {
+ return false
+ }
+ m.ciphertext = data[4:]
+ return true
+}
+
+type finishedMsg struct {
+ raw []byte
+ verifyData []byte
+}
+
+func (m *finishedMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ x = make([]byte, 16)
+ x[0] = typeFinished
+ x[3] = 12
+ copy(x[4:], m.verifyData)
+ m.raw = x
+ return
+}
+
+func (m *finishedMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) != 4+12 {
+ return false
+ }
+ m.verifyData = data[4:]
+ return true
+}
+
+type nextProtoMsg struct {
+ raw []byte
+ proto string
+}
+
+func (m *nextProtoMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+ l := len(m.proto)
+ if l > 255 {
+ l = 255
+ }
+
+ padding := 32 - (l+2)%32
+ length := l + padding + 2
+ x := make([]byte, length+4)
+ x[0] = typeNextProtocol
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ y := x[4:]
+ y[0] = byte(l)
+ copy(y[1:], []byte(m.proto[0:l]))
+ y = y[1+l:]
+ y[0] = byte(padding)
+
+ m.raw = x
+
+ return x
+}
+
+func (m *nextProtoMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 5 {
+ return false
+ }
+ data = data[4:]
+ protoLen := int(data[0])
+ data = data[1:]
+ if len(data) < protoLen {
+ return false
+ }
+ m.proto = string(data[0:protoLen])
+ data = data[protoLen:]
+
+ if len(data) < 1 {
+ return false
+ }
+ paddingLen := int(data[0])
+ data = data[1:]
+ if len(data) != paddingLen {
+ return false
+ }
+
+ return true
+}
+
+type certificateRequestMsg struct {
+ raw []byte
+ certificateTypes []byte
+ certificateAuthorities [][]byte
+}
+
+func (m *certificateRequestMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ // See http://tools.ietf.org/html/rfc4346#section-7.4.4
+ length := 1 + len(m.certificateTypes) + 2
+ for _, ca := range m.certificateAuthorities {
+ length += 2 + len(ca)
+ }
+
+ x = make([]byte, 4+length)
+ x[0] = typeCertificateRequest
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ x[4] = uint8(len(m.certificateTypes))
+
+ copy(x[5:], m.certificateTypes)
+ y := x[5+len(m.certificateTypes):]
+
+ numCA := len(m.certificateAuthorities)
+ y[0] = uint8(numCA >> 8)
+ y[1] = uint8(numCA)
+ y = y[2:]
+ for _, ca := range m.certificateAuthorities {
+ y[0] = uint8(len(ca) >> 8)
+ y[1] = uint8(len(ca))
+ y = y[2:]
+ copy(y, ca)
+ y = y[len(ca):]
+ }
+
+ m.raw = x
+
+ return
+}
+
+func (m *certificateRequestMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 5 {
+ return false
+ }
+
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ if uint32(len(data))-4 != length {
+ return false
+ }
+
+ numCertTypes := int(data[4])
+ data = data[5:]
+ if numCertTypes == 0 || len(data) <= numCertTypes {
+ return false
+ }
+
+ m.certificateTypes = make([]byte, numCertTypes)
+ if copy(m.certificateTypes, data) != numCertTypes {
+ return false
+ }
+
+ data = data[numCertTypes:]
+ if len(data) < 2 {
+ return false
+ }
+
+ numCAs := uint16(data[0])<<16 | uint16(data[1])
+ data = data[2:]
+
+ m.certificateAuthorities = make([][]byte, numCAs)
+ for i := uint16(0); i < numCAs; i++ {
+ if len(data) < 2 {
+ return false
+ }
+ caLen := uint16(data[0])<<16 | uint16(data[1])
+
+ data = data[2:]
+ if len(data) < int(caLen) {
+ return false
+ }
+
+ ca := make([]byte, caLen)
+ copy(ca, data)
+ m.certificateAuthorities[i] = ca
+ data = data[caLen:]
+ }
+
+ if len(data) > 0 {
+ return false
+ }
+
+ return true
+}
+
+type certificateVerifyMsg struct {
+ raw []byte
+ signature []byte
+}
+
+func (m *certificateVerifyMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ // See http://tools.ietf.org/html/rfc4346#section-7.4.8
+ siglength := len(m.signature)
+ length := 2 + siglength
+ x = make([]byte, 4+length)
+ x[0] = typeCertificateVerify
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ x[4] = uint8(siglength >> 8)
+ x[5] = uint8(siglength)
+ copy(x[6:], m.signature)
+
+ m.raw = x
+
+ return
+}
+
+func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 6 {
+ return false
+ }
+
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ if uint32(len(data))-4 != length {
+ return false
+ }
+
+ siglength := int(data[4])<<8 + int(data[5])
+ if len(data)-6 != siglength {
+ return false
+ }
+
+ m.signature = data[6:]
+
+ return true
+}
diff --git a/libgo/go/crypto/tls/handshake_messages_test.go b/libgo/go/crypto/tls/handshake_messages_test.go
new file mode 100644
index 000000000..21577dd0b
--- /dev/null
+++ b/libgo/go/crypto/tls/handshake_messages_test.go
@@ -0,0 +1,202 @@
+// 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 tls
+
+import (
+ "rand"
+ "reflect"
+ "testing"
+ "testing/quick"
+)
+
+var tests = []interface{}{
+ &clientHelloMsg{},
+ &serverHelloMsg{},
+
+ &certificateMsg{},
+ &certificateRequestMsg{},
+ &certificateVerifyMsg{},
+ &certificateStatusMsg{},
+ &clientKeyExchangeMsg{},
+ &finishedMsg{},
+ &nextProtoMsg{},
+}
+
+type testMessage interface {
+ marshal() []byte
+ unmarshal([]byte) bool
+}
+
+func TestMarshalUnmarshal(t *testing.T) {
+ rand := rand.New(rand.NewSource(0))
+ for i, iface := range tests {
+ ty := reflect.NewValue(iface).Type()
+
+ for j := 0; j < 100; j++ {
+ v, ok := quick.Value(ty, rand)
+ if !ok {
+ t.Errorf("#%d: failed to create value", i)
+ break
+ }
+
+ m1 := v.Interface().(testMessage)
+ marshaled := m1.marshal()
+ m2 := iface.(testMessage)
+ if !m2.unmarshal(marshaled) {
+ t.Errorf("#%d failed to unmarshal %#v %x", i, m1, marshaled)
+ break
+ }
+ m2.marshal() // to fill any marshal cache in the message
+
+ if !reflect.DeepEqual(m1, m2) {
+ t.Errorf("#%d got:%#v want:%#v %x", i, m2, m1, marshaled)
+ break
+ }
+
+ if i >= 2 {
+ // The first two message types (ClientHello and
+ // ServerHello) are allowed to have parsable
+ // prefixes because the extension data is
+ // optional.
+ for j := 0; j < len(marshaled); j++ {
+ if m2.unmarshal(marshaled[0:j]) {
+ t.Errorf("#%d unmarshaled a prefix of length %d of %#v", i, j, m1)
+ break
+ }
+ }
+ }
+ }
+ }
+}
+
+func TestFuzz(t *testing.T) {
+ rand := rand.New(rand.NewSource(0))
+ for _, iface := range tests {
+ m := iface.(testMessage)
+
+ for j := 0; j < 1000; j++ {
+ len := rand.Intn(100)
+ bytes := randomBytes(len, rand)
+ // This just looks for crashes due to bounds errors etc.
+ m.unmarshal(bytes)
+ }
+ }
+}
+
+func randomBytes(n int, rand *rand.Rand) []byte {
+ r := make([]byte, n)
+ for i := 0; i < n; i++ {
+ r[i] = byte(rand.Int31())
+ }
+ return r
+}
+
+func randomString(n int, rand *rand.Rand) string {
+ b := randomBytes(n, rand)
+ return string(b)
+}
+
+func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &clientHelloMsg{}
+ m.vers = uint16(rand.Intn(65536))
+ m.random = randomBytes(32, rand)
+ m.sessionId = randomBytes(rand.Intn(32), rand)
+ m.cipherSuites = make([]uint16, rand.Intn(63)+1)
+ for i := 0; i < len(m.cipherSuites); i++ {
+ m.cipherSuites[i] = uint16(rand.Int31())
+ }
+ m.compressionMethods = randomBytes(rand.Intn(63)+1, rand)
+ if rand.Intn(10) > 5 {
+ m.nextProtoNeg = true
+ }
+ if rand.Intn(10) > 5 {
+ m.serverName = randomString(rand.Intn(255), rand)
+ }
+ m.ocspStapling = rand.Intn(10) > 5
+ m.supportedPoints = randomBytes(rand.Intn(5)+1, rand)
+ m.supportedCurves = make([]uint16, rand.Intn(5)+1)
+ for i, _ := range m.supportedCurves {
+ m.supportedCurves[i] = uint16(rand.Intn(30000))
+ }
+
+ return reflect.NewValue(m)
+}
+
+func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &serverHelloMsg{}
+ m.vers = uint16(rand.Intn(65536))
+ m.random = randomBytes(32, rand)
+ m.sessionId = randomBytes(rand.Intn(32), rand)
+ m.cipherSuite = uint16(rand.Int31())
+ m.compressionMethod = uint8(rand.Intn(256))
+
+ if rand.Intn(10) > 5 {
+ m.nextProtoNeg = true
+
+ n := rand.Intn(10)
+ m.nextProtos = make([]string, n)
+ for i := 0; i < n; i++ {
+ m.nextProtos[i] = randomString(20, rand)
+ }
+ }
+
+ return reflect.NewValue(m)
+}
+
+func (*certificateMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateMsg{}
+ numCerts := rand.Intn(20)
+ m.certificates = make([][]byte, numCerts)
+ for i := 0; i < numCerts; i++ {
+ m.certificates[i] = randomBytes(rand.Intn(10)+1, rand)
+ }
+ return reflect.NewValue(m)
+}
+
+func (*certificateRequestMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateRequestMsg{}
+ m.certificateTypes = randomBytes(rand.Intn(5)+1, rand)
+ numCAs := rand.Intn(100)
+ m.certificateAuthorities = make([][]byte, numCAs)
+ for i := 0; i < numCAs; i++ {
+ m.certificateAuthorities[i] = randomBytes(rand.Intn(15)+1, rand)
+ }
+ return reflect.NewValue(m)
+}
+
+func (*certificateVerifyMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateVerifyMsg{}
+ m.signature = randomBytes(rand.Intn(15)+1, rand)
+ return reflect.NewValue(m)
+}
+
+func (*certificateStatusMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateStatusMsg{}
+ if rand.Intn(10) > 5 {
+ m.statusType = statusTypeOCSP
+ m.response = randomBytes(rand.Intn(10)+1, rand)
+ } else {
+ m.statusType = 42
+ }
+ return reflect.NewValue(m)
+}
+
+func (*clientKeyExchangeMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &clientKeyExchangeMsg{}
+ m.ciphertext = randomBytes(rand.Intn(1000)+1, rand)
+ return reflect.NewValue(m)
+}
+
+func (*finishedMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &finishedMsg{}
+ m.verifyData = randomBytes(12, rand)
+ return reflect.NewValue(m)
+}
+
+func (*nextProtoMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &nextProtoMsg{}
+ m.proto = randomString(rand.Intn(255), rand)
+ return reflect.NewValue(m)
+}
diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go
new file mode 100644
index 000000000..955811ada
--- /dev/null
+++ b/libgo/go/crypto/tls/handshake_server.go
@@ -0,0 +1,285 @@
+// 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 tls
+
+import (
+ "crypto/rsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "io"
+ "os"
+)
+
+func (c *Conn) serverHandshake() os.Error {
+ config := c.config
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ clientHello, ok := msg.(*clientHelloMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ vers, ok := mutualVersion(clientHello.vers)
+ if !ok {
+ return c.sendAlert(alertProtocolVersion)
+ }
+ c.vers = vers
+ c.haveVers = true
+
+ finishedHash := newFinishedHash()
+ finishedHash.Write(clientHello.marshal())
+
+ hello := new(serverHelloMsg)
+
+ supportedCurve := false
+Curves:
+ for _, curve := range clientHello.supportedCurves {
+ switch curve {
+ case curveP256, curveP384, curveP521:
+ supportedCurve = true
+ break Curves
+ }
+ }
+
+ supportedPointFormat := false
+ for _, pointFormat := range clientHello.supportedPoints {
+ if pointFormat == pointFormatUncompressed {
+ supportedPointFormat = true
+ break
+ }
+ }
+
+ ellipticOk := supportedCurve && supportedPointFormat
+
+ var suite *cipherSuite
+ var suiteId uint16
+ for _, id := range clientHello.cipherSuites {
+ for _, supported := range config.cipherSuites() {
+ if id == supported {
+ suite = cipherSuites[id]
+ // Don't select a ciphersuite which we can't
+ // support for this client.
+ if suite.elliptic && !ellipticOk {
+ continue
+ }
+ suiteId = id
+ break
+ }
+ }
+ }
+
+ foundCompression := false
+ // We only support null compression, so check that the client offered it.
+ for _, compression := range clientHello.compressionMethods {
+ if compression == compressionNone {
+ foundCompression = true
+ break
+ }
+ }
+
+ if suite == nil || !foundCompression {
+ return c.sendAlert(alertHandshakeFailure)
+ }
+
+ hello.vers = vers
+ hello.cipherSuite = suiteId
+ t := uint32(config.time())
+ hello.random = make([]byte, 32)
+ hello.random[0] = byte(t >> 24)
+ hello.random[1] = byte(t >> 16)
+ hello.random[2] = byte(t >> 8)
+ hello.random[3] = byte(t)
+ _, err = io.ReadFull(config.rand(), hello.random[4:])
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ hello.compressionMethod = compressionNone
+ if clientHello.nextProtoNeg {
+ hello.nextProtoNeg = true
+ hello.nextProtos = config.NextProtos
+ }
+
+ finishedHash.Write(hello.marshal())
+ c.writeRecord(recordTypeHandshake, hello.marshal())
+
+ if len(config.Certificates) == 0 {
+ return c.sendAlert(alertInternalError)
+ }
+
+ certMsg := new(certificateMsg)
+ certMsg.certificates = config.Certificates[0].Certificate
+ finishedHash.Write(certMsg.marshal())
+ c.writeRecord(recordTypeHandshake, certMsg.marshal())
+
+ keyAgreement := suite.ka()
+
+ skx, err := keyAgreement.generateServerKeyExchange(config, clientHello, hello)
+ if err != nil {
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+ if skx != nil {
+ finishedHash.Write(skx.marshal())
+ c.writeRecord(recordTypeHandshake, skx.marshal())
+ }
+
+ if config.AuthenticateClient {
+ // Request a client certificate
+ certReq := new(certificateRequestMsg)
+ certReq.certificateTypes = []byte{certTypeRSASign}
+ // An empty list of certificateAuthorities signals to
+ // the client that it may send any certificate in response
+ // to our request.
+
+ finishedHash.Write(certReq.marshal())
+ c.writeRecord(recordTypeHandshake, certReq.marshal())
+ }
+
+ helloDone := new(serverHelloDoneMsg)
+ finishedHash.Write(helloDone.marshal())
+ c.writeRecord(recordTypeHandshake, helloDone.marshal())
+
+ var pub *rsa.PublicKey
+ if config.AuthenticateClient {
+ // Get client certificate
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ certMsg, ok = msg.(*certificateMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(certMsg.marshal())
+
+ certs := make([]*x509.Certificate, len(certMsg.certificates))
+ for i, asn1Data := range certMsg.certificates {
+ cert, err := x509.ParseCertificate(asn1Data)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return os.ErrorString("could not parse client's certificate: " + err.String())
+ }
+ certs[i] = cert
+ }
+
+ // TODO(agl): do better validation of certs: max path length, name restrictions etc.
+ 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())
+ }
+ }
+
+ if len(certs) > 0 {
+ key, ok := certs[0].PublicKey.(*rsa.PublicKey)
+ if !ok {
+ return c.sendAlert(alertUnsupportedCertificate)
+ }
+ pub = key
+ c.peerCertificates = certs
+ }
+ }
+
+ // Get client key exchange
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ ckx, ok := msg.(*clientKeyExchangeMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(ckx.marshal())
+
+ // If we received a client cert in response to our certificate request message,
+ // the client will send us a certificateVerifyMsg immediately after the
+ // clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceeding
+ // handshake-layer messages that is signed using the private key corresponding
+ // to the client's certificate. This allows us to verify that the client is in
+ // posession of the private key of the certificate.
+ if len(c.peerCertificates) > 0 {
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ certVerify, ok := msg.(*certificateVerifyMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+
+ digest := make([]byte, 36)
+ copy(digest[0:16], finishedHash.serverMD5.Sum())
+ copy(digest[16:36], finishedHash.serverSHA1.Sum())
+ err = rsa.VerifyPKCS1v15(pub, rsa.HashMD5SHA1, digest, certVerify.signature)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return os.ErrorString("could not validate signature of connection nonces: " + err.String())
+ }
+
+ finishedHash.Write(certVerify.marshal())
+ }
+
+ preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx)
+ if err != nil {
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+
+ masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromPreMasterSecret10(preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)
+
+ clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */ )
+ clientHash := suite.mac(clientMAC)
+ c.in.prepareCipherSpec(clientCipher, clientHash)
+ c.readRecord(recordTypeChangeCipherSpec)
+ if err := c.error(); err != nil {
+ return err
+ }
+
+ if hello.nextProtoNeg {
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ nextProto, ok := msg.(*nextProtoMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(nextProto.marshal())
+ c.clientProtocol = nextProto.proto
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ clientFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+
+ verify := finishedHash.clientSum(masterSecret)
+ if len(verify) != len(clientFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
+ return c.sendAlert(alertHandshakeFailure)
+ }
+
+ finishedHash.Write(clientFinished.marshal())
+
+ serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */ )
+ serverHash := suite.mac(serverMAC)
+ c.out.prepareCipherSpec(serverCipher, serverHash)
+ c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+
+ finished := new(finishedMsg)
+ finished.verifyData = finishedHash.serverSum(masterSecret)
+ c.writeRecord(recordTypeHandshake, finished.marshal())
+
+ c.handshakeComplete = true
+ c.cipherSuite = suiteId
+
+ return nil
+}
diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go
new file mode 100644
index 000000000..5cf3ae049
--- /dev/null
+++ b/libgo/go/crypto/tls/handshake_server_test.go
@@ -0,0 +1,516 @@
+// 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 tls
+
+import (
+ "big"
+ "bytes"
+ "crypto/rsa"
+ "encoding/hex"
+ "flag"
+ "io"
+ "net"
+ "os"
+ "testing"
+)
+
+type zeroSource struct{}
+
+func (zeroSource) Read(b []byte) (n int, err os.Error) {
+ for i := range b {
+ b[i] = 0
+ }
+
+ return len(b), nil
+}
+
+var testConfig *Config
+
+func init() {
+ testConfig = new(Config)
+ testConfig.Time = func() int64 { return 0 }
+ testConfig.Rand = zeroSource{}
+ testConfig.Certificates = make([]Certificate, 1)
+ testConfig.Certificates[0].Certificate = [][]byte{testCertificate}
+ testConfig.Certificates[0].PrivateKey = testPrivateKey
+ testConfig.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
+}
+
+func testClientHelloFailure(t *testing.T, m handshakeMessage, expected os.Error) {
+ // Create in-memory network connection,
+ // send message to server. Should return
+ // expected error.
+ c, s := net.Pipe()
+ go func() {
+ cli := Client(c, testConfig)
+ if ch, ok := m.(*clientHelloMsg); ok {
+ cli.vers = ch.vers
+ }
+ cli.writeRecord(recordTypeHandshake, m.marshal())
+ c.Close()
+ }()
+ err := Server(s, testConfig).Handshake()
+ s.Close()
+ if e, ok := err.(*net.OpError); !ok || e.Error != expected {
+ t.Errorf("Got error: %s; expected: %s", err, expected)
+ }
+}
+
+func TestSimpleError(t *testing.T) {
+ testClientHelloFailure(t, &serverHelloDoneMsg{}, alertUnexpectedMessage)
+}
+
+var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205, 0x0300}
+
+func TestRejectBadProtocolVersion(t *testing.T) {
+ for _, v := range badProtocolVersions {
+ testClientHelloFailure(t, &clientHelloMsg{vers: v}, alertProtocolVersion)
+ }
+}
+
+func TestNoSuiteOverlap(t *testing.T) {
+ clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{0xff00}, []uint8{0}, false, "", false, nil, nil}
+ testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+
+}
+
+func TestNoCompressionOverlap(t *testing.T) {
+ clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{TLS_RSA_WITH_RC4_128_SHA}, []uint8{0xff}, false, "", false, nil, nil}
+ testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+}
+
+func TestAlertForwarding(t *testing.T) {
+ c, s := net.Pipe()
+ go func() {
+ Client(c, testConfig).sendAlert(alertUnknownCA)
+ c.Close()
+ }()
+
+ err := Server(s, testConfig).Handshake()
+ s.Close()
+ if e, ok := err.(*net.OpError); !ok || e.Error != os.Error(alertUnknownCA) {
+ t.Errorf("Got error: %s; expected: %s", err, alertUnknownCA)
+ }
+}
+
+func TestClose(t *testing.T) {
+ c, s := net.Pipe()
+ go c.Close()
+
+ err := Server(s, testConfig).Handshake()
+ s.Close()
+ if err != os.EOF {
+ t.Errorf("Got error: %s; expected: %s", err, os.EOF)
+ }
+}
+
+
+func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config) {
+ c, s := net.Pipe()
+ srv := Server(s, config)
+ go func() {
+ srv.Write([]byte("hello, world\n"))
+ srv.Close()
+ }()
+
+ defer c.Close()
+ for i, b := range serverScript {
+ if i%2 == 0 {
+ c.Write(b)
+ continue
+ }
+ bb := make([]byte, len(b))
+ _, err := io.ReadFull(c, bb)
+ if err != nil {
+ t.Fatalf("%s #%d: %s", name, i, err)
+ }
+ if !bytes.Equal(b, bb) {
+ t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
+ }
+ }
+}
+
+func TestHandshakeServerRC4(t *testing.T) {
+ testServerScript(t, "RC4", rc4ServerScript, testConfig)
+}
+
+func TestHandshakeServerAES(t *testing.T) {
+ aesConfig := new(Config)
+ *aesConfig = *testConfig
+ aesConfig.CipherSuites = []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}
+ testServerScript(t, "AES", aesServerScript, aesConfig)
+}
+
+var serve = flag.Bool("serve", false, "run a TLS server on :10443")
+
+func TestRunServer(t *testing.T) {
+ if !*serve {
+ return
+ }
+
+ l, err := Listen("tcp", ":10443", testConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for {
+ c, err := l.Accept()
+ if err != nil {
+ break
+ }
+ _, err = c.Write([]byte("hello, world\n"))
+ if err != nil {
+ t.Errorf("error from TLS: %s", err)
+ break
+ }
+ c.Close()
+ }
+}
+
+func bigFromString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 10)
+ return ret
+}
+
+func fromHex(s string) []byte {
+ b, _ := hex.DecodeString(s)
+ return b
+}
+
+var testCertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")
+
+var testPrivateKey = &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
+ E: 65537,
+ },
+ D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
+ P: bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
+ Q: bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
+}
+
+// Script of interaction with gnutls implementation.
+// The values for this test are obtained by building and running in server mode:
+// % gotest -match "TestRunServer" -serve
+// and then:
+// % gnutls-cli --insecure --debug 100 -p 10443 localhost > /tmp/log 2>&1
+// % python parse-gnutls-cli-debug-log.py < /tmp/log
+var rc4ServerScript = [][]byte{
+ {
+ 0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00,
+ 0x7b, 0x03, 0x02, 0x4d, 0x08, 0x1f, 0x5a, 0x7a,
+ 0x0a, 0x92, 0x2f, 0xf0, 0x73, 0x16, 0x3a, 0x88,
+ 0x14, 0x85, 0x4c, 0x98, 0x15, 0x7b, 0x65, 0xe0,
+ 0x78, 0xd0, 0xed, 0xd0, 0xf3, 0x65, 0x20, 0xeb,
+ 0x80, 0xd1, 0x0b, 0x00, 0x00, 0x34, 0x00, 0x33,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+ 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+ 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+ 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+ 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+ 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+ 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09,
+ 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff,
+ 0x01, 0x00, 0x01, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+ 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
+ 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
+ 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
+ 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
+ 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+ 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
+ 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
+ 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
+ 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
+ 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
+ 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+ 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+ 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
+ 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
+ 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
+ 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
+ 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
+ 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
+ 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
+ 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
+ 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
+ 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
+ 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
+ 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
+ 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
+ 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
+ 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
+ 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
+ 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
+ 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
+ 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
+ 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
+ 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
+ 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
+ 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
+ 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
+ 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+ 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
+ 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
+ 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
+ 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
+ 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
+ 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
+ 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
+ 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
+ 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
+ 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
+ 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
+ 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
+ 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
+ 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
+ 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
+ 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
+ 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
+ 0x00, 0x00, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
+ 0x82, 0x00, 0x80, 0x3c, 0x13, 0xd7, 0x12, 0xc1,
+ 0x6a, 0xf0, 0x3f, 0x8c, 0xa1, 0x35, 0x5d, 0xc5,
+ 0x89, 0x1e, 0x9e, 0xcd, 0x32, 0xc7, 0x9e, 0xe6,
+ 0xae, 0xd5, 0xf1, 0xbf, 0x70, 0xd7, 0xa9, 0xef,
+ 0x2c, 0x4c, 0xf4, 0x22, 0xbc, 0x17, 0x17, 0xaa,
+ 0x05, 0xf3, 0x9f, 0x80, 0xf2, 0xe9, 0x82, 0x2f,
+ 0x2a, 0x15, 0x54, 0x0d, 0x16, 0x0e, 0x77, 0x4c,
+ 0x28, 0x3c, 0x03, 0x2d, 0x2d, 0xd7, 0xc8, 0x64,
+ 0xd9, 0x59, 0x4b, 0x1c, 0xf4, 0xde, 0xff, 0x2f,
+ 0xbc, 0x94, 0xaf, 0x18, 0x26, 0x37, 0xce, 0x4f,
+ 0x84, 0x74, 0x2e, 0x45, 0x66, 0x7c, 0x0c, 0x54,
+ 0x46, 0x36, 0x5f, 0x65, 0x21, 0x7b, 0x83, 0x8c,
+ 0x6d, 0x76, 0xcd, 0x0d, 0x9f, 0xda, 0x1c, 0xa4,
+ 0x6e, 0xfe, 0xb1, 0xf7, 0x09, 0x0d, 0xfb, 0x74,
+ 0x66, 0x34, 0x99, 0x89, 0x7f, 0x5f, 0x77, 0x87,
+ 0x4a, 0x66, 0x4b, 0xa9, 0x59, 0x57, 0xe3, 0x56,
+ 0x0d, 0xdd, 0xd8, 0x14, 0x03, 0x01, 0x00, 0x01,
+ 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc0, 0x4e,
+ 0xd3, 0x0f, 0xb5, 0xc0, 0x57, 0xa6, 0x18, 0x80,
+ 0x80, 0x6b, 0x49, 0xfe, 0xbd, 0x3a, 0x7a, 0x2c,
+ 0xef, 0x70, 0xb5, 0x1c, 0xd2, 0xdf, 0x5f, 0x78,
+ 0x5a, 0xd8, 0x4f, 0xa0, 0x95, 0xb4, 0xb3, 0xb5,
+ 0xaa, 0x3b,
+ },
+
+ {
+ 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x01, 0x00, 0x24, 0x9d, 0xc9, 0xda, 0xdf, 0xeb,
+ 0xc8, 0xdb, 0xf8, 0x94, 0xa5, 0xef, 0xd5, 0xfc,
+ 0x89, 0x01, 0x64, 0x30, 0x77, 0x5a, 0x18, 0x4b,
+ 0x16, 0x79, 0x9c, 0xf6, 0xf5, 0x09, 0x22, 0x12,
+ 0x4c, 0x3e, 0xa8, 0x8e, 0x91, 0xa5, 0x24,
+ },
+}
+
+var aesServerScript = [][]byte{
+ {
+ 0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00,
+ 0x7b, 0x03, 0x02, 0x4d, 0x08, 0x2d, 0x0b, 0xb3,
+ 0x57, 0x85, 0x71, 0x4b, 0xfb, 0x34, 0xab, 0x16,
+ 0xd4, 0x92, 0x50, 0x81, 0x16, 0x95, 0x11, 0x28,
+ 0x1a, 0xcb, 0xff, 0x09, 0x4d, 0x23, 0xa6, 0xfe,
+ 0x2e, 0xbb, 0x78, 0x00, 0x00, 0x34, 0x00, 0x33,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+ 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+ 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+ 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+ 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+ 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+ 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09,
+ 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff,
+ 0x01, 0x00, 0x01, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+ 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x16,
+ 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
+ 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
+ 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
+ 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+ 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
+ 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
+ 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
+ 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
+ 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
+ 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+ 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+ 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
+ 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
+ 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
+ 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
+ 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
+ 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
+ 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
+ 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
+ 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
+ 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
+ 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
+ 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
+ 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
+ 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
+ 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
+ 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
+ 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
+ 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
+ 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
+ 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
+ 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
+ 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
+ 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
+ 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
+ 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+ 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
+ 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
+ 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
+ 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
+ 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
+ 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
+ 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
+ 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
+ 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
+ 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
+ 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
+ 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
+ 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
+ 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
+ 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
+ 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
+ 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
+ 0x00, 0x00, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
+ 0x82, 0x00, 0x80, 0x71, 0x9c, 0xe7, 0x23, 0xfc,
+ 0xb9, 0x19, 0x29, 0x82, 0xbf, 0xef, 0x08, 0xf7,
+ 0x99, 0x36, 0xc3, 0x4c, 0x6f, 0x05, 0xd2, 0x8b,
+ 0x62, 0x2b, 0x19, 0x9b, 0x7f, 0xc0, 0xcc, 0x48,
+ 0x30, 0x5f, 0xcd, 0xc3, 0x70, 0x55, 0x53, 0x73,
+ 0xfa, 0x79, 0x74, 0xf3, 0xa3, 0x76, 0x9f, 0xa1,
+ 0x7f, 0x98, 0xc2, 0xc0, 0xe3, 0xc5, 0xa0, 0x31,
+ 0x2f, 0xa6, 0xe8, 0x1e, 0x61, 0x46, 0xb3, 0x9b,
+ 0x4b, 0x16, 0xf1, 0x2d, 0xc7, 0x63, 0x7f, 0x79,
+ 0x22, 0x30, 0xd1, 0xf2, 0xfc, 0x77, 0x98, 0x0a,
+ 0x16, 0x11, 0x63, 0x71, 0x7f, 0x70, 0xef, 0x16,
+ 0xbb, 0x39, 0x87, 0x34, 0xac, 0x49, 0xbd, 0x07,
+ 0x67, 0xcb, 0x9c, 0xcc, 0xde, 0xef, 0xb1, 0xe0,
+ 0xdb, 0x01, 0xb5, 0x35, 0xa9, 0xb3, 0x10, 0x0c,
+ 0x4b, 0xee, 0xb3, 0x4e, 0xfd, 0xbe, 0x15, 0x27,
+ 0xf0, 0x46, 0xb2, 0x38, 0xba, 0x5f, 0xcc, 0x89,
+ 0xec, 0x29, 0x82, 0x14, 0x03, 0x01, 0x00, 0x01,
+ 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x3c, 0xfb,
+ 0xa4, 0x12, 0xcb, 0x00, 0xf9, 0x57, 0x7e, 0x9b,
+ 0xc9, 0xdc, 0x0c, 0xba, 0x9a, 0x81, 0x62, 0xfb,
+ 0x26, 0x13, 0x53, 0xfe, 0xaa, 0xcc, 0x82, 0xbb,
+ 0xb6, 0x67, 0x7f, 0x39, 0xbe, 0x4d, 0xbb, 0xc0,
+ 0x6c, 0x24, 0x31, 0x83, 0xa5, 0x50, 0x3a, 0x75,
+ 0x32, 0x64, 0xb5, 0xdb, 0xbe, 0x0a,
+ },
+
+ {
+ 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x01, 0x00, 0x30, 0x43, 0x24, 0x42, 0x55, 0x08,
+ 0xe4, 0xc2, 0x15, 0xc9, 0xdb, 0x71, 0x69, 0xee,
+ 0x09, 0xc5, 0x1c, 0xfd, 0x46, 0x10, 0xa0, 0x68,
+ 0x21, 0xf2, 0x48, 0xac, 0x6c, 0xc0, 0x2b, 0x62,
+ 0x07, 0x8f, 0x48, 0x33, 0x0a, 0x6b, 0x62, 0x28,
+ 0x2e, 0x2c, 0xad, 0xcb, 0x34, 0x85, 0xca, 0x2e,
+ 0xcd, 0x84, 0xf0,
+ },
+}
diff --git a/libgo/go/crypto/tls/key_agreement.go b/libgo/go/crypto/tls/key_agreement.go
new file mode 100644
index 000000000..861c64f04
--- /dev/null
+++ b/libgo/go/crypto/tls/key_agreement.go
@@ -0,0 +1,246 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "big"
+ "crypto/elliptic"
+ "crypto/md5"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/x509"
+ "io"
+ "os"
+)
+
+// rsaKeyAgreement implements the standard TLS key agreement where the client
+// encrypts the pre-master secret to the server's public key.
+type rsaKeyAgreement struct{}
+
+func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, os.Error) {
+ return nil, nil
+}
+
+func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) {
+ preMasterSecret := make([]byte, 48)
+ _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+ if err != nil {
+ return nil, err
+ }
+
+ if len(ckx.ciphertext) < 2 {
+ return nil, os.ErrorString("bad ClientKeyExchange")
+ }
+ ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
+ if ciphertextLen != len(ckx.ciphertext)-2 {
+ return nil, os.ErrorString("bad ClientKeyExchange")
+ }
+ ciphertext := ckx.ciphertext[2:]
+
+ err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ciphertext, preMasterSecret)
+ if err != nil {
+ return nil, err
+ }
+ // We don't check the version number in the premaster secret. For one,
+ // by checking it, we would leak information about the validity of the
+ // encrypted pre-master secret. Secondly, it provides only a small
+ // benefit against a downgrade attack and some implementations send the
+ // wrong version anyway. See the discussion at the end of section
+ // 7.4.7.1 of RFC 4346.
+ return preMasterSecret, nil
+}
+
+func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
+ return os.ErrorString("unexpected ServerKeyExchange")
+}
+
+func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
+ preMasterSecret := make([]byte, 48)
+ preMasterSecret[0] = byte(clientHello.vers >> 8)
+ preMasterSecret[1] = byte(clientHello.vers)
+ _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+ if err != nil {
+ return nil, nil, err
+ }
+
+ encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret)
+ if err != nil {
+ return nil, nil, err
+ }
+ ckx := new(clientKeyExchangeMsg)
+ ckx.ciphertext = make([]byte, len(encrypted)+2)
+ ckx.ciphertext[0] = byte(len(encrypted) >> 8)
+ ckx.ciphertext[1] = byte(len(encrypted))
+ copy(ckx.ciphertext[2:], encrypted)
+ return preMasterSecret, ckx, nil
+}
+
+
+// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the
+// concatenation of an MD5 and SHA1 hash.
+func md5SHA1Hash(slices ...[]byte) []byte {
+ md5sha1 := make([]byte, md5.Size+sha1.Size)
+ hmd5 := md5.New()
+ for _, slice := range slices {
+ hmd5.Write(slice)
+ }
+ copy(md5sha1, hmd5.Sum())
+
+ hsha1 := sha1.New()
+ for _, slice := range slices {
+ hsha1.Write(slice)
+ }
+ copy(md5sha1[md5.Size:], hsha1.Sum())
+ return md5sha1
+}
+
+// ecdheRSAKeyAgreement implements a TLS key agreement where the server
+// generates a ephemeral EC public/private key pair and signs it. The
+// pre-master secret is then calculated using ECDH.
+type ecdheRSAKeyAgreement struct {
+ privateKey []byte
+ curve *elliptic.Curve
+ x, y *big.Int
+}
+
+func (ka *ecdheRSAKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, os.Error) {
+ var curveid uint16
+
+Curve:
+ for _, c := range clientHello.supportedCurves {
+ switch c {
+ case curveP256:
+ ka.curve = elliptic.P256()
+ curveid = c
+ break Curve
+ case curveP384:
+ ka.curve = elliptic.P384()
+ curveid = c
+ break Curve
+ case curveP521:
+ ka.curve = elliptic.P521()
+ curveid = c
+ break Curve
+ }
+ }
+
+ var x, y *big.Int
+ var err os.Error
+ ka.privateKey, x, y, err = ka.curve.GenerateKey(config.rand())
+ if err != nil {
+ return nil, err
+ }
+ ecdhePublic := ka.curve.Marshal(x, y)
+
+ // http://tools.ietf.org/html/rfc4492#section-5.4
+ serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic))
+ serverECDHParams[0] = 3 // named curve
+ serverECDHParams[1] = byte(curveid >> 8)
+ serverECDHParams[2] = byte(curveid)
+ serverECDHParams[3] = byte(len(ecdhePublic))
+ copy(serverECDHParams[4:], ecdhePublic)
+
+ md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
+ sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, rsa.HashMD5SHA1, md5sha1)
+ if err != nil {
+ return nil, os.ErrorString("failed to sign ECDHE parameters: " + err.String())
+ }
+
+ skx := new(serverKeyExchangeMsg)
+ skx.key = make([]byte, len(serverECDHParams)+2+len(sig))
+ copy(skx.key, serverECDHParams)
+ k := skx.key[len(serverECDHParams):]
+ k[0] = byte(len(sig) >> 8)
+ k[1] = byte(len(sig))
+ copy(k[2:], sig)
+
+ return skx, nil
+}
+
+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")
+ }
+ x, y := ka.curve.Unmarshal(ckx.ciphertext[1:])
+ if x == nil {
+ return nil, os.ErrorString("bad ClientKeyExchange")
+ }
+ x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
+ preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3)
+ xBytes := x.Bytes()
+ copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
+
+ return preMasterSecret, nil
+}
+
+func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
+ if len(skx.key) < 4 {
+ goto Error
+ }
+ if skx.key[0] != 3 { // named curve
+ return os.ErrorString("server selected unsupported curve")
+ }
+ curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2])
+
+ switch curveid {
+ case curveP256:
+ ka.curve = elliptic.P256()
+ case curveP384:
+ ka.curve = elliptic.P384()
+ case curveP521:
+ ka.curve = elliptic.P521()
+ default:
+ return os.ErrorString("server selected unsupported curve")
+ }
+
+ publicLen := int(skx.key[3])
+ if publicLen+4 > len(skx.key) {
+ goto Error
+ }
+ ka.x, ka.y = ka.curve.Unmarshal(skx.key[4 : 4+publicLen])
+ if ka.x == nil {
+ goto Error
+ }
+ serverECDHParams := skx.key[:4+publicLen]
+
+ sig := skx.key[4+publicLen:]
+ if len(sig) < 2 {
+ goto Error
+ }
+ sigLen := int(sig[0])<<8 | int(sig[1])
+ if sigLen+2 != len(sig) {
+ goto Error
+ }
+ sig = sig[2:]
+
+ md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams)
+ return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), rsa.HashMD5SHA1, 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")
+ }
+ priv, mx, my, err := ka.curve.GenerateKey(config.rand())
+ if err != nil {
+ return nil, nil, err
+ }
+ x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv)
+ preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3)
+ xBytes := x.Bytes()
+ copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
+
+ serialised := ka.curve.Marshal(mx, my)
+
+ ckx := new(clientKeyExchangeMsg)
+ ckx.ciphertext = make([]byte, 1+len(serialised))
+ ckx.ciphertext[0] = byte(len(serialised))
+ copy(ckx.ciphertext[1:], serialised)
+
+ return preMasterSecret, ckx, nil
+}
diff --git a/libgo/go/crypto/tls/prf.go b/libgo/go/crypto/tls/prf.go
new file mode 100644
index 000000000..478cf65f9
--- /dev/null
+++ b/libgo/go/crypto/tls/prf.go
@@ -0,0 +1,153 @@
+// 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 tls
+
+import (
+ "crypto/hmac"
+ "crypto/md5"
+ "crypto/sha1"
+ "hash"
+ "os"
+)
+
+// Split a premaster secret in two as specified in RFC 4346, section 5.
+func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
+ s1 = secret[0 : (len(secret)+1)/2]
+ s2 = secret[len(secret)/2:]
+ return
+}
+
+// pHash implements the P_hash function, as defined in RFC 4346, section 5.
+func pHash(result, secret, seed []byte, hash func() hash.Hash) {
+ h := hmac.New(hash, secret)
+ h.Write(seed)
+ a := h.Sum()
+
+ j := 0
+ for j < len(result) {
+ h.Reset()
+ h.Write(a)
+ h.Write(seed)
+ b := h.Sum()
+ todo := len(b)
+ if j+todo > len(result) {
+ todo = len(result) - j
+ }
+ copy(result[j:j+todo], b)
+ j += todo
+
+ h.Reset()
+ h.Write(a)
+ a = h.Sum()
+ }
+}
+
+// pRF10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
+func pRF10(result, secret, label, seed []byte) {
+ hashSHA1 := sha1.New
+ hashMD5 := md5.New
+
+ labelAndSeed := make([]byte, len(label)+len(seed))
+ copy(labelAndSeed, label)
+ copy(labelAndSeed[len(label):], seed)
+
+ s1, s2 := splitPreMasterSecret(secret)
+ pHash(result, s1, labelAndSeed, hashMD5)
+ result2 := make([]byte, len(result))
+ pHash(result2, s2, labelAndSeed, hashSHA1)
+
+ for i, b := range result2 {
+ result[i] ^= b
+ }
+}
+
+const (
+ tlsRandomLength = 32 // Length of a random nonce in TLS 1.1.
+ masterSecretLength = 48 // Length of a master secret in TLS 1.1.
+ finishedVerifyLength = 12 // Length of verify_data in a Finished message.
+)
+
+var masterSecretLabel = []byte("master secret")
+var keyExpansionLabel = []byte("key expansion")
+var clientFinishedLabel = []byte("client finished")
+var serverFinishedLabel = []byte("server finished")
+
+// keysFromPreMasterSecret generates the connection keys from the pre master
+// secret, given the lengths of the MAC key, cipher key and IV, as defined in
+// RFC 2246, section 6.3.
+func keysFromPreMasterSecret10(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+ var seed [tlsRandomLength * 2]byte
+ copy(seed[0:len(clientRandom)], clientRandom)
+ copy(seed[len(clientRandom):], serverRandom)
+ masterSecret = make([]byte, masterSecretLength)
+ pRF10(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+
+ copy(seed[0:len(clientRandom)], serverRandom)
+ copy(seed[len(serverRandom):], clientRandom)
+
+ n := 2*macLen + 2*keyLen + 2*ivLen
+ keyMaterial := make([]byte, n)
+ pRF10(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+ clientMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ serverMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ clientKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ serverKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ clientIV = keyMaterial[:ivLen]
+ keyMaterial = keyMaterial[ivLen:]
+ serverIV = keyMaterial[:ivLen]
+ return
+}
+
+// A finishedHash calculates the hash of a set of handshake messages suitable
+// for including in a Finished message.
+type finishedHash struct {
+ clientMD5 hash.Hash
+ clientSHA1 hash.Hash
+ serverMD5 hash.Hash
+ serverSHA1 hash.Hash
+}
+
+func newFinishedHash() finishedHash {
+ return finishedHash{md5.New(), sha1.New(), md5.New(), sha1.New()}
+}
+
+func (h finishedHash) Write(msg []byte) (n int, err os.Error) {
+ h.clientMD5.Write(msg)
+ h.clientSHA1.Write(msg)
+ h.serverMD5.Write(msg)
+ h.serverSHA1.Write(msg)
+ return len(msg), nil
+}
+
+// finishedSum calculates the contents of the verify_data member of a Finished
+// message given the MD5 and SHA1 hashes of a set of handshake messages.
+func finishedSum(md5, sha1, label, masterSecret []byte) []byte {
+ seed := make([]byte, len(md5)+len(sha1))
+ copy(seed, md5)
+ copy(seed[len(md5):], sha1)
+ out := make([]byte, finishedVerifyLength)
+ pRF10(out, masterSecret, label, seed)
+ return out
+}
+
+// clientSum returns the contents of the verify_data member of a client's
+// Finished message.
+func (h finishedHash) clientSum(masterSecret []byte) []byte {
+ md5 := h.clientMD5.Sum()
+ sha1 := h.clientSHA1.Sum()
+ return finishedSum(md5, sha1, clientFinishedLabel, masterSecret)
+}
+
+// serverSum returns the contents of the verify_data member of a server's
+// Finished message.
+func (h finishedHash) serverSum(masterSecret []byte) []byte {
+ md5 := h.serverMD5.Sum()
+ sha1 := h.serverSHA1.Sum()
+ return finishedSum(md5, sha1, serverFinishedLabel, masterSecret)
+}
diff --git a/libgo/go/crypto/tls/prf_test.go b/libgo/go/crypto/tls/prf_test.go
new file mode 100644
index 000000000..f8c4acb9d
--- /dev/null
+++ b/libgo/go/crypto/tls/prf_test.go
@@ -0,0 +1,104 @@
+// 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 tls
+
+import (
+ "encoding/hex"
+ "testing"
+)
+
+type testSplitPreMasterSecretTest struct {
+ in, out1, out2 string
+}
+
+var testSplitPreMasterSecretTests = []testSplitPreMasterSecretTest{
+ {"", "", ""},
+ {"00", "00", "00"},
+ {"0011", "00", "11"},
+ {"001122", "0011", "1122"},
+ {"00112233", "0011", "2233"},
+}
+
+func TestSplitPreMasterSecret(t *testing.T) {
+ for i, test := range testSplitPreMasterSecretTests {
+ in, _ := hex.DecodeString(test.in)
+ out1, out2 := splitPreMasterSecret(in)
+ s1 := hex.EncodeToString(out1)
+ s2 := hex.EncodeToString(out2)
+ if s1 != test.out1 || s2 != test.out2 {
+ t.Errorf("#%d: got: (%s, %s) want: (%s, %s)", i, s1, s2, test.out1, test.out2)
+ }
+ }
+}
+
+type testKeysFromTest struct {
+ preMasterSecret string
+ clientRandom, serverRandom string
+ masterSecret string
+ clientMAC, serverMAC string
+ clientKey, serverKey string
+ macLen, keyLen int
+}
+
+func TestKeysFromPreMasterSecret(t *testing.T) {
+ for i, test := range testKeysFromTests {
+ in, _ := hex.DecodeString(test.preMasterSecret)
+ clientRandom, _ := hex.DecodeString(test.clientRandom)
+ serverRandom, _ := hex.DecodeString(test.serverRandom)
+ master, clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromPreMasterSecret10(in, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
+ masterString := hex.EncodeToString(master)
+ clientMACString := hex.EncodeToString(clientMAC)
+ serverMACString := hex.EncodeToString(serverMAC)
+ clientKeyString := hex.EncodeToString(clientKey)
+ serverKeyString := hex.EncodeToString(serverKey)
+ if masterString != test.masterSecret ||
+ clientMACString != test.clientMAC ||
+ serverMACString != test.serverMAC ||
+ clientKeyString != test.clientKey ||
+ serverKeyString != test.serverKey {
+ t.Errorf("#%d: got: (%s, %s, %s, %s, %s) want: (%s, %s, %s, %s %s)", i, masterString, clientMACString, serverMACString, clientKeyString, serverMACString, test.masterSecret, test.clientMAC, test.serverMAC, test.clientKey, test.serverKey)
+ }
+ }
+}
+
+// These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
+var testKeysFromTests = []testKeysFromTest{
+ {
+ "0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
+ "4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
+ "4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
+ "3d851bab6e5556e959a16bc36d66cfae32f672bfa9ecdef6096cbb1b23472df1da63dbbd9827606413221d149ed08ceb",
+ "805aaa19b3d2c0a0759a4b6c9959890e08480119",
+ "2d22f9fe519c075c16448305ceee209fc24ad109",
+ "d50b5771244f850cd8117a9ccafe2cf1",
+ "e076e33206b30507a85c32855acd0919",
+ 20,
+ 16,
+ },
+ {
+ "03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
+ "4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
+ "4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
+ "7d64be7c80c59b740200b4b9c26d0baaa1c5ae56705acbcf2307fe62beb4728c19392c83f20483801cce022c77645460",
+ "97742ed60a0554ca13f04f97ee193177b971e3b0",
+ "37068751700400e03a8477a5c7eec0813ab9e0dc",
+ "207cddbc600d2a200abac6502053ee5c",
+ "df3f94f6e1eacc753b815fe16055cd43",
+ 20,
+ 16,
+ },
+ {
+ "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
+ "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
+ "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
+ "1aff2e7a2c4279d0126f57a65a77a8d9d0087cf2733366699bec27eb53d5740705a8574bb1acc2abbe90e44f0dd28d6c",
+ "3c7647c93c1379a31a609542aa44e7f117a70085",
+ "0d73102994be74a575a3ead8532590ca32a526d4",
+ "ac7581b0b6c10d85bbd905ffbf36c65e",
+ "ff07edde49682b45466bd2e39464b306",
+ 20,
+ 16,
+ },
+}
diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go
new file mode 100644
index 000000000..b11d3225d
--- /dev/null
+++ b/libgo/go/crypto/tls/tls.go
@@ -0,0 +1,167 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package partially implements the TLS 1.1 protocol, as specified in RFC 4346.
+package tls
+
+import (
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "io/ioutil"
+ "net"
+ "os"
+ "strings"
+)
+
+// Server returns a new TLS server side connection
+// using conn as the underlying transport.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func Server(conn net.Conn, config *Config) *Conn {
+ return &Conn{conn: conn, config: config}
+}
+
+// Client returns a new TLS client side connection
+// using conn as the underlying transport.
+// Client interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Client(conn net.Conn, config *Config) *Conn {
+ return &Conn{conn: conn, config: config, isClient: true}
+}
+
+// A Listener implements a network listener (net.Listener) for TLS connections.
+type Listener struct {
+ listener net.Listener
+ config *Config
+}
+
+// Accept waits for and returns the next incoming TLS connection.
+// The returned connection c is a *tls.Conn.
+func (l *Listener) Accept() (c net.Conn, err os.Error) {
+ c, err = l.listener.Accept()
+ if err != nil {
+ return
+ }
+ c = Server(c, l.config)
+ return
+}
+
+// Close closes the listener.
+func (l *Listener) Close() os.Error { return l.listener.Close() }
+
+// Addr returns the listener's network address.
+func (l *Listener) Addr() net.Addr { return l.listener.Addr() }
+
+// NewListener creates a Listener which accepts connections from an inner
+// Listener and wraps each connection with Server.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func NewListener(listener net.Listener, config *Config) (l *Listener) {
+ l = new(Listener)
+ l.listener = listener
+ l.config = config
+ return
+}
+
+// Listen creates a TLS listener accepting connections on the
+// given network address using net.Listen.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func Listen(network, laddr string, config *Config) (*Listener, os.Error) {
+ if config == nil || len(config.Certificates) == 0 {
+ return nil, os.NewError("tls.Listen: no certificates in configuration")
+ }
+ l, err := net.Listen(network, laddr)
+ if err != nil {
+ return nil, err
+ }
+ return NewListener(l, config), nil
+}
+
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, laddr, raddr string, config *Config) (*Conn, os.Error) {
+ c, err := net.Dial(network, laddr, raddr)
+ if err != nil {
+ return nil, err
+ }
+
+ colonPos := strings.LastIndex(raddr, ":")
+ if colonPos == -1 {
+ colonPos = len(raddr)
+ }
+ hostname := raddr[:colonPos]
+
+ if config == nil {
+ config = defaultConfig()
+ }
+ if config.ServerName != "" {
+ // Make a copy to avoid polluting argument or default.
+ c := *config
+ c.ServerName = hostname
+ config = &c
+ }
+ conn := Client(c, config)
+ if err = conn.Handshake(); err != nil {
+ c.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+// LoadX509KeyPair reads and parses a public/private key pair from a pair of
+// files. The files must contain PEM encoded data.
+func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.Error) {
+ certPEMBlock, err := ioutil.ReadFile(certFile)
+ if err != nil {
+ return
+ }
+
+ certDERBlock, _ := pem.Decode(certPEMBlock)
+ if certDERBlock == nil {
+ err = os.ErrorString("crypto/tls: failed to parse certificate PEM data")
+ return
+ }
+
+ cert.Certificate = [][]byte{certDERBlock.Bytes}
+
+ keyPEMBlock, err := ioutil.ReadFile(keyFile)
+ if err != nil {
+ return
+ }
+
+ keyDERBlock, _ := pem.Decode(keyPEMBlock)
+ if keyDERBlock == nil {
+ err = os.ErrorString("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")
+ return
+ }
+
+ cert.PrivateKey = key
+
+ // We don't need to parse the public key for TLS, but we so do anyway
+ // to check that it looks sane and matches the private key.
+ x509Cert, err := x509.ParseCertificate(certDERBlock.Bytes)
+ if err != nil {
+ return
+ }
+
+ 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")
+ return
+ }
+
+ return
+}
diff --git a/libgo/go/crypto/twofish/twofish.go b/libgo/go/crypto/twofish/twofish.go
new file mode 100644
index 000000000..62253e797
--- /dev/null
+++ b/libgo/go/crypto/twofish/twofish.go
@@ -0,0 +1,358 @@
+// 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 package implements Bruce Schneier's Twofish encryption algorithm.
+package twofish
+
+// Twofish is defined in http://www.schneier.com/paper-twofish-paper.pdf [TWOFISH]
+
+// This code is a port of the LibTom C implementation.
+// See http://libtom.org/?page=features&newsitems=5&whatfile=crypt.
+// LibTomCrypt is free for all purposes under the public domain.
+// It was heavily inspired by the go blowfish package.
+
+import (
+ "os"
+ "strconv"
+)
+
+// BlockSize is the constant block size of Twofish.
+const BlockSize = 16
+
+const mdsPolynomial = 0x169 // x^8 + x^6 + x^5 + x^3 + 1, see [TWOFISH] 4.2
+const rsPolynomial = 0x14d // x^8 + x^6 + x^3 + x^2 + 1, see [TWOFISH] 4.3
+
+// A Cipher is an instance of Twofish encryption using a particular key.
+type Cipher struct {
+ s [4][256]uint32
+ k [40]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/twofish: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a Cipher.
+// The key argument should be the Twofish key, 16, 24 or 32 bytes.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ keylen := len(key)
+
+ if keylen != 16 && keylen != 24 && keylen != 32 {
+ return nil, KeySizeError(keylen)
+ }
+
+ // k is the number of 64 bit words in key
+ k := keylen / 8
+
+ // Create the S[..] words
+ var S [4 * 4]byte
+ for i := 0; i < k; i++ {
+ // Computes [y0 y1 y2 y3] = rs . [x0 x1 x2 x3 x4 x5 x6 x7]
+ for j, rsRow := range rs {
+ for k, rsVal := range rsRow {
+ S[4*i+j] ^= gfMult(key[8*i+k], rsVal, rsPolynomial)
+ }
+ }
+ }
+
+ // Calculate subkeys
+ c := new(Cipher)
+ var tmp [4]byte
+ for i := byte(0); i < 20; i++ {
+ // A = h(p * 2x, Me)
+ for j := range tmp {
+ tmp[j] = 2 * i
+ }
+ A := h(tmp[:], key, 0)
+
+ // B = rolc(h(p * (2x + 1), Mo), 8)
+ for j := range tmp {
+ tmp[j] = 2*i + 1
+ }
+ B := h(tmp[:], key, 1)
+ B = rol(B, 8)
+
+ c.k[2*i] = A + B
+
+ // K[2i+1] = (A + 2B) <<< 9
+ c.k[2*i+1] = rol(2*B+A, 9)
+ }
+
+ // Calculate sboxes
+ switch k {
+ case 2:
+ for i := range c.s[0] {
+ c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][byte(i)]^S[0]]^S[4]], 0)
+ c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][byte(i)]^S[1]]^S[5]], 1)
+ c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][byte(i)]^S[2]]^S[6]], 2)
+ c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][byte(i)]^S[3]]^S[7]], 3)
+ }
+ case 3:
+ for i := range c.s[0] {
+ c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]], 0)
+ c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[1]]^S[5]]^S[9]], 1)
+ c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]], 2)
+ c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[3]]^S[7]]^S[11]], 3)
+ }
+ default:
+ for i := range c.s[0] {
+ c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]]^S[12]], 0)
+ c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[1]]^S[5]]^S[9]]^S[13]], 1)
+ c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]]^S[14]], 2)
+ c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][sbox[1][byte(i)]^S[3]]^S[7]]^S[11]]^S[15]], 3)
+ }
+ }
+
+ return c, nil
+}
+
+// Reset zeros the key data, so that it will no longer appear in the process's
+// memory.
+func (c *Cipher) Reset() {
+ for i := range c.k {
+ c.k[i] = 0
+ }
+ for i := range c.s {
+ for j := 0; j < 265; j++ {
+ c.s[i][j] = 0
+ }
+ }
+}
+
+// BlockSize returns the Twofish block size, 16 bytes.
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// store32l stores src in dst in little-endian form.
+func store32l(dst []byte, src uint32) {
+ dst[0] = byte(src)
+ dst[1] = byte(src >> 8)
+ dst[2] = byte(src >> 16)
+ dst[3] = byte(src >> 24)
+ return
+}
+
+// load32l reads a little-endian uint32 from src.
+func load32l(src []byte) uint32 {
+ return uint32(src[0]) | uint32(src[1])<<8 | uint32(src[2])<<16 | uint32(src[3])<<24
+}
+
+// rol returns x after a left circular rotation of y bits.
+func rol(x, y uint32) uint32 {
+ return (x << (y & 31)) | (x >> (32 - (y & 31)))
+}
+
+// ror returns x after a right circular rotation of y bits.
+func ror(x, y uint32) uint32 {
+ return (x >> (y & 31)) | (x << (32 - (y & 31)))
+}
+
+// The RS matrix. See [TWOFISH] 4.3
+var rs = [4][8]byte{
+ {0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E},
+ {0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5},
+ {0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19},
+ {0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03},
+}
+
+// sbox tables
+var sbox = [2][256]byte{
+ {
+ 0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38,
+ 0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48,
+ 0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82,
+ 0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61,
+ 0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1,
+ 0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7,
+ 0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71,
+ 0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7,
+ 0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90,
+ 0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef,
+ 0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64,
+ 0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a,
+ 0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d,
+ 0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
+ 0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4,
+ 0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0,
+ },
+ {
+ 0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b,
+ 0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f,
+ 0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5,
+ 0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51,
+ 0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c,
+ 0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8,
+ 0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2,
+ 0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17,
+ 0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e,
+ 0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9,
+ 0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48,
+ 0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64,
+ 0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69,
+ 0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc,
+ 0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9,
+ 0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91,
+ },
+}
+
+// gfMult returns a·b in GF(2^8)/p
+func gfMult(a, b byte, p uint32) byte {
+ B := [2]uint32{0, uint32(b)}
+ P := [2]uint32{0, p}
+ var result uint32
+
+ // branchless GF multiplier
+ for i := 0; i < 7; i++ {
+ result ^= B[a&1]
+ a >>= 1
+ B[1] = P[B[1]>>7] ^ (B[1] << 1)
+ }
+ result ^= B[a&1]
+ return byte(result)
+}
+
+// mdsColumnMult calculates y{col} where [y0 y1 y2 y3] = MDS · [x0]
+func mdsColumnMult(in byte, col int) uint32 {
+ mul01 := in
+ mul5B := gfMult(in, 0x5B, mdsPolynomial)
+ mulEF := gfMult(in, 0xEF, mdsPolynomial)
+
+ switch col {
+ case 0:
+ return uint32(mul01) | uint32(mul5B)<<8 | uint32(mulEF)<<16 | uint32(mulEF)<<24
+ case 1:
+ return uint32(mulEF) | uint32(mulEF)<<8 | uint32(mul5B)<<16 | uint32(mul01)<<24
+ case 2:
+ return uint32(mul5B) | uint32(mulEF)<<8 | uint32(mul01)<<16 | uint32(mulEF)<<24
+ case 3:
+ return uint32(mul5B) | uint32(mul01)<<8 | uint32(mulEF)<<16 | uint32(mul5B)<<24
+ }
+
+ panic("unreachable")
+}
+
+// h implements the S-box generation function. See [TWOFISH] 4.3.5
+func h(in, key []byte, offset int) uint32 {
+ var y [4]byte
+ for x := range y {
+ y[x] = in[x]
+ }
+ switch len(key) / 8 {
+ case 4:
+ y[0] = sbox[1][y[0]] ^ key[4*(6+offset)+0]
+ y[1] = sbox[0][y[1]] ^ key[4*(6+offset)+1]
+ y[2] = sbox[0][y[2]] ^ key[4*(6+offset)+2]
+ y[3] = sbox[1][y[3]] ^ key[4*(6+offset)+3]
+ fallthrough
+ case 3:
+ y[0] = sbox[1][y[0]] ^ key[4*(4+offset)+0]
+ y[1] = sbox[1][y[1]] ^ key[4*(4+offset)+1]
+ y[2] = sbox[0][y[2]] ^ key[4*(4+offset)+2]
+ y[3] = sbox[0][y[3]] ^ key[4*(4+offset)+3]
+ fallthrough
+ case 2:
+ y[0] = sbox[1][sbox[0][sbox[0][y[0]]^key[4*(2+offset)+0]]^key[4*(0+offset)+0]]
+ y[1] = sbox[0][sbox[0][sbox[1][y[1]]^key[4*(2+offset)+1]]^key[4*(0+offset)+1]]
+ y[2] = sbox[1][sbox[1][sbox[0][y[2]]^key[4*(2+offset)+2]]^key[4*(0+offset)+2]]
+ y[3] = sbox[0][sbox[1][sbox[1][y[3]]^key[4*(2+offset)+3]]^key[4*(0+offset)+3]]
+ }
+ // [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3]
+ var mdsMult uint32
+ for i := range y {
+ mdsMult ^= mdsColumnMult(y[i], i)
+ }
+ return mdsMult
+}
+
+// Encrypt encrypts a 16-byte block from src to dst, which may overlap.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) {
+ S1 := c.s[0]
+ S2 := c.s[1]
+ S3 := c.s[2]
+ S4 := c.s[3]
+
+ // Load input
+ ia := load32l(src[0:4])
+ ib := load32l(src[4:8])
+ ic := load32l(src[8:12])
+ id := load32l(src[12:16])
+
+ // Pre-whitening
+ ia ^= c.k[0]
+ ib ^= c.k[1]
+ ic ^= c.k[2]
+ id ^= c.k[3]
+
+ for i := 0; i < 8; i++ {
+ k := c.k[8+i*4 : 12+i*4]
+ t2 := S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
+ t1 := S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
+ ic = ror(ic^(t1+k[0]), 1)
+ id = rol(id, 1) ^ (t2 + t1 + k[1])
+
+ t2 = S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
+ t1 = S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
+ ia = ror(ia^(t1+k[2]), 1)
+ ib = rol(ib, 1) ^ (t2 + t1 + k[3])
+ }
+
+ // Output with "undo last swap"
+ ta := ic ^ c.k[4]
+ tb := id ^ c.k[5]
+ tc := ia ^ c.k[6]
+ td := ib ^ c.k[7]
+
+ store32l(dst[0:4], ta)
+ store32l(dst[4:8], tb)
+ store32l(dst[8:12], tc)
+ store32l(dst[12:16], td)
+}
+
+// Decrypt decrypts a 16-byte block from src to dst, which may overlap.
+func (c *Cipher) Decrypt(dst, src []byte) {
+ S1 := c.s[0]
+ S2 := c.s[1]
+ S3 := c.s[2]
+ S4 := c.s[3]
+
+ // Load input
+ ta := load32l(src[0:4])
+ tb := load32l(src[4:8])
+ tc := load32l(src[8:12])
+ td := load32l(src[12:16])
+
+ // Undo undo final swap
+ ia := tc ^ c.k[6]
+ ib := td ^ c.k[7]
+ ic := ta ^ c.k[4]
+ id := tb ^ c.k[5]
+
+ for i := 8; i > 0; i-- {
+ k := c.k[4+i*4 : 8+i*4]
+ t2 := S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
+ t1 := S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
+ ia = rol(ia, 1) ^ (t1 + k[2])
+ ib = ror(ib^(t2+t1+k[3]), 1)
+
+ t2 = S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
+ t1 = S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
+ ic = rol(ic, 1) ^ (t1 + k[0])
+ id = ror(id^(t2+t1+k[1]), 1)
+ }
+
+ // Undo pre-whitening
+ ia ^= c.k[0]
+ ib ^= c.k[1]
+ ic ^= c.k[2]
+ id ^= c.k[3]
+
+ store32l(dst[0:4], ia)
+ store32l(dst[4:8], ib)
+ store32l(dst[8:12], ic)
+ store32l(dst[12:16], id)
+}
diff --git a/libgo/go/crypto/twofish/twofish_test.go b/libgo/go/crypto/twofish/twofish_test.go
new file mode 100644
index 000000000..303081f3f
--- /dev/null
+++ b/libgo/go/crypto/twofish/twofish_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 twofish
+
+import (
+ "bytes"
+ "testing"
+)
+
+var qbox = [2][4][16]byte{
+ {
+ {0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4},
+ {0xE, 0xC, 0xB, 0x8, 0x1, 0x2, 0x3, 0x5, 0xF, 0x4, 0xA, 0x6, 0x7, 0x0, 0x9, 0xD},
+ {0xB, 0xA, 0x5, 0xE, 0x6, 0xD, 0x9, 0x0, 0xC, 0x8, 0xF, 0x3, 0x2, 0x4, 0x7, 0x1},
+ {0xD, 0x7, 0xF, 0x4, 0x1, 0x2, 0x6, 0xE, 0x9, 0xB, 0x3, 0x0, 0x8, 0x5, 0xC, 0xA},
+ },
+ {
+ {0x2, 0x8, 0xB, 0xD, 0xF, 0x7, 0x6, 0xE, 0x3, 0x1, 0x9, 0x4, 0x0, 0xA, 0xC, 0x5},
+ {0x1, 0xE, 0x2, 0xB, 0x4, 0xC, 0x3, 0x7, 0x6, 0xD, 0xA, 0x5, 0xF, 0x9, 0x0, 0x8},
+ {0x4, 0xC, 0x7, 0x5, 0x1, 0x6, 0x9, 0xA, 0x0, 0xE, 0xD, 0x8, 0x2, 0xB, 0x3, 0xF},
+ {0xB, 0x9, 0x5, 0x1, 0xC, 0x3, 0xD, 0xE, 0x6, 0x4, 0x7, 0xF, 0x2, 0x0, 0x8, 0xA},
+ },
+}
+
+// genSbox generates the variable sbox
+func genSbox(qi int, x byte) byte {
+ a0, b0 := x/16, x%16
+ for i := 0; i < 2; i++ {
+ a1 := a0 ^ b0
+ b1 := (a0 ^ ((b0 << 3) | (b0 >> 1)) ^ (a0 << 3)) & 15
+ a0 = qbox[qi][2*i][a1]
+ b0 = qbox[qi][2*i+1][b1]
+ }
+ return (b0 << 4) + a0
+}
+
+func TestSbox(t *testing.T) {
+ for n := range sbox {
+ for m := range sbox[n] {
+ if genSbox(n, byte(m)) != sbox[n][m] {
+ t.Errorf("#%d|%d: sbox value = %d want %d", n, m, sbox[n][m], genSbox(n, byte(m)))
+ }
+ }
+ }
+}
+
+var testVectors = []struct {
+ key []byte
+ dec []byte
+ enc []byte
+}{
+ // These tests are extracted from LibTom
+ {
+ []byte{0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A},
+ []byte{0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E, 0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19},
+ []byte{0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85, 0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3},
+ },
+ {
+ []byte{0x88, 0xB2, 0xB2, 0x70, 0x6B, 0x10, 0x5E, 0x36, 0xB4, 0x46, 0xBB, 0x6D, 0x73, 0x1A, 0x1E, 0x88,
+ 0xEF, 0xA7, 0x1F, 0x78, 0x89, 0x65, 0xBD, 0x44},
+ []byte{0x39, 0xDA, 0x69, 0xD6, 0xBA, 0x49, 0x97, 0xD5, 0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2},
+ []byte{0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45, 0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65},
+ },
+ {
+ []byte{0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46, 0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D,
+ 0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B, 0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F},
+ []byte{0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F, 0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6},
+ []byte{0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97, 0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA},
+ },
+ // These test are derived from http://www.schneier.com/code/ecb_ival.txt
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ },
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xCF, 0xD1, 0xD2, 0xE5, 0xA9, 0xBE, 0x9C, 0xDF, 0x50, 0x1F, 0x13, 0xB8, 0x92, 0xBD, 0x22, 0x48},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ },
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x37, 0x52, 0x7B, 0xE0, 0x05, 0x23, 0x34, 0xB8, 0x9F, 0x0C, 0xFC, 0xCA, 0xE8, 0x7C, 0xFA, 0x20},
+ },
+}
+
+func TestCipher(t *testing.T) {
+ for n, tt := range testVectors {
+ // Test if the plaintext (dec) is encrypts to the given
+ // ciphertext (enc) using the given key. Test also if enc can
+ // be decrypted again into dec.
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("#%d: NewCipher: %v", n, err)
+ return
+ }
+
+ buf := make([]byte, 16)
+ c.Encrypt(buf, tt.dec)
+ if !bytes.Equal(buf, tt.enc) {
+ t.Errorf("#%d: encrypt = %x want %x", n, buf, tt.enc)
+ }
+ c.Decrypt(buf, tt.enc)
+ if !bytes.Equal(buf, tt.dec) {
+ t.Errorf("#%d: decrypt = %x want %x", n, buf, tt.dec)
+ }
+
+ // Test that 16 zero bytes, encrypted 1000 times then decrypted
+ // 1000 times results in zero bytes again.
+ zero := make([]byte, 16)
+ buf = make([]byte, 16)
+ for i := 0; i < 1000; i++ {
+ c.Encrypt(buf, buf)
+ }
+ for i := 0; i < 1000; i++ {
+ c.Decrypt(buf, buf)
+ }
+ if !bytes.Equal(buf, zero) {
+ t.Errorf("#%d: encrypt/decrypt 1000: have %x want %x", n, buf, zero)
+ }
+ }
+}
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go
new file mode 100644
index 000000000..6199e8db9
--- /dev/null
+++ b/libgo/go/crypto/x509/x509.go
@@ -0,0 +1,854 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package parses X.509-encoded keys and certificates.
+package x509
+
+import (
+ "asn1"
+ "big"
+ "container/vector"
+ "crypto/rsa"
+ "crypto/sha1"
+ "hash"
+ "io"
+ "os"
+ "strings"
+ "time"
+)
+
+// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
+type pkcs1PrivateKey struct {
+ Version int
+ N asn1.RawValue
+ E int
+ D asn1.RawValue
+ P asn1.RawValue
+ Q asn1.RawValue
+}
+
+// rawValueIsInteger returns true iff the given ASN.1 RawValue is an INTEGER type.
+func rawValueIsInteger(raw *asn1.RawValue) bool {
+ return raw.Class == 0 && raw.Tag == 2 && raw.IsCompound == false
+}
+
+// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
+func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
+ var priv pkcs1PrivateKey
+ rest, err := asn1.Unmarshal(der, &priv)
+ if len(rest) > 0 {
+ err = asn1.SyntaxError{"trailing data"}
+ return
+ }
+ if err != nil {
+ return
+ }
+
+ if !rawValueIsInteger(&priv.N) ||
+ !rawValueIsInteger(&priv.D) ||
+ !rawValueIsInteger(&priv.P) ||
+ !rawValueIsInteger(&priv.Q) {
+ err = asn1.StructuralError{"tags don't match"}
+ return
+ }
+
+ key = &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ E: priv.E,
+ N: new(big.Int).SetBytes(priv.N.Bytes),
+ },
+ D: new(big.Int).SetBytes(priv.D.Bytes),
+ P: new(big.Int).SetBytes(priv.P.Bytes),
+ Q: new(big.Int).SetBytes(priv.Q.Bytes),
+ }
+
+ err = key.Validate()
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
+func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
+ priv := pkcs1PrivateKey{
+ Version: 1,
+ N: asn1.RawValue{Tag: 2, Bytes: key.PublicKey.N.Bytes()},
+ E: key.PublicKey.E,
+ D: asn1.RawValue{Tag: 2, Bytes: key.D.Bytes()},
+ P: asn1.RawValue{Tag: 2, Bytes: key.P.Bytes()},
+ Q: asn1.RawValue{Tag: 2, Bytes: key.Q.Bytes()},
+ }
+
+ b, _ := asn1.Marshal(priv)
+ return b
+}
+
+// These structures reflect the ASN.1 structure of X.509 certificates.:
+
+type certificate struct {
+ TBSCertificate tbsCertificate
+ SignatureAlgorithm algorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+type tbsCertificate struct {
+ Raw asn1.RawContent
+ Version int "optional,explicit,default:1,tag:0"
+ SerialNumber asn1.RawValue
+ SignatureAlgorithm algorithmIdentifier
+ Issuer rdnSequence
+ Validity validity
+ Subject rdnSequence
+ PublicKey publicKeyInfo
+ UniqueId asn1.BitString "optional,tag:1"
+ SubjectUniqueId asn1.BitString "optional,tag:2"
+ Extensions []extension "optional,explicit,tag:3"
+}
+
+type algorithmIdentifier struct {
+ Algorithm asn1.ObjectIdentifier
+}
+
+type rdnSequence []relativeDistinguishedNameSET
+
+type relativeDistinguishedNameSET []attributeTypeAndValue
+
+type attributeTypeAndValue struct {
+ Type asn1.ObjectIdentifier
+ Value interface{}
+}
+
+type validity struct {
+ NotBefore, NotAfter *time.Time
+}
+
+type publicKeyInfo struct {
+ Algorithm algorithmIdentifier
+ PublicKey asn1.BitString
+}
+
+type extension struct {
+ Id asn1.ObjectIdentifier
+ Critical bool "optional"
+ Value []byte
+}
+
+// RFC 5280, 4.2.1.1
+type authKeyId struct {
+ Id []byte "optional,tag:0"
+}
+
+type SignatureAlgorithm int
+
+const (
+ UnknownSignatureAlgorithm SignatureAlgorithm = iota
+ MD2WithRSA
+ MD5WithRSA
+ SHA1WithRSA
+ SHA256WithRSA
+ SHA384WithRSA
+ SHA512WithRSA
+)
+
+type PublicKeyAlgorithm int
+
+const (
+ UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
+ RSA
+)
+
+// Name represents an X.509 distinguished name. This only includes the common
+// elements of a DN. Additional elements in the name are ignored.
+type Name struct {
+ Country, Organization, OrganizationalUnit []string
+ Locality, Province []string
+ StreetAddress, PostalCode []string
+ SerialNumber, CommonName string
+}
+
+func (n *Name) fillFromRDNSequence(rdns *rdnSequence) {
+ for _, rdn := range *rdns {
+ if len(rdn) == 0 {
+ continue
+ }
+ atv := rdn[0]
+ value, ok := atv.Value.(string)
+ if !ok {
+ continue
+ }
+
+ t := atv.Type
+ if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
+ switch t[3] {
+ case 3:
+ n.CommonName = value
+ case 5:
+ n.SerialNumber = value
+ case 6:
+ n.Country = append(n.Country, value)
+ case 7:
+ n.Locality = append(n.Locality, value)
+ case 8:
+ n.Province = append(n.Province, value)
+ case 9:
+ n.StreetAddress = append(n.StreetAddress, value)
+ case 10:
+ n.Organization = append(n.Organization, value)
+ case 11:
+ n.OrganizationalUnit = append(n.OrganizationalUnit, value)
+ case 17:
+ n.PostalCode = append(n.PostalCode, value)
+ }
+ }
+ }
+}
+
+var (
+ oidCountry = []int{2, 5, 4, 6}
+ oidOrganization = []int{2, 5, 4, 10}
+ oidOrganizationalUnit = []int{2, 5, 4, 11}
+ oidCommonName = []int{2, 5, 4, 3}
+ oidSerialNumber = []int{2, 5, 4, 5}
+ oidLocatity = []int{2, 5, 4, 7}
+ oidProvince = []int{2, 5, 4, 8}
+ oidStreetAddress = []int{2, 5, 4, 9}
+ oidPostalCode = []int{2, 5, 4, 17}
+)
+
+// appendRDNs appends a relativeDistinguishedNameSET to the given rdnSequence
+// and returns the new value. The relativeDistinguishedNameSET contains an
+// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
+// search for AttributeTypeAndValue.
+func appendRDNs(in rdnSequence, values []string, oid asn1.ObjectIdentifier) rdnSequence {
+ if len(values) == 0 {
+ return in
+ }
+
+ s := make([]attributeTypeAndValue, len(values))
+ for i, value := range values {
+ s[i].Type = oid
+ s[i].Value = value
+ }
+
+ return append(in, s)
+}
+
+func (n Name) toRDNSequence() (ret rdnSequence) {
+ ret = appendRDNs(ret, n.Country, oidCountry)
+ ret = appendRDNs(ret, n.Organization, oidOrganization)
+ ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
+ ret = appendRDNs(ret, n.Locality, oidLocatity)
+ ret = appendRDNs(ret, n.Province, oidProvince)
+ ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
+ ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
+ if len(n.CommonName) > 0 {
+ ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
+ }
+ if len(n.SerialNumber) > 0 {
+ ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
+ }
+
+ return ret
+}
+
+func getSignatureAlgorithmFromOID(oid []int) SignatureAlgorithm {
+ if len(oid) == 7 && oid[0] == 1 && oid[1] == 2 && oid[2] == 840 &&
+ oid[3] == 113549 && oid[4] == 1 && oid[5] == 1 {
+ switch oid[6] {
+ case 2:
+ return MD2WithRSA
+ case 4:
+ return MD5WithRSA
+ case 5:
+ return SHA1WithRSA
+ case 11:
+ return SHA256WithRSA
+ case 12:
+ return SHA384WithRSA
+ case 13:
+ return SHA512WithRSA
+ }
+ }
+
+ return UnknownSignatureAlgorithm
+}
+
+func getPublicKeyAlgorithmFromOID(oid []int) PublicKeyAlgorithm {
+ if len(oid) == 7 && oid[0] == 1 && oid[1] == 2 && oid[2] == 840 &&
+ oid[3] == 113549 && oid[4] == 1 && oid[5] == 1 {
+ switch oid[6] {
+ case 1:
+ return RSA
+ }
+ }
+
+ return UnknownPublicKeyAlgorithm
+}
+
+// KeyUsage represents the set of actions that are valid for a given key. It's
+// a bitmap of the KeyUsage* constants.
+type KeyUsage int
+
+const (
+ KeyUsageDigitalSignature KeyUsage = 1 << iota
+ KeyUsageContentCommitment
+ KeyUsageKeyEncipherment
+ KeyUsageDataEncipherment
+ KeyUsageKeyAgreement
+ KeyUsageCertSign
+ KeyUsageCRLSign
+ KeyUsageEncipherOnly
+ KeyUsageDecipherOnly
+)
+
+// A Certificate represents an X.509 certificate.
+type Certificate struct {
+ Raw []byte // Raw ASN.1 DER contents.
+ Signature []byte
+ SignatureAlgorithm SignatureAlgorithm
+
+ PublicKeyAlgorithm PublicKeyAlgorithm
+ PublicKey interface{}
+
+ Version int
+ SerialNumber []byte
+ Issuer Name
+ Subject Name
+ NotBefore, NotAfter *time.Time // Validity bounds.
+ KeyUsage KeyUsage
+
+ BasicConstraintsValid bool // if true then the next two fields are valid.
+ IsCA bool
+ MaxPathLen int
+
+ SubjectKeyId []byte
+ AuthorityKeyId []byte
+
+ // Subject Alternate Name values
+ DNSNames []string
+ EmailAddresses []string
+
+ PolicyIdentifiers []asn1.ObjectIdentifier
+}
+
+// UnsupportedAlgorithmError results from attempting to perform an operation
+// that involves algorithms that are not currently implemented.
+type UnsupportedAlgorithmError struct{}
+
+func (UnsupportedAlgorithmError) String() string {
+ return "cannot verify signature: algorithm unimplemented"
+}
+
+// ConstraintViolationError results when a requested usage is not permitted by
+// a certificate. For example: checking a signature when the public key isn't a
+// certificate signing key.
+type ConstraintViolationError struct{}
+
+func (ConstraintViolationError) String() string {
+ return "invalid signature: parent certificate cannot sign this kind of certificate"
+}
+
+// CheckSignatureFrom verifies that the signature on c is a valid signature
+// from parent.
+func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.Error) {
+ // RFC 5280, 4.2.1.9:
+ // "If the basic constraints extension is not present in a version 3
+ // certificate, or the extension is present but the cA boolean is not
+ // asserted, then the certified public key MUST NOT be used to verify
+ // certificate signatures."
+ if parent.Version == 3 && !parent.BasicConstraintsValid ||
+ parent.BasicConstraintsValid && !parent.IsCA {
+ return ConstraintViolationError{}
+ }
+
+ if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCertSign == 0 {
+ return ConstraintViolationError{}
+ }
+
+ if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm {
+ return UnsupportedAlgorithmError{}
+ }
+
+ // TODO(agl): don't ignore the path length constraint.
+
+ var h hash.Hash
+ var hashType rsa.PKCS1v15Hash
+
+ switch c.SignatureAlgorithm {
+ case SHA1WithRSA:
+ h = sha1.New()
+ hashType = rsa.HashSHA1
+ default:
+ return UnsupportedAlgorithmError{}
+ }
+
+ pub, ok := parent.PublicKey.(*rsa.PublicKey)
+ if !ok {
+ return UnsupportedAlgorithmError{}
+ }
+
+ h.Write(c.Raw)
+ digest := h.Sum()
+
+ return rsa.VerifyPKCS1v15(pub, hashType, digest, c.Signature)
+}
+
+func matchHostnames(pattern, host string) bool {
+ if len(pattern) == 0 || len(host) == 0 {
+ return false
+ }
+
+ patternParts := strings.Split(pattern, ".", -1)
+ hostParts := strings.Split(host, ".", -1)
+
+ if len(patternParts) != len(hostParts) {
+ return false
+ }
+
+ for i, patternPart := range patternParts {
+ if patternPart == "*" {
+ continue
+ }
+ if patternPart != hostParts[i] {
+ return false
+ }
+ }
+
+ return true
+}
+
+type HostnameError struct {
+ Certificate *Certificate
+ Host string
+}
+
+func (h *HostnameError) String() string {
+ var valid string
+ c := h.Certificate
+ if len(c.DNSNames) > 0 {
+ valid = strings.Join(c.DNSNames, ", ")
+ } else {
+ valid = c.Subject.CommonName
+ }
+ return "certificate is valid for " + valid + ", not " + h.Host
+}
+
+// VerifyHostname returns nil if c is a valid certificate for the named host.
+// Otherwise it returns an os.Error describing the mismatch.
+func (c *Certificate) VerifyHostname(h string) os.Error {
+ if len(c.DNSNames) > 0 {
+ for _, match := range c.DNSNames {
+ if matchHostnames(match, h) {
+ return nil
+ }
+ }
+ // If Subject Alt Name is given, we ignore the common name.
+ } else if matchHostnames(c.Subject.CommonName, h) {
+ return nil
+ }
+
+ return &HostnameError{c, h}
+}
+
+type UnhandledCriticalExtension struct{}
+
+func (h UnhandledCriticalExtension) String() string {
+ return "unhandled critical extension"
+}
+
+type basicConstraints struct {
+ IsCA bool "optional"
+ MaxPathLen int "optional"
+}
+
+type rsaPublicKey struct {
+ N asn1.RawValue
+ E int
+}
+
+// RFC 5280 4.2.1.4
+type policyInformation struct {
+ Policy asn1.ObjectIdentifier
+ // policyQualifiers omitted
+}
+
+func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.Error) {
+ switch algo {
+ case RSA:
+ p := new(rsaPublicKey)
+ _, err := asn1.Unmarshal(asn1Data, p)
+ if err != nil {
+ return nil, err
+ }
+
+ if !rawValueIsInteger(&p.N) {
+ return nil, asn1.StructuralError{"tags don't match"}
+ }
+
+ pub := &rsa.PublicKey{
+ E: p.E,
+ N: new(big.Int).SetBytes(p.N.Bytes),
+ }
+ return pub, nil
+ default:
+ return nil, nil
+ }
+
+ panic("unreachable")
+}
+
+func parseCertificate(in *certificate) (*Certificate, os.Error) {
+ out := new(Certificate)
+ out.Raw = in.TBSCertificate.Raw
+
+ out.Signature = in.SignatureValue.RightAlign()
+ out.SignatureAlgorithm =
+ getSignatureAlgorithmFromOID(in.TBSCertificate.SignatureAlgorithm.Algorithm)
+
+ out.PublicKeyAlgorithm =
+ getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)
+ var err os.Error
+ out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, in.TBSCertificate.PublicKey.PublicKey.RightAlign())
+ if err != nil {
+ return nil, err
+ }
+
+ out.Version = in.TBSCertificate.Version + 1
+ out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes
+ out.Issuer.fillFromRDNSequence(&in.TBSCertificate.Issuer)
+ out.Subject.fillFromRDNSequence(&in.TBSCertificate.Subject)
+ out.NotBefore = in.TBSCertificate.Validity.NotBefore
+ out.NotAfter = in.TBSCertificate.Validity.NotAfter
+
+ for _, e := range in.TBSCertificate.Extensions {
+ if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
+ switch e.Id[3] {
+ case 15:
+ // RFC 5280, 4.2.1.3
+ var usageBits asn1.BitString
+ _, err := asn1.Unmarshal(e.Value, &usageBits)
+
+ if err == nil {
+ var usage int
+ for i := 0; i < 9; i++ {
+ if usageBits.At(i) != 0 {
+ usage |= 1 << uint(i)
+ }
+ }
+ out.KeyUsage = KeyUsage(usage)
+ continue
+ }
+ case 19:
+ // RFC 5280, 4.2.1.9
+ var constriants basicConstraints
+ _, err := asn1.Unmarshal(e.Value, &constriants)
+
+ if err == nil {
+ out.BasicConstraintsValid = true
+ out.IsCA = constriants.IsCA
+ out.MaxPathLen = constriants.MaxPathLen
+ continue
+ }
+ case 17:
+ // RFC 5280, 4.2.1.6
+
+ // SubjectAltName ::= GeneralNames
+ //
+ // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ //
+ // GeneralName ::= CHOICE {
+ // otherName [0] OtherName,
+ // rfc822Name [1] IA5String,
+ // dNSName [2] IA5String,
+ // x400Address [3] ORAddress,
+ // directoryName [4] Name,
+ // ediPartyName [5] EDIPartyName,
+ // uniformResourceIdentifier [6] IA5String,
+ // iPAddress [7] OCTET STRING,
+ // registeredID [8] OBJECT IDENTIFIER }
+ var seq asn1.RawValue
+ _, err := asn1.Unmarshal(e.Value, &seq)
+ if err != nil {
+ return nil, err
+ }
+ if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
+ return nil, asn1.StructuralError{"bad SAN sequence"}
+ }
+
+ parsedName := false
+
+ rest := seq.Bytes
+ for len(rest) > 0 {
+ var v asn1.RawValue
+ rest, err = asn1.Unmarshal(rest, &v)
+ if err != nil {
+ return nil, err
+ }
+ switch v.Tag {
+ case 1:
+ out.EmailAddresses = append(out.EmailAddresses, string(v.Bytes))
+ parsedName = true
+ case 2:
+ out.DNSNames = append(out.DNSNames, string(v.Bytes))
+ parsedName = true
+ }
+ }
+
+ if parsedName {
+ continue
+ }
+ // If we didn't parse any of the names then we
+ // fall through to the critical check below.
+
+ case 35:
+ // RFC 5280, 4.2.1.1
+ var a authKeyId
+ _, err = asn1.Unmarshal(e.Value, &a)
+ if err != nil {
+ return nil, err
+ }
+ out.AuthorityKeyId = a.Id
+ continue
+
+ case 14:
+ // RFC 5280, 4.2.1.2
+ var keyid []byte
+ _, err = asn1.Unmarshal(e.Value, &keyid)
+ if err != nil {
+ return nil, err
+ }
+ out.SubjectKeyId = keyid
+ continue
+
+ case 32:
+ // RFC 5280 4.2.1.4: Certificate Policies
+ var policies []policyInformation
+ if _, err = asn1.Unmarshal(e.Value, &policies); err != nil {
+ return nil, err
+ }
+ out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies))
+ for i, policy := range policies {
+ out.PolicyIdentifiers[i] = policy.Policy
+ }
+ }
+ }
+
+ if e.Critical {
+ return out, UnhandledCriticalExtension{}
+ }
+ }
+
+ return out, nil
+}
+
+// ParseCertificate parses a single certificate from the given ASN.1 DER data.
+func ParseCertificate(asn1Data []byte) (*Certificate, os.Error) {
+ var cert certificate
+ rest, err := asn1.Unmarshal(asn1Data, &cert)
+ if err != nil {
+ return nil, err
+ }
+ if len(rest) > 0 {
+ return nil, asn1.SyntaxError{"trailing data"}
+ }
+
+ return parseCertificate(&cert)
+}
+
+// ParseCertificates parses one or more certificates from the given ASN.1 DER
+// data. The certificates must be concatenated with no intermediate padding.
+func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) {
+ v := new(vector.Vector)
+
+ for len(asn1Data) > 0 {
+ cert := new(certificate)
+ var err os.Error
+ asn1Data, err = asn1.Unmarshal(asn1Data, cert)
+ if err != nil {
+ return nil, err
+ }
+ v.Push(cert)
+ }
+
+ ret := make([]*Certificate, v.Len())
+ for i := 0; i < v.Len(); i++ {
+ cert, err := parseCertificate(v.At(i).(*certificate))
+ if err != nil {
+ return nil, err
+ }
+ ret[i] = cert
+ }
+
+ return ret, nil
+}
+
+func reverseBitsInAByte(in byte) byte {
+ b1 := in>>4 | in<<4
+ b2 := b1>>2&0x33 | b1<<2&0xcc
+ b3 := b2>>1&0x55 | b2<<1&0xaa
+ return b3
+}
+
+var (
+ oidExtensionSubjectKeyId = []int{2, 5, 29, 14}
+ oidExtensionKeyUsage = []int{2, 5, 29, 15}
+ oidExtensionAuthorityKeyId = []int{2, 5, 29, 35}
+ oidExtensionBasicConstraints = []int{2, 5, 29, 19}
+ oidExtensionSubjectAltName = []int{2, 5, 29, 17}
+ oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
+)
+
+func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
+ ret = make([]extension, 6 /* maximum number of elements. */ )
+ n := 0
+
+ if template.KeyUsage != 0 {
+ ret[n].Id = oidExtensionKeyUsage
+ ret[n].Critical = true
+
+ var a [2]byte
+ a[0] = reverseBitsInAByte(byte(template.KeyUsage))
+ a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8))
+
+ l := 1
+ if a[1] != 0 {
+ l = 2
+ }
+
+ ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8})
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if template.BasicConstraintsValid {
+ ret[n].Id = oidExtensionBasicConstraints
+ ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen})
+ ret[n].Critical = true
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(template.SubjectKeyId) > 0 {
+ ret[n].Id = oidExtensionSubjectKeyId
+ ret[n].Value, err = asn1.Marshal(template.SubjectKeyId)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(template.AuthorityKeyId) > 0 {
+ ret[n].Id = oidExtensionAuthorityKeyId
+ ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId})
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(template.DNSNames) > 0 {
+ ret[n].Id = oidExtensionSubjectAltName
+ rawValues := make([]asn1.RawValue, len(template.DNSNames))
+ for i, name := range template.DNSNames {
+ rawValues[i] = asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)}
+ }
+ ret[n].Value, err = asn1.Marshal(rawValues)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(template.PolicyIdentifiers) > 0 {
+ ret[n].Id = oidExtensionCertificatePolicies
+ policies := make([]policyInformation, len(template.PolicyIdentifiers))
+ for i, policy := range template.PolicyIdentifiers {
+ policies[i].Policy = policy
+ }
+ ret[n].Value, err = asn1.Marshal(policies)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ // Adding another extension here? Remember to update the maximum number
+ // of elements in the make() at the top of the function.
+
+ return ret[0:n], nil
+}
+
+var (
+ oidSHA1WithRSA = []int{1, 2, 840, 113549, 1, 1, 5}
+ oidRSA = []int{1, 2, 840, 113549, 1, 1, 1}
+)
+
+// CreateSelfSignedCertificate creates a new certificate based on
+// a template. The following members of template are used: SerialNumber,
+// Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA,
+// MaxPathLen, SubjectKeyId, DNSNames.
+//
+// The certificate is signed by parent. If parent is equal to template then the
+// certificate is self-signed. The parameter pub is the public key of the
+// signee and priv is the private key of the signer.
+//
+// The returned slice is the certificate in DER encoding.
+func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.PublicKey, priv *rsa.PrivateKey) (cert []byte, err os.Error) {
+ asn1PublicKey, err := asn1.Marshal(rsaPublicKey{
+ N: asn1.RawValue{Tag: 2, Bytes: pub.N.Bytes()},
+ E: pub.E,
+ })
+ if err != nil {
+ return
+ }
+
+ if len(parent.SubjectKeyId) > 0 {
+ template.AuthorityKeyId = parent.SubjectKeyId
+ }
+
+ extensions, err := buildExtensions(template)
+ if err != nil {
+ return
+ }
+
+ encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey}
+ c := tbsCertificate{
+ Version: 2,
+ SerialNumber: asn1.RawValue{Bytes: template.SerialNumber, Tag: 2},
+ SignatureAlgorithm: algorithmIdentifier{oidSHA1WithRSA},
+ Issuer: parent.Subject.toRDNSequence(),
+ Validity: validity{template.NotBefore, template.NotAfter},
+ Subject: template.Subject.toRDNSequence(),
+ PublicKey: publicKeyInfo{algorithmIdentifier{oidRSA}, encodedPublicKey},
+ Extensions: extensions,
+ }
+
+ tbsCertContents, err := asn1.Marshal(c)
+ if err != nil {
+ return
+ }
+
+ c.Raw = tbsCertContents
+
+ h := sha1.New()
+ h.Write(tbsCertContents)
+ digest := h.Sum()
+
+ signature, err := rsa.SignPKCS1v15(rand, priv, rsa.HashSHA1, digest)
+ if err != nil {
+ return
+ }
+
+ cert, err = asn1.Marshal(certificate{
+ c,
+ algorithmIdentifier{oidSHA1WithRSA},
+ asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+ })
+ return
+}
diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go
new file mode 100644
index 000000000..2fe47fdbe
--- /dev/null
+++ b/libgo/go/crypto/x509/x509_test.go
@@ -0,0 +1,198 @@
+// 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 x509
+
+import (
+ "asn1"
+ "big"
+ "crypto/rand"
+ "crypto/rsa"
+ "encoding/hex"
+ "encoding/pem"
+ "reflect"
+ "testing"
+ "time"
+)
+
+func TestParsePKCS1PrivateKey(t *testing.T) {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ priv, err := ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ t.Errorf("Failed to parse private key: %s", err)
+ }
+ if !reflect.DeepEqual(priv, rsaPrivateKey) {
+ t.Errorf("got:%+v want:%+v", priv, rsaPrivateKey)
+ }
+}
+
+var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA PRIVATE KEY-----
+`
+
+func bigFromString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 10)
+ return ret
+}
+
+var rsaPrivateKey = &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ N: bigFromString("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"),
+ E: 65537,
+ },
+ D: bigFromString("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861"),
+ P: bigFromString("98920366548084643601728869055592650835572950932266967461790948584315647051443"),
+ Q: bigFromString("94560208308847015747498523884063394671606671904944666360068158221458669711639"),
+}
+
+type matchHostnamesTest struct {
+ pattern, host string
+ ok bool
+}
+
+var matchHostnamesTests = []matchHostnamesTest{
+ {"a.b.c", "a.b.c", true},
+ {"a.b.c", "b.b.c", false},
+ {"", "b.b.c", false},
+ {"a.b.c", "", false},
+ {"example.com", "example.com", true},
+ {"example.com", "www.example.com", false},
+ {"*.example.com", "www.example.com", true},
+ {"*.example.com", "xyz.www.example.com", false},
+ {"*.*.example.com", "xyz.www.example.com", true},
+ {"*.www.*.com", "xyz.www.example.com", true},
+}
+
+func TestMatchHostnames(t *testing.T) {
+ for i, test := range matchHostnamesTests {
+ r := matchHostnames(test.pattern, test.host)
+ if r != test.ok {
+ t.Errorf("#%d mismatch got: %t want: %t", i, r, test.ok)
+ }
+ }
+}
+
+func TestCertificateParse(t *testing.T) {
+ s, _ := hex.DecodeString(certBytes)
+ certs, err := ParseCertificates(s)
+ if err != nil {
+ t.Error(err)
+ }
+ if len(certs) != 2 {
+ t.Errorf("Wrong number of certs: got %d want 2", len(certs))
+ return
+ }
+
+ err = certs[0].CheckSignatureFrom(certs[1])
+ if err != nil {
+ t.Error(err)
+ }
+
+ if err := certs[0].VerifyHostname("mail.google.com"); err != nil {
+ t.Error(err)
+ }
+}
+
+var certBytes = "308203223082028ba00302010202106edf0d9499fd4533dd1297fc42a93be1300d06092a864886" +
+ "f70d0101050500304c310b3009060355040613025a4131253023060355040a131c546861777465" +
+ "20436f6e73756c74696e67202850747929204c74642e311630140603550403130d546861777465" +
+ "20534743204341301e170d3039303332353136343932395a170d3130303332353136343932395a" +
+ "3069310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630" +
+ "140603550407130d4d6f756e7461696e205669657731133011060355040a130a476f6f676c6520" +
+ "496e63311830160603550403130f6d61696c2e676f6f676c652e636f6d30819f300d06092a8648" +
+ "86f70d010101050003818d0030818902818100c5d6f892fccaf5614b064149e80a2c9581a218ef" +
+ "41ec35bd7a58125ae76f9ea54ddc893abbeb029f6b73616bf0ffd868791fba7af9c4aebf3706ba" +
+ "3eeaeed27435b4ddcfb157c05f351d66aa87fee0de072d66d773affbd36ab78bef090e0cc861a9" +
+ "03ac90dd98b51c9c41566c017f0beec3bff391051ffba0f5cc6850ad2a590203010001a381e730" +
+ "81e430280603551d250421301f06082b0601050507030106082b06010505070302060960864801" +
+ "86f842040130360603551d1f042f302d302ba029a0278625687474703a2f2f63726c2e74686177" +
+ "74652e636f6d2f54686177746553474343412e63726c307206082b060105050701010466306430" +
+ "2206082b060105050730018616687474703a2f2f6f6373702e7468617774652e636f6d303e0608" +
+ "2b060105050730028632687474703a2f2f7777772e7468617774652e636f6d2f7265706f736974" +
+ "6f72792f5468617774655f5347435f43412e637274300c0603551d130101ff04023000300d0609" +
+ "2a864886f70d01010505000381810062f1f3050ebc105e497c7aedf87e24d2f4a986bb3b837bd1" +
+ "9b91ebcad98b065992f6bd2b49b7d6d3cb2e427a99d606c7b1d46352527fac39e6a8b6726de5bf" +
+ "70212a52cba07634a5e332011bd1868e78eb5e3c93cf03072276786f207494feaa0ed9d53b2110" +
+ "a76571f90209cdae884385c882587030ee15f33d761e2e45a6bc308203233082028ca003020102" +
+ "020430000002300d06092a864886f70d0101050500305f310b3009060355040613025553311730" +
+ "15060355040a130e566572695369676e2c20496e632e31373035060355040b132e436c61737320" +
+ "33205075626c6963205072696d6172792043657274696669636174696f6e20417574686f726974" +
+ "79301e170d3034303531333030303030305a170d3134303531323233353935395a304c310b3009" +
+ "060355040613025a4131253023060355040a131c54686177746520436f6e73756c74696e672028" +
+ "50747929204c74642e311630140603550403130d5468617774652053474320434130819f300d06" +
+ "092a864886f70d010101050003818d0030818902818100d4d367d08d157faecd31fe7d1d91a13f" +
+ "0b713cacccc864fb63fc324b0794bd6f80ba2fe10493c033fc093323e90b742b71c403c6d2cde2" +
+ "2ff50963cdff48a500bfe0e7f388b72d32de9836e60aad007bc4644a3b847503f270927d0e62f5" +
+ "21ab693684317590f8bfc76c881b06957cc9e5a8de75a12c7a68dfd5ca1c875860190203010001" +
+ "a381fe3081fb30120603551d130101ff040830060101ff020100300b0603551d0f040403020106" +
+ "301106096086480186f842010104040302010630280603551d110421301fa41d301b3119301706" +
+ "035504031310507269766174654c6162656c332d313530310603551d1f042a30283026a024a022" +
+ "8620687474703a2f2f63726c2e766572697369676e2e636f6d2f706361332e63726c303206082b" +
+ "0601050507010104263024302206082b060105050730018616687474703a2f2f6f6373702e7468" +
+ "617774652e636f6d30340603551d25042d302b06082b0601050507030106082b06010505070302" +
+ "06096086480186f8420401060a6086480186f845010801300d06092a864886f70d010105050003" +
+ "81810055ac63eadea1ddd2905f9f0bce76be13518f93d9052bc81b774bad6950a1eededcfddb07" +
+ "e9e83994dcab72792f06bfab8170c4a8edea5334edef1e53d906c7562bd15cf4d18a8eb42bb137" +
+ "9048084225c53e8acb7feb6f04d16dc574a2f7a27c7b603c77cd0ece48027f012fb69b37e02a2a" +
+ "36dcd585d6ace53f546f961e05af"
+
+func TestCreateSelfSignedCertificate(t *testing.T) {
+ random := rand.Reader
+
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ priv, err := ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ t.Errorf("Failed to parse private key: %s", err)
+ return
+ }
+
+ template := Certificate{
+ SerialNumber: []byte{1},
+ Subject: Name{
+ CommonName: "test.example.com",
+ Organization: []string{"Acme Co"},
+ },
+ NotBefore: time.SecondsToUTC(1000),
+ NotAfter: time.SecondsToUTC(100000),
+
+ SubjectKeyId: []byte{1, 2, 3, 4},
+ KeyUsage: KeyUsageCertSign,
+
+ BasicConstraintsValid: true,
+ IsCA: true,
+ DNSNames: []string{"test.example.com"},
+
+ PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
+ }
+
+ derBytes, err := CreateCertificate(random, &template, &template, &priv.PublicKey, priv)
+ if err != nil {
+ t.Errorf("Failed to create certificate: %s", err)
+ return
+ }
+
+ cert, err := ParseCertificate(derBytes)
+ if err != nil {
+ t.Errorf("Failed to parse certificate: %s", err)
+ return
+ }
+
+ if len(cert.PolicyIdentifiers) != 1 || !cert.PolicyIdentifiers[0].Equal(template.PolicyIdentifiers[0]) {
+ t.Errorf("Failed to parse policy identifiers: got:%#v want:%#v", cert.PolicyIdentifiers, template.PolicyIdentifiers)
+ }
+
+ err = cert.CheckSignatureFrom(cert)
+ if err != nil {
+ t.Errorf("Signature verification failed: %s", err)
+ return
+ }
+}
diff --git a/libgo/go/crypto/xtea/block.go b/libgo/go/crypto/xtea/block.go
new file mode 100644
index 000000000..3ac36d038
--- /dev/null
+++ b/libgo/go/crypto/xtea/block.go
@@ -0,0 +1,66 @@
+// 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.
+
+/*
+ Implementation adapted from Needham and Wheeler's paper:
+ http://www.cix.co.uk/~klockstone/xtea.pdf
+
+ A precalculated look up table is used during encryption/decryption for values that are based purely on the key.
+*/
+
+package xtea
+
+// XTEA is based on 64 rounds.
+const numRounds = 64
+
+// blockToUint32 reads an 8 byte slice into two uint32s.
+// The block is treated as big endian.
+func blockToUint32(src []byte) (uint32, uint32) {
+ r0 := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r1 := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+ return r0, r1
+}
+
+// uint32ToBlock writes two unint32s into an 8 byte data block.
+// Values are written as big endian.
+func uint32ToBlock(v0, v1 uint32, dst []byte) {
+ dst[0] = byte(v0 >> 24)
+ dst[1] = byte(v0 >> 16)
+ dst[2] = byte(v0 >> 8)
+ dst[3] = byte(v0)
+ dst[4] = byte(v1 >> 24)
+ dst[5] = byte(v1 >> 16)
+ dst[6] = byte(v1 >> 8)
+ dst[7] = byte(v1 >> 0)
+}
+
+// encryptBlock encrypts a single 8 byte block using XTEA.
+func encryptBlock(c *Cipher, dst, src []byte) {
+ v0, v1 := blockToUint32(src)
+
+ // Two rounds of XTEA applied per loop
+ for i := 0; i < numRounds; {
+ v0 += ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
+ i++
+ v1 += ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
+ i++
+ }
+
+ uint32ToBlock(v0, v1, dst)
+}
+
+// decryptBlock decrypt a single 8 byte block using XTEA.
+func decryptBlock(c *Cipher, dst, src []byte) {
+ v0, v1 := blockToUint32(src)
+
+ // Two rounds of XTEA applied per loop
+ for i := numRounds; i > 0; {
+ i--
+ v1 -= ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
+ i--
+ v0 -= ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
+ }
+
+ uint32ToBlock(v0, v1, dst)
+}
diff --git a/libgo/go/crypto/xtea/cipher.go b/libgo/go/crypto/xtea/cipher.go
new file mode 100644
index 000000000..b0fa2a184
--- /dev/null
+++ b/libgo/go/crypto/xtea/cipher.go
@@ -0,0 +1,92 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements XTEA encryption, as defined in Needham and
+// Wheeler's 1997 technical report, "Tea extensions."
+package xtea
+
+// For details, see http://www.cix.co.uk/~klockstone/xtea.pdf
+
+import (
+ "os"
+ "strconv"
+)
+
+// The XTEA block size in bytes.
+const BlockSize = 8
+
+// A Cipher is an instance of an XTEA cipher using a particular key.
+// table contains a series of precalculated values that are used each round.
+type Cipher struct {
+ table [64]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/xtea: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new Cipher.
+// The key argument should be the XTEA key.
+// XTEA only supports 128 bit (16 byte) keys.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ k := len(key)
+ switch k {
+ default:
+ return nil, KeySizeError(k)
+ case 16:
+ break
+ }
+
+ c := new(Cipher)
+ initCipher(c, key)
+
+ return c, nil
+}
+
+// BlockSize returns the XTEA block size, 8 bytes.
+// It is necessary to satisfy the Cipher interface in the
+// package "crypto/block".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 8 byte buffer src using the key and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c, dst, src) }
+
+// Decrypt decrypts the 8 byte buffer src using the key k and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c, dst, src) }
+
+// Reset zeros the table, so that it will no longer appear in the process's memory.
+func (c *Cipher) Reset() {
+ for i := 0; i < len(c.table); i++ {
+ c.table[i] = 0
+ }
+}
+
+// initCipher initializes the cipher context by creating a look up table
+// of precalculated values that are based on the key.
+func initCipher(c *Cipher, key []byte) {
+ // Load the key into four uint32s
+ var k [4]uint32
+ for i := 0; i < len(k); i++ {
+ j := i << 2 // Multiply by 4
+ k[i] = uint32(key[j+0])<<24 | uint32(key[j+1])<<16 | uint32(key[j+2])<<8 | uint32(key[j+3])
+ }
+
+ // Precalculate the table
+ const delta = 0x9E3779B9
+ var sum uint32 = 0
+
+ // Two rounds of XTEA applied per loop
+ for i := 0; i < numRounds; {
+ c.table[i] = sum + k[sum&3]
+ i++
+ sum += delta
+ c.table[i] = sum + k[(sum>>11)&3]
+ i++
+ }
+}
diff --git a/libgo/go/crypto/xtea/xtea_test.go b/libgo/go/crypto/xtea/xtea_test.go
new file mode 100644
index 000000000..03934f169
--- /dev/null
+++ b/libgo/go/crypto/xtea/xtea_test.go
@@ -0,0 +1,246 @@
+// 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 xtea
+
+import (
+ "testing"
+)
+
+// A sample test key for when we just want to initialise a cipher
+var testKey = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}
+
+// Test that the block size for XTEA is correct
+func TestBlocksize(t *testing.T) {
+ if BlockSize != 8 {
+ t.Errorf("BlockSize constant - expected 8, got %d", BlockSize)
+ return
+ }
+
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+ return
+ }
+
+ result := c.BlockSize()
+ if result != 8 {
+ t.Errorf("BlockSize function - expected 8, gotr %d", result)
+ return
+ }
+}
+
+// A series of test values to confirm that the Cipher.table array was initialised correctly
+var testTable = []uint32{
+ 0x00112233, 0x6B1568B8, 0xE28CE030, 0xC5089E2D, 0xC5089E2D, 0x1EFBD3A2, 0xA7845C2A, 0x78EF0917,
+ 0x78EF0917, 0x172682D0, 0x5B6AC714, 0x822AC955, 0x3DE68511, 0xDC1DFECA, 0x2062430E, 0x3611343F,
+ 0xF1CCEFFB, 0x900469B4, 0xD448ADF8, 0x2E3BE36D, 0xB6C46BF5, 0x994029F2, 0x994029F2, 0xF3335F67,
+ 0x6AAAD6DF, 0x4D2694DC, 0x4D2694DC, 0xEB5E0E95, 0x2FA252D9, 0x4551440A, 0x121E10D6, 0xB0558A8F,
+ 0xE388BDC3, 0x0A48C004, 0xC6047BC0, 0x643BF579, 0xA88039BD, 0x02736F32, 0x8AFBF7BA, 0x5C66A4A7,
+ 0x5C66A4A7, 0xC76AEB2C, 0x3EE262A4, 0x215E20A1, 0x215E20A1, 0x7B515616, 0x03D9DE9E, 0x1988CFCF,
+ 0xD5448B8B, 0x737C0544, 0xB7C04988, 0xDE804BC9, 0x9A3C0785, 0x3873813E, 0x7CB7C582, 0xD6AAFAF7,
+ 0x4E22726F, 0x309E306C, 0x309E306C, 0x8A9165E1, 0x1319EE69, 0xF595AC66, 0xF595AC66, 0x4F88E1DB,
+}
+
+// Test that the cipher context is initialised correctly
+func TestCipherInit(t *testing.T) {
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+ return
+ }
+
+ for i := 0; i < len(c.table); i++ {
+ if c.table[i] != testTable[i] {
+ t.Errorf("NewCipher() failed to initialise Cipher.table[%d] correctly. Expected %08X, got %08X", i, testTable[i], c.table[i])
+ break
+ }
+ }
+}
+
+// Test that invalid key sizes return an error
+func TestInvalidKeySize(t *testing.T) {
+ // Test a long key
+ key := []byte{
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ }
+
+ _, err := NewCipher(key)
+ if err == nil {
+ t.Errorf("Invalid key size %d didn't result in an error.", len(key))
+ }
+
+ // Test a short key
+ key = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}
+
+ _, err = NewCipher(key)
+ if err == nil {
+ t.Errorf("Invalid key size %d didn't result in an error.", len(key))
+ }
+}
+
+// Test that we can correctly decode some bytes we have encoded
+func TestEncodeDecode(t *testing.T) {
+ original := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}
+ input := original
+ output := make([]byte, BlockSize)
+
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+ return
+ }
+
+ // Encrypt the input block
+ c.Encrypt(output, input)
+
+ // Check that the output does not match the input
+ differs := false
+ for i := 0; i < len(input); i++ {
+ if output[i] != input[i] {
+ differs = true
+ break
+ }
+ }
+ if differs == false {
+ t.Error("Cipher.Encrypt: Failed to encrypt the input block.")
+ return
+ }
+
+ // Decrypt the block we just encrypted
+ input = output
+ output = make([]byte, BlockSize)
+ c.Decrypt(output, input)
+
+ // Check that the output from decrypt matches our initial input
+ for i := 0; i < len(input); i++ {
+ if output[i] != original[i] {
+ t.Errorf("Decrypted byte %d differed. Expected %02X, got %02X\n", i, original[i], output[i])
+ return
+ }
+ }
+}
+
+// Test Vectors
+type CryptTest struct {
+ key []byte
+ plainText []byte
+ cipherText []byte
+}
+
+var CryptTests = []CryptTest{
+ // These were sourced from http://www.freemedialibrary.com/index.php/XTEA_test_vectors
+ {
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5},
+ },
+ {
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ []byte{0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8},
+ },
+ {
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ []byte{0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ },
+
+ // These vectors are from http://wiki.secondlife.com/wiki/XTEA_Strong_Encryption_Implementation#Bouncy_Castle_C.23_API
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xDE, 0xE9, 0xD4, 0xD8, 0xF7, 0x13, 0x1E, 0xD9},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
+ []byte{0x06, 0x5C, 0x1B, 0x89, 0x75, 0xC6, 0xA8, 0x16},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x1F, 0xF9, 0xA0, 0x26, 0x1A, 0xC6, 0x42, 0x64},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
+ []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
+ []byte{0x8C, 0x67, 0x15, 0x5B, 0x2E, 0xF9, 0x1E, 0xAD},
+ },
+}
+
+// Test encryption
+func TestCipherEncrypt(t *testing.T) {
+ for i, tt := range CryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
+ continue
+ }
+
+ out := make([]byte, len(tt.plainText))
+ c.Encrypt(out, tt.plainText)
+
+ for j := 0; j < len(out); j++ {
+ if out[j] != tt.cipherText[j] {
+ t.Errorf("Cipher.Encrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.cipherText[j])
+ break
+ }
+ }
+ }
+}
+
+// Test decryption
+func TestCipherDecrypt(t *testing.T) {
+ for i, tt := range CryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
+ continue
+ }
+
+ out := make([]byte, len(tt.cipherText))
+ c.Decrypt(out, tt.cipherText)
+
+ for j := 0; j < len(out); j++ {
+ if out[j] != tt.plainText[j] {
+ t.Errorf("Cipher.Decrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.plainText[j])
+ break
+ }
+ }
+ }
+}
+
+// Test resetting the cipher context
+func TestReset(t *testing.T) {
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+ return
+ }
+
+ c.Reset()
+ for i := 0; i < len(c.table); i++ {
+ if c.table[i] != 0 {
+ t.Errorf("Cipher.Reset: Failed to clear Cipher.table[%d]. expected 0, got %08X", i, c.table[i])
+ return
+ }
+ }
+}
diff --git a/libgo/go/debug/dwarf/buf.go b/libgo/go/debug/dwarf/buf.go
new file mode 100644
index 000000000..2d29cebdd
--- /dev/null
+++ b/libgo/go/debug/dwarf/buf.go
@@ -0,0 +1,154 @@
+// 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.
+
+// Buffered reading and decoding of DWARF data streams.
+
+package dwarf
+
+import (
+ "encoding/binary"
+ "os"
+ "strconv"
+)
+
+// Data buffer being decoded.
+type buf struct {
+ dwarf *Data
+ order binary.ByteOrder
+ name string
+ off Offset
+ data []byte
+ addrsize int
+ err os.Error
+}
+
+func makeBuf(d *Data, name string, off Offset, data []byte, addrsize int) buf {
+ return buf{d, d.order, name, off, data, addrsize, nil}
+}
+
+func (b *buf) uint8() uint8 {
+ if len(b.data) < 1 {
+ b.error("underflow")
+ return 0
+ }
+ val := b.data[0]
+ b.data = b.data[1:]
+ b.off++
+ return val
+}
+
+func (b *buf) bytes(n int) []byte {
+ if len(b.data) < n {
+ b.error("underflow")
+ return nil
+ }
+ data := b.data[0:n]
+ b.data = b.data[n:]
+ b.off += Offset(n)
+ return data
+}
+
+func (b *buf) skip(n int) { b.bytes(n) }
+
+func (b *buf) string() string {
+ for i := 0; i < len(b.data); i++ {
+ if b.data[i] == 0 {
+ s := string(b.data[0:i])
+ b.data = b.data[i+1:]
+ b.off += Offset(i + 1)
+ return s
+ }
+ }
+ b.error("underflow")
+ return ""
+}
+
+func (b *buf) uint16() uint16 {
+ a := b.bytes(2)
+ if a == nil {
+ return 0
+ }
+ return b.order.Uint16(a)
+}
+
+func (b *buf) uint32() uint32 {
+ a := b.bytes(4)
+ if a == nil {
+ return 0
+ }
+ return b.order.Uint32(a)
+}
+
+func (b *buf) uint64() uint64 {
+ a := b.bytes(8)
+ if a == nil {
+ return 0
+ }
+ return b.order.Uint64(a)
+}
+
+// Read a varint, which is 7 bits per byte, little endian.
+// the 0x80 bit means read another byte.
+func (b *buf) varint() (c uint64, bits uint) {
+ for i := 0; i < len(b.data); i++ {
+ byte := b.data[i]
+ c |= uint64(byte&0x7F) << bits
+ bits += 7
+ if byte&0x80 == 0 {
+ b.off += Offset(i + 1)
+ b.data = b.data[i+1:]
+ return c, bits
+ }
+ }
+ return 0, 0
+}
+
+// Unsigned int is just a varint.
+func (b *buf) uint() uint64 {
+ x, _ := b.varint()
+ return x
+}
+
+// Signed int is a sign-extended varint.
+func (b *buf) int() int64 {
+ ux, bits := b.varint()
+ x := int64(ux)
+ if x&(1<<(bits-1)) != 0 {
+ x |= -1 << bits
+ }
+ return x
+}
+
+// Address-sized uint.
+func (b *buf) addr() uint64 {
+ switch b.addrsize {
+ case 1:
+ return uint64(b.uint8())
+ case 2:
+ return uint64(b.uint16())
+ case 4:
+ return uint64(b.uint32())
+ case 8:
+ return uint64(b.uint64())
+ }
+ b.error("unknown address size")
+ return 0
+}
+
+func (b *buf) error(s string) {
+ if b.err == nil {
+ b.data = nil
+ b.err = DecodeError{b.name, b.off, s}
+ }
+}
+
+type DecodeError struct {
+ Name string
+ Offset Offset
+ Error string
+}
+
+func (e DecodeError) String() string {
+ return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.Itob64(int64(e.Offset), 16) + ": " + e.Error
+}
diff --git a/libgo/go/debug/dwarf/const.go b/libgo/go/debug/dwarf/const.go
new file mode 100644
index 000000000..1a3fec155
--- /dev/null
+++ b/libgo/go/debug/dwarf/const.go
@@ -0,0 +1,433 @@
+// 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.
+
+// Constants
+
+package dwarf
+
+import "strconv"
+
+// An Attr identifies the attribute type in a DWARF Entry's Field.
+type Attr uint32
+
+const (
+ AttrSibling Attr = 0x01
+ AttrLocation Attr = 0x02
+ AttrName Attr = 0x03
+ AttrOrdering Attr = 0x09
+ AttrByteSize Attr = 0x0B
+ AttrBitOffset Attr = 0x0C
+ AttrBitSize Attr = 0x0D
+ AttrStmtList Attr = 0x10
+ AttrLowpc Attr = 0x11
+ AttrHighpc Attr = 0x12
+ AttrLanguage Attr = 0x13
+ AttrDiscr Attr = 0x15
+ AttrDiscrValue Attr = 0x16
+ AttrVisibility Attr = 0x17
+ AttrImport Attr = 0x18
+ AttrStringLength Attr = 0x19
+ AttrCommonRef Attr = 0x1A
+ AttrCompDir Attr = 0x1B
+ AttrConstValue Attr = 0x1C
+ AttrContainingType Attr = 0x1D
+ AttrDefaultValue Attr = 0x1E
+ AttrInline Attr = 0x20
+ AttrIsOptional Attr = 0x21
+ AttrLowerBound Attr = 0x22
+ AttrProducer Attr = 0x25
+ AttrPrototyped Attr = 0x27
+ AttrReturnAddr Attr = 0x2A
+ AttrStartScope Attr = 0x2C
+ AttrStrideSize Attr = 0x2E
+ AttrUpperBound Attr = 0x2F
+ AttrAbstractOrigin Attr = 0x31
+ AttrAccessibility Attr = 0x32
+ AttrAddrClass Attr = 0x33
+ AttrArtificial Attr = 0x34
+ AttrBaseTypes Attr = 0x35
+ AttrCalling Attr = 0x36
+ AttrCount Attr = 0x37
+ AttrDataMemberLoc Attr = 0x38
+ AttrDeclColumn Attr = 0x39
+ AttrDeclFile Attr = 0x3A
+ AttrDeclLine Attr = 0x3B
+ AttrDeclaration Attr = 0x3C
+ AttrDiscrList Attr = 0x3D
+ AttrEncoding Attr = 0x3E
+ AttrExternal Attr = 0x3F
+ AttrFrameBase Attr = 0x40
+ AttrFriend Attr = 0x41
+ AttrIdentifierCase Attr = 0x42
+ AttrMacroInfo Attr = 0x43
+ AttrNamelistItem Attr = 0x44
+ AttrPriority Attr = 0x45
+ AttrSegment Attr = 0x46
+ AttrSpecification Attr = 0x47
+ AttrStaticLink Attr = 0x48
+ AttrType Attr = 0x49
+ AttrUseLocation Attr = 0x4A
+ AttrVarParam Attr = 0x4B
+ AttrVirtuality Attr = 0x4C
+ AttrVtableElemLoc Attr = 0x4D
+ AttrAllocated Attr = 0x4E
+ AttrAssociated Attr = 0x4F
+ AttrDataLocation Attr = 0x50
+ AttrStride Attr = 0x51
+ AttrEntrypc Attr = 0x52
+ AttrUseUTF8 Attr = 0x53
+ AttrExtension Attr = 0x54
+ AttrRanges Attr = 0x55
+ AttrTrampoline Attr = 0x56
+ AttrCallColumn Attr = 0x57
+ AttrCallFile Attr = 0x58
+ AttrCallLine Attr = 0x59
+ AttrDescription Attr = 0x5A
+)
+
+var attrNames = [...]string{
+ AttrSibling: "Sibling",
+ AttrLocation: "Location",
+ AttrName: "Name",
+ AttrOrdering: "Ordering",
+ AttrByteSize: "ByteSize",
+ AttrBitOffset: "BitOffset",
+ AttrBitSize: "BitSize",
+ AttrStmtList: "StmtList",
+ AttrLowpc: "Lowpc",
+ AttrHighpc: "Highpc",
+ AttrLanguage: "Language",
+ AttrDiscr: "Discr",
+ AttrDiscrValue: "DiscrValue",
+ AttrVisibility: "Visibility",
+ AttrImport: "Import",
+ AttrStringLength: "StringLength",
+ AttrCommonRef: "CommonRef",
+ AttrCompDir: "CompDir",
+ AttrConstValue: "ConstValue",
+ AttrContainingType: "ContainingType",
+ AttrDefaultValue: "DefaultValue",
+ AttrInline: "Inline",
+ AttrIsOptional: "IsOptional",
+ AttrLowerBound: "LowerBound",
+ AttrProducer: "Producer",
+ AttrPrototyped: "Prototyped",
+ AttrReturnAddr: "ReturnAddr",
+ AttrStartScope: "StartScope",
+ AttrStrideSize: "StrideSize",
+ AttrUpperBound: "UpperBound",
+ AttrAbstractOrigin: "AbstractOrigin",
+ AttrAccessibility: "Accessibility",
+ AttrAddrClass: "AddrClass",
+ AttrArtificial: "Artificial",
+ AttrBaseTypes: "BaseTypes",
+ AttrCalling: "Calling",
+ AttrCount: "Count",
+ AttrDataMemberLoc: "DataMemberLoc",
+ AttrDeclColumn: "DeclColumn",
+ AttrDeclFile: "DeclFile",
+ AttrDeclLine: "DeclLine",
+ AttrDeclaration: "Declaration",
+ AttrDiscrList: "DiscrList",
+ AttrEncoding: "Encoding",
+ AttrExternal: "External",
+ AttrFrameBase: "FrameBase",
+ AttrFriend: "Friend",
+ AttrIdentifierCase: "IdentifierCase",
+ AttrMacroInfo: "MacroInfo",
+ AttrNamelistItem: "NamelistItem",
+ AttrPriority: "Priority",
+ AttrSegment: "Segment",
+ AttrSpecification: "Specification",
+ AttrStaticLink: "StaticLink",
+ AttrType: "Type",
+ AttrUseLocation: "UseLocation",
+ AttrVarParam: "VarParam",
+ AttrVirtuality: "Virtuality",
+ AttrVtableElemLoc: "VtableElemLoc",
+ AttrAllocated: "Allocated",
+ AttrAssociated: "Associated",
+ AttrDataLocation: "DataLocation",
+ AttrStride: "Stride",
+ AttrEntrypc: "Entrypc",
+ AttrUseUTF8: "UseUTF8",
+ AttrExtension: "Extension",
+ AttrRanges: "Ranges",
+ AttrTrampoline: "Trampoline",
+ AttrCallColumn: "CallColumn",
+ AttrCallFile: "CallFile",
+ AttrCallLine: "CallLine",
+ AttrDescription: "Description",
+}
+
+func (a Attr) String() string {
+ if int(a) < len(attrNames) {
+ s := attrNames[a]
+ if s != "" {
+ return s
+ }
+ }
+ return strconv.Itoa(int(a))
+}
+
+func (a Attr) GoString() string {
+ if int(a) < len(attrNames) {
+ s := attrNames[a]
+ if s != "" {
+ return "dwarf.Attr" + s
+ }
+ }
+ return "dwarf.Attr(" + strconv.Itoa64(int64(a)) + ")"
+}
+
+// A format is a DWARF data encoding format.
+type format uint32
+
+const (
+ // value formats
+ formAddr format = 0x01
+ formDwarfBlock2 format = 0x03
+ formDwarfBlock4 format = 0x04
+ formData2 format = 0x05
+ formData4 format = 0x06
+ formData8 format = 0x07
+ formString format = 0x08
+ formDwarfBlock format = 0x09
+ formDwarfBlock1 format = 0x0A
+ formData1 format = 0x0B
+ formFlag format = 0x0C
+ formSdata format = 0x0D
+ formStrp format = 0x0E
+ formUdata format = 0x0F
+ formRefAddr format = 0x10
+ formRef1 format = 0x11
+ formRef2 format = 0x12
+ formRef4 format = 0x13
+ formRef8 format = 0x14
+ formRefUdata format = 0x15
+ formIndirect format = 0x16
+)
+
+// A Tag is the classification (the type) of an Entry.
+type Tag uint32
+
+const (
+ TagArrayType Tag = 0x01
+ TagClassType Tag = 0x02
+ TagEntryPoint Tag = 0x03
+ TagEnumerationType Tag = 0x04
+ TagFormalParameter Tag = 0x05
+ TagImportedDeclaration Tag = 0x08
+ TagLabel Tag = 0x0A
+ TagLexDwarfBlock Tag = 0x0B
+ TagMember Tag = 0x0D
+ TagPointerType Tag = 0x0F
+ TagReferenceType Tag = 0x10
+ TagCompileUnit Tag = 0x11
+ TagStringType Tag = 0x12
+ TagStructType Tag = 0x13
+ TagSubroutineType Tag = 0x15
+ TagTypedef Tag = 0x16
+ TagUnionType Tag = 0x17
+ TagUnspecifiedParameters Tag = 0x18
+ TagVariant Tag = 0x19
+ TagCommonDwarfBlock Tag = 0x1A
+ TagCommonInclusion Tag = 0x1B
+ TagInheritance Tag = 0x1C
+ TagInlinedSubroutine Tag = 0x1D
+ TagModule Tag = 0x1E
+ TagPtrToMemberType Tag = 0x1F
+ TagSetType Tag = 0x20
+ TagSubrangeType Tag = 0x21
+ TagWithStmt Tag = 0x22
+ TagAccessDeclaration Tag = 0x23
+ TagBaseType Tag = 0x24
+ TagCatchDwarfBlock Tag = 0x25
+ TagConstType Tag = 0x26
+ TagConstant Tag = 0x27
+ TagEnumerator Tag = 0x28
+ TagFileType Tag = 0x29
+ TagFriend Tag = 0x2A
+ TagNamelist Tag = 0x2B
+ TagNamelistItem Tag = 0x2C
+ TagPackedType Tag = 0x2D
+ TagSubprogram Tag = 0x2E
+ TagTemplateTypeParameter Tag = 0x2F
+ TagTemplateValueParameter Tag = 0x30
+ TagThrownType Tag = 0x31
+ TagTryDwarfBlock Tag = 0x32
+ TagVariantPart Tag = 0x33
+ TagVariable Tag = 0x34
+ TagVolatileType Tag = 0x35
+ TagDwarfProcedure Tag = 0x36
+ TagRestrictType Tag = 0x37
+ TagInterfaceType Tag = 0x38
+ TagNamespace Tag = 0x39
+ TagImportedModule Tag = 0x3A
+ TagUnspecifiedType Tag = 0x3B
+ TagPartialUnit Tag = 0x3C
+ TagImportedUnit Tag = 0x3D
+ TagMutableType Tag = 0x3E
+)
+
+var tagNames = [...]string{
+ TagArrayType: "ArrayType",
+ TagClassType: "ClassType",
+ TagEntryPoint: "EntryPoint",
+ TagEnumerationType: "EnumerationType",
+ TagFormalParameter: "FormalParameter",
+ TagImportedDeclaration: "ImportedDeclaration",
+ TagLabel: "Label",
+ TagLexDwarfBlock: "LexDwarfBlock",
+ TagMember: "Member",
+ TagPointerType: "PointerType",
+ TagReferenceType: "ReferenceType",
+ TagCompileUnit: "CompileUnit",
+ TagStringType: "StringType",
+ TagStructType: "StructType",
+ TagSubroutineType: "SubroutineType",
+ TagTypedef: "Typedef",
+ TagUnionType: "UnionType",
+ TagUnspecifiedParameters: "UnspecifiedParameters",
+ TagVariant: "Variant",
+ TagCommonDwarfBlock: "CommonDwarfBlock",
+ TagCommonInclusion: "CommonInclusion",
+ TagInheritance: "Inheritance",
+ TagInlinedSubroutine: "InlinedSubroutine",
+ TagModule: "Module",
+ TagPtrToMemberType: "PtrToMemberType",
+ TagSetType: "SetType",
+ TagSubrangeType: "SubrangeType",
+ TagWithStmt: "WithStmt",
+ TagAccessDeclaration: "AccessDeclaration",
+ TagBaseType: "BaseType",
+ TagCatchDwarfBlock: "CatchDwarfBlock",
+ TagConstType: "ConstType",
+ TagConstant: "Constant",
+ TagEnumerator: "Enumerator",
+ TagFileType: "FileType",
+ TagFriend: "Friend",
+ TagNamelist: "Namelist",
+ TagNamelistItem: "NamelistItem",
+ TagPackedType: "PackedType",
+ TagSubprogram: "Subprogram",
+ TagTemplateTypeParameter: "TemplateTypeParameter",
+ TagTemplateValueParameter: "TemplateValueParameter",
+ TagThrownType: "ThrownType",
+ TagTryDwarfBlock: "TryDwarfBlock",
+ TagVariantPart: "VariantPart",
+ TagVariable: "Variable",
+ TagVolatileType: "VolatileType",
+ TagDwarfProcedure: "DwarfProcedure",
+ TagRestrictType: "RestrictType",
+ TagInterfaceType: "InterfaceType",
+ TagNamespace: "Namespace",
+ TagImportedModule: "ImportedModule",
+ TagUnspecifiedType: "UnspecifiedType",
+ TagPartialUnit: "PartialUnit",
+ TagImportedUnit: "ImportedUnit",
+ TagMutableType: "MutableType",
+}
+
+func (t Tag) String() string {
+ if int(t) < len(tagNames) {
+ s := tagNames[t]
+ if s != "" {
+ return s
+ }
+ }
+ return strconv.Itoa(int(t))
+}
+
+func (t Tag) GoString() string {
+ if int(t) < len(tagNames) {
+ s := tagNames[t]
+ if s != "" {
+ return "dwarf.Tag" + s
+ }
+ }
+ return "dwarf.Tag(" + strconv.Itoa64(int64(t)) + ")"
+}
+
+// Location expression operators.
+// The debug info encodes value locations like 8(R3)
+// as a sequence of these op codes.
+// This package does not implement full expressions;
+// the opPlusUconst operator is expected by the type parser.
+const (
+ opAddr = 0x03 /* 1 op, const addr */
+ opDeref = 0x06
+ opConst1u = 0x08 /* 1 op, 1 byte const */
+ opConst1s = 0x09 /* " signed */
+ opConst2u = 0x0A /* 1 op, 2 byte const */
+ opConst2s = 0x0B /* " signed */
+ opConst4u = 0x0C /* 1 op, 4 byte const */
+ opConst4s = 0x0D /* " signed */
+ opConst8u = 0x0E /* 1 op, 8 byte const */
+ opConst8s = 0x0F /* " signed */
+ opConstu = 0x10 /* 1 op, LEB128 const */
+ opConsts = 0x11 /* " signed */
+ opDup = 0x12
+ opDrop = 0x13
+ opOver = 0x14
+ opPick = 0x15 /* 1 op, 1 byte stack index */
+ opSwap = 0x16
+ opRot = 0x17
+ opXderef = 0x18
+ opAbs = 0x19
+ opAnd = 0x1A
+ opDiv = 0x1B
+ opMinus = 0x1C
+ opMod = 0x1D
+ opMul = 0x1E
+ opNeg = 0x1F
+ opNot = 0x20
+ opOr = 0x21
+ opPlus = 0x22
+ opPlusUconst = 0x23 /* 1 op, ULEB128 addend */
+ opShl = 0x24
+ opShr = 0x25
+ opShra = 0x26
+ opXor = 0x27
+ opSkip = 0x2F /* 1 op, signed 2-byte constant */
+ opBra = 0x28 /* 1 op, signed 2-byte constant */
+ opEq = 0x29
+ opGe = 0x2A
+ opGt = 0x2B
+ opLe = 0x2C
+ opLt = 0x2D
+ opNe = 0x2E
+ opLit0 = 0x30
+ /* OpLitN = OpLit0 + N for N = 0..31 */
+ opReg0 = 0x50
+ /* OpRegN = OpReg0 + N for N = 0..31 */
+ opBreg0 = 0x70 /* 1 op, signed LEB128 constant */
+ /* OpBregN = OpBreg0 + N for N = 0..31 */
+ opRegx = 0x90 /* 1 op, ULEB128 register */
+ opFbreg = 0x91 /* 1 op, SLEB128 offset */
+ opBregx = 0x92 /* 2 op, ULEB128 reg; SLEB128 off */
+ opPiece = 0x93 /* 1 op, ULEB128 size of piece */
+ opDerefSize = 0x94 /* 1-byte size of data retrieved */
+ opXderefSize = 0x95 /* 1-byte size of data retrieved */
+ opNop = 0x96
+ /* next four new in Dwarf v3 */
+ opPushObjAddr = 0x97
+ opCall2 = 0x98 /* 2-byte offset of DIE */
+ opCall4 = 0x99 /* 4-byte offset of DIE */
+ opCallRef = 0x9A /* 4- or 8- byte offset of DIE */
+ /* 0xE0-0xFF reserved for user-specific */
+)
+
+// Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry.
+const (
+ encAddress = 0x01
+ encBoolean = 0x02
+ encComplexFloat = 0x03
+ encFloat = 0x04
+ encSigned = 0x05
+ encSignedChar = 0x06
+ encUnsigned = 0x07
+ encUnsignedChar = 0x08
+ encImaginaryFloat = 0x09
+)
diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go
new file mode 100644
index 000000000..549e5c2cc
--- /dev/null
+++ b/libgo/go/debug/dwarf/entry.go
@@ -0,0 +1,343 @@
+// 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.
+
+// DWARF debug information entry parser.
+// An entry is a sequence of data items of a given format.
+// The first word in the entry is an index into what DWARF
+// calls the ``abbreviation table.'' An abbreviation is really
+// just a type descriptor: it's an array of attribute tag/value format pairs.
+
+package dwarf
+
+import "os"
+
+// a single entry's description: a sequence of attributes
+type abbrev struct {
+ tag Tag
+ children bool
+ field []afield
+}
+
+type afield struct {
+ attr Attr
+ fmt format
+}
+
+// a map from entry format ids to their descriptions
+type abbrevTable map[uint32]abbrev
+
+// ParseAbbrev returns the abbreviation table that starts at byte off
+// in the .debug_abbrev section.
+func (d *Data) parseAbbrev(off uint32) (abbrevTable, os.Error) {
+ if m, ok := d.abbrevCache[off]; ok {
+ return m, nil
+ }
+
+ data := d.abbrev
+ if off > uint32(len(data)) {
+ data = nil
+ } else {
+ data = data[off:]
+ }
+ b := makeBuf(d, "abbrev", 0, data, 0)
+
+ // Error handling is simplified by the buf getters
+ // returning an endless stream of 0s after an error.
+ m := make(abbrevTable)
+ for {
+ // Table ends with id == 0.
+ id := uint32(b.uint())
+ if id == 0 {
+ break
+ }
+
+ // Walk over attributes, counting.
+ n := 0
+ b1 := b // Read from copy of b.
+ b1.uint()
+ b1.uint8()
+ for {
+ tag := b1.uint()
+ fmt := b1.uint()
+ if tag == 0 && fmt == 0 {
+ break
+ }
+ n++
+ }
+ if b1.err != nil {
+ return nil, b1.err
+ }
+
+ // Walk over attributes again, this time writing them down.
+ var a abbrev
+ a.tag = Tag(b.uint())
+ a.children = b.uint8() != 0
+ a.field = make([]afield, n)
+ for i := range a.field {
+ a.field[i].attr = Attr(b.uint())
+ a.field[i].fmt = format(b.uint())
+ }
+ b.uint()
+ b.uint()
+
+ m[id] = a
+ }
+ if b.err != nil {
+ return nil, b.err
+ }
+ d.abbrevCache[off] = m
+ return m, nil
+}
+
+// An entry is a sequence of attribute/value pairs.
+type Entry struct {
+ Offset Offset // offset of Entry in DWARF info
+ Tag Tag // tag (kind of Entry)
+ Children bool // whether Entry is followed by children
+ Field []Field
+}
+
+// A Field is a single attribute/value pair in an Entry.
+type Field struct {
+ Attr Attr
+ Val interface{}
+}
+
+// Val returns the value associated with attribute Attr in Entry,
+// or nil if there is no such attribute.
+//
+// A common idiom is to merge the check for nil return with
+// the check that the value has the expected dynamic type, as in:
+// v, ok := e.Val(AttrSibling).(int64);
+//
+func (e *Entry) Val(a Attr) interface{} {
+ for _, f := range e.Field {
+ if f.Attr == a {
+ return f.Val
+ }
+ }
+ return nil
+}
+
+// An Offset represents the location of an Entry within the DWARF info.
+// (See Reader.Seek.)
+type Offset uint32
+
+// Entry reads a single entry from buf, decoding
+// according to the given abbreviation table.
+func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
+ off := b.off
+ id := uint32(b.uint())
+ if id == 0 {
+ return &Entry{}
+ }
+ a, ok := atab[id]
+ if !ok {
+ b.error("unknown abbreviation table index")
+ return nil
+ }
+ e := &Entry{
+ Offset: off,
+ Tag: a.tag,
+ Children: a.children,
+ Field: make([]Field, len(a.field)),
+ }
+ for i := range e.Field {
+ e.Field[i].Attr = a.field[i].attr
+ fmt := a.field[i].fmt
+ if fmt == formIndirect {
+ fmt = format(b.uint())
+ }
+ var val interface{}
+ switch fmt {
+ default:
+ b.error("unknown entry attr format")
+
+ // address
+ case formAddr:
+ val = b.addr()
+
+ // block
+ case formDwarfBlock1:
+ val = b.bytes(int(b.uint8()))
+ case formDwarfBlock2:
+ val = b.bytes(int(b.uint16()))
+ case formDwarfBlock4:
+ val = b.bytes(int(b.uint32()))
+ case formDwarfBlock:
+ val = b.bytes(int(b.uint()))
+
+ // constant
+ case formData1:
+ val = int64(b.uint8())
+ case formData2:
+ val = int64(b.uint16())
+ case formData4:
+ val = int64(b.uint32())
+ case formData8:
+ val = int64(b.uint64())
+ case formSdata:
+ val = int64(b.int())
+ case formUdata:
+ val = int64(b.uint())
+
+ // flag
+ case formFlag:
+ val = b.uint8() == 1
+
+ // reference to other entry
+ case formRefAddr:
+ val = Offset(b.addr())
+ case formRef1:
+ val = Offset(b.uint8()) + ubase
+ case formRef2:
+ val = Offset(b.uint16()) + ubase
+ case formRef4:
+ val = Offset(b.uint32()) + ubase
+ case formRef8:
+ val = Offset(b.uint64()) + ubase
+ case formRefUdata:
+ val = Offset(b.uint()) + ubase
+
+ // string
+ case formString:
+ val = b.string()
+ case formStrp:
+ off := b.uint32() // offset into .debug_str
+ if b.err != nil {
+ return nil
+ }
+ b1 := makeBuf(b.dwarf, "str", 0, b.dwarf.str, 0)
+ b1.skip(int(off))
+ val = b1.string()
+ if b1.err != nil {
+ b.err = b1.err
+ return nil
+ }
+ }
+ e.Field[i].Val = val
+ }
+ if b.err != nil {
+ return nil
+ }
+ return e
+}
+
+// A Reader allows reading Entry structures from a DWARF ``info'' section.
+// The Entry structures are arranged in a tree. The Reader's Next function
+// return successive entries from a pre-order traversal of the tree.
+// If an entry has children, its Children field will be true, and the children
+// follow, terminated by an Entry with Tag 0.
+type Reader struct {
+ b buf
+ d *Data
+ err os.Error
+ unit int
+ lastChildren bool // .Children of last entry returned by Next
+ lastSibling Offset // .Val(AttrSibling) of last entry returned by Next
+}
+
+// Reader returns a new Reader for Data.
+// The reader is positioned at byte offset 0 in the DWARF ``info'' section.
+func (d *Data) Reader() *Reader {
+ r := &Reader{d: d}
+ r.Seek(0)
+ return r
+}
+
+// Seek positions the Reader at offset off in the encoded entry stream.
+// Offset 0 can be used to denote the first entry.
+func (r *Reader) Seek(off Offset) {
+ d := r.d
+ r.err = nil
+ r.lastChildren = false
+ if off == 0 {
+ if len(d.unit) == 0 {
+ return
+ }
+ u := &d.unit[0]
+ r.unit = 0
+ r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize)
+ return
+ }
+
+ // TODO(rsc): binary search (maybe a new package)
+ var i int
+ var u *unit
+ for i = range d.unit {
+ u = &d.unit[i]
+ if u.off <= off && off < u.off+Offset(len(u.data)) {
+ r.unit = i
+ r.b = makeBuf(r.d, "info", off, u.data[off-u.off:], u.addrsize)
+ return
+ }
+ }
+ r.err = os.NewError("offset out of range")
+}
+
+// maybeNextUnit advances to the next unit if this one is finished.
+func (r *Reader) maybeNextUnit() {
+ for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
+ r.unit++
+ u := &r.d.unit[r.unit]
+ r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize)
+ }
+}
+
+// Next reads the next entry from the encoded entry stream.
+// It returns nil, nil when it reaches the end of the section.
+// It returns an error if the current offset is invalid or the data at the
+// offset cannot be decoded as a valid Entry.
+func (r *Reader) Next() (*Entry, os.Error) {
+ if r.err != nil {
+ return nil, r.err
+ }
+ r.maybeNextUnit()
+ if len(r.b.data) == 0 {
+ return nil, nil
+ }
+ u := &r.d.unit[r.unit]
+ e := r.b.entry(u.atable, u.base)
+ if r.b.err != nil {
+ r.err = r.b.err
+ return nil, r.err
+ }
+ if e != nil {
+ r.lastChildren = e.Children
+ if r.lastChildren {
+ r.lastSibling, _ = e.Val(AttrSibling).(Offset)
+ }
+ } else {
+ r.lastChildren = false
+ }
+ return e, nil
+}
+
+// SkipChildren skips over the child entries associated with
+// the last Entry returned by Next. If that Entry did not have
+// children or Next has not been called, SkipChildren is a no-op.
+func (r *Reader) SkipChildren() {
+ if r.err != nil || !r.lastChildren {
+ return
+ }
+
+ // If the last entry had a sibling attribute,
+ // that attribute gives the offset of the next
+ // sibling, so we can avoid decoding the
+ // child subtrees.
+ if r.lastSibling >= r.b.off {
+ r.Seek(r.lastSibling)
+ return
+ }
+
+ for {
+ e, err := r.Next()
+ if err != nil || e == nil || e.Tag == 0 {
+ break
+ }
+ if e.Children {
+ r.SkipChildren()
+ }
+ }
+}
diff --git a/libgo/go/debug/dwarf/open.go b/libgo/go/debug/dwarf/open.go
new file mode 100644
index 000000000..cb009e0e0
--- /dev/null
+++ b/libgo/go/debug/dwarf/open.go
@@ -0,0 +1,80 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package provides access to DWARF debugging information
+// loaded from executable files, as defined in the DWARF 2.0 Standard
+// at http://dwarfstd.org/doc/dwarf-2.0.0.pdf
+package dwarf
+
+import (
+ "encoding/binary"
+ "os"
+)
+
+// Data represents the DWARF debugging information
+// loaded from an executable file (for example, an ELF or Mach-O executable).
+type Data struct {
+ // raw data
+ abbrev []byte
+ aranges []byte
+ frame []byte
+ info []byte
+ line []byte
+ pubnames []byte
+ ranges []byte
+ str []byte
+
+ // parsed data
+ abbrevCache map[uint32]abbrevTable
+ addrsize int
+ order binary.ByteOrder
+ typeCache map[Offset]Type
+ unit []unit
+}
+
+// New returns a new Data object initialized from the given parameters.
+// Clients should typically use [TODO(rsc): method to be named later] instead of calling
+// New directly.
+//
+// The []byte arguments are the data from the corresponding debug section
+// in the object file; for example, for an ELF object, abbrev is the contents of
+// the ".debug_abbrev" section.
+func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, os.Error) {
+ d := &Data{
+ abbrev: abbrev,
+ aranges: aranges,
+ frame: frame,
+ info: info,
+ line: line,
+ pubnames: pubnames,
+ ranges: ranges,
+ str: str,
+ abbrevCache: make(map[uint32]abbrevTable),
+ typeCache: make(map[Offset]Type),
+ }
+
+ // Sniff .debug_info to figure out byte order.
+ // bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3).
+ if len(d.info) < 6 {
+ return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
+ }
+ x, y := d.info[4], d.info[5]
+ switch {
+ case x == 0 && y == 0:
+ return nil, DecodeError{"info", 4, "unsupported version 0"}
+ case x == 0:
+ d.order = binary.BigEndian
+ case y == 0:
+ d.order = binary.LittleEndian
+ default:
+ return nil, DecodeError{"info", 4, "cannot determine byte order"}
+ }
+
+ u, err := d.parseUnits()
+ if err != nil {
+ return nil, err
+ }
+ d.unit = u
+ return d, nil
+}
diff --git a/libgo/go/debug/dwarf/testdata/typedef.c b/libgo/go/debug/dwarf/testdata/typedef.c
new file mode 100644
index 000000000..664d021ce
--- /dev/null
+++ b/libgo/go/debug/dwarf/testdata/typedef.c
@@ -0,0 +1,79 @@
+// 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.
+
+/*
+Linux ELF:
+gcc -gdwarf-2 -m64 -c typedef.c && gcc -gdwarf-2 -m64 -o typedef.elf typedef.o
+
+OS X Mach-O:
+gcc -gdwarf-2 -m64 -c typedef.c -o typedef.macho
+*/
+#include <complex.h>
+
+typedef volatile int* t_ptr_volatile_int;
+typedef const char *t_ptr_const_char;
+typedef long t_long;
+typedef unsigned short t_ushort;
+typedef int t_func_int_of_float_double(float, double);
+typedef int (*t_ptr_func_int_of_float_double)(float, double);
+typedef int (*t_ptr_func_int_of_float_complex)(float complex);
+typedef int (*t_ptr_func_int_of_double_complex)(double complex);
+typedef int (*t_ptr_func_int_of_long_double_complex)(long double complex);
+typedef int *t_func_ptr_int_of_char_schar_uchar(char, signed char, unsigned char);
+typedef void t_func_void_of_char(char);
+typedef void t_func_void_of_void(void);
+typedef void t_func_void_of_ptr_char_dots(char*, ...);
+typedef struct my_struct {
+ volatile int vi;
+ char x : 1;
+ int y : 4;
+ long long array[40];
+} t_my_struct;
+typedef union my_union {
+ volatile int vi;
+ char x : 1;
+ int y : 4;
+ long long array[40];
+} t_my_union;
+typedef enum my_enum {
+ e1 = 1,
+ e2 = 2,
+ e3 = -5,
+ e4 = 1000000000000000LL,
+} t_my_enum;
+
+typedef struct list t_my_list;
+struct list {
+ short val;
+ t_my_list *next;
+};
+
+typedef struct tree {
+ struct tree *left, *right;
+ unsigned long long val;
+} t_my_tree;
+
+t_ptr_volatile_int *a2;
+t_ptr_const_char **a3a;
+t_long *a4;
+t_ushort *a5;
+t_func_int_of_float_double *a6;
+t_ptr_func_int_of_float_double *a7;
+t_func_ptr_int_of_char_schar_uchar *a8;
+t_func_void_of_char *a9;
+t_func_void_of_void *a10;
+t_func_void_of_ptr_char_dots *a11;
+t_my_struct *a12;
+t_my_union *a12a;
+t_my_enum *a13;
+t_my_list *a14;
+t_my_tree *a15;
+t_ptr_func_int_of_float_complex *a16;
+t_ptr_func_int_of_double_complex *a17;
+t_ptr_func_int_of_long_double_complex *a18;
+
+int main()
+{
+ return 0;
+}
diff --git a/libgo/go/debug/dwarf/testdata/typedef.elf b/libgo/go/debug/dwarf/testdata/typedef.elf
new file mode 100755
index 000000000..44df8da9b
--- /dev/null
+++ b/libgo/go/debug/dwarf/testdata/typedef.elf
Binary files differ
diff --git a/libgo/go/debug/dwarf/testdata/typedef.macho b/libgo/go/debug/dwarf/testdata/typedef.macho
new file mode 100644
index 000000000..41019c1e1
--- /dev/null
+++ b/libgo/go/debug/dwarf/testdata/typedef.macho
Binary files differ
diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go
new file mode 100644
index 000000000..902a545f8
--- /dev/null
+++ b/libgo/go/debug/dwarf/type.go
@@ -0,0 +1,583 @@
+// 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.
+
+// DWARF type information structures.
+// The format is heavily biased toward C, but for simplicity
+// the String methods use a pseudo-Go syntax.
+
+package dwarf
+
+import (
+ "os"
+ "strconv"
+)
+
+// A Type conventionally represents a pointer to any of the
+// specific Type structures (CharType, StructType, etc.).
+type Type interface {
+ Common() *CommonType
+ String() string
+ Size() int64
+}
+
+// A CommonType holds fields common to multiple types.
+// If a field is not known or not applicable for a given type,
+// the zero value is used.
+type CommonType struct {
+ ByteSize int64 // size of value of this type, in bytes
+ Name string // name that can be used to refer to type
+}
+
+func (c *CommonType) Common() *CommonType { return c }
+
+func (c *CommonType) Size() int64 { return c.ByteSize }
+
+// Basic types
+
+// A BasicType holds fields common to all basic types.
+type BasicType struct {
+ CommonType
+ BitSize int64
+ BitOffset int64
+}
+
+func (b *BasicType) Basic() *BasicType { return b }
+
+func (t *BasicType) String() string {
+ if t.Name != "" {
+ return t.Name
+ }
+ return "?"
+}
+
+// A CharType represents a signed character type.
+type CharType struct {
+ BasicType
+}
+
+// A UcharType represents an unsigned character type.
+type UcharType struct {
+ BasicType
+}
+
+// An IntType represents a signed integer type.
+type IntType struct {
+ BasicType
+}
+
+// A UintType represents an unsigned integer type.
+type UintType struct {
+ BasicType
+}
+
+// A FloatType represents a floating point type.
+type FloatType struct {
+ BasicType
+}
+
+// A ComplexType represents a complex floating point type.
+type ComplexType struct {
+ BasicType
+}
+
+// A BoolType represents a boolean type.
+type BoolType struct {
+ BasicType
+}
+
+// An AddrType represents a machine address type.
+type AddrType struct {
+ BasicType
+}
+
+// qualifiers
+
+// A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier.
+type QualType struct {
+ CommonType
+ Qual string
+ Type Type
+}
+
+func (t *QualType) String() string { return t.Qual + " " + t.Type.String() }
+
+func (t *QualType) Size() int64 { return t.Type.Size() }
+
+// An ArrayType represents a fixed size array type.
+type ArrayType struct {
+ CommonType
+ Type Type
+ StrideBitSize int64 // if > 0, number of bits to hold each element
+ Count int64 // if == -1, an incomplete array, like char x[].
+}
+
+func (t *ArrayType) String() string {
+ return "[" + strconv.Itoa64(t.Count) + "]" + t.Type.String()
+}
+
+func (t *ArrayType) Size() int64 { return t.Count * t.Type.Size() }
+
+// A VoidType represents the C void type.
+type VoidType struct {
+ CommonType
+}
+
+func (t *VoidType) String() string { return "void" }
+
+// A PtrType represents a pointer type.
+type PtrType struct {
+ CommonType
+ Type Type
+}
+
+func (t *PtrType) String() string { return "*" + t.Type.String() }
+
+// A StructType represents a struct, union, or C++ class type.
+type StructType struct {
+ CommonType
+ StructName string
+ Kind string // "struct", "union", or "class".
+ Field []*StructField
+ Incomplete bool // if true, struct, union, class is declared but not defined
+}
+
+// A StructField represents a field in a struct, union, or C++ class type.
+type StructField struct {
+ Name string
+ Type Type
+ ByteOffset int64
+ ByteSize int64
+ BitOffset int64 // within the ByteSize bytes at ByteOffset
+ BitSize int64 // zero if not a bit field
+}
+
+func (t *StructType) String() string {
+ if t.StructName != "" {
+ return t.Kind + " " + t.StructName
+ }
+ return t.Defn()
+}
+
+func (t *StructType) Defn() string {
+ s := t.Kind
+ if t.StructName != "" {
+ s += " " + t.StructName
+ }
+ if t.Incomplete {
+ s += " /*incomplete*/"
+ return s
+ }
+ s += " {"
+ for i, f := range t.Field {
+ if i > 0 {
+ s += "; "
+ }
+ s += f.Name + " " + f.Type.String()
+ s += "@" + strconv.Itoa64(f.ByteOffset)
+ if f.BitSize > 0 {
+ s += " : " + strconv.Itoa64(f.BitSize)
+ s += "@" + strconv.Itoa64(f.BitOffset)
+ }
+ }
+ s += "}"
+ return s
+}
+
+// An EnumType represents an enumerated type.
+// The only indication of its native integer type is its ByteSize
+// (inside CommonType).
+type EnumType struct {
+ CommonType
+ EnumName string
+ Val []*EnumValue
+}
+
+// An EnumValue represents a single enumeration value.
+type EnumValue struct {
+ Name string
+ Val int64
+}
+
+func (t *EnumType) String() string {
+ s := "enum"
+ if t.EnumName != "" {
+ s += " " + t.EnumName
+ }
+ s += " {"
+ for i, v := range t.Val {
+ if i > 0 {
+ s += "; "
+ }
+ s += v.Name + "=" + strconv.Itoa64(v.Val)
+ }
+ s += "}"
+ return s
+}
+
+// A FuncType represents a function type.
+type FuncType struct {
+ CommonType
+ ReturnType Type
+ ParamType []Type
+}
+
+func (t *FuncType) String() string {
+ s := "func("
+ for i, t := range t.ParamType {
+ if i > 0 {
+ s += ", "
+ }
+ s += t.String()
+ }
+ s += ")"
+ if t.ReturnType != nil {
+ s += " " + t.ReturnType.String()
+ }
+ return s
+}
+
+// A DotDotDotType represents the variadic ... function parameter.
+type DotDotDotType struct {
+ CommonType
+}
+
+func (t *DotDotDotType) String() string { return "..." }
+
+// A TypedefType represents a named type.
+type TypedefType struct {
+ CommonType
+ Type Type
+}
+
+func (t *TypedefType) String() string { return t.Name }
+
+func (t *TypedefType) Size() int64 { return t.Type.Size() }
+
+func (d *Data) Type(off Offset) (Type, os.Error) {
+ if t, ok := d.typeCache[off]; ok {
+ return t, nil
+ }
+
+ r := d.Reader()
+ r.Seek(off)
+ e, err := r.Next()
+ if err != nil {
+ return nil, err
+ }
+ if e == nil || e.Offset != off {
+ return nil, DecodeError{"info", off, "no type at offset"}
+ }
+
+ // Parse type from Entry.
+ // Must always set d.typeCache[off] before calling
+ // d.Type recursively, to handle circular types correctly.
+ var typ Type
+
+ // Get next child; set err if error happens.
+ next := func() *Entry {
+ if !e.Children {
+ return nil
+ }
+ kid, err1 := r.Next()
+ if err1 != nil {
+ err = err1
+ return nil
+ }
+ if kid == nil {
+ err = DecodeError{"info", r.b.off, "unexpected end of DWARF entries"}
+ return nil
+ }
+ if kid.Tag == 0 {
+ return nil
+ }
+ return kid
+ }
+
+ // Get Type referred to by Entry's AttrType field.
+ // Set err if error happens. Not having a type is an error.
+ typeOf := func(e *Entry) Type {
+ toff, ok := e.Val(AttrType).(Offset)
+ if !ok {
+ // It appears that no Type means "void".
+ return new(VoidType)
+ }
+ var t Type
+ if t, err = d.Type(toff); err != nil {
+ return nil
+ }
+ return t
+ }
+
+ switch e.Tag {
+ case TagArrayType:
+ // Multi-dimensional array. (DWARF v2 §5.4)
+ // Attributes:
+ // AttrType:subtype [required]
+ // AttrStrideSize: size in bits of each element of the array
+ // AttrByteSize: size of entire array
+ // Children:
+ // TagSubrangeType or TagEnumerationType giving one dimension.
+ // dimensions are in left to right order.
+ t := new(ArrayType)
+ typ = t
+ d.typeCache[off] = t
+ if t.Type = typeOf(e); err != nil {
+ goto Error
+ }
+ t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64)
+
+ // Accumulate dimensions,
+ ndim := 0
+ for kid := next(); kid != nil; kid = next() {
+ // TODO(rsc): Can also be TagEnumerationType
+ // but haven't seen that in the wild yet.
+ switch kid.Tag {
+ case TagSubrangeType:
+ max, ok := kid.Val(AttrUpperBound).(int64)
+ if !ok {
+ max = -2 // Count == -1, as in x[].
+ }
+ if ndim == 0 {
+ t.Count = max + 1
+ } else {
+ // Multidimensional array.
+ // Create new array type underneath this one.
+ t.Type = &ArrayType{Type: t.Type, Count: max + 1}
+ }
+ ndim++
+ case TagEnumerationType:
+ err = DecodeError{"info", kid.Offset, "cannot handle enumeration type as array bound"}
+ goto Error
+ }
+ }
+ if ndim == 0 {
+ err = DecodeError{"info", e.Offset, "missing dimension for array"}
+ goto Error
+ }
+
+ case TagBaseType:
+ // Basic type. (DWARF v2 §5.1)
+ // Attributes:
+ // AttrName: name of base type in programming language of the compilation unit [required]
+ // AttrEncoding: encoding value for type (encFloat etc) [required]
+ // AttrByteSize: size of type in bytes [required]
+ // AttrBitOffset: for sub-byte types, size in bits
+ // AttrBitSize: for sub-byte types, bit offset of high order bit in the AttrByteSize bytes
+ name, _ := e.Val(AttrName).(string)
+ enc, ok := e.Val(AttrEncoding).(int64)
+ if !ok {
+ err = DecodeError{"info", e.Offset, "missing encoding attribute for " + name}
+ goto Error
+ }
+ switch enc {
+ default:
+ err = DecodeError{"info", e.Offset, "unrecognized encoding attribute value"}
+ goto Error
+
+ case encAddress:
+ typ = new(AddrType)
+ case encBoolean:
+ typ = new(BoolType)
+ case encComplexFloat:
+ typ = new(ComplexType)
+ case encFloat:
+ typ = new(FloatType)
+ case encSigned:
+ typ = new(IntType)
+ case encUnsigned:
+ typ = new(UintType)
+ case encSignedChar:
+ typ = new(CharType)
+ case encUnsignedChar:
+ typ = new(UcharType)
+ }
+ d.typeCache[off] = typ
+ t := typ.(interface {
+ Basic() *BasicType
+ }).Basic()
+ t.Name = name
+ t.BitSize, _ = e.Val(AttrBitSize).(int64)
+ t.BitOffset, _ = e.Val(AttrBitOffset).(int64)
+
+ case TagClassType, TagStructType, TagUnionType:
+ // Structure, union, or class type. (DWARF v2 §5.5)
+ // Attributes:
+ // AttrName: name of struct, union, or class
+ // AttrByteSize: byte size [required]
+ // AttrDeclaration: if true, struct/union/class is incomplete
+ // Children:
+ // TagMember to describe one member.
+ // AttrName: name of member [required]
+ // AttrType: type of member [required]
+ // AttrByteSize: size in bytes
+ // AttrBitOffset: bit offset within bytes for bit fields
+ // AttrBitSize: bit size for bit fields
+ // AttrDataMemberLoc: location within struct [required for struct, class]
+ // There is much more to handle C++, all ignored for now.
+ t := new(StructType)
+ typ = t
+ d.typeCache[off] = t
+ switch e.Tag {
+ case TagClassType:
+ t.Kind = "class"
+ case TagStructType:
+ t.Kind = "struct"
+ case TagUnionType:
+ t.Kind = "union"
+ }
+ t.StructName, _ = e.Val(AttrName).(string)
+ t.Incomplete = e.Val(AttrDeclaration) != nil
+ t.Field = make([]*StructField, 0, 8)
+ for kid := next(); kid != nil; kid = next() {
+ if kid.Tag == TagMember {
+ f := new(StructField)
+ if f.Type = typeOf(kid); err != nil {
+ goto Error
+ }
+ if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
+ b := makeBuf(d, "location", 0, loc, d.addrsize)
+ if b.uint8() != opPlusUconst {
+ err = DecodeError{"info", kid.Offset, "unexpected opcode"}
+ goto Error
+ }
+ f.ByteOffset = int64(b.uint())
+ if b.err != nil {
+ err = b.err
+ goto Error
+ }
+ }
+ f.Name, _ = kid.Val(AttrName).(string)
+ f.ByteSize, _ = kid.Val(AttrByteSize).(int64)
+ f.BitOffset, _ = kid.Val(AttrBitOffset).(int64)
+ f.BitSize, _ = kid.Val(AttrBitSize).(int64)
+ t.Field = append(t.Field, f)
+ }
+ }
+
+ case TagConstType, TagVolatileType, TagRestrictType:
+ // Type modifier (DWARF v2 §5.2)
+ // Attributes:
+ // AttrType: subtype
+ t := new(QualType)
+ typ = t
+ d.typeCache[off] = t
+ if t.Type = typeOf(e); err != nil {
+ goto Error
+ }
+ switch e.Tag {
+ case TagConstType:
+ t.Qual = "const"
+ case TagRestrictType:
+ t.Qual = "restrict"
+ case TagVolatileType:
+ t.Qual = "volatile"
+ }
+
+ case TagEnumerationType:
+ // Enumeration type (DWARF v2 §5.6)
+ // Attributes:
+ // AttrName: enum name if any
+ // AttrByteSize: bytes required to represent largest value
+ // Children:
+ // TagEnumerator:
+ // AttrName: name of constant
+ // AttrConstValue: value of constant
+ t := new(EnumType)
+ typ = t
+ d.typeCache[off] = t
+ t.EnumName, _ = e.Val(AttrName).(string)
+ t.Val = make([]*EnumValue, 0, 8)
+ for kid := next(); kid != nil; kid = next() {
+ if kid.Tag == TagEnumerator {
+ f := new(EnumValue)
+ f.Name, _ = kid.Val(AttrName).(string)
+ f.Val, _ = kid.Val(AttrConstValue).(int64)
+ n := len(t.Val)
+ if n >= cap(t.Val) {
+ val := make([]*EnumValue, n, n*2)
+ copy(val, t.Val)
+ t.Val = val
+ }
+ t.Val = t.Val[0 : n+1]
+ t.Val[n] = f
+ }
+ }
+
+ case TagPointerType:
+ // Type modifier (DWARF v2 §5.2)
+ // Attributes:
+ // AttrType: subtype [not required! void* has no AttrType]
+ // AttrAddrClass: address class [ignored]
+ t := new(PtrType)
+ typ = t
+ d.typeCache[off] = t
+ if e.Val(AttrType) == nil {
+ t.Type = &VoidType{}
+ break
+ }
+ t.Type = typeOf(e)
+
+ case TagSubroutineType:
+ // Subroutine type. (DWARF v2 §5.7)
+ // Attributes:
+ // AttrType: type of return value if any
+ // AttrName: possible name of type [ignored]
+ // AttrPrototyped: whether used ANSI C prototye [ignored]
+ // Children:
+ // TagFormalParameter: typed parameter
+ // AttrType: type of parameter
+ // TagUnspecifiedParameter: final ...
+ t := new(FuncType)
+ typ = t
+ d.typeCache[off] = t
+ if t.ReturnType = typeOf(e); err != nil {
+ goto Error
+ }
+ t.ParamType = make([]Type, 0, 8)
+ for kid := next(); kid != nil; kid = next() {
+ var tkid Type
+ switch kid.Tag {
+ default:
+ continue
+ case TagFormalParameter:
+ if tkid = typeOf(kid); err != nil {
+ goto Error
+ }
+ case TagUnspecifiedParameters:
+ tkid = &DotDotDotType{}
+ }
+ t.ParamType = append(t.ParamType, tkid)
+ }
+
+ case TagTypedef:
+ // Typedef (DWARF v2 §5.3)
+ // Attributes:
+ // AttrName: name [required]
+ // AttrType: type definition [required]
+ t := new(TypedefType)
+ typ = t
+ d.typeCache[off] = t
+ t.Name, _ = e.Val(AttrName).(string)
+ t.Type = typeOf(e)
+ }
+
+ if err != nil {
+ goto Error
+ }
+
+ b, ok := e.Val(AttrByteSize).(int64)
+ if !ok {
+ b = -1
+ }
+ typ.Common().ByteSize = b
+
+ return typ, nil
+
+Error:
+ // If the parse fails, take the type out of the cache
+ // so that the next call with this offset doesn't hit
+ // the cache and return success.
+ d.typeCache[off] = nil, false
+ return nil, err
+}
diff --git a/libgo/go/debug/dwarf/type_test.go b/libgo/go/debug/dwarf/type_test.go
new file mode 100644
index 000000000..e01f7353a
--- /dev/null
+++ b/libgo/go/debug/dwarf/type_test.go
@@ -0,0 +1,112 @@
+// 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 dwarf_test
+
+import (
+ . "debug/dwarf"
+ "debug/elf"
+ "debug/macho"
+ "testing"
+)
+
+var typedefTests = map[string]string{
+ "t_ptr_volatile_int": "*volatile int",
+ "t_ptr_const_char": "*const char",
+ "t_long": "long int",
+ "t_ushort": "short unsigned int",
+ "t_func_int_of_float_double": "func(float, double) int",
+ "t_ptr_func_int_of_float_double": "*func(float, double) int",
+ "t_ptr_func_int_of_float_complex": "*func(complex float) int",
+ "t_ptr_func_int_of_double_complex": "*func(complex double) int",
+ "t_ptr_func_int_of_long_double_complex": "*func(complex long double) int",
+ "t_func_ptr_int_of_char_schar_uchar": "func(char, signed char, unsigned char) *int",
+ "t_func_void_of_char": "func(char) void",
+ "t_func_void_of_void": "func() void",
+ "t_func_void_of_ptr_char_dots": "func(*char, ...) void",
+ "t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; array [40]long long int@8}",
+ "t_my_union": "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}",
+ "t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}",
+ "t_my_list": "struct list {val short int@0; next *t_my_list@8}",
+ "t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}",
+}
+
+func elfData(t *testing.T, name string) *Data {
+ f, err := elf.Open(name)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ d, err := f.DWARF()
+ if err != nil {
+ t.Fatal(err)
+ }
+ return d
+}
+
+func machoData(t *testing.T, name string) *Data {
+ f, err := macho.Open(name)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ d, err := f.DWARF()
+ if err != nil {
+ t.Fatal(err)
+ }
+ return d
+}
+
+
+func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf")) }
+
+func TestTypedefsMachO(t *testing.T) {
+ testTypedefs(t, machoData(t, "testdata/typedef.macho"))
+}
+
+func testTypedefs(t *testing.T, d *Data) {
+ r := d.Reader()
+ seen := make(map[string]bool)
+ for {
+ e, err := r.Next()
+ if err != nil {
+ t.Fatal("r.Next:", err)
+ }
+ if e == nil {
+ break
+ }
+ if e.Tag == TagTypedef {
+ typ, err := d.Type(e.Offset)
+ if err != nil {
+ t.Fatal("d.Type:", err)
+ }
+ t1 := typ.(*TypedefType)
+ var typstr string
+ if ts, ok := t1.Type.(*StructType); ok {
+ typstr = ts.Defn()
+ } else {
+ typstr = t1.Type.String()
+ }
+
+ if want, ok := typedefTests[t1.Name]; ok {
+ if seen[t1.Name] {
+ t.Errorf("multiple definitions for %s", t1.Name)
+ }
+ seen[t1.Name] = true
+ if typstr != want {
+ t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want)
+ }
+ }
+ }
+ if e.Tag != TagCompileUnit {
+ r.SkipChildren()
+ }
+ }
+
+ for k := range typedefTests {
+ if !seen[k] {
+ t.Errorf("missing %s", k)
+ }
+ }
+}
diff --git a/libgo/go/debug/dwarf/unit.go b/libgo/go/debug/dwarf/unit.go
new file mode 100644
index 000000000..02cb363b4
--- /dev/null
+++ b/libgo/go/debug/dwarf/unit.go
@@ -0,0 +1,62 @@
+// 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 dwarf
+
+import (
+ "os"
+ "strconv"
+)
+
+// DWARF debug info is split into a sequence of compilation units.
+// Each unit has its own abbreviation table and address size.
+
+type unit struct {
+ base Offset // byte offset of header within the aggregate info
+ off Offset // byte offset of data within the aggregate info
+ data []byte
+ atable abbrevTable
+ addrsize int
+}
+
+func (d *Data) parseUnits() ([]unit, os.Error) {
+ // Count units.
+ nunit := 0
+ b := makeBuf(d, "info", 0, d.info, 0)
+ for len(b.data) > 0 {
+ b.skip(int(b.uint32()))
+ nunit++
+ }
+ if b.err != nil {
+ return nil, b.err
+ }
+
+ // Again, this time writing them down.
+ b = makeBuf(d, "info", 0, d.info, 0)
+ units := make([]unit, nunit)
+ for i := range units {
+ u := &units[i]
+ u.base = b.off
+ n := b.uint32()
+ if vers := b.uint16(); vers != 2 {
+ b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
+ break
+ }
+ atable, err := d.parseAbbrev(b.uint32())
+ if err != nil {
+ if b.err == nil {
+ b.err = err
+ }
+ break
+ }
+ u.atable = atable
+ u.addrsize = int(b.uint8())
+ u.off = b.off
+ u.data = b.bytes(int(n - (2 + 4 + 1)))
+ }
+ if b.err != nil {
+ return nil, b.err
+ }
+ return units, nil
+}
diff --git a/libgo/go/debug/elf/elf.go b/libgo/go/debug/elf/elf.go
new file mode 100644
index 000000000..74e979986
--- /dev/null
+++ b/libgo/go/debug/elf/elf.go
@@ -0,0 +1,1506 @@
+/*
+ * ELF constants and data structures
+ *
+ * Derived from:
+ * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
+ * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
+ * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
+ * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
+ * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
+ * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
+ *
+ * Copyright (c) 1996-1998 John D. Polstra. All rights reserved.
+ * Copyright (c) 2001 David E. O'Brien
+ * Portions Copyright 2009 The Go Authors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+package elf
+
+import "strconv"
+
+/*
+ * Constants
+ */
+
+// Indexes into the Header.Ident array.
+const (
+ EI_CLASS = 4 /* Class of machine. */
+ EI_DATA = 5 /* Data format. */
+ EI_VERSION = 6 /* ELF format version. */
+ EI_OSABI = 7 /* Operating system / ABI identification */
+ EI_ABIVERSION = 8 /* ABI version */
+ EI_PAD = 9 /* Start of padding (per SVR4 ABI). */
+ EI_NIDENT = 16 /* Size of e_ident array. */
+)
+
+// Initial magic number for ELF files.
+const ELFMAG = "\177ELF"
+
+// Version is found in Header.Ident[EI_VERSION] and Header.Version.
+type Version byte
+
+const (
+ EV_NONE Version = 0
+ EV_CURRENT Version = 1
+)
+
+var versionStrings = []intName{
+ {0, "EV_NONE"},
+ {1, "EV_CURRENT"},
+}
+
+func (i Version) String() string { return stringName(uint32(i), versionStrings, false) }
+func (i Version) GoString() string { return stringName(uint32(i), versionStrings, true) }
+
+// Class is found in Header.Ident[EI_CLASS] and Header.Class.
+type Class byte
+
+const (
+ ELFCLASSNONE Class = 0 /* Unknown class. */
+ ELFCLASS32 Class = 1 /* 32-bit architecture. */
+ ELFCLASS64 Class = 2 /* 64-bit architecture. */
+)
+
+var classStrings = []intName{
+ {0, "ELFCLASSNONE"},
+ {1, "ELFCLASS32"},
+ {2, "ELFCLASS64"},
+}
+
+func (i Class) String() string { return stringName(uint32(i), classStrings, false) }
+func (i Class) GoString() string { return stringName(uint32(i), classStrings, true) }
+
+// Data is found in Header.Ident[EI_DATA] and Header.Data.
+type Data byte
+
+const (
+ ELFDATANONE Data = 0 /* Unknown data format. */
+ ELFDATA2LSB Data = 1 /* 2's complement little-endian. */
+ ELFDATA2MSB Data = 2 /* 2's complement big-endian. */
+)
+
+var dataStrings = []intName{
+ {0, "ELFDATANONE"},
+ {1, "ELFDATA2LSB"},
+ {2, "ELFDATA2MSB"},
+}
+
+func (i Data) String() string { return stringName(uint32(i), dataStrings, false) }
+func (i Data) GoString() string { return stringName(uint32(i), dataStrings, true) }
+
+// OSABI is found in Header.Ident[EI_OSABI] and Header.OSABI.
+type OSABI byte
+
+const (
+ ELFOSABI_NONE OSABI = 0 /* UNIX System V ABI */
+ ELFOSABI_HPUX OSABI = 1 /* HP-UX operating system */
+ ELFOSABI_NETBSD OSABI = 2 /* NetBSD */
+ ELFOSABI_LINUX OSABI = 3 /* GNU/Linux */
+ ELFOSABI_HURD OSABI = 4 /* GNU/Hurd */
+ ELFOSABI_86OPEN OSABI = 5 /* 86Open common IA32 ABI */
+ ELFOSABI_SOLARIS OSABI = 6 /* Solaris */
+ ELFOSABI_AIX OSABI = 7 /* AIX */
+ ELFOSABI_IRIX OSABI = 8 /* IRIX */
+ ELFOSABI_FREEBSD OSABI = 9 /* FreeBSD */
+ ELFOSABI_TRU64 OSABI = 10 /* TRU64 UNIX */
+ ELFOSABI_MODESTO OSABI = 11 /* Novell Modesto */
+ ELFOSABI_OPENBSD OSABI = 12 /* OpenBSD */
+ ELFOSABI_OPENVMS OSABI = 13 /* Open VMS */
+ ELFOSABI_NSK OSABI = 14 /* HP Non-Stop Kernel */
+ ELFOSABI_ARM OSABI = 97 /* ARM */
+ ELFOSABI_STANDALONE OSABI = 255 /* Standalone (embedded) application */
+)
+
+var osabiStrings = []intName{
+ {0, "ELFOSABI_NONE"},
+ {1, "ELFOSABI_HPUX"},
+ {2, "ELFOSABI_NETBSD"},
+ {3, "ELFOSABI_LINUX"},
+ {4, "ELFOSABI_HURD"},
+ {5, "ELFOSABI_86OPEN"},
+ {6, "ELFOSABI_SOLARIS"},
+ {7, "ELFOSABI_AIX"},
+ {8, "ELFOSABI_IRIX"},
+ {9, "ELFOSABI_FREEBSD"},
+ {10, "ELFOSABI_TRU64"},
+ {11, "ELFOSABI_MODESTO"},
+ {12, "ELFOSABI_OPENBSD"},
+ {13, "ELFOSABI_OPENVMS"},
+ {14, "ELFOSABI_NSK"},
+ {97, "ELFOSABI_ARM"},
+ {255, "ELFOSABI_STANDALONE"},
+}
+
+func (i OSABI) String() string { return stringName(uint32(i), osabiStrings, false) }
+func (i OSABI) GoString() string { return stringName(uint32(i), osabiStrings, true) }
+
+// Type is found in Header.Type.
+type Type uint16
+
+const (
+ ET_NONE Type = 0 /* Unknown type. */
+ ET_REL Type = 1 /* Relocatable. */
+ ET_EXEC Type = 2 /* Executable. */
+ ET_DYN Type = 3 /* Shared object. */
+ ET_CORE Type = 4 /* Core file. */
+ ET_LOOS Type = 0xfe00 /* First operating system specific. */
+ ET_HIOS Type = 0xfeff /* Last operating system-specific. */
+ ET_LOPROC Type = 0xff00 /* First processor-specific. */
+ ET_HIPROC Type = 0xffff /* Last processor-specific. */
+)
+
+var typeStrings = []intName{
+ {0, "ET_NONE"},
+ {1, "ET_REL"},
+ {2, "ET_EXEC"},
+ {3, "ET_DYN"},
+ {4, "ET_CORE"},
+ {0xfe00, "ET_LOOS"},
+ {0xfeff, "ET_HIOS"},
+ {0xff00, "ET_LOPROC"},
+ {0xffff, "ET_HIPROC"},
+}
+
+func (i Type) String() string { return stringName(uint32(i), typeStrings, false) }
+func (i Type) GoString() string { return stringName(uint32(i), typeStrings, true) }
+
+// Machine is found in Header.Machine.
+type Machine uint16
+
+const (
+ EM_NONE Machine = 0 /* Unknown machine. */
+ EM_M32 Machine = 1 /* AT&T WE32100. */
+ EM_SPARC Machine = 2 /* Sun SPARC. */
+ EM_386 Machine = 3 /* Intel i386. */
+ EM_68K Machine = 4 /* Motorola 68000. */
+ EM_88K Machine = 5 /* Motorola 88000. */
+ EM_860 Machine = 7 /* Intel i860. */
+ EM_MIPS Machine = 8 /* MIPS R3000 Big-Endian only. */
+ EM_S370 Machine = 9 /* IBM System/370. */
+ EM_MIPS_RS3_LE Machine = 10 /* MIPS R3000 Little-Endian. */
+ EM_PARISC Machine = 15 /* HP PA-RISC. */
+ EM_VPP500 Machine = 17 /* Fujitsu VPP500. */
+ EM_SPARC32PLUS Machine = 18 /* SPARC v8plus. */
+ EM_960 Machine = 19 /* Intel 80960. */
+ EM_PPC Machine = 20 /* PowerPC 32-bit. */
+ EM_PPC64 Machine = 21 /* PowerPC 64-bit. */
+ EM_S390 Machine = 22 /* IBM System/390. */
+ EM_V800 Machine = 36 /* NEC V800. */
+ EM_FR20 Machine = 37 /* Fujitsu FR20. */
+ EM_RH32 Machine = 38 /* TRW RH-32. */
+ EM_RCE Machine = 39 /* Motorola RCE. */
+ EM_ARM Machine = 40 /* ARM. */
+ EM_SH Machine = 42 /* Hitachi SH. */
+ EM_SPARCV9 Machine = 43 /* SPARC v9 64-bit. */
+ EM_TRICORE Machine = 44 /* Siemens TriCore embedded processor. */
+ EM_ARC Machine = 45 /* Argonaut RISC Core. */
+ EM_H8_300 Machine = 46 /* Hitachi H8/300. */
+ EM_H8_300H Machine = 47 /* Hitachi H8/300H. */
+ EM_H8S Machine = 48 /* Hitachi H8S. */
+ EM_H8_500 Machine = 49 /* Hitachi H8/500. */
+ EM_IA_64 Machine = 50 /* Intel IA-64 Processor. */
+ EM_MIPS_X Machine = 51 /* Stanford MIPS-X. */
+ EM_COLDFIRE Machine = 52 /* Motorola ColdFire. */
+ EM_68HC12 Machine = 53 /* Motorola M68HC12. */
+ EM_MMA Machine = 54 /* Fujitsu MMA. */
+ EM_PCP Machine = 55 /* Siemens PCP. */
+ EM_NCPU Machine = 56 /* Sony nCPU. */
+ EM_NDR1 Machine = 57 /* Denso NDR1 microprocessor. */
+ EM_STARCORE Machine = 58 /* Motorola Star*Core processor. */
+ EM_ME16 Machine = 59 /* Toyota ME16 processor. */
+ EM_ST100 Machine = 60 /* STMicroelectronics ST100 processor. */
+ EM_TINYJ Machine = 61 /* Advanced Logic Corp. TinyJ processor. */
+ EM_X86_64 Machine = 62 /* Advanced Micro Devices x86-64 */
+
+ /* Non-standard or deprecated. */
+ EM_486 Machine = 6 /* Intel i486. */
+ EM_MIPS_RS4_BE Machine = 10 /* MIPS R4000 Big-Endian */
+ EM_ALPHA_STD Machine = 41 /* Digital Alpha (standard value). */
+ EM_ALPHA Machine = 0x9026 /* Alpha (written in the absence of an ABI) */
+)
+
+var machineStrings = []intName{
+ {0, "EM_NONE"},
+ {1, "EM_M32"},
+ {2, "EM_SPARC"},
+ {3, "EM_386"},
+ {4, "EM_68K"},
+ {5, "EM_88K"},
+ {7, "EM_860"},
+ {8, "EM_MIPS"},
+ {9, "EM_S370"},
+ {10, "EM_MIPS_RS3_LE"},
+ {15, "EM_PARISC"},
+ {17, "EM_VPP500"},
+ {18, "EM_SPARC32PLUS"},
+ {19, "EM_960"},
+ {20, "EM_PPC"},
+ {21, "EM_PPC64"},
+ {22, "EM_S390"},
+ {36, "EM_V800"},
+ {37, "EM_FR20"},
+ {38, "EM_RH32"},
+ {39, "EM_RCE"},
+ {40, "EM_ARM"},
+ {42, "EM_SH"},
+ {43, "EM_SPARCV9"},
+ {44, "EM_TRICORE"},
+ {45, "EM_ARC"},
+ {46, "EM_H8_300"},
+ {47, "EM_H8_300H"},
+ {48, "EM_H8S"},
+ {49, "EM_H8_500"},
+ {50, "EM_IA_64"},
+ {51, "EM_MIPS_X"},
+ {52, "EM_COLDFIRE"},
+ {53, "EM_68HC12"},
+ {54, "EM_MMA"},
+ {55, "EM_PCP"},
+ {56, "EM_NCPU"},
+ {57, "EM_NDR1"},
+ {58, "EM_STARCORE"},
+ {59, "EM_ME16"},
+ {60, "EM_ST100"},
+ {61, "EM_TINYJ"},
+ {62, "EM_X86_64"},
+
+ /* Non-standard or deprecated. */
+ {6, "EM_486"},
+ {10, "EM_MIPS_RS4_BE"},
+ {41, "EM_ALPHA_STD"},
+ {0x9026, "EM_ALPHA"},
+}
+
+func (i Machine) String() string { return stringName(uint32(i), machineStrings, false) }
+func (i Machine) GoString() string { return stringName(uint32(i), machineStrings, true) }
+
+// Special section indices.
+type SectionIndex int
+
+const (
+ SHN_UNDEF SectionIndex = 0 /* Undefined, missing, irrelevant. */
+ SHN_LORESERVE SectionIndex = 0xff00 /* First of reserved range. */
+ SHN_LOPROC SectionIndex = 0xff00 /* First processor-specific. */
+ SHN_HIPROC SectionIndex = 0xff1f /* Last processor-specific. */
+ SHN_LOOS SectionIndex = 0xff20 /* First operating system-specific. */
+ SHN_HIOS SectionIndex = 0xff3f /* Last operating system-specific. */
+ SHN_ABS SectionIndex = 0xfff1 /* Absolute values. */
+ SHN_COMMON SectionIndex = 0xfff2 /* Common data. */
+ SHN_XINDEX SectionIndex = 0xffff /* Escape -- index stored elsewhere. */
+ SHN_HIRESERVE SectionIndex = 0xffff /* Last of reserved range. */
+)
+
+var shnStrings = []intName{
+ {0, "SHN_UNDEF"},
+ {0xff00, "SHN_LOPROC"},
+ {0xff20, "SHN_LOOS"},
+ {0xfff1, "SHN_ABS"},
+ {0xfff2, "SHN_COMMON"},
+ {0xffff, "SHN_XINDEX"},
+}
+
+func (i SectionIndex) String() string { return stringName(uint32(i), shnStrings, false) }
+func (i SectionIndex) GoString() string { return stringName(uint32(i), shnStrings, true) }
+
+// Section type.
+type SectionType uint32
+
+const (
+ SHT_NULL SectionType = 0 /* inactive */
+ SHT_PROGBITS SectionType = 1 /* program defined information */
+ SHT_SYMTAB SectionType = 2 /* symbol table section */
+ SHT_STRTAB SectionType = 3 /* string table section */
+ SHT_RELA SectionType = 4 /* relocation section with addends */
+ SHT_HASH SectionType = 5 /* symbol hash table section */
+ SHT_DYNAMIC SectionType = 6 /* dynamic section */
+ SHT_NOTE SectionType = 7 /* note section */
+ SHT_NOBITS SectionType = 8 /* no space section */
+ SHT_REL SectionType = 9 /* relocation section - no addends */
+ SHT_SHLIB SectionType = 10 /* reserved - purpose unknown */
+ SHT_DYNSYM SectionType = 11 /* dynamic symbol table section */
+ SHT_INIT_ARRAY SectionType = 14 /* Initialization function pointers. */
+ SHT_FINI_ARRAY SectionType = 15 /* Termination function pointers. */
+ SHT_PREINIT_ARRAY SectionType = 16 /* Pre-initialization function ptrs. */
+ SHT_GROUP SectionType = 17 /* Section group. */
+ SHT_SYMTAB_SHNDX SectionType = 18 /* Section indexes (see SHN_XINDEX). */
+ SHT_LOOS SectionType = 0x60000000 /* First of OS specific semantics */
+ SHT_HIOS SectionType = 0x6fffffff /* Last of OS specific semantics */
+ SHT_LOPROC SectionType = 0x70000000 /* reserved range for processor */
+ SHT_HIPROC SectionType = 0x7fffffff /* specific section header types */
+ SHT_LOUSER SectionType = 0x80000000 /* reserved range for application */
+ SHT_HIUSER SectionType = 0xffffffff /* specific indexes */
+)
+
+var shtStrings = []intName{
+ {0, "SHT_NULL"},
+ {1, "SHT_PROGBITS"},
+ {2, "SHT_SYMTAB"},
+ {3, "SHT_STRTAB"},
+ {4, "SHT_RELA"},
+ {5, "SHT_HASH"},
+ {6, "SHT_DYNAMIC"},
+ {7, "SHT_NOTE"},
+ {8, "SHT_NOBITS"},
+ {9, "SHT_REL"},
+ {10, "SHT_SHLIB"},
+ {11, "SHT_DYNSYM"},
+ {14, "SHT_INIT_ARRAY"},
+ {15, "SHT_FINI_ARRAY"},
+ {16, "SHT_PREINIT_ARRAY"},
+ {17, "SHT_GROUP"},
+ {18, "SHT_SYMTAB_SHNDX"},
+ {0x60000000, "SHT_LOOS"},
+ {0x6fffffff, "SHT_HIOS"},
+ {0x70000000, "SHT_LOPROC"},
+ {0x7fffffff, "SHT_HIPROC"},
+ {0x80000000, "SHT_LOUSER"},
+ {0xffffffff, "SHT_HIUSER"},
+}
+
+func (i SectionType) String() string { return stringName(uint32(i), shtStrings, false) }
+func (i SectionType) GoString() string { return stringName(uint32(i), shtStrings, true) }
+
+// Section flags.
+type SectionFlag uint32
+
+const (
+ SHF_WRITE SectionFlag = 0x1 /* Section contains writable data. */
+ SHF_ALLOC SectionFlag = 0x2 /* Section occupies memory. */
+ SHF_EXECINSTR SectionFlag = 0x4 /* Section contains instructions. */
+ SHF_MERGE SectionFlag = 0x10 /* Section may be merged. */
+ SHF_STRINGS SectionFlag = 0x20 /* Section contains strings. */
+ SHF_INFO_LINK SectionFlag = 0x40 /* sh_info holds section index. */
+ SHF_LINK_ORDER SectionFlag = 0x80 /* Special ordering requirements. */
+ SHF_OS_NONCONFORMING SectionFlag = 0x100 /* OS-specific processing required. */
+ SHF_GROUP SectionFlag = 0x200 /* Member of section group. */
+ SHF_TLS SectionFlag = 0x400 /* Section contains TLS data. */
+ SHF_MASKOS SectionFlag = 0x0ff00000 /* OS-specific semantics. */
+ SHF_MASKPROC SectionFlag = 0xf0000000 /* Processor-specific semantics. */
+)
+
+var shfStrings = []intName{
+ {0x1, "SHF_WRITE"},
+ {0x2, "SHF_ALLOC"},
+ {0x4, "SHF_EXECINSTR"},
+ {0x10, "SHF_MERGE"},
+ {0x20, "SHF_STRINGS"},
+ {0x40, "SHF_INFO_LINK"},
+ {0x80, "SHF_LINK_ORDER"},
+ {0x100, "SHF_OS_NONCONFORMING"},
+ {0x200, "SHF_GROUP"},
+ {0x400, "SHF_TLS"},
+}
+
+func (i SectionFlag) String() string { return flagName(uint32(i), shfStrings, false) }
+func (i SectionFlag) GoString() string { return flagName(uint32(i), shfStrings, true) }
+
+// Prog.Type
+type ProgType int
+
+const (
+ PT_NULL ProgType = 0 /* Unused entry. */
+ PT_LOAD ProgType = 1 /* Loadable segment. */
+ PT_DYNAMIC ProgType = 2 /* Dynamic linking information segment. */
+ PT_INTERP ProgType = 3 /* Pathname of interpreter. */
+ PT_NOTE ProgType = 4 /* Auxiliary information. */
+ PT_SHLIB ProgType = 5 /* Reserved (not used). */
+ PT_PHDR ProgType = 6 /* Location of program header itself. */
+ PT_TLS ProgType = 7 /* Thread local storage segment */
+ PT_LOOS ProgType = 0x60000000 /* First OS-specific. */
+ PT_HIOS ProgType = 0x6fffffff /* Last OS-specific. */
+ PT_LOPROC ProgType = 0x70000000 /* First processor-specific type. */
+ PT_HIPROC ProgType = 0x7fffffff /* Last processor-specific type. */
+)
+
+var ptStrings = []intName{
+ {0, "PT_NULL"},
+ {1, "PT_LOAD"},
+ {2, "PT_DYNAMIC"},
+ {3, "PT_INTERP"},
+ {4, "PT_NOTE"},
+ {5, "PT_SHLIB"},
+ {6, "PT_PHDR"},
+ {7, "PT_TLS"},
+ {0x60000000, "PT_LOOS"},
+ {0x6fffffff, "PT_HIOS"},
+ {0x70000000, "PT_LOPROC"},
+ {0x7fffffff, "PT_HIPROC"},
+}
+
+func (i ProgType) String() string { return stringName(uint32(i), ptStrings, false) }
+func (i ProgType) GoString() string { return stringName(uint32(i), ptStrings, true) }
+
+// Prog.Flag
+type ProgFlag uint32
+
+const (
+ PF_X ProgFlag = 0x1 /* Executable. */
+ PF_W ProgFlag = 0x2 /* Writable. */
+ PF_R ProgFlag = 0x4 /* Readable. */
+ PF_MASKOS ProgFlag = 0x0ff00000 /* Operating system-specific. */
+ PF_MASKPROC ProgFlag = 0xf0000000 /* Processor-specific. */
+)
+
+var pfStrings = []intName{
+ {0x1, "PF_X"},
+ {0x2, "PF_W"},
+ {0x4, "PF_R"},
+}
+
+func (i ProgFlag) String() string { return flagName(uint32(i), pfStrings, false) }
+func (i ProgFlag) GoString() string { return flagName(uint32(i), pfStrings, true) }
+
+// Dyn.Tag
+type DynTag int
+
+const (
+ DT_NULL DynTag = 0 /* Terminating entry. */
+ DT_NEEDED DynTag = 1 /* String table offset of a needed shared library. */
+ DT_PLTRELSZ DynTag = 2 /* Total size in bytes of PLT relocations. */
+ DT_PLTGOT DynTag = 3 /* Processor-dependent address. */
+ DT_HASH DynTag = 4 /* Address of symbol hash table. */
+ DT_STRTAB DynTag = 5 /* Address of string table. */
+ DT_SYMTAB DynTag = 6 /* Address of symbol table. */
+ DT_RELA DynTag = 7 /* Address of ElfNN_Rela relocations. */
+ DT_RELASZ DynTag = 8 /* Total size of ElfNN_Rela relocations. */
+ DT_RELAENT DynTag = 9 /* Size of each ElfNN_Rela relocation entry. */
+ DT_STRSZ DynTag = 10 /* Size of string table. */
+ DT_SYMENT DynTag = 11 /* Size of each symbol table entry. */
+ DT_INIT DynTag = 12 /* Address of initialization function. */
+ DT_FINI DynTag = 13 /* Address of finalization function. */
+ DT_SONAME DynTag = 14 /* String table offset of shared object name. */
+ DT_RPATH DynTag = 15 /* String table offset of library path. [sup] */
+ DT_SYMBOLIC DynTag = 16 /* Indicates "symbolic" linking. [sup] */
+ DT_REL DynTag = 17 /* Address of ElfNN_Rel relocations. */
+ DT_RELSZ DynTag = 18 /* Total size of ElfNN_Rel relocations. */
+ DT_RELENT DynTag = 19 /* Size of each ElfNN_Rel relocation. */
+ DT_PLTREL DynTag = 20 /* Type of relocation used for PLT. */
+ DT_DEBUG DynTag = 21 /* Reserved (not used). */
+ DT_TEXTREL DynTag = 22 /* Indicates there may be relocations in non-writable segments. [sup] */
+ DT_JMPREL DynTag = 23 /* Address of PLT relocations. */
+ DT_BIND_NOW DynTag = 24 /* [sup] */
+ DT_INIT_ARRAY DynTag = 25 /* Address of the array of pointers to initialization functions */
+ DT_FINI_ARRAY DynTag = 26 /* Address of the array of pointers to termination functions */
+ DT_INIT_ARRAYSZ DynTag = 27 /* Size in bytes of the array of initialization functions. */
+ DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of terminationfunctions. */
+ DT_RUNPATH DynTag = 29 /* String table offset of a null-terminated library search path string. */
+ DT_FLAGS DynTag = 30 /* Object specific flag values. */
+ DT_ENCODING DynTag = 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 */
+ DT_PREINIT_ARRAY DynTag = 32 /* Address of the array of pointers to pre-initialization functions. */
+ DT_PREINIT_ARRAYSZ DynTag = 33 /* Size in bytes of the array of pre-initialization functions. */
+ DT_LOOS DynTag = 0x6000000d /* First OS-specific */
+ DT_HIOS DynTag = 0x6ffff000 /* Last OS-specific */
+ DT_LOPROC DynTag = 0x70000000 /* First processor-specific type. */
+ DT_HIPROC DynTag = 0x7fffffff /* Last processor-specific type. */
+)
+
+var dtStrings = []intName{
+ {0, "DT_NULL"},
+ {1, "DT_NEEDED"},
+ {2, "DT_PLTRELSZ"},
+ {3, "DT_PLTGOT"},
+ {4, "DT_HASH"},
+ {5, "DT_STRTAB"},
+ {6, "DT_SYMTAB"},
+ {7, "DT_RELA"},
+ {8, "DT_RELASZ"},
+ {9, "DT_RELAENT"},
+ {10, "DT_STRSZ"},
+ {11, "DT_SYMENT"},
+ {12, "DT_INIT"},
+ {13, "DT_FINI"},
+ {14, "DT_SONAME"},
+ {15, "DT_RPATH"},
+ {16, "DT_SYMBOLIC"},
+ {17, "DT_REL"},
+ {18, "DT_RELSZ"},
+ {19, "DT_RELENT"},
+ {20, "DT_PLTREL"},
+ {21, "DT_DEBUG"},
+ {22, "DT_TEXTREL"},
+ {23, "DT_JMPREL"},
+ {24, "DT_BIND_NOW"},
+ {25, "DT_INIT_ARRAY"},
+ {26, "DT_FINI_ARRAY"},
+ {27, "DT_INIT_ARRAYSZ"},
+ {28, "DT_FINI_ARRAYSZ"},
+ {29, "DT_RUNPATH"},
+ {30, "DT_FLAGS"},
+ {32, "DT_ENCODING"},
+ {32, "DT_PREINIT_ARRAY"},
+ {33, "DT_PREINIT_ARRAYSZ"},
+ {0x6000000d, "DT_LOOS"},
+ {0x6ffff000, "DT_HIOS"},
+ {0x70000000, "DT_LOPROC"},
+ {0x7fffffff, "DT_HIPROC"},
+}
+
+func (i DynTag) String() string { return stringName(uint32(i), dtStrings, false) }
+func (i DynTag) GoString() string { return stringName(uint32(i), dtStrings, true) }
+
+// DT_FLAGS values.
+type DynFlag int
+
+const (
+ DF_ORIGIN DynFlag = 0x0001 /* Indicates that the object being loaded may
+ make reference to the
+ $ORIGIN substitution string */
+ DF_SYMBOLIC DynFlag = 0x0002 /* Indicates "symbolic" linking. */
+ DF_TEXTREL DynFlag = 0x0004 /* Indicates there may be relocations in non-writable segments. */
+ DF_BIND_NOW DynFlag = 0x0008 /* Indicates that the dynamic linker should
+ process all relocations for the object
+ containing this entry before transferring
+ control to the program. */
+ DF_STATIC_TLS DynFlag = 0x0010 /* Indicates that the shared object or
+ executable contains code using a static
+ thread-local storage scheme. */
+)
+
+var dflagStrings = []intName{
+ {0x0001, "DF_ORIGIN"},
+ {0x0002, "DF_SYMBOLIC"},
+ {0x0004, "DF_TEXTREL"},
+ {0x0008, "DF_BIND_NOW"},
+ {0x0010, "DF_STATIC_TLS"},
+}
+
+func (i DynFlag) String() string { return flagName(uint32(i), dflagStrings, false) }
+func (i DynFlag) GoString() string { return flagName(uint32(i), dflagStrings, true) }
+
+// NType values; used in core files.
+type NType int
+
+const (
+ NT_PRSTATUS NType = 1 /* Process status. */
+ NT_FPREGSET NType = 2 /* Floating point registers. */
+ NT_PRPSINFO NType = 3 /* Process state info. */
+)
+
+var ntypeStrings = []intName{
+ {1, "NT_PRSTATUS"},
+ {2, "NT_FPREGSET"},
+ {3, "NT_PRPSINFO"},
+}
+
+func (i NType) String() string { return stringName(uint32(i), ntypeStrings, false) }
+func (i NType) GoString() string { return stringName(uint32(i), ntypeStrings, true) }
+
+/* Symbol Binding - ELFNN_ST_BIND - st_info */
+type SymBind int
+
+const (
+ STB_LOCAL SymBind = 0 /* Local symbol */
+ STB_GLOBAL SymBind = 1 /* Global symbol */
+ STB_WEAK SymBind = 2 /* like global - lower precedence */
+ STB_LOOS SymBind = 10 /* Reserved range for operating system */
+ STB_HIOS SymBind = 12 /* specific semantics. */
+ STB_LOPROC SymBind = 13 /* reserved range for processor */
+ STB_HIPROC SymBind = 15 /* specific semantics. */
+)
+
+var stbStrings = []intName{
+ {0, "STB_LOCAL"},
+ {1, "STB_GLOBAL"},
+ {2, "STB_WEAK"},
+ {10, "STB_LOOS"},
+ {12, "STB_HIOS"},
+ {13, "STB_LOPROC"},
+ {15, "STB_HIPROC"},
+}
+
+func (i SymBind) String() string { return stringName(uint32(i), stbStrings, false) }
+func (i SymBind) GoString() string { return stringName(uint32(i), stbStrings, true) }
+
+/* Symbol type - ELFNN_ST_TYPE - st_info */
+type SymType int
+
+const (
+ STT_NOTYPE SymType = 0 /* Unspecified type. */
+ STT_OBJECT SymType = 1 /* Data object. */
+ STT_FUNC SymType = 2 /* Function. */
+ STT_SECTION SymType = 3 /* Section. */
+ STT_FILE SymType = 4 /* Source file. */
+ STT_COMMON SymType = 5 /* Uninitialized common block. */
+ STT_TLS SymType = 6 /* TLS object. */
+ STT_LOOS SymType = 10 /* Reserved range for operating system */
+ STT_HIOS SymType = 12 /* specific semantics. */
+ STT_LOPROC SymType = 13 /* reserved range for processor */
+ STT_HIPROC SymType = 15 /* specific semantics. */
+)
+
+var sttStrings = []intName{
+ {0, "STT_NOTYPE"},
+ {1, "STT_OBJECT"},
+ {2, "STT_FUNC"},
+ {3, "STT_SECTION"},
+ {4, "STT_FILE"},
+ {5, "STT_COMMON"},
+ {6, "STT_TLS"},
+ {10, "STT_LOOS"},
+ {12, "STT_HIOS"},
+ {13, "STT_LOPROC"},
+ {15, "STT_HIPROC"},
+}
+
+func (i SymType) String() string { return stringName(uint32(i), sttStrings, false) }
+func (i SymType) GoString() string { return stringName(uint32(i), sttStrings, true) }
+
+/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */
+type SymVis int
+
+const (
+ STV_DEFAULT SymVis = 0x0 /* Default visibility (see binding). */
+ STV_INTERNAL SymVis = 0x1 /* Special meaning in relocatable objects. */
+ STV_HIDDEN SymVis = 0x2 /* Not visible. */
+ STV_PROTECTED SymVis = 0x3 /* Visible but not preemptible. */
+)
+
+var stvStrings = []intName{
+ {0x0, "STV_DEFAULT"},
+ {0x1, "STV_INTERNAL"},
+ {0x2, "STV_HIDDEN"},
+ {0x3, "STV_PROTECTED"},
+}
+
+func (i SymVis) String() string { return stringName(uint32(i), stvStrings, false) }
+func (i SymVis) GoString() string { return stringName(uint32(i), stvStrings, true) }
+
+/*
+ * Relocation types.
+ */
+
+// Relocation types for x86-64.
+type R_X86_64 int
+
+const (
+ R_X86_64_NONE R_X86_64 = 0 /* No relocation. */
+ R_X86_64_64 R_X86_64 = 1 /* Add 64 bit symbol value. */
+ R_X86_64_PC32 R_X86_64 = 2 /* PC-relative 32 bit signed sym value. */
+ R_X86_64_GOT32 R_X86_64 = 3 /* PC-relative 32 bit GOT offset. */
+ R_X86_64_PLT32 R_X86_64 = 4 /* PC-relative 32 bit PLT offset. */
+ R_X86_64_COPY R_X86_64 = 5 /* Copy data from shared object. */
+ R_X86_64_GLOB_DAT R_X86_64 = 6 /* Set GOT entry to data address. */
+ R_X86_64_JMP_SLOT R_X86_64 = 7 /* Set GOT entry to code address. */
+ R_X86_64_RELATIVE R_X86_64 = 8 /* Add load address of shared object. */
+ R_X86_64_GOTPCREL R_X86_64 = 9 /* Add 32 bit signed pcrel offset to GOT. */
+ R_X86_64_32 R_X86_64 = 10 /* Add 32 bit zero extended symbol value */
+ R_X86_64_32S R_X86_64 = 11 /* Add 32 bit sign extended symbol value */
+ R_X86_64_16 R_X86_64 = 12 /* Add 16 bit zero extended symbol value */
+ R_X86_64_PC16 R_X86_64 = 13 /* Add 16 bit signed extended pc relative symbol value */
+ R_X86_64_8 R_X86_64 = 14 /* Add 8 bit zero extended symbol value */
+ R_X86_64_PC8 R_X86_64 = 15 /* Add 8 bit signed extended pc relative symbol value */
+ R_X86_64_DTPMOD64 R_X86_64 = 16 /* ID of module containing symbol */
+ R_X86_64_DTPOFF64 R_X86_64 = 17 /* Offset in TLS block */
+ R_X86_64_TPOFF64 R_X86_64 = 18 /* Offset in static TLS block */
+ R_X86_64_TLSGD R_X86_64 = 19 /* PC relative offset to GD GOT entry */
+ R_X86_64_TLSLD R_X86_64 = 20 /* PC relative offset to LD GOT entry */
+ R_X86_64_DTPOFF32 R_X86_64 = 21 /* Offset in TLS block */
+ R_X86_64_GOTTPOFF R_X86_64 = 22 /* PC relative offset to IE GOT entry */
+ R_X86_64_TPOFF32 R_X86_64 = 23 /* Offset in static TLS block */
+)
+
+var rx86_64Strings = []intName{
+ {0, "R_X86_64_NONE"},
+ {1, "R_X86_64_64"},
+ {2, "R_X86_64_PC32"},
+ {3, "R_X86_64_GOT32"},
+ {4, "R_X86_64_PLT32"},
+ {5, "R_X86_64_COPY"},
+ {6, "R_X86_64_GLOB_DAT"},
+ {7, "R_X86_64_JMP_SLOT"},
+ {8, "R_X86_64_RELATIVE"},
+ {9, "R_X86_64_GOTPCREL"},
+ {10, "R_X86_64_32"},
+ {11, "R_X86_64_32S"},
+ {12, "R_X86_64_16"},
+ {13, "R_X86_64_PC16"},
+ {14, "R_X86_64_8"},
+ {15, "R_X86_64_PC8"},
+ {16, "R_X86_64_DTPMOD64"},
+ {17, "R_X86_64_DTPOFF64"},
+ {18, "R_X86_64_TPOFF64"},
+ {19, "R_X86_64_TLSGD"},
+ {20, "R_X86_64_TLSLD"},
+ {21, "R_X86_64_DTPOFF32"},
+ {22, "R_X86_64_GOTTPOFF"},
+ {23, "R_X86_64_TPOFF32"},
+}
+
+func (i R_X86_64) String() string { return stringName(uint32(i), rx86_64Strings, false) }
+func (i R_X86_64) GoString() string { return stringName(uint32(i), rx86_64Strings, true) }
+
+// Relocation types for Alpha.
+type R_ALPHA int
+
+const (
+ R_ALPHA_NONE R_ALPHA = 0 /* No reloc */
+ R_ALPHA_REFLONG R_ALPHA = 1 /* Direct 32 bit */
+ R_ALPHA_REFQUAD R_ALPHA = 2 /* Direct 64 bit */
+ R_ALPHA_GPREL32 R_ALPHA = 3 /* GP relative 32 bit */
+ R_ALPHA_LITERAL R_ALPHA = 4 /* GP relative 16 bit w/optimization */
+ R_ALPHA_LITUSE R_ALPHA = 5 /* Optimization hint for LITERAL */
+ R_ALPHA_GPDISP R_ALPHA = 6 /* Add displacement to GP */
+ R_ALPHA_BRADDR R_ALPHA = 7 /* PC+4 relative 23 bit shifted */
+ R_ALPHA_HINT R_ALPHA = 8 /* PC+4 relative 16 bit shifted */
+ R_ALPHA_SREL16 R_ALPHA = 9 /* PC relative 16 bit */
+ R_ALPHA_SREL32 R_ALPHA = 10 /* PC relative 32 bit */
+ R_ALPHA_SREL64 R_ALPHA = 11 /* PC relative 64 bit */
+ R_ALPHA_OP_PUSH R_ALPHA = 12 /* OP stack push */
+ R_ALPHA_OP_STORE R_ALPHA = 13 /* OP stack pop and store */
+ R_ALPHA_OP_PSUB R_ALPHA = 14 /* OP stack subtract */
+ R_ALPHA_OP_PRSHIFT R_ALPHA = 15 /* OP stack right shift */
+ R_ALPHA_GPVALUE R_ALPHA = 16
+ R_ALPHA_GPRELHIGH R_ALPHA = 17
+ R_ALPHA_GPRELLOW R_ALPHA = 18
+ R_ALPHA_IMMED_GP_16 R_ALPHA = 19
+ R_ALPHA_IMMED_GP_HI32 R_ALPHA = 20
+ R_ALPHA_IMMED_SCN_HI32 R_ALPHA = 21
+ R_ALPHA_IMMED_BR_HI32 R_ALPHA = 22
+ R_ALPHA_IMMED_LO32 R_ALPHA = 23
+ R_ALPHA_COPY R_ALPHA = 24 /* Copy symbol at runtime */
+ R_ALPHA_GLOB_DAT R_ALPHA = 25 /* Create GOT entry */
+ R_ALPHA_JMP_SLOT R_ALPHA = 26 /* Create PLT entry */
+ R_ALPHA_RELATIVE R_ALPHA = 27 /* Adjust by program base */
+)
+
+var ralphaStrings = []intName{
+ {0, "R_ALPHA_NONE"},
+ {1, "R_ALPHA_REFLONG"},
+ {2, "R_ALPHA_REFQUAD"},
+ {3, "R_ALPHA_GPREL32"},
+ {4, "R_ALPHA_LITERAL"},
+ {5, "R_ALPHA_LITUSE"},
+ {6, "R_ALPHA_GPDISP"},
+ {7, "R_ALPHA_BRADDR"},
+ {8, "R_ALPHA_HINT"},
+ {9, "R_ALPHA_SREL16"},
+ {10, "R_ALPHA_SREL32"},
+ {11, "R_ALPHA_SREL64"},
+ {12, "R_ALPHA_OP_PUSH"},
+ {13, "R_ALPHA_OP_STORE"},
+ {14, "R_ALPHA_OP_PSUB"},
+ {15, "R_ALPHA_OP_PRSHIFT"},
+ {16, "R_ALPHA_GPVALUE"},
+ {17, "R_ALPHA_GPRELHIGH"},
+ {18, "R_ALPHA_GPRELLOW"},
+ {19, "R_ALPHA_IMMED_GP_16"},
+ {20, "R_ALPHA_IMMED_GP_HI32"},
+ {21, "R_ALPHA_IMMED_SCN_HI32"},
+ {22, "R_ALPHA_IMMED_BR_HI32"},
+ {23, "R_ALPHA_IMMED_LO32"},
+ {24, "R_ALPHA_COPY"},
+ {25, "R_ALPHA_GLOB_DAT"},
+ {26, "R_ALPHA_JMP_SLOT"},
+ {27, "R_ALPHA_RELATIVE"},
+}
+
+func (i R_ALPHA) String() string { return stringName(uint32(i), ralphaStrings, false) }
+func (i R_ALPHA) GoString() string { return stringName(uint32(i), ralphaStrings, true) }
+
+// Relocation types for ARM.
+type R_ARM int
+
+const (
+ R_ARM_NONE R_ARM = 0 /* No relocation. */
+ R_ARM_PC24 R_ARM = 1
+ R_ARM_ABS32 R_ARM = 2
+ R_ARM_REL32 R_ARM = 3
+ R_ARM_PC13 R_ARM = 4
+ R_ARM_ABS16 R_ARM = 5
+ R_ARM_ABS12 R_ARM = 6
+ R_ARM_THM_ABS5 R_ARM = 7
+ R_ARM_ABS8 R_ARM = 8
+ R_ARM_SBREL32 R_ARM = 9
+ R_ARM_THM_PC22 R_ARM = 10
+ R_ARM_THM_PC8 R_ARM = 11
+ R_ARM_AMP_VCALL9 R_ARM = 12
+ R_ARM_SWI24 R_ARM = 13
+ R_ARM_THM_SWI8 R_ARM = 14
+ R_ARM_XPC25 R_ARM = 15
+ R_ARM_THM_XPC22 R_ARM = 16
+ R_ARM_COPY R_ARM = 20 /* Copy data from shared object. */
+ R_ARM_GLOB_DAT R_ARM = 21 /* Set GOT entry to data address. */
+ R_ARM_JUMP_SLOT R_ARM = 22 /* Set GOT entry to code address. */
+ R_ARM_RELATIVE R_ARM = 23 /* Add load address of shared object. */
+ R_ARM_GOTOFF R_ARM = 24 /* Add GOT-relative symbol address. */
+ R_ARM_GOTPC R_ARM = 25 /* Add PC-relative GOT table address. */
+ R_ARM_GOT32 R_ARM = 26 /* Add PC-relative GOT offset. */
+ R_ARM_PLT32 R_ARM = 27 /* Add PC-relative PLT offset. */
+ R_ARM_GNU_VTENTRY R_ARM = 100
+ R_ARM_GNU_VTINHERIT R_ARM = 101
+ R_ARM_RSBREL32 R_ARM = 250
+ R_ARM_THM_RPC22 R_ARM = 251
+ R_ARM_RREL32 R_ARM = 252
+ R_ARM_RABS32 R_ARM = 253
+ R_ARM_RPC24 R_ARM = 254
+ R_ARM_RBASE R_ARM = 255
+)
+
+var rarmStrings = []intName{
+ {0, "R_ARM_NONE"},
+ {1, "R_ARM_PC24"},
+ {2, "R_ARM_ABS32"},
+ {3, "R_ARM_REL32"},
+ {4, "R_ARM_PC13"},
+ {5, "R_ARM_ABS16"},
+ {6, "R_ARM_ABS12"},
+ {7, "R_ARM_THM_ABS5"},
+ {8, "R_ARM_ABS8"},
+ {9, "R_ARM_SBREL32"},
+ {10, "R_ARM_THM_PC22"},
+ {11, "R_ARM_THM_PC8"},
+ {12, "R_ARM_AMP_VCALL9"},
+ {13, "R_ARM_SWI24"},
+ {14, "R_ARM_THM_SWI8"},
+ {15, "R_ARM_XPC25"},
+ {16, "R_ARM_THM_XPC22"},
+ {20, "R_ARM_COPY"},
+ {21, "R_ARM_GLOB_DAT"},
+ {22, "R_ARM_JUMP_SLOT"},
+ {23, "R_ARM_RELATIVE"},
+ {24, "R_ARM_GOTOFF"},
+ {25, "R_ARM_GOTPC"},
+ {26, "R_ARM_GOT32"},
+ {27, "R_ARM_PLT32"},
+ {100, "R_ARM_GNU_VTENTRY"},
+ {101, "R_ARM_GNU_VTINHERIT"},
+ {250, "R_ARM_RSBREL32"},
+ {251, "R_ARM_THM_RPC22"},
+ {252, "R_ARM_RREL32"},
+ {253, "R_ARM_RABS32"},
+ {254, "R_ARM_RPC24"},
+ {255, "R_ARM_RBASE"},
+}
+
+func (i R_ARM) String() string { return stringName(uint32(i), rarmStrings, false) }
+func (i R_ARM) GoString() string { return stringName(uint32(i), rarmStrings, true) }
+
+// Relocation types for 386.
+type R_386 int
+
+const (
+ R_386_NONE R_386 = 0 /* No relocation. */
+ R_386_32 R_386 = 1 /* Add symbol value. */
+ R_386_PC32 R_386 = 2 /* Add PC-relative symbol value. */
+ R_386_GOT32 R_386 = 3 /* Add PC-relative GOT offset. */
+ R_386_PLT32 R_386 = 4 /* Add PC-relative PLT offset. */
+ R_386_COPY R_386 = 5 /* Copy data from shared object. */
+ R_386_GLOB_DAT R_386 = 6 /* Set GOT entry to data address. */
+ R_386_JMP_SLOT R_386 = 7 /* Set GOT entry to code address. */
+ R_386_RELATIVE R_386 = 8 /* Add load address of shared object. */
+ R_386_GOTOFF R_386 = 9 /* Add GOT-relative symbol address. */
+ R_386_GOTPC R_386 = 10 /* Add PC-relative GOT table address. */
+ R_386_TLS_TPOFF R_386 = 14 /* Negative offset in static TLS block */
+ R_386_TLS_IE R_386 = 15 /* Absolute address of GOT for -ve static TLS */
+ R_386_TLS_GOTIE R_386 = 16 /* GOT entry for negative static TLS block */
+ R_386_TLS_LE R_386 = 17 /* Negative offset relative to static TLS */
+ R_386_TLS_GD R_386 = 18 /* 32 bit offset to GOT (index,off) pair */
+ R_386_TLS_LDM R_386 = 19 /* 32 bit offset to GOT (index,zero) pair */
+ R_386_TLS_GD_32 R_386 = 24 /* 32 bit offset to GOT (index,off) pair */
+ R_386_TLS_GD_PUSH R_386 = 25 /* pushl instruction for Sun ABI GD sequence */
+ R_386_TLS_GD_CALL R_386 = 26 /* call instruction for Sun ABI GD sequence */
+ R_386_TLS_GD_POP R_386 = 27 /* popl instruction for Sun ABI GD sequence */
+ R_386_TLS_LDM_32 R_386 = 28 /* 32 bit offset to GOT (index,zero) pair */
+ R_386_TLS_LDM_PUSH R_386 = 29 /* pushl instruction for Sun ABI LD sequence */
+ R_386_TLS_LDM_CALL R_386 = 30 /* call instruction for Sun ABI LD sequence */
+ R_386_TLS_LDM_POP R_386 = 31 /* popl instruction for Sun ABI LD sequence */
+ R_386_TLS_LDO_32 R_386 = 32 /* 32 bit offset from start of TLS block */
+ R_386_TLS_IE_32 R_386 = 33 /* 32 bit offset to GOT static TLS offset entry */
+ R_386_TLS_LE_32 R_386 = 34 /* 32 bit offset within static TLS block */
+ R_386_TLS_DTPMOD32 R_386 = 35 /* GOT entry containing TLS index */
+ R_386_TLS_DTPOFF32 R_386 = 36 /* GOT entry containing TLS offset */
+ R_386_TLS_TPOFF32 R_386 = 37 /* GOT entry of -ve static TLS offset */
+)
+
+var r386Strings = []intName{
+ {0, "R_386_NONE"},
+ {1, "R_386_32"},
+ {2, "R_386_PC32"},
+ {3, "R_386_GOT32"},
+ {4, "R_386_PLT32"},
+ {5, "R_386_COPY"},
+ {6, "R_386_GLOB_DAT"},
+ {7, "R_386_JMP_SLOT"},
+ {8, "R_386_RELATIVE"},
+ {9, "R_386_GOTOFF"},
+ {10, "R_386_GOTPC"},
+ {14, "R_386_TLS_TPOFF"},
+ {15, "R_386_TLS_IE"},
+ {16, "R_386_TLS_GOTIE"},
+ {17, "R_386_TLS_LE"},
+ {18, "R_386_TLS_GD"},
+ {19, "R_386_TLS_LDM"},
+ {24, "R_386_TLS_GD_32"},
+ {25, "R_386_TLS_GD_PUSH"},
+ {26, "R_386_TLS_GD_CALL"},
+ {27, "R_386_TLS_GD_POP"},
+ {28, "R_386_TLS_LDM_32"},
+ {29, "R_386_TLS_LDM_PUSH"},
+ {30, "R_386_TLS_LDM_CALL"},
+ {31, "R_386_TLS_LDM_POP"},
+ {32, "R_386_TLS_LDO_32"},
+ {33, "R_386_TLS_IE_32"},
+ {34, "R_386_TLS_LE_32"},
+ {35, "R_386_TLS_DTPMOD32"},
+ {36, "R_386_TLS_DTPOFF32"},
+ {37, "R_386_TLS_TPOFF32"},
+}
+
+func (i R_386) String() string { return stringName(uint32(i), r386Strings, false) }
+func (i R_386) GoString() string { return stringName(uint32(i), r386Strings, true) }
+
+// Relocation types for PowerPC.
+type R_PPC int
+
+const (
+ R_PPC_NONE R_PPC = 0 /* No relocation. */
+ R_PPC_ADDR32 R_PPC = 1
+ R_PPC_ADDR24 R_PPC = 2
+ R_PPC_ADDR16 R_PPC = 3
+ R_PPC_ADDR16_LO R_PPC = 4
+ R_PPC_ADDR16_HI R_PPC = 5
+ R_PPC_ADDR16_HA R_PPC = 6
+ R_PPC_ADDR14 R_PPC = 7
+ R_PPC_ADDR14_BRTAKEN R_PPC = 8
+ R_PPC_ADDR14_BRNTAKEN R_PPC = 9
+ R_PPC_REL24 R_PPC = 10
+ R_PPC_REL14 R_PPC = 11
+ R_PPC_REL14_BRTAKEN R_PPC = 12
+ R_PPC_REL14_BRNTAKEN R_PPC = 13
+ R_PPC_GOT16 R_PPC = 14
+ R_PPC_GOT16_LO R_PPC = 15
+ R_PPC_GOT16_HI R_PPC = 16
+ R_PPC_GOT16_HA R_PPC = 17
+ R_PPC_PLTREL24 R_PPC = 18
+ R_PPC_COPY R_PPC = 19
+ R_PPC_GLOB_DAT R_PPC = 20
+ R_PPC_JMP_SLOT R_PPC = 21
+ R_PPC_RELATIVE R_PPC = 22
+ R_PPC_LOCAL24PC R_PPC = 23
+ R_PPC_UADDR32 R_PPC = 24
+ R_PPC_UADDR16 R_PPC = 25
+ R_PPC_REL32 R_PPC = 26
+ R_PPC_PLT32 R_PPC = 27
+ R_PPC_PLTREL32 R_PPC = 28
+ R_PPC_PLT16_LO R_PPC = 29
+ R_PPC_PLT16_HI R_PPC = 30
+ R_PPC_PLT16_HA R_PPC = 31
+ R_PPC_SDAREL16 R_PPC = 32
+ R_PPC_SECTOFF R_PPC = 33
+ R_PPC_SECTOFF_LO R_PPC = 34
+ R_PPC_SECTOFF_HI R_PPC = 35
+ R_PPC_SECTOFF_HA R_PPC = 36
+ R_PPC_TLS R_PPC = 67
+ R_PPC_DTPMOD32 R_PPC = 68
+ R_PPC_TPREL16 R_PPC = 69
+ R_PPC_TPREL16_LO R_PPC = 70
+ R_PPC_TPREL16_HI R_PPC = 71
+ R_PPC_TPREL16_HA R_PPC = 72
+ R_PPC_TPREL32 R_PPC = 73
+ R_PPC_DTPREL16 R_PPC = 74
+ R_PPC_DTPREL16_LO R_PPC = 75
+ R_PPC_DTPREL16_HI R_PPC = 76
+ R_PPC_DTPREL16_HA R_PPC = 77
+ R_PPC_DTPREL32 R_PPC = 78
+ R_PPC_GOT_TLSGD16 R_PPC = 79
+ R_PPC_GOT_TLSGD16_LO R_PPC = 80
+ R_PPC_GOT_TLSGD16_HI R_PPC = 81
+ R_PPC_GOT_TLSGD16_HA R_PPC = 82
+ R_PPC_GOT_TLSLD16 R_PPC = 83
+ R_PPC_GOT_TLSLD16_LO R_PPC = 84
+ R_PPC_GOT_TLSLD16_HI R_PPC = 85
+ R_PPC_GOT_TLSLD16_HA R_PPC = 86
+ R_PPC_GOT_TPREL16 R_PPC = 87
+ R_PPC_GOT_TPREL16_LO R_PPC = 88
+ R_PPC_GOT_TPREL16_HI R_PPC = 89
+ R_PPC_GOT_TPREL16_HA R_PPC = 90
+ R_PPC_EMB_NADDR32 R_PPC = 101
+ R_PPC_EMB_NADDR16 R_PPC = 102
+ R_PPC_EMB_NADDR16_LO R_PPC = 103
+ R_PPC_EMB_NADDR16_HI R_PPC = 104
+ R_PPC_EMB_NADDR16_HA R_PPC = 105
+ R_PPC_EMB_SDAI16 R_PPC = 106
+ R_PPC_EMB_SDA2I16 R_PPC = 107
+ R_PPC_EMB_SDA2REL R_PPC = 108
+ R_PPC_EMB_SDA21 R_PPC = 109
+ R_PPC_EMB_MRKREF R_PPC = 110
+ R_PPC_EMB_RELSEC16 R_PPC = 111
+ R_PPC_EMB_RELST_LO R_PPC = 112
+ R_PPC_EMB_RELST_HI R_PPC = 113
+ R_PPC_EMB_RELST_HA R_PPC = 114
+ R_PPC_EMB_BIT_FLD R_PPC = 115
+ R_PPC_EMB_RELSDA R_PPC = 116
+)
+
+var rppcStrings = []intName{
+ {0, "R_PPC_NONE"},
+ {1, "R_PPC_ADDR32"},
+ {2, "R_PPC_ADDR24"},
+ {3, "R_PPC_ADDR16"},
+ {4, "R_PPC_ADDR16_LO"},
+ {5, "R_PPC_ADDR16_HI"},
+ {6, "R_PPC_ADDR16_HA"},
+ {7, "R_PPC_ADDR14"},
+ {8, "R_PPC_ADDR14_BRTAKEN"},
+ {9, "R_PPC_ADDR14_BRNTAKEN"},
+ {10, "R_PPC_REL24"},
+ {11, "R_PPC_REL14"},
+ {12, "R_PPC_REL14_BRTAKEN"},
+ {13, "R_PPC_REL14_BRNTAKEN"},
+ {14, "R_PPC_GOT16"},
+ {15, "R_PPC_GOT16_LO"},
+ {16, "R_PPC_GOT16_HI"},
+ {17, "R_PPC_GOT16_HA"},
+ {18, "R_PPC_PLTREL24"},
+ {19, "R_PPC_COPY"},
+ {20, "R_PPC_GLOB_DAT"},
+ {21, "R_PPC_JMP_SLOT"},
+ {22, "R_PPC_RELATIVE"},
+ {23, "R_PPC_LOCAL24PC"},
+ {24, "R_PPC_UADDR32"},
+ {25, "R_PPC_UADDR16"},
+ {26, "R_PPC_REL32"},
+ {27, "R_PPC_PLT32"},
+ {28, "R_PPC_PLTREL32"},
+ {29, "R_PPC_PLT16_LO"},
+ {30, "R_PPC_PLT16_HI"},
+ {31, "R_PPC_PLT16_HA"},
+ {32, "R_PPC_SDAREL16"},
+ {33, "R_PPC_SECTOFF"},
+ {34, "R_PPC_SECTOFF_LO"},
+ {35, "R_PPC_SECTOFF_HI"},
+ {36, "R_PPC_SECTOFF_HA"},
+
+ {67, "R_PPC_TLS"},
+ {68, "R_PPC_DTPMOD32"},
+ {69, "R_PPC_TPREL16"},
+ {70, "R_PPC_TPREL16_LO"},
+ {71, "R_PPC_TPREL16_HI"},
+ {72, "R_PPC_TPREL16_HA"},
+ {73, "R_PPC_TPREL32"},
+ {74, "R_PPC_DTPREL16"},
+ {75, "R_PPC_DTPREL16_LO"},
+ {76, "R_PPC_DTPREL16_HI"},
+ {77, "R_PPC_DTPREL16_HA"},
+ {78, "R_PPC_DTPREL32"},
+ {79, "R_PPC_GOT_TLSGD16"},
+ {80, "R_PPC_GOT_TLSGD16_LO"},
+ {81, "R_PPC_GOT_TLSGD16_HI"},
+ {82, "R_PPC_GOT_TLSGD16_HA"},
+ {83, "R_PPC_GOT_TLSLD16"},
+ {84, "R_PPC_GOT_TLSLD16_LO"},
+ {85, "R_PPC_GOT_TLSLD16_HI"},
+ {86, "R_PPC_GOT_TLSLD16_HA"},
+ {87, "R_PPC_GOT_TPREL16"},
+ {88, "R_PPC_GOT_TPREL16_LO"},
+ {89, "R_PPC_GOT_TPREL16_HI"},
+ {90, "R_PPC_GOT_TPREL16_HA"},
+
+ {101, "R_PPC_EMB_NADDR32"},
+ {102, "R_PPC_EMB_NADDR16"},
+ {103, "R_PPC_EMB_NADDR16_LO"},
+ {104, "R_PPC_EMB_NADDR16_HI"},
+ {105, "R_PPC_EMB_NADDR16_HA"},
+ {106, "R_PPC_EMB_SDAI16"},
+ {107, "R_PPC_EMB_SDA2I16"},
+ {108, "R_PPC_EMB_SDA2REL"},
+ {109, "R_PPC_EMB_SDA21"},
+ {110, "R_PPC_EMB_MRKREF"},
+ {111, "R_PPC_EMB_RELSEC16"},
+ {112, "R_PPC_EMB_RELST_LO"},
+ {113, "R_PPC_EMB_RELST_HI"},
+ {114, "R_PPC_EMB_RELST_HA"},
+ {115, "R_PPC_EMB_BIT_FLD"},
+ {116, "R_PPC_EMB_RELSDA"},
+}
+
+func (i R_PPC) String() string { return stringName(uint32(i), rppcStrings, false) }
+func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) }
+
+// Relocation types for SPARC.
+type R_SPARC int
+
+const (
+ R_SPARC_NONE R_SPARC = 0
+ R_SPARC_8 R_SPARC = 1
+ R_SPARC_16 R_SPARC = 2
+ R_SPARC_32 R_SPARC = 3
+ R_SPARC_DISP8 R_SPARC = 4
+ R_SPARC_DISP16 R_SPARC = 5
+ R_SPARC_DISP32 R_SPARC = 6
+ R_SPARC_WDISP30 R_SPARC = 7
+ R_SPARC_WDISP22 R_SPARC = 8
+ R_SPARC_HI22 R_SPARC = 9
+ R_SPARC_22 R_SPARC = 10
+ R_SPARC_13 R_SPARC = 11
+ R_SPARC_LO10 R_SPARC = 12
+ R_SPARC_GOT10 R_SPARC = 13
+ R_SPARC_GOT13 R_SPARC = 14
+ R_SPARC_GOT22 R_SPARC = 15
+ R_SPARC_PC10 R_SPARC = 16
+ R_SPARC_PC22 R_SPARC = 17
+ R_SPARC_WPLT30 R_SPARC = 18
+ R_SPARC_COPY R_SPARC = 19
+ R_SPARC_GLOB_DAT R_SPARC = 20
+ R_SPARC_JMP_SLOT R_SPARC = 21
+ R_SPARC_RELATIVE R_SPARC = 22
+ R_SPARC_UA32 R_SPARC = 23
+ R_SPARC_PLT32 R_SPARC = 24
+ R_SPARC_HIPLT22 R_SPARC = 25
+ R_SPARC_LOPLT10 R_SPARC = 26
+ R_SPARC_PCPLT32 R_SPARC = 27
+ R_SPARC_PCPLT22 R_SPARC = 28
+ R_SPARC_PCPLT10 R_SPARC = 29
+ R_SPARC_10 R_SPARC = 30
+ R_SPARC_11 R_SPARC = 31
+ R_SPARC_64 R_SPARC = 32
+ R_SPARC_OLO10 R_SPARC = 33
+ R_SPARC_HH22 R_SPARC = 34
+ R_SPARC_HM10 R_SPARC = 35
+ R_SPARC_LM22 R_SPARC = 36
+ R_SPARC_PC_HH22 R_SPARC = 37
+ R_SPARC_PC_HM10 R_SPARC = 38
+ R_SPARC_PC_LM22 R_SPARC = 39
+ R_SPARC_WDISP16 R_SPARC = 40
+ R_SPARC_WDISP19 R_SPARC = 41
+ R_SPARC_GLOB_JMP R_SPARC = 42
+ R_SPARC_7 R_SPARC = 43
+ R_SPARC_5 R_SPARC = 44
+ R_SPARC_6 R_SPARC = 45
+ R_SPARC_DISP64 R_SPARC = 46
+ R_SPARC_PLT64 R_SPARC = 47
+ R_SPARC_HIX22 R_SPARC = 48
+ R_SPARC_LOX10 R_SPARC = 49
+ R_SPARC_H44 R_SPARC = 50
+ R_SPARC_M44 R_SPARC = 51
+ R_SPARC_L44 R_SPARC = 52
+ R_SPARC_REGISTER R_SPARC = 53
+ R_SPARC_UA64 R_SPARC = 54
+ R_SPARC_UA16 R_SPARC = 55
+)
+
+var rsparcStrings = []intName{
+ {0, "R_SPARC_NONE"},
+ {1, "R_SPARC_8"},
+ {2, "R_SPARC_16"},
+ {3, "R_SPARC_32"},
+ {4, "R_SPARC_DISP8"},
+ {5, "R_SPARC_DISP16"},
+ {6, "R_SPARC_DISP32"},
+ {7, "R_SPARC_WDISP30"},
+ {8, "R_SPARC_WDISP22"},
+ {9, "R_SPARC_HI22"},
+ {10, "R_SPARC_22"},
+ {11, "R_SPARC_13"},
+ {12, "R_SPARC_LO10"},
+ {13, "R_SPARC_GOT10"},
+ {14, "R_SPARC_GOT13"},
+ {15, "R_SPARC_GOT22"},
+ {16, "R_SPARC_PC10"},
+ {17, "R_SPARC_PC22"},
+ {18, "R_SPARC_WPLT30"},
+ {19, "R_SPARC_COPY"},
+ {20, "R_SPARC_GLOB_DAT"},
+ {21, "R_SPARC_JMP_SLOT"},
+ {22, "R_SPARC_RELATIVE"},
+ {23, "R_SPARC_UA32"},
+ {24, "R_SPARC_PLT32"},
+ {25, "R_SPARC_HIPLT22"},
+ {26, "R_SPARC_LOPLT10"},
+ {27, "R_SPARC_PCPLT32"},
+ {28, "R_SPARC_PCPLT22"},
+ {29, "R_SPARC_PCPLT10"},
+ {30, "R_SPARC_10"},
+ {31, "R_SPARC_11"},
+ {32, "R_SPARC_64"},
+ {33, "R_SPARC_OLO10"},
+ {34, "R_SPARC_HH22"},
+ {35, "R_SPARC_HM10"},
+ {36, "R_SPARC_LM22"},
+ {37, "R_SPARC_PC_HH22"},
+ {38, "R_SPARC_PC_HM10"},
+ {39, "R_SPARC_PC_LM22"},
+ {40, "R_SPARC_WDISP16"},
+ {41, "R_SPARC_WDISP19"},
+ {42, "R_SPARC_GLOB_JMP"},
+ {43, "R_SPARC_7"},
+ {44, "R_SPARC_5"},
+ {45, "R_SPARC_6"},
+ {46, "R_SPARC_DISP64"},
+ {47, "R_SPARC_PLT64"},
+ {48, "R_SPARC_HIX22"},
+ {49, "R_SPARC_LOX10"},
+ {50, "R_SPARC_H44"},
+ {51, "R_SPARC_M44"},
+ {52, "R_SPARC_L44"},
+ {53, "R_SPARC_REGISTER"},
+ {54, "R_SPARC_UA64"},
+ {55, "R_SPARC_UA16"},
+}
+
+func (i R_SPARC) String() string { return stringName(uint32(i), rsparcStrings, false) }
+func (i R_SPARC) GoString() string { return stringName(uint32(i), rsparcStrings, true) }
+
+// Magic number for the elf trampoline, chosen wisely to be an immediate value.
+const ARM_MAGIC_TRAMP_NUMBER = 0x5c000003
+
+
+// ELF32 File header.
+type Header32 struct {
+ Ident [EI_NIDENT]byte /* File identification. */
+ Type uint16 /* File type. */
+ Machine uint16 /* Machine architecture. */
+ Version uint32 /* ELF format version. */
+ Entry uint32 /* Entry point. */
+ Phoff uint32 /* Program header file offset. */
+ Shoff uint32 /* Section header file offset. */
+ Flags uint32 /* Architecture-specific flags. */
+ Ehsize uint16 /* Size of ELF header in bytes. */
+ Phentsize uint16 /* Size of program header entry. */
+ Phnum uint16 /* Number of program header entries. */
+ Shentsize uint16 /* Size of section header entry. */
+ Shnum uint16 /* Number of section header entries. */
+ Shstrndx uint16 /* Section name strings section. */
+}
+
+// ELF32 Section header.
+type Section32 struct {
+ Name uint32 /* Section name (index into the section header string table). */
+ Type uint32 /* Section type. */
+ Flags uint32 /* Section flags. */
+ Addr uint32 /* Address in memory image. */
+ Off uint32 /* Offset in file. */
+ Size uint32 /* Size in bytes. */
+ Link uint32 /* Index of a related section. */
+ Info uint32 /* Depends on section type. */
+ Addralign uint32 /* Alignment in bytes. */
+ Entsize uint32 /* Size of each entry in section. */
+}
+
+// ELF32 Program header.
+type Prog32 struct {
+ Type uint32 /* Entry type. */
+ Off uint32 /* File offset of contents. */
+ Vaddr uint32 /* Virtual address in memory image. */
+ Paddr uint32 /* Physical address (not used). */
+ Filesz uint32 /* Size of contents in file. */
+ Memsz uint32 /* Size of contents in memory. */
+ Flags uint32 /* Access permission flags. */
+ Align uint32 /* Alignment in memory and file. */
+}
+
+// ELF32 Dynamic structure. The ".dynamic" section contains an array of them.
+type Dyn32 struct {
+ Tag int32 /* Entry type. */
+ Val uint32 /* Integer/Address value. */
+}
+
+/*
+ * Relocation entries.
+ */
+
+// ELF32 Relocations that don't need an addend field.
+type Rel32 struct {
+ Off uint32 /* Location to be relocated. */
+ Info uint32 /* Relocation type and symbol index. */
+}
+
+// ELF32 Relocations that need an addend field.
+type Rela32 struct {
+ Off uint32 /* Location to be relocated. */
+ Info uint32 /* Relocation type and symbol index. */
+ Addend int32 /* Addend. */
+}
+
+func R_SYM32(info uint32) uint32 { return uint32(info >> 8) }
+func R_TYPE32(info uint32) uint32 { return uint32(info & 0xff) }
+func R_INFO32(sym, typ uint32) uint32 { return sym<<8 | typ }
+
+// ELF32 Symbol.
+type Sym32 struct {
+ Name uint32
+ Value uint32
+ Size uint32
+ Info uint8
+ Other uint8
+ Shndx uint16
+}
+
+const Sym32Size = 16
+
+func ST_BIND(info uint8) SymBind { return SymBind(info >> 4) }
+func ST_TYPE(info uint8) SymType { return SymType(info & 0xF) }
+func ST_INFO(bind SymBind, typ SymType) uint8 {
+ return uint8(bind)<<4 | uint8(typ)&0xf
+}
+func ST_VISIBILITY(other uint8) SymVis { return SymVis(other & 3) }
+
+/*
+ * ELF64
+ */
+
+// ELF64 file header.
+type Header64 struct {
+ Ident [EI_NIDENT]byte /* File identification. */
+ Type uint16 /* File type. */
+ Machine uint16 /* Machine architecture. */
+ Version uint32 /* ELF format version. */
+ Entry uint64 /* Entry point. */
+ Phoff uint64 /* Program header file offset. */
+ Shoff uint64 /* Section header file offset. */
+ Flags uint32 /* Architecture-specific flags. */
+ Ehsize uint16 /* Size of ELF header in bytes. */
+ Phentsize uint16 /* Size of program header entry. */
+ Phnum uint16 /* Number of program header entries. */
+ Shentsize uint16 /* Size of section header entry. */
+ Shnum uint16 /* Number of section header entries. */
+ Shstrndx uint16 /* Section name strings section. */
+}
+
+// ELF64 Section header.
+type Section64 struct {
+ Name uint32 /* Section name (index into the section header string table). */
+ Type uint32 /* Section type. */
+ Flags uint64 /* Section flags. */
+ Addr uint64 /* Address in memory image. */
+ Off uint64 /* Offset in file. */
+ Size uint64 /* Size in bytes. */
+ Link uint32 /* Index of a related section. */
+ Info uint32 /* Depends on section type. */
+ Addralign uint64 /* Alignment in bytes. */
+ Entsize uint64 /* Size of each entry in section. */
+}
+
+// ELF64 Program header.
+type Prog64 struct {
+ Type uint32 /* Entry type. */
+ Flags uint32 /* Access permission flags. */
+ Off uint64 /* File offset of contents. */
+ Vaddr uint64 /* Virtual address in memory image. */
+ Paddr uint64 /* Physical address (not used). */
+ Filesz uint64 /* Size of contents in file. */
+ Memsz uint64 /* Size of contents in memory. */
+ Align uint64 /* Alignment in memory and file. */
+}
+
+// ELF64 Dynamic structure. The ".dynamic" section contains an array of them.
+type Dyn64 struct {
+ Tag int64 /* Entry type. */
+ Val uint64 /* Integer/address value */
+}
+
+/*
+ * Relocation entries.
+ */
+
+/* ELF64 relocations that don't need an addend field. */
+type Rel64 struct {
+ Off uint64 /* Location to be relocated. */
+ Info uint64 /* Relocation type and symbol index. */
+}
+
+/* ELF64 relocations that need an addend field. */
+type Rela64 struct {
+ Off uint64 /* Location to be relocated. */
+ Info uint64 /* Relocation type and symbol index. */
+ Addend int64 /* Addend. */
+}
+
+func R_SYM64(info uint64) uint32 { return uint32(info >> 32) }
+func R_TYPE64(info uint64) uint32 { return uint32(info) }
+func R_INFO(sym, typ uint32) uint64 { return uint64(sym)<<32 | uint64(typ) }
+
+
+// ELF64 symbol table entries.
+type Sym64 struct {
+ Name uint32 /* String table index of name. */
+ Info uint8 /* Type and binding information. */
+ Other uint8 /* Reserved (not used). */
+ Shndx uint16 /* Section index of symbol. */
+ Value uint64 /* Symbol value. */
+ Size uint64 /* Size of associated object. */
+}
+
+const Sym64Size = 24
+
+type intName struct {
+ i uint32
+ s string
+}
+
+func stringName(i uint32, names []intName, goSyntax bool) string {
+ for _, n := range names {
+ if n.i == i {
+ if goSyntax {
+ return "elf." + n.s
+ }
+ return n.s
+ }
+ }
+
+ // second pass - look for smaller to add with.
+ // assume sorted already
+ for j := len(names) - 1; j >= 0; j-- {
+ n := names[j]
+ if n.i < i {
+ s := n.s
+ if goSyntax {
+ s = "elf." + s
+ }
+ return s + "+" + strconv.Uitoa64(uint64(i-n.i))
+ }
+ }
+
+ return strconv.Uitoa64(uint64(i))
+}
+
+func flagName(i uint32, names []intName, goSyntax bool) string {
+ s := ""
+ for _, n := range names {
+ if n.i&i == n.i {
+ if len(s) > 0 {
+ s += "+"
+ }
+ if goSyntax {
+ s += "elf."
+ }
+ s += n.s
+ i -= n.i
+ }
+ }
+ if len(s) == 0 {
+ return "0x" + strconv.Uitob64(uint64(i), 16)
+ }
+ if i != 0 {
+ s += "+0x" + strconv.Uitob64(uint64(i), 16)
+ }
+ return s
+}
diff --git a/libgo/go/debug/elf/elf_test.go b/libgo/go/debug/elf/elf_test.go
new file mode 100644
index 000000000..67b961b5c
--- /dev/null
+++ b/libgo/go/debug/elf/elf_test.go
@@ -0,0 +1,49 @@
+// 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 elf
+
+import (
+ "fmt"
+ "testing"
+)
+
+type nameTest struct {
+ val interface{}
+ str string
+}
+
+var nameTests = []nameTest{
+ {ELFOSABI_LINUX, "ELFOSABI_LINUX"},
+ {ET_EXEC, "ET_EXEC"},
+ {EM_860, "EM_860"},
+ {SHN_LOPROC, "SHN_LOPROC"},
+ {SHT_PROGBITS, "SHT_PROGBITS"},
+ {SHF_MERGE + SHF_TLS, "SHF_MERGE+SHF_TLS"},
+ {PT_LOAD, "PT_LOAD"},
+ {PF_W + PF_R + 0x50, "PF_W+PF_R+0x50"},
+ {DT_SYMBOLIC, "DT_SYMBOLIC"},
+ {DF_BIND_NOW, "DF_BIND_NOW"},
+ {NT_FPREGSET, "NT_FPREGSET"},
+ {STB_GLOBAL, "STB_GLOBAL"},
+ {STT_COMMON, "STT_COMMON"},
+ {STV_HIDDEN, "STV_HIDDEN"},
+ {R_X86_64_PC32, "R_X86_64_PC32"},
+ {R_ALPHA_OP_PUSH, "R_ALPHA_OP_PUSH"},
+ {R_ARM_THM_ABS5, "R_ARM_THM_ABS5"},
+ {R_386_GOT32, "R_386_GOT32"},
+ {R_PPC_GOT16_HI, "R_PPC_GOT16_HI"},
+ {R_SPARC_GOT22, "R_SPARC_GOT22"},
+ {ET_LOOS + 5, "ET_LOOS+5"},
+ {ProgFlag(0x50), "0x50"},
+}
+
+func TestNames(t *testing.T) {
+ for i, tt := range nameTests {
+ s := fmt.Sprint(tt.val)
+ if s != tt.str {
+ t.Errorf("#%d: want %q have %q", i, s, tt.str)
+ }
+ }
+}
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
new file mode 100644
index 000000000..e69317a75
--- /dev/null
+++ b/libgo/go/debug/elf/file.go
@@ -0,0 +1,605 @@
+// 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 elf implements access to ELF object files.
+package elf
+
+import (
+ "bytes"
+ "debug/dwarf"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+)
+
+// TODO: error reporting detail
+
+/*
+ * Internal ELF representation
+ */
+
+// A FileHeader represents an ELF file header.
+type FileHeader struct {
+ Class Class
+ Data Data
+ Version Version
+ OSABI OSABI
+ ABIVersion uint8
+ ByteOrder binary.ByteOrder
+ Type Type
+ Machine Machine
+}
+
+// A File represents an open ELF file.
+type File struct {
+ FileHeader
+ Sections []*Section
+ Progs []*Prog
+ closer io.Closer
+}
+
+// A SectionHeader represents a single ELF section header.
+type SectionHeader struct {
+ Name string
+ Type SectionType
+ Flags SectionFlag
+ Addr uint64
+ Offset uint64
+ Size uint64
+ Link uint32
+ Info uint32
+ Addralign uint64
+ Entsize uint64
+}
+
+// A Section represents a single section in an ELF file.
+type Section struct {
+ SectionHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the ELF section.
+func (s *Section) Data() ([]byte, os.Error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ return dat[0:n], err
+}
+
+// stringTable reads and returns the string table given by the
+// 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 f.Sections[link].Data()
+}
+
+// Open returns a new ReadSeeker reading the ELF section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+// A ProgHeader represents a single ELF program header.
+type ProgHeader struct {
+ Type ProgType
+ Flags ProgFlag
+ Vaddr uint64
+ Paddr uint64
+ Filesz uint64
+ Memsz uint64
+ Align uint64
+}
+
+// A Prog represents a single ELF program header in an ELF binary.
+type Prog struct {
+ ProgHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Open returns a new ReadSeeker reading the ELF program body.
+func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
+
+// A Symbol represents an entry in an ELF symbol table section.
+type Symbol struct {
+ Name string
+ Info, Other byte
+ Section SectionIndex
+ Value, Size uint64
+}
+
+/*
+ * ELF reader
+ */
+
+type FormatError struct {
+ off int64
+ msg string
+ val interface{}
+}
+
+func (e *FormatError) String() string {
+ msg := e.msg
+ if e.val != nil {
+ msg += fmt.Sprintf(" '%v' ", e.val)
+ }
+ msg += fmt.Sprintf("in record at byte %#x", e.off)
+ return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as an ELF binary.
+func Open(name string) (*File, os.Error) {
+ f, err := os.Open(name, os.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ ff, err := NewFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() os.Error {
+ var err os.Error
+ if f.closer != nil {
+ err = f.closer.Close()
+ f.closer = nil
+ }
+ return err
+}
+
+// SectionByType returns the first section in f with the
+// given type, or nil if there is no such section.
+func (f *File) SectionByType(typ SectionType) *Section {
+ for _, s := range f.Sections {
+ if s.Type == typ {
+ return s
+ }
+ }
+ return nil
+}
+
+// NewFile creates a new File for accessing an ELF binary in an underlying reader.
+// The ELF binary is expected to start at position 0 in the ReaderAt.
+func NewFile(r io.ReaderAt) (*File, os.Error) {
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+ // Read and decode ELF identifier
+ var ident [16]uint8
+ if _, err := r.ReadAt(ident[0:], 0); err != nil {
+ return nil, err
+ }
+ if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
+ return nil, &FormatError{0, "bad magic number", ident[0:4]}
+ }
+
+ f := new(File)
+ f.Class = Class(ident[EI_CLASS])
+ switch f.Class {
+ case ELFCLASS32:
+ case ELFCLASS64:
+ // ok
+ default:
+ return nil, &FormatError{0, "unknown ELF class", f.Class}
+ }
+
+ f.Data = Data(ident[EI_DATA])
+ switch f.Data {
+ case ELFDATA2LSB:
+ f.ByteOrder = binary.LittleEndian
+ case ELFDATA2MSB:
+ f.ByteOrder = binary.BigEndian
+ default:
+ return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
+ }
+
+ f.Version = Version(ident[EI_VERSION])
+ if f.Version != EV_CURRENT {
+ return nil, &FormatError{0, "unknown ELF version", f.Version}
+ }
+
+ f.OSABI = OSABI(ident[EI_OSABI])
+ f.ABIVersion = ident[EI_ABIVERSION]
+
+ // Read ELF file header
+ var shoff int64
+ var shentsize, shnum, shstrndx int
+ shstrndx = -1
+ switch f.Class {
+ case ELFCLASS32:
+ hdr := new(Header32)
+ sr.Seek(0, 0)
+ if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
+ return nil, err
+ }
+ f.Type = Type(hdr.Type)
+ f.Machine = Machine(hdr.Machine)
+ if v := Version(hdr.Version); v != f.Version {
+ return nil, &FormatError{0, "mismatched ELF version", v}
+ }
+ shoff = int64(hdr.Shoff)
+ shentsize = int(hdr.Shentsize)
+ shnum = int(hdr.Shnum)
+ shstrndx = int(hdr.Shstrndx)
+ case ELFCLASS64:
+ hdr := new(Header64)
+ sr.Seek(0, 0)
+ if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
+ return nil, err
+ }
+ f.Type = Type(hdr.Type)
+ f.Machine = Machine(hdr.Machine)
+ if v := Version(hdr.Version); v != f.Version {
+ return nil, &FormatError{0, "mismatched ELF version", v}
+ }
+ shoff = int64(hdr.Shoff)
+ shentsize = int(hdr.Shentsize)
+ shnum = int(hdr.Shnum)
+ shstrndx = int(hdr.Shstrndx)
+ }
+ if shstrndx < 0 || shstrndx >= shnum {
+ return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
+ }
+
+ // Read program headers
+ // TODO
+
+ // Read section headers
+ f.Sections = make([]*Section, shnum)
+ names := make([]uint32, shnum)
+ for i := 0; i < shnum; i++ {
+ off := shoff + int64(i)*int64(shentsize)
+ sr.Seek(off, 0)
+ s := new(Section)
+ switch f.Class {
+ case ELFCLASS32:
+ sh := new(Section32)
+ if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
+ return nil, err
+ }
+ names[i] = sh.Name
+ s.SectionHeader = SectionHeader{
+ Type: SectionType(sh.Type),
+ Flags: SectionFlag(sh.Flags),
+ Addr: uint64(sh.Addr),
+ Offset: uint64(sh.Off),
+ Size: uint64(sh.Size),
+ Link: uint32(sh.Link),
+ Info: uint32(sh.Info),
+ Addralign: uint64(sh.Addralign),
+ Entsize: uint64(sh.Entsize),
+ }
+ case ELFCLASS64:
+ sh := new(Section64)
+ if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
+ return nil, err
+ }
+ names[i] = sh.Name
+ s.SectionHeader = SectionHeader{
+ Type: SectionType(sh.Type),
+ Flags: SectionFlag(sh.Flags),
+ Offset: uint64(sh.Off),
+ Size: uint64(sh.Size),
+ Addr: uint64(sh.Addr),
+ Link: uint32(sh.Link),
+ Info: uint32(sh.Info),
+ Addralign: uint64(sh.Addralign),
+ Entsize: uint64(sh.Entsize),
+ }
+ }
+ s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
+ s.ReaderAt = s.sr
+ f.Sections[i] = s
+ }
+
+ // Load section header string table.
+ shstrtab, err := f.Sections[shstrndx].Data()
+ if err != nil {
+ return nil, err
+ }
+ for i, s := range f.Sections {
+ var ok bool
+ s.Name, ok = getString(shstrtab, int(names[i]))
+ if !ok {
+ return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
+ }
+ }
+
+ return f, nil
+}
+
+// getSymbols returns a slice of Symbols from parsing the symbol table
+// with the given type.
+func (f *File) getSymbols(typ SectionType) ([]Symbol, os.Error) {
+ switch f.Class {
+ case ELFCLASS64:
+ return f.getSymbols64(typ)
+
+ case ELFCLASS32:
+ return f.getSymbols32(typ)
+ }
+
+ return nil, os.ErrorString("not implemented")
+}
+
+func (f *File) getSymbols32(typ SectionType) ([]Symbol, os.Error) {
+ symtabSection := f.SectionByType(typ)
+ if symtabSection == nil {
+ return nil, os.ErrorString("no symbol section")
+ }
+
+ data, err := symtabSection.Data()
+ if err != nil {
+ return nil, os.ErrorString("cannot load symbol section")
+ }
+ symtab := bytes.NewBuffer(data)
+ if symtab.Len()%Sym32Size != 0 {
+ return nil, os.ErrorString("length of symbol section is not a multiple of SymSize")
+ }
+
+ strdata, err := f.stringTable(symtabSection.Link)
+ if err != nil {
+ return nil, os.ErrorString("cannot load string table section")
+ }
+
+ // The first entry is all zeros.
+ var skip [Sym32Size]byte
+ symtab.Read(skip[0:])
+
+ symbols := make([]Symbol, symtab.Len()/Sym32Size)
+
+ i := 0
+ var sym Sym32
+ for symtab.Len() > 0 {
+ binary.Read(symtab, f.ByteOrder, &sym)
+ str, _ := getString(strdata, int(sym.Name))
+ symbols[i].Name = str
+ symbols[i].Info = sym.Info
+ symbols[i].Other = sym.Other
+ symbols[i].Section = SectionIndex(sym.Shndx)
+ symbols[i].Value = uint64(sym.Value)
+ symbols[i].Size = uint64(sym.Size)
+ i++
+ }
+
+ return symbols, nil
+}
+
+func (f *File) getSymbols64(typ SectionType) ([]Symbol, os.Error) {
+ symtabSection := f.SectionByType(typ)
+ if symtabSection == nil {
+ return nil, os.ErrorString("no symbol section")
+ }
+
+ data, err := symtabSection.Data()
+ if err != nil {
+ return nil, os.ErrorString("cannot load symbol section")
+ }
+ symtab := bytes.NewBuffer(data)
+ if symtab.Len()%Sym64Size != 0 {
+ return nil, os.ErrorString("length of symbol section is not a multiple of Sym64Size")
+ }
+
+ strdata, err := f.stringTable(symtabSection.Link)
+ if err != nil {
+ return nil, os.ErrorString("cannot load string table section")
+ }
+
+ // The first entry is all zeros.
+ var skip [Sym64Size]byte
+ symtab.Read(skip[0:])
+
+ symbols := make([]Symbol, symtab.Len()/Sym64Size)
+
+ i := 0
+ var sym Sym64
+ for symtab.Len() > 0 {
+ binary.Read(symtab, f.ByteOrder, &sym)
+ str, _ := getString(strdata, int(sym.Name))
+ symbols[i].Name = str
+ symbols[i].Info = sym.Info
+ symbols[i].Other = sym.Other
+ symbols[i].Section = SectionIndex(sym.Shndx)
+ symbols[i].Value = sym.Value
+ symbols[i].Size = sym.Size
+ i++
+ }
+
+ return symbols, nil
+}
+
+// getString extracts a string from an ELF string table.
+func getString(section []byte, start int) (string, bool) {
+ if start < 0 || start >= len(section) {
+ return "", false
+ }
+
+ for end := start; end < len(section); end++ {
+ if section[end] == 0 {
+ return string(section[start:end]), true
+ }
+ }
+ return "", false
+}
+
+// Section returns a section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+ for _, s := range f.Sections {
+ if s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
+
+// applyRelocations applies relocations to dst. rels is a relocations section
+// in RELA format.
+func (f *File) applyRelocations(dst []byte, rels []byte) os.Error {
+ if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
+ return f.applyRelocationsAMD64(dst, rels)
+ }
+
+ return os.ErrorString("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")
+ }
+
+ symbols, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewBuffer(rels)
+ var rela Rela64
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rela)
+ symNo := rela.Info >> 32
+ t := R_X86_64(rela.Info & 0xffff)
+
+ if symNo >= uint64(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo]
+ if SymType(sym.Info&0xf) != STT_SECTION {
+ // We don't handle non-section relocations for now.
+ continue
+ }
+
+ switch t {
+ case R_X86_64_64:
+ if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
+ case R_X86_64_32:
+ if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
+ }
+ }
+
+ return nil
+}
+
+func (f *File) DWARF() (*dwarf.Data, os.Error) {
+ // There are many other DWARF sections, but these
+ // are the required ones, and the debug/dwarf package
+ // does not use the others, so don't bother loading them.
+ var names = [...]string{"abbrev", "info", "str"}
+ var dat [len(names)][]byte
+ for i, name := range names {
+ name = ".debug_" + name
+ s := f.Section(name)
+ if s == nil {
+ continue
+ }
+ b, err := s.Data()
+ if err != nil && uint64(len(b)) < s.Size {
+ return nil, err
+ }
+ dat[i] = b
+ }
+
+ // If there's a relocation table for .debug_info, we have to process it
+ // now otherwise the data in .debug_info is invalid for x86-64 objects.
+ rela := f.Section(".rela.debug_info")
+ if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
+ data, err := rela.Data()
+ if err != nil {
+ return nil, err
+ }
+ err = f.applyRelocations(dat[1], data)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ abbrev, info, str := dat[0], dat[1], dat[2]
+ return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+}
+
+// ImportedSymbols returns the names of all symbols
+// referred to by the binary f that are expected to be
+// satisfied by other libraries at dynamic load time.
+// It does not return weak symbols.
+func (f *File) ImportedSymbols() ([]string, os.Error) {
+ sym, err := f.getSymbols(SHT_DYNSYM)
+ if err != nil {
+ return nil, err
+ }
+ var all []string
+ for _, s := range sym {
+ if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
+ all = append(all, s.Name)
+ }
+ }
+ return all, nil
+}
+
+// ImportedLibraries returns the names of all libraries
+// referred to by the binary f that are expected to be
+// linked with the binary at dynamic link time.
+func (f *File) ImportedLibraries() ([]string, os.Error) {
+ ds := f.SectionByType(SHT_DYNAMIC)
+ if ds == nil {
+ // not dynamic, so no libraries
+ return nil, nil
+ }
+ d, err := ds.Data()
+ if err != nil {
+ return nil, err
+ }
+ str, err := f.stringTable(ds.Link)
+ if err != nil {
+ return nil, err
+ }
+ var all []string
+ for len(d) > 0 {
+ var tag DynTag
+ var value uint64
+ switch f.Class {
+ case ELFCLASS32:
+ tag = DynTag(f.ByteOrder.Uint32(d[0:4]))
+ value = uint64(f.ByteOrder.Uint32(d[4:8]))
+ d = d[8:]
+ case ELFCLASS64:
+ tag = DynTag(f.ByteOrder.Uint64(d[0:8]))
+ value = f.ByteOrder.Uint64(d[8:16])
+ d = d[16:]
+ }
+ if tag == DT_NEEDED {
+ s, ok := getString(str, int(value))
+ if ok {
+ all = append(all, s)
+ }
+ }
+ }
+
+ return all, nil
+}
diff --git a/libgo/go/debug/elf/file_test.go b/libgo/go/debug/elf/file_test.go
new file mode 100644
index 000000000..84068ea12
--- /dev/null
+++ b/libgo/go/debug/elf/file_test.go
@@ -0,0 +1,180 @@
+// 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 elf
+
+import (
+ "debug/dwarf"
+ "encoding/binary"
+ "reflect"
+ "testing"
+)
+
+type fileTest struct {
+ file string
+ hdr FileHeader
+ sections []SectionHeader
+}
+
+var fileTests = []fileTest{
+ {
+ "testdata/gcc-386-freebsd-exec",
+ FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386},
+ []SectionHeader{
+ {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ {".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0},
+ {".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4},
+ {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10},
+ {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0},
+ {".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8},
+ {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0},
+ {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4},
+ {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0},
+ {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0},
+ {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0},
+ {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0},
+ {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0},
+ {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8},
+ {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0},
+ {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0},
+ {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0},
+ {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4},
+ {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0},
+ {".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0},
+ {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0},
+ {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0},
+ {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0},
+ {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0},
+ {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0},
+ {".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0},
+ {".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0},
+ {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0},
+ {".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
+ {".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
+ },
+ },
+ {
+ "testdata/gcc-amd64-linux-exec",
+ FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64},
+ []SectionHeader{
+ {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ {".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0},
+ {".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0},
+ {".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4},
+ {".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0},
+ {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18},
+ {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0},
+ {".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2},
+ {".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0},
+ {".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18},
+ {".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18},
+ {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0},
+ {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10},
+ {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0},
+ {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0},
+ {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0},
+ {".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0},
+ {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0},
+ {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0},
+ {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0},
+ {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0},
+ {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10},
+ {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8},
+ {".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8},
+ {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0},
+ {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0},
+ {".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0},
+ {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0},
+ {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0},
+ {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0},
+ {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0},
+ {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0},
+ {".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1},
+ {".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0},
+ {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0},
+ {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
+ {".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
+ },
+ },
+}
+
+func TestOpen(t *testing.T) {
+ for i := range fileTests {
+ tt := &fileTests[i]
+
+ f, err := Open(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+ continue
+ }
+ for i, s := range f.Sections {
+ if i >= len(tt.sections) {
+ break
+ }
+ sh := &tt.sections[i]
+ if !reflect.DeepEqual(&s.SectionHeader, sh) {
+ t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh)
+ }
+ }
+ tn := len(tt.sections)
+ fn := len(f.Sections)
+ if tn != fn {
+ t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+ }
+ }
+}
+
+type relocationTest struct {
+ file string
+ firstEntry *dwarf.Entry
+}
+
+var relocationTests = []relocationTest{
+ {
+ "testdata/go-relocation-test-gcc441-x86-64.o",
+ &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",
+ &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",
+ &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)}}},
+ },
+}
+
+func TestDWARFRelocations(t *testing.T) {
+ for i, test := range relocationTests {
+ f, err := Open(test.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ dwarf, err := f.DWARF()
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ reader := dwarf.Reader()
+ // Checking only the first entry is sufficient since it has
+ // many different strings. If the relocation had failed, all
+ // the string offsets would be zero and all the strings would
+ // end up being the same.
+ firstEntry, err := reader.Next()
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ if !reflect.DeepEqual(test.firstEntry, firstEntry) {
+ t.Errorf("#%d: mismatch: got:%#v want:%#v", i, firstEntry, test.firstEntry)
+ continue
+ }
+ }
+}
diff --git a/libgo/go/debug/elf/testdata/gcc-386-freebsd-exec b/libgo/go/debug/elf/testdata/gcc-386-freebsd-exec
new file mode 100755
index 000000000..7af9c58ca
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/gcc-386-freebsd-exec
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/gcc-amd64-linux-exec b/libgo/go/debug/elf/testdata/gcc-amd64-linux-exec
new file mode 100755
index 000000000..c6cb1de28
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/gcc-amd64-linux-exec
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o b/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o
new file mode 100644
index 000000000..a7c6d6e56
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o
new file mode 100644
index 000000000..2d37ab6e6
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o
Binary files differ
diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o
new file mode 100644
index 000000000..0d59fe303
--- /dev/null
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o
Binary files differ
diff --git a/libgo/go/debug/gosym/pclinetest.h b/libgo/go/debug/gosym/pclinetest.h
new file mode 100644
index 000000000..a6c40e76c
--- /dev/null
+++ b/libgo/go/debug/gosym/pclinetest.h
@@ -0,0 +1,7 @@
+// Empty include file to generate z symbols
+
+
+
+
+
+// EOF
diff --git a/libgo/go/debug/gosym/pclinetest.s b/libgo/go/debug/gosym/pclinetest.s
new file mode 100644
index 000000000..519656b63
--- /dev/null
+++ b/libgo/go/debug/gosym/pclinetest.s
@@ -0,0 +1,89 @@
+TEXT linefrompc(SB),7,$0 // Each byte stores its line delta
+BYTE $2;
+BYTE $1;
+BYTE $1; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1;
+BYTE $1;
+BYTE $1; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+#include "pclinetest.h"
+BYTE $2;
+#include "pclinetest.h"
+BYTE $2;
+
+TEXT pcfromline(SB),7,$0 // Each record stores its line delta, then n, then n more bytes
+BYTE $31; BYTE $0;
+BYTE $1; BYTE $1; BYTE $0;
+BYTE $1; BYTE $0;
+
+BYTE $2; BYTE $4; BYTE $0; BYTE $0; BYTE $0; BYTE $0;
+
+
+#include "pclinetest.h"
+BYTE $4; BYTE $0;
+
+
+BYTE $3; BYTE $3; BYTE $0; BYTE $0; BYTE $0;
+#include "pclinetest.h"
+
+
+BYTE $4; BYTE $3; BYTE $0; BYTE $0; BYTE $0;
+
+TEXT main(SB),7,$0
+ // Prevent GC of our test symbols
+ CALL linefrompc(SB)
+ CALL pcfromline(SB)
+
+// Keep the linker happy
+TEXT runtime·morestack(SB),7,$0
+ RET
+
+TEXT runtime·morestack00(SB),7,$0
+ RET
+
+TEXT runtime·morestack10(SB),7,$0
+ RET
+
+TEXT runtime·morestack01(SB),7,$0
+ RET
+
+TEXT runtime·morestack11(SB),7,$0
+ RET
+
+TEXT runtime·morestack8(SB),7,$0
+ RET
+
+TEXT runtime·morestack16(SB),7,$0
+ RET
+
+TEXT runtime·morestack24(SB),7,$0
+ RET
+
+TEXT runtime·morestack32(SB),7,$0
+ RET
+
+TEXT runtime·morestack40(SB),7,$0
+ RET
+
+TEXT runtime·morestack48(SB),7,$0
+ RET
+
+TEXT runtime·morestack8(SB),7,$0
+ RET
+
diff --git a/libgo/go/debug/gosym/pclntab.go b/libgo/go/debug/gosym/pclntab.go
new file mode 100644
index 000000000..9d7b0d15f
--- /dev/null
+++ b/libgo/go/debug/gosym/pclntab.go
@@ -0,0 +1,82 @@
+// 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.
+
+/*
+ * Line tables
+ */
+
+package gosym
+
+import "encoding/binary"
+
+type LineTable struct {
+ Data []byte
+ PC uint64
+ Line int
+}
+
+// TODO(rsc): Need to pull in quantum from architecture definition.
+const quantum = 1
+
+func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) {
+ // The PC/line table can be thought of as a sequence of
+ // <pc update>* <line update>
+ // batches. Each update batch results in a (pc, line) pair,
+ // where line applies to every PC from pc up to but not
+ // including the pc of the next pair.
+ //
+ // Here we process each update individually, which simplifies
+ // the code, but makes the corner cases more confusing.
+ b, pc, line = t.Data, t.PC, t.Line
+ for pc <= targetPC && line != targetLine && len(b) > 0 {
+ code := b[0]
+ b = b[1:]
+ switch {
+ case code == 0:
+ if len(b) < 4 {
+ b = b[0:0]
+ break
+ }
+ val := binary.BigEndian.Uint32(b)
+ b = b[4:]
+ line += int(val)
+ case code <= 64:
+ line += int(code)
+ case code <= 128:
+ line -= int(code - 64)
+ default:
+ pc += quantum * uint64(code-128)
+ continue
+ }
+ pc += quantum
+ }
+ return b, pc, line
+}
+
+func (t *LineTable) slice(pc uint64) *LineTable {
+ data, pc, line := t.parse(pc, -1)
+ return &LineTable{data, pc, line}
+}
+
+func (t *LineTable) PCToLine(pc uint64) int {
+ _, _, line := t.parse(pc, -1)
+ return line
+}
+
+func (t *LineTable) LineToPC(line int, maxpc uint64) uint64 {
+ _, pc, line1 := t.parse(maxpc, line)
+ if line1 != line {
+ return 0
+ }
+ // Subtract quantum from PC to account for post-line increment
+ return pc - quantum
+}
+
+// NewLineTable returns a new PC/line table
+// corresponding to the encoded data.
+// Text must be the start address of the
+// corresponding text segment.
+func NewLineTable(data []byte, text uint64) *LineTable {
+ return &LineTable{data, text, 0}
+}
diff --git a/libgo/go/debug/gosym/pclntab_test.go b/libgo/go/debug/gosym/pclntab_test.go
new file mode 100644
index 000000000..908702173
--- /dev/null
+++ b/libgo/go/debug/gosym/pclntab_test.go
@@ -0,0 +1,207 @@
+// 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 gosym
+
+import (
+ "debug/elf"
+ "os"
+ "testing"
+ "syscall"
+)
+
+func dotest() bool {
+ // For now, only works on ELF platforms.
+ return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
+}
+
+func getTable(t *testing.T) *Table {
+ f, tab := crack(os.Args[0], t)
+ f.Close()
+ return tab
+}
+
+func crack(file string, t *testing.T) (*elf.File, *Table) {
+ // Open self
+ f, err := elf.Open(file)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return parse(file, f, t)
+}
+
+func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
+ symdat, err := f.Section(".gosymtab").Data()
+ if err != nil {
+ f.Close()
+ t.Fatalf("reading %s gosymtab: %v", file, err)
+ }
+ pclndat, err := f.Section(".gopclntab").Data()
+ if err != nil {
+ f.Close()
+ t.Fatalf("reading %s gopclntab: %v", file, err)
+ }
+
+ pcln := NewLineTable(pclndat, f.Section(".text").Addr)
+ tab, err := NewTable(symdat, pcln)
+ if err != nil {
+ f.Close()
+ t.Fatalf("parsing %s gosymtab: %v", file, err)
+ }
+
+ return f, tab
+}
+
+var goarch = os.Getenv("O")
+
+func TestLineFromAline(t *testing.T) {
+ if !dotest() {
+ return
+ }
+
+ tab := getTable(t)
+
+ // Find the sym package
+ pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
+ if pkg == nil {
+ t.Fatalf("nil pkg")
+ }
+
+ // Walk every absolute line and ensure that we hit every
+ // source line monotonically
+ lastline := make(map[string]int)
+ final := -1
+ for i := 0; i < 10000; i++ {
+ path, line := pkg.lineFromAline(i)
+ // Check for end of object
+ if path == "" {
+ if final == -1 {
+ final = i - 1
+ }
+ continue
+ } else if final != -1 {
+ t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
+ }
+ // It's okay to see files multiple times (e.g., sys.a)
+ if line == 1 {
+ lastline[path] = 1
+ continue
+ }
+ // Check that the is the next line in path
+ ll, ok := lastline[path]
+ if !ok {
+ t.Errorf("file %s starts on line %d", path, line)
+ } else if line != ll+1 {
+ t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
+ }
+ lastline[path] = line
+ }
+ if final == -1 {
+ t.Errorf("never reached end of object")
+ }
+}
+
+func TestLineAline(t *testing.T) {
+ if !dotest() {
+ return
+ }
+
+ tab := getTable(t)
+
+ for _, o := range tab.Files {
+ // A source file can appear multiple times in a
+ // object. alineFromLine will always return alines in
+ // the first file, so track which lines we've seen.
+ found := make(map[string]int)
+ for i := 0; i < 1000; i++ {
+ path, line := o.lineFromAline(i)
+ if path == "" {
+ break
+ }
+
+ // cgo files are full of 'Z' symbols, which we don't handle
+ if len(path) > 4 && path[len(path)-4:] == ".cgo" {
+ continue
+ }
+
+ if minline, ok := found[path]; path != "" && ok {
+ if minline >= line {
+ // We've already covered this file
+ continue
+ }
+ }
+ found[path] = line
+
+ a, err := o.alineFromLine(path, line)
+ if err != nil {
+ t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
+ } else if a != i {
+ t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
+ }
+ }
+ }
+}
+
+// gotest: if [ "$(uname)-$(uname -m)" = Linux-x86_64 -a "$GOARCH" = amd64 ]; then
+// gotest: mkdir -p _test && $AS pclinetest.s && $LD -E main -o _test/pclinetest pclinetest.$O
+// gotest: fi
+func TestPCLine(t *testing.T) {
+ if !dotest() {
+ return
+ }
+
+ f, tab := crack("_test/pclinetest", t)
+ text := f.Section(".text")
+ textdat, err := text.Data()
+ if err != nil {
+ t.Fatalf("reading .text: %v", err)
+ }
+
+ // Test PCToLine
+ sym := tab.LookupFunc("linefrompc")
+ wantLine := 0
+ for pc := sym.Entry; pc < sym.End; pc++ {
+ file, line, fn := tab.PCToLine(pc)
+ off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
+ wantLine += int(textdat[off])
+ if fn == nil {
+ t.Errorf("failed to get line of PC %#x", pc)
+ } else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
+ t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
+ }
+ }
+
+ // Test LineToPC
+ sym = tab.LookupFunc("pcfromline")
+ lookupline := -1
+ wantLine = 0
+ off := uint64(0) // TODO(rsc): should not need off; bug in 8g
+ for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
+ file, line, fn := tab.PCToLine(pc)
+ off = pc - text.Addr
+ wantLine += int(textdat[off])
+ if line != wantLine {
+ t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
+ off = pc + 1 - text.Addr
+ continue
+ }
+ if lookupline == -1 {
+ lookupline = line
+ }
+ for ; lookupline <= line; lookupline++ {
+ pc2, fn2, err := tab.LineToPC(file, lookupline)
+ if lookupline != line {
+ // Should be nothing on this line
+ if err == nil {
+ t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
+ }
+ } else if err != nil {
+ t.Errorf("failed to get PC of line %d: %s", lookupline, err)
+ } else if pc != pc2 {
+ t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
+ }
+ }
+ off = pc + 1 - text.Addr
+ }
+}
diff --git a/libgo/go/debug/gosym/symtab.go b/libgo/go/debug/gosym/symtab.go
new file mode 100644
index 000000000..dea460d71
--- /dev/null
+++ b/libgo/go/debug/gosym/symtab.go
@@ -0,0 +1,548 @@
+// 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 gosym implements access to the Go symbol
+// and line number tables embedded in Go binaries generated
+// by the gc compilers.
+package gosym
+
+// The table format is a variant of the format used in Plan 9's a.out
+// format, documented at http://plan9.bell-labs.com/magic/man2html/6/a.out.
+// The best reference for the differences between the Plan 9 format
+// and the Go format is the runtime source, specifically ../../runtime/symtab.c.
+
+import (
+ "encoding/binary"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+/*
+ * Symbols
+ */
+
+// A Sym represents a single symbol table entry.
+type Sym struct {
+ Value uint64
+ Type byte
+ Name string
+ GoType uint64
+ // If this symbol if a function symbol, the corresponding Func
+ Func *Func
+}
+
+// Static returns whether this symbol is static (not visible outside its file).
+func (s *Sym) Static() bool { return s.Type >= 'a' }
+
+// PackageName returns the package part of the symbol name,
+// or the empty string if there is none.
+func (s *Sym) PackageName() string {
+ if i := strings.Index(s.Name, "."); i != -1 {
+ return s.Name[0:i]
+ }
+ return ""
+}
+
+// ReceiverName returns the receiver type name of this symbol,
+// or the empty string if there is none.
+func (s *Sym) ReceiverName() string {
+ l := strings.Index(s.Name, ".")
+ r := strings.LastIndex(s.Name, ".")
+ if l == -1 || r == -1 || l == r {
+ return ""
+ }
+ return s.Name[l+1 : r]
+}
+
+// BaseName returns the symbol name without the package or receiver name.
+func (s *Sym) BaseName() string {
+ if i := strings.LastIndex(s.Name, "."); i != -1 {
+ return s.Name[i+1:]
+ }
+ return s.Name
+}
+
+// A Func collects information about a single function.
+type Func struct {
+ Entry uint64
+ *Sym
+ End uint64
+ Params []*Sym
+ Locals []*Sym
+ FrameSize int
+ LineTable *LineTable
+ Obj *Obj
+}
+
+// An Obj represents a single object file.
+type Obj struct {
+ Funcs []Func
+ Paths []Sym
+}
+
+/*
+ * Symbol tables
+ */
+
+// Table represents a Go symbol table. It stores all of the
+// symbols decoded from the program and provides methods to translate
+// between symbols, names, and addresses.
+type Table struct {
+ Syms []Sym
+ Funcs []Func
+ Files map[string]*Obj
+ Objs []Obj
+ // textEnd uint64;
+}
+
+type sym struct {
+ value uint32
+ gotype uint32
+ typ byte
+ name []byte
+}
+
+func walksymtab(data []byte, fn func(sym) os.Error) os.Error {
+ var s sym
+ p := data
+ for len(p) >= 6 {
+ s.value = binary.BigEndian.Uint32(p[0:4])
+ typ := p[4]
+ if typ&0x80 == 0 {
+ return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
+ }
+ typ &^= 0x80
+ s.typ = typ
+ p = p[5:]
+ var i int
+ var nnul int
+ for i = 0; i < len(p); i++ {
+ if p[i] == 0 {
+ nnul = 1
+ break
+ }
+ }
+ switch typ {
+ case 'z', 'Z':
+ p = p[i+nnul:]
+ for i = 0; i+2 <= len(p); i += 2 {
+ if p[i] == 0 && p[i+1] == 0 {
+ nnul = 2
+ break
+ }
+ }
+ }
+ if i+nnul+4 > len(p) {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ s.name = p[0:i]
+ i += nnul
+ s.gotype = binary.BigEndian.Uint32(p[i : i+4])
+ p = p[i+4:]
+ fn(s)
+ }
+ return nil
+}
+
+// NewTable decodes the Go symbol table in data,
+// returning an in-memory representation.
+func NewTable(symtab []byte, pcln *LineTable) (*Table, os.Error) {
+ var n int
+ err := walksymtab(symtab, func(s sym) os.Error {
+ n++
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ var t Table
+ fname := make(map[uint16]string)
+ t.Syms = make([]Sym, 0, n)
+ nf := 0
+ nz := 0
+ lasttyp := uint8(0)
+ err = walksymtab(symtab, func(s sym) os.Error {
+ n := len(t.Syms)
+ t.Syms = t.Syms[0 : n+1]
+ ts := &t.Syms[n]
+ ts.Type = s.typ
+ ts.Value = uint64(s.value)
+ ts.GoType = uint64(s.gotype)
+ switch s.typ {
+ default:
+ // rewrite name to use . instead of · (c2 b7)
+ w := 0
+ b := s.name
+ for i := 0; i < len(b); i++ {
+ if b[i] == 0xc2 && i+1 < len(b) && b[i+1] == 0xb7 {
+ i++
+ b[i] = '.'
+ }
+ b[w] = b[i]
+ w++
+ }
+ ts.Name = string(s.name[0:w])
+ case 'z', 'Z':
+ if lasttyp != 'z' && lasttyp != 'Z' {
+ nz++
+ }
+ for i := 0; i < len(s.name); i += 2 {
+ eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
+ elt, ok := fname[eltIdx]
+ if !ok {
+ return &DecodingError{-1, "bad filename code", eltIdx}
+ }
+ if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
+ ts.Name += "/"
+ }
+ ts.Name += elt
+ }
+ }
+ switch s.typ {
+ case 'T', 't', 'L', 'l':
+ nf++
+ case 'f':
+ fname[uint16(s.value)] = ts.Name
+ }
+ lasttyp = s.typ
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ t.Funcs = make([]Func, 0, nf)
+ t.Objs = make([]Obj, 0, nz)
+ t.Files = make(map[string]*Obj)
+
+ // Count text symbols and attach frame sizes, parameters, and
+ // locals to them. Also, find object file boundaries.
+ var obj *Obj
+ lastf := 0
+ for i := 0; i < len(t.Syms); i++ {
+ sym := &t.Syms[i]
+ switch sym.Type {
+ case 'Z', 'z': // path symbol
+ // Finish the current object
+ if obj != nil {
+ obj.Funcs = t.Funcs[lastf:]
+ }
+ lastf = len(t.Funcs)
+
+ // Start new object
+ n := len(t.Objs)
+ t.Objs = t.Objs[0 : n+1]
+ obj = &t.Objs[n]
+
+ // Count & copy path symbols
+ var end int
+ for end = i + 1; end < len(t.Syms); end++ {
+ if c := t.Syms[end].Type; c != 'Z' && c != 'z' {
+ break
+ }
+ }
+ obj.Paths = t.Syms[i:end]
+ i = end - 1 // loop will i++
+
+ // Record file names
+ depth := 0
+ for j := range obj.Paths {
+ s := &obj.Paths[j]
+ if s.Name == "" {
+ depth--
+ } else {
+ if depth == 0 {
+ t.Files[s.Name] = obj
+ }
+ depth++
+ }
+ }
+
+ case 'T', 't', 'L', 'l': // text symbol
+ if n := len(t.Funcs); n > 0 {
+ t.Funcs[n-1].End = sym.Value
+ }
+ if sym.Name == "etext" {
+ continue
+ }
+
+ // Count parameter and local (auto) syms
+ var np, na int
+ var end int
+ countloop:
+ for end = i + 1; end < len(t.Syms); end++ {
+ switch t.Syms[end].Type {
+ case 'T', 't', 'L', 'l', 'Z', 'z':
+ break countloop
+ case 'p':
+ np++
+ case 'a':
+ na++
+ }
+ }
+
+ // Fill in the function symbol
+ n := len(t.Funcs)
+ t.Funcs = t.Funcs[0 : n+1]
+ fn := &t.Funcs[n]
+ sym.Func = fn
+ fn.Params = make([]*Sym, 0, np)
+ fn.Locals = make([]*Sym, 0, na)
+ fn.Sym = sym
+ fn.Entry = sym.Value
+ fn.Obj = obj
+ if pcln != nil {
+ fn.LineTable = pcln.slice(fn.Entry)
+ pcln = fn.LineTable
+ }
+ for j := i; j < end; j++ {
+ s := &t.Syms[j]
+ switch s.Type {
+ case 'm':
+ fn.FrameSize = int(s.Value)
+ case 'p':
+ n := len(fn.Params)
+ fn.Params = fn.Params[0 : n+1]
+ fn.Params[n] = s
+ case 'a':
+ n := len(fn.Locals)
+ fn.Locals = fn.Locals[0 : n+1]
+ fn.Locals[n] = s
+ }
+ }
+ i = end - 1 // loop will i++
+ }
+ }
+ if obj != nil {
+ obj.Funcs = t.Funcs[lastf:]
+ }
+ return &t, nil
+}
+
+// PCToFunc returns the function containing the program counter pc,
+// or nil if there is no such function.
+func (t *Table) PCToFunc(pc uint64) *Func {
+ funcs := t.Funcs
+ for len(funcs) > 0 {
+ m := len(funcs) / 2
+ fn := &funcs[m]
+ switch {
+ case pc < fn.Entry:
+ funcs = funcs[0:m]
+ case fn.Entry <= pc && pc < fn.End:
+ return fn
+ default:
+ funcs = funcs[m+1:]
+ }
+ }
+ return nil
+}
+
+// PCToLine looks up line number information for a program counter.
+// If there is no information, it returns fn == nil.
+func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) {
+ if fn = t.PCToFunc(pc); fn == nil {
+ return
+ }
+ file, line = fn.Obj.lineFromAline(fn.LineTable.PCToLine(pc))
+ return
+}
+
+// LineToPC looks up the first program counter on the given line in
+// the named file. Returns UnknownPathError or UnknownLineError if
+// there is an error looking up this line.
+func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err os.Error) {
+ obj, ok := t.Files[file]
+ if !ok {
+ return 0, nil, UnknownFileError(file)
+ }
+ abs, err := obj.alineFromLine(file, line)
+ if err != nil {
+ return
+ }
+ for i := range obj.Funcs {
+ f := &obj.Funcs[i]
+ pc := f.LineTable.LineToPC(abs, f.End)
+ if pc != 0 {
+ return pc, f, nil
+ }
+ }
+ return 0, nil, &UnknownLineError{file, line}
+}
+
+// LookupSym returns the text, data, or bss symbol with the given name,
+// or nil if no such symbol is found.
+func (t *Table) LookupSym(name string) *Sym {
+ // TODO(austin) Maybe make a map
+ for i := range t.Syms {
+ s := &t.Syms[i]
+ switch s.Type {
+ case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
+ if s.Name == name {
+ return s
+ }
+ }
+ }
+ return nil
+}
+
+// LookupFunc returns the text, data, or bss symbol with the given name,
+// or nil if no such symbol is found.
+func (t *Table) LookupFunc(name string) *Func {
+ for i := range t.Funcs {
+ f := &t.Funcs[i]
+ if f.Sym.Name == name {
+ return f
+ }
+ }
+ return nil
+}
+
+// SymByAddr returns the text, data, or bss symbol starting at the given address.
+// TODO(rsc): Allow lookup by any address within the symbol.
+func (t *Table) SymByAddr(addr uint64) *Sym {
+ // TODO(austin) Maybe make a map
+ for i := range t.Syms {
+ s := &t.Syms[i]
+ switch s.Type {
+ case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b':
+ if s.Value == addr {
+ return s
+ }
+ }
+ }
+ return nil
+}
+
+/*
+ * Object files
+ */
+
+func (o *Obj) lineFromAline(aline int) (string, int) {
+ type stackEnt struct {
+ path string
+ start int
+ offset int
+ prev *stackEnt
+ }
+
+ noPath := &stackEnt{"", 0, 0, nil}
+ tos := noPath
+
+ // TODO(austin) I have no idea how 'Z' symbols work, except
+ // that they pop the stack.
+pathloop:
+ for _, s := range o.Paths {
+ val := int(s.Value)
+ switch {
+ case val > aline:
+ break pathloop
+
+ case val == 1:
+ // Start a new stack
+ tos = &stackEnt{s.Name, val, 0, noPath}
+
+ case s.Name == "":
+ // Pop
+ if tos == noPath {
+ return "<malformed symbol table>", 0
+ }
+ tos.prev.offset += val - tos.start
+ tos = tos.prev
+
+ default:
+ // Push
+ tos = &stackEnt{s.Name, val, 0, tos}
+ }
+ }
+
+ if tos == noPath {
+ return "", 0
+ }
+ return tos.path, aline - tos.start - tos.offset + 1
+}
+
+func (o *Obj) alineFromLine(path string, line int) (int, os.Error) {
+ if line < 1 {
+ return 0, &UnknownLineError{path, line}
+ }
+
+ for i, s := range o.Paths {
+ // Find this path
+ if s.Name != path {
+ continue
+ }
+
+ // Find this line at this stack level
+ depth := 0
+ var incstart int
+ line += int(s.Value)
+ pathloop:
+ for _, s := range o.Paths[i:] {
+ val := int(s.Value)
+ switch {
+ case depth == 1 && val >= line:
+ return line - 1, nil
+
+ case s.Name == "":
+ depth--
+ if depth == 0 {
+ break pathloop
+ } else if depth == 1 {
+ line += val - incstart
+ }
+
+ default:
+ if depth == 1 {
+ incstart = val
+ }
+ depth++
+ }
+ }
+ return 0, &UnknownLineError{path, line}
+ }
+ return 0, UnknownFileError(path)
+}
+
+/*
+ * Errors
+ */
+
+// UnknownFileError represents a failure to find the specific file in
+// the symbol table.
+type UnknownFileError string
+
+func (e UnknownFileError) String() string { return "unknown file: " + string(e) }
+
+// UnknownLineError represents a failure to map a line to a program
+// counter, either because the line is beyond the bounds of the file
+// or because there is no code on the given line.
+type UnknownLineError struct {
+ File string
+ Line int
+}
+
+func (e *UnknownLineError) String() string {
+ return "no code at " + e.File + ":" + strconv.Itoa(e.Line)
+}
+
+// DecodingError represents an error during the decoding of
+// the symbol table.
+type DecodingError struct {
+ off int
+ msg string
+ val interface{}
+}
+
+func (e *DecodingError) String() string {
+ msg := e.msg
+ if e.val != nil {
+ msg += fmt.Sprintf(" '%v'", e.val)
+ }
+ msg += fmt.Sprintf(" at byte %#x", e.off)
+ return msg
+}
diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go
new file mode 100644
index 000000000..fd8da9449
--- /dev/null
+++ b/libgo/go/debug/macho/file.go
@@ -0,0 +1,517 @@
+// 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 macho implements access to Mach-O object files, as defined by
+// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html.
+package macho
+
+// High level access to low level data structures.
+
+import (
+ "bytes"
+ "debug/dwarf"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+)
+
+// A File represents an open Mach-O file.
+type File struct {
+ FileHeader
+ ByteOrder binary.ByteOrder
+ Loads []Load
+ Sections []*Section
+
+ Symtab *Symtab
+ Dysymtab *Dysymtab
+
+ closer io.Closer
+}
+
+// A Load represents any Mach-O load command.
+type Load interface {
+ Raw() []byte
+}
+
+// A LoadBytes is the uninterpreted bytes of a Mach-O load command.
+type LoadBytes []byte
+
+func (b LoadBytes) Raw() []byte { return b }
+
+// A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command.
+type SegmentHeader struct {
+ Cmd LoadCmd
+ Len uint32
+ Name string
+ Addr uint64
+ Memsz uint64
+ Offset uint64
+ Filesz uint64
+ Maxprot uint32
+ Prot uint32
+ Nsect uint32
+ Flag uint32
+}
+
+// A Segment represents a Mach-O 32-bit or 64-bit load segment command.
+type Segment struct {
+ LoadBytes
+ SegmentHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the segment.
+func (s *Segment) Data() ([]byte, os.Error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the segment.
+func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+type SectionHeader struct {
+ Name string
+ Seg string
+ Addr uint64
+ Size uint64
+ Offset uint32
+ Align uint32
+ Reloff uint32
+ Nreloc uint32
+ Flags uint32
+}
+
+type Section struct {
+ SectionHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the Mach-O section.
+func (s *Section) Data() ([]byte, os.Error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the Mach-O section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+// A Dylib represents a Mach-O load dynamic library command.
+type Dylib struct {
+ LoadBytes
+ Name string
+ Time uint32
+ CurrentVersion uint32
+ CompatVersion uint32
+}
+
+// A Symtab represents a Mach-O symbol table command.
+type Symtab struct {
+ LoadBytes
+ SymtabCmd
+ Syms []Symbol
+}
+
+// A Dysymtab represents a Mach-O dynamic symbol table command.
+type Dysymtab struct {
+ LoadBytes
+ DysymtabCmd
+ IndirectSyms []uint32 // indices into Symtab.Syms
+}
+
+/*
+ * Mach-O reader
+ */
+
+type FormatError struct {
+ off int64
+ msg string
+ val interface{}
+}
+
+func (e *FormatError) String() string {
+ msg := e.msg
+ if e.val != nil {
+ msg += fmt.Sprintf(" '%v'", e.val)
+ }
+ msg += fmt.Sprintf(" in record at byte %#x", e.off)
+ return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as a Mach-O binary.
+func Open(name string) (*File, os.Error) {
+ f, err := os.Open(name, os.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ ff, err := NewFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() os.Error {
+ var err os.Error
+ if f.closer != nil {
+ err = f.closer.Close()
+ f.closer = nil
+ }
+ return err
+}
+
+// NewFile creates a new File for acecssing a Mach-O binary in an underlying reader.
+// The Mach-O binary is expected to start at position 0 in the ReaderAt.
+func NewFile(r io.ReaderAt) (*File, os.Error) {
+ f := new(File)
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+ // Read and decode Mach magic to determine byte order, size.
+ // Magic32 and Magic64 differ only in the bottom bit.
+ var ident [4]byte
+ if _, err := r.ReadAt(ident[0:], 0); err != nil {
+ return nil, err
+ }
+ be := binary.BigEndian.Uint32(ident[0:])
+ le := binary.LittleEndian.Uint32(ident[0:])
+ switch Magic32 &^ 1 {
+ case be &^ 1:
+ f.ByteOrder = binary.BigEndian
+ f.Magic = be
+ case le &^ 1:
+ f.ByteOrder = binary.LittleEndian
+ f.Magic = le
+ default:
+ return nil, &FormatError{0, "invalid magic number", nil}
+ }
+
+ // Read entire file header.
+ if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil {
+ return nil, err
+ }
+
+ // Then load commands.
+ offset := int64(fileHeaderSize32)
+ if f.Magic == Magic64 {
+ offset = fileHeaderSize64
+ }
+ dat := make([]byte, f.Cmdsz)
+ if _, err := r.ReadAt(dat, offset); err != nil {
+ return nil, err
+ }
+ f.Loads = make([]Load, f.Ncmd)
+ bo := f.ByteOrder
+ for i := range f.Loads {
+ // Each load command begins with uint32 command and length.
+ if len(dat) < 8 {
+ return nil, &FormatError{offset, "command block too small", nil}
+ }
+ cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8])
+ if siz < 8 || siz > uint32(len(dat)) {
+ return nil, &FormatError{offset, "invalid command block size", nil}
+ }
+ var cmddat []byte
+ cmddat, dat = dat[0:siz], dat[siz:]
+ offset += int64(siz)
+ var s *Segment
+ switch cmd {
+ default:
+ f.Loads[i] = LoadBytes(cmddat)
+
+ case LoadCmdDylib:
+ var hdr DylibCmd
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &hdr); err != nil {
+ return nil, err
+ }
+ l := new(Dylib)
+ if hdr.Name >= uint32(len(cmddat)) {
+ return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name}
+ }
+ l.Name = cstring(cmddat[hdr.Name:])
+ l.Time = hdr.Time
+ l.CurrentVersion = hdr.CurrentVersion
+ l.CompatVersion = hdr.CompatVersion
+ l.LoadBytes = LoadBytes(cmddat)
+ f.Loads[i] = l
+
+ case LoadCmdSymtab:
+ var hdr SymtabCmd
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &hdr); err != nil {
+ return nil, err
+ }
+ strtab := make([]byte, hdr.Strsize)
+ if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil {
+ return nil, err
+ }
+ var symsz int
+ if f.Magic == Magic64 {
+ symsz = 16
+ } else {
+ symsz = 12
+ }
+ symdat := make([]byte, int(hdr.Nsyms)*symsz)
+ if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil {
+ return nil, err
+ }
+ st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset)
+ if err != nil {
+ return nil, err
+ }
+ f.Loads[i] = st
+ f.Symtab = st
+
+ case LoadCmdDysymtab:
+ var hdr DysymtabCmd
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &hdr); err != nil {
+ return nil, err
+ }
+ dat := make([]byte, hdr.Nindirectsyms*4)
+ if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
+ return nil, err
+ }
+ x := make([]uint32, hdr.Nindirectsyms)
+ if err := binary.Read(bytes.NewBuffer(dat), bo, x); err != nil {
+ return nil, err
+ }
+ st := new(Dysymtab)
+ st.LoadBytes = LoadBytes(cmddat)
+ st.DysymtabCmd = hdr
+ st.IndirectSyms = x
+ f.Loads[i] = st
+ f.Dysymtab = st
+
+ case LoadCmdSegment:
+ var seg32 Segment32
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &seg32); err != nil {
+ return nil, err
+ }
+ s = new(Segment)
+ s.LoadBytes = cmddat
+ s.Cmd = cmd
+ s.Len = siz
+ s.Name = cstring(seg32.Name[0:])
+ s.Addr = uint64(seg32.Addr)
+ s.Memsz = uint64(seg32.Memsz)
+ s.Offset = uint64(seg32.Offset)
+ s.Filesz = uint64(seg32.Filesz)
+ s.Maxprot = seg32.Maxprot
+ s.Prot = seg32.Prot
+ s.Nsect = seg32.Nsect
+ s.Flag = seg32.Flag
+ f.Loads[i] = s
+ for i := 0; i < int(s.Nsect); i++ {
+ var sh32 Section32
+ if err := binary.Read(b, bo, &sh32); err != nil {
+ return nil, err
+ }
+ sh := new(Section)
+ sh.Name = cstring(sh32.Name[0:])
+ sh.Seg = cstring(sh32.Seg[0:])
+ sh.Addr = uint64(sh32.Addr)
+ sh.Size = uint64(sh32.Size)
+ sh.Offset = sh32.Offset
+ sh.Align = sh32.Align
+ sh.Reloff = sh32.Reloff
+ sh.Nreloc = sh32.Nreloc
+ sh.Flags = sh32.Flags
+ f.pushSection(sh, r)
+ }
+
+ case LoadCmdSegment64:
+ var seg64 Segment64
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &seg64); err != nil {
+ return nil, err
+ }
+ s = new(Segment)
+ s.LoadBytes = cmddat
+ s.Cmd = cmd
+ s.Len = siz
+ s.Name = cstring(seg64.Name[0:])
+ s.Addr = seg64.Addr
+ s.Memsz = seg64.Memsz
+ s.Offset = seg64.Offset
+ s.Filesz = seg64.Filesz
+ s.Maxprot = seg64.Maxprot
+ s.Prot = seg64.Prot
+ s.Nsect = seg64.Nsect
+ s.Flag = seg64.Flag
+ f.Loads[i] = s
+ for i := 0; i < int(s.Nsect); i++ {
+ var sh64 Section64
+ if err := binary.Read(b, bo, &sh64); err != nil {
+ return nil, err
+ }
+ sh := new(Section)
+ sh.Name = cstring(sh64.Name[0:])
+ sh.Seg = cstring(sh64.Seg[0:])
+ sh.Addr = sh64.Addr
+ sh.Size = sh64.Size
+ sh.Offset = sh64.Offset
+ sh.Align = sh64.Align
+ sh.Reloff = sh64.Reloff
+ sh.Nreloc = sh64.Nreloc
+ sh.Flags = sh64.Flags
+ f.pushSection(sh, r)
+ }
+ }
+ if s != nil {
+ s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz))
+ s.ReaderAt = s.sr
+ }
+ }
+ return f, nil
+}
+
+func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, os.Error) {
+ bo := f.ByteOrder
+ symtab := make([]Symbol, hdr.Nsyms)
+ b := bytes.NewBuffer(symdat)
+ for i := range symtab {
+ var n Nlist64
+ if f.Magic == Magic64 {
+ if err := binary.Read(b, bo, &n); err != nil {
+ return nil, err
+ }
+ } else {
+ var n32 Nlist32
+ if err := binary.Read(b, bo, &n32); err != nil {
+ return nil, err
+ }
+ n.Name = n32.Name
+ n.Type = n32.Type
+ n.Sect = n32.Sect
+ n.Desc = n32.Desc
+ n.Value = uint64(n32.Value)
+ }
+ sym := &symtab[i]
+ if n.Name >= uint32(len(strtab)) {
+ return nil, &FormatError{offset, "invalid name in symbol table", n.Name}
+ }
+ sym.Name = cstring(strtab[n.Name:])
+ sym.Type = n.Type
+ sym.Sect = n.Sect
+ sym.Desc = n.Desc
+ sym.Value = n.Value
+ }
+ st := new(Symtab)
+ st.LoadBytes = LoadBytes(cmddat)
+ st.Syms = symtab
+ return st, nil
+}
+
+func (f *File) pushSection(sh *Section, r io.ReaderAt) {
+ f.Sections = append(f.Sections, sh)
+ sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size))
+ sh.ReaderAt = sh.sr
+}
+
+func cstring(b []byte) string {
+ var i int
+ for i = 0; i < len(b) && b[i] != 0; i++ {
+ }
+ return string(b[0:i])
+}
+
+// Segment returns the first Segment with the given name, or nil if no such segment exists.
+func (f *File) Segment(name string) *Segment {
+ for _, l := range f.Loads {
+ if s, ok := l.(*Segment); ok && s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
+
+// Section returns the first section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+ for _, s := range f.Sections {
+ if s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
+
+// DWARF returns the DWARF debug information for the Mach-O file.
+func (f *File) DWARF() (*dwarf.Data, os.Error) {
+ // There are many other DWARF sections, but these
+ // are the required ones, and the debug/dwarf package
+ // does not use the others, so don't bother loading them.
+ var names = [...]string{"abbrev", "info", "str"}
+ var dat [len(names)][]byte
+ for i, name := range names {
+ name = "__debug_" + name
+ s := f.Section(name)
+ if s == nil {
+ return nil, os.NewError("missing Mach-O section " + name)
+ }
+ b, err := s.Data()
+ if err != nil && uint64(len(b)) < s.Size {
+ return nil, err
+ }
+ dat[i] = b
+ }
+
+ abbrev, info, str := dat[0], dat[1], dat[2]
+ return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+}
+
+// ImportedSymbols returns the names of all symbols
+// referred to by the binary f that are expected to be
+// satisfied by other libraries at dynamic load time.
+func (f *File) ImportedSymbols() ([]string, os.Error) {
+ if f.Dysymtab == nil || f.Symtab == nil {
+ return nil, &FormatError{0, "missing symbol table", nil}
+ }
+
+ st := f.Symtab
+ dt := f.Dysymtab
+ var all []string
+ for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] {
+ all = append(all, s.Name)
+ }
+ return all, nil
+}
+
+// ImportedLibraries returns the paths of all libraries
+// referred to by the binary f that are expected to be
+// linked with the binary at dynamic link time.
+func (f *File) ImportedLibraries() ([]string, os.Error) {
+ var all []string
+ for _, l := range f.Loads {
+ if lib, ok := l.(*Dylib); ok {
+ all = append(all, lib.Name)
+ }
+ }
+ return all, nil
+}
diff --git a/libgo/go/debug/macho/file_test.go b/libgo/go/debug/macho/file_test.go
new file mode 100644
index 000000000..56d8a20be
--- /dev/null
+++ b/libgo/go/debug/macho/file_test.go
@@ -0,0 +1,167 @@
+// 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 macho
+
+import (
+ "reflect"
+ "testing"
+)
+
+type fileTest struct {
+ file string
+ hdr FileHeader
+ segments []*SegmentHeader
+ sections []*SectionHeader
+}
+
+var fileTests = []fileTest{
+ {
+ "testdata/gcc-386-darwin-exec",
+ FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0xc, 0x3c0, 0x85},
+ []*SegmentHeader{
+ &SegmentHeader{LoadCmdSegment, 0x38, "__PAGEZERO", 0x0, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ &SegmentHeader{LoadCmdSegment, 0xc0, "__TEXT", 0x1000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x2, 0x0},
+ &SegmentHeader{LoadCmdSegment, 0xc0, "__DATA", 0x2000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x2, 0x0},
+ &SegmentHeader{LoadCmdSegment, 0x7c, "__IMPORT", 0x3000, 0x1000, 0x2000, 0x1000, 0x7, 0x7, 0x1, 0x0},
+ &SegmentHeader{LoadCmdSegment, 0x38, "__LINKEDIT", 0x4000, 0x1000, 0x3000, 0x12c, 0x7, 0x1, 0x0, 0x0},
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ },
+ []*SectionHeader{
+ &SectionHeader{"__text", "__TEXT", 0x1f68, 0x88, 0xf68, 0x2, 0x0, 0x0, 0x80000400},
+ &SectionHeader{"__cstring", "__TEXT", 0x1ff0, 0xd, 0xff0, 0x0, 0x0, 0x0, 0x2},
+ &SectionHeader{"__data", "__DATA", 0x2000, 0x14, 0x1000, 0x2, 0x0, 0x0, 0x0},
+ &SectionHeader{"__dyld", "__DATA", 0x2014, 0x1c, 0x1014, 0x2, 0x0, 0x0, 0x0},
+ &SectionHeader{"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008},
+ },
+ },
+ {
+ "testdata/gcc-amd64-darwin-exec",
+ FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0xb, 0x568, 0x85},
+ []*SegmentHeader{
+ &SegmentHeader{LoadCmdSegment64, 0x48, "__PAGEZERO", 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x5, 0x0},
+ &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x3, 0x0},
+ &SegmentHeader{LoadCmdSegment64, 0x48, "__LINKEDIT", 0x100002000, 0x1000, 0x2000, 0x140, 0x7, 0x1, 0x0, 0x0},
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ },
+ []*SectionHeader{
+ &SectionHeader{"__text", "__TEXT", 0x100000f14, 0x6d, 0xf14, 0x2, 0x0, 0x0, 0x80000400},
+ &SectionHeader{"__symbol_stub1", "__TEXT", 0x100000f81, 0xc, 0xf81, 0x0, 0x0, 0x0, 0x80000408},
+ &SectionHeader{"__stub_helper", "__TEXT", 0x100000f90, 0x18, 0xf90, 0x2, 0x0, 0x0, 0x0},
+ &SectionHeader{"__cstring", "__TEXT", 0x100000fa8, 0xd, 0xfa8, 0x0, 0x0, 0x0, 0x2},
+ &SectionHeader{"__eh_frame", "__TEXT", 0x100000fb8, 0x48, 0xfb8, 0x3, 0x0, 0x0, 0x6000000b},
+ &SectionHeader{"__data", "__DATA", 0x100001000, 0x1c, 0x1000, 0x3, 0x0, 0x0, 0x0},
+ &SectionHeader{"__dyld", "__DATA", 0x100001020, 0x38, 0x1020, 0x3, 0x0, 0x0, 0x0},
+ &SectionHeader{"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7},
+ },
+ },
+ {
+ "testdata/gcc-amd64-darwin-exec-debug",
+ FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0xa, 0x4, 0x5a0, 0},
+ []*SegmentHeader{
+ nil,
+ &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x0, 0x7, 0x5, 0x5, 0x0},
+ &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x0, 0x0, 0x7, 0x3, 0x3, 0x0},
+ &SegmentHeader{LoadCmdSegment64, 0x278, "__DWARF", 0x100002000, 0x1000, 0x1000, 0x1bc, 0x7, 0x3, 0x7, 0x0},
+ },
+ []*SectionHeader{
+ &SectionHeader{"__text", "__TEXT", 0x100000f14, 0x0, 0x0, 0x2, 0x0, 0x0, 0x80000400},
+ &SectionHeader{"__symbol_stub1", "__TEXT", 0x100000f81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000408},
+ &SectionHeader{"__stub_helper", "__TEXT", 0x100000f90, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0},
+ &SectionHeader{"__cstring", "__TEXT", 0x100000fa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2},
+ &SectionHeader{"__eh_frame", "__TEXT", 0x100000fb8, 0x0, 0x0, 0x3, 0x0, 0x0, 0x6000000b},
+ &SectionHeader{"__data", "__DATA", 0x100001000, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
+ &SectionHeader{"__dyld", "__DATA", 0x100001020, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
+ &SectionHeader{"__la_symbol_ptr", "__DATA", 0x100001058, 0x0, 0x0, 0x2, 0x0, 0x0, 0x7},
+ &SectionHeader{"__debug_abbrev", "__DWARF", 0x100002000, 0x36, 0x1000, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_aranges", "__DWARF", 0x100002036, 0x30, 0x1036, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_frame", "__DWARF", 0x100002066, 0x40, 0x1066, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_info", "__DWARF", 0x1000020a6, 0x54, 0x10a6, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_line", "__DWARF", 0x1000020fa, 0x47, 0x10fa, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_pubnames", "__DWARF", 0x100002141, 0x1b, 0x1141, 0x0, 0x0, 0x0, 0x0},
+ &SectionHeader{"__debug_str", "__DWARF", 0x10000215c, 0x60, 0x115c, 0x0, 0x0, 0x0, 0x0},
+ },
+ },
+}
+
+func TestOpen(t *testing.T) {
+ for i := range fileTests {
+ tt := &fileTests[i]
+
+ f, err := Open(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+ continue
+ }
+ for i, l := range f.Loads {
+ if i >= len(tt.segments) {
+ break
+ }
+ sh := tt.segments[i]
+ s, ok := l.(*Segment)
+ if sh == nil {
+ if ok {
+ t.Errorf("open %s, section %d: skipping %#v\n", tt.file, i, &s.SegmentHeader)
+ }
+ continue
+ }
+ if !ok {
+ t.Errorf("open %s, section %d: not *Segment\n", tt.file, i)
+ continue
+ }
+ have := &s.SegmentHeader
+ want := sh
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, segment %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+ }
+ tn := len(tt.segments)
+ fn := len(f.Loads)
+ if tn != fn {
+ t.Errorf("open %s: len(Loads) = %d, want %d", tt.file, fn, tn)
+ }
+
+ for i, sh := range f.Sections {
+ if i >= len(tt.sections) {
+ break
+ }
+ have := &sh.SectionHeader
+ want := tt.sections[i]
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+ }
+ tn = len(tt.sections)
+ fn = len(f.Sections)
+ if tn != fn {
+ t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+ }
+
+ }
+}
+
+func TestOpenFailure(t *testing.T) {
+ filename := "file.go" // not a Mach-O file
+ _, err := Open(filename) // don't crash
+ if err == nil {
+ t.Errorf("open %s: succeeded unexpectedly", filename)
+ }
+}
diff --git a/libgo/go/debug/macho/macho.go b/libgo/go/debug/macho/macho.go
new file mode 100644
index 000000000..1386f5acf
--- /dev/null
+++ b/libgo/go/debug/macho/macho.go
@@ -0,0 +1,305 @@
+// 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.
+
+// Mach-O header data structures
+// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
+
+package macho
+
+import "strconv"
+
+// A FileHeader represents a Mach-O file header.
+type FileHeader struct {
+ Magic uint32
+ Cpu Cpu
+ SubCpu uint32
+ Type Type
+ Ncmd uint32
+ Cmdsz uint32
+ Flags uint32
+}
+
+const (
+ fileHeaderSize32 = 7 * 4
+ fileHeaderSize64 = 8 * 4
+)
+
+const (
+ Magic32 uint32 = 0xfeedface
+ Magic64 uint32 = 0xfeedfacf
+)
+
+// A Type is a Mach-O file type, either an object or an executable.
+type Type uint32
+
+const (
+ TypeObj Type = 1
+ TypeExec Type = 2
+)
+
+// A Cpu is a Mach-O cpu type.
+type Cpu uint32
+
+const (
+ Cpu386 Cpu = 7
+ CpuAmd64 Cpu = Cpu386 + 1<<24
+)
+
+var cpuStrings = []intName{
+ {uint32(Cpu386), "Cpu386"},
+ {uint32(CpuAmd64), "CpuAmd64"},
+}
+
+func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) }
+func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) }
+
+// A LoadCmd is a Mach-O load command.
+type LoadCmd uint32
+
+const (
+ LoadCmdSegment LoadCmd = 1
+ LoadCmdSymtab LoadCmd = 2
+ LoadCmdThread LoadCmd = 4
+ LoadCmdUnixThread LoadCmd = 5 // thread+stack
+ LoadCmdDysymtab LoadCmd = 11
+ LoadCmdDylib LoadCmd = 12
+ LoadCmdDylinker LoadCmd = 15
+ LoadCmdSegment64 LoadCmd = 25
+)
+
+var cmdStrings = []intName{
+ {uint32(LoadCmdSegment), "LoadCmdSegment"},
+ {uint32(LoadCmdThread), "LoadCmdThread"},
+ {uint32(LoadCmdUnixThread), "LoadCmdUnixThread"},
+ {uint32(LoadCmdDylib), "LoadCmdDylib"},
+ {uint32(LoadCmdSegment64), "LoadCmdSegment64"},
+}
+
+func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) }
+func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) }
+
+// A Segment64 is a 64-bit Mach-O segment load command.
+type Segment64 struct {
+ Cmd LoadCmd
+ Len uint32
+ Name [16]byte
+ Addr uint64
+ Memsz uint64
+ Offset uint64
+ Filesz uint64
+ Maxprot uint32
+ Prot uint32
+ Nsect uint32
+ Flag uint32
+}
+
+// A Segment32 is a 32-bit Mach-O segment load command.
+type Segment32 struct {
+ Cmd LoadCmd
+ Len uint32
+ Name [16]byte
+ Addr uint32
+ Memsz uint32
+ Offset uint32
+ Filesz uint32
+ Maxprot uint32
+ Prot uint32
+ Nsect uint32
+ Flag uint32
+}
+
+// A DylibCmd is a Mach-O load dynamic library command.
+type DylibCmd struct {
+ Cmd LoadCmd
+ Len uint32
+ Name uint32
+ Time uint32
+ CurrentVersion uint32
+ CompatVersion uint32
+}
+
+// A Section32 is a 32-bit Mach-O section header.
+type Section32 struct {
+ Name [16]byte
+ Seg [16]byte
+ Addr uint32
+ Size uint32
+ Offset uint32
+ Align uint32
+ Reloff uint32
+ Nreloc uint32
+ Flags uint32
+ Reserve1 uint32
+ Reserve2 uint32
+}
+
+// A Section32 is a 64-bit Mach-O section header.
+type Section64 struct {
+ Name [16]byte
+ Seg [16]byte
+ Addr uint64
+ Size uint64
+ Offset uint32
+ Align uint32
+ Reloff uint32
+ Nreloc uint32
+ Flags uint32
+ Reserve1 uint32
+ Reserve2 uint32
+ Reserve3 uint32
+}
+
+// A SymtabCmd is a Mach-O symbol table command.
+type SymtabCmd struct {
+ Cmd LoadCmd
+ Len uint32
+ Symoff uint32
+ Nsyms uint32
+ Stroff uint32
+ Strsize uint32
+}
+
+// A DysymtabCmd is a Mach-O dynamic symbol table command.
+type DysymtabCmd struct {
+ Cmd LoadCmd
+ Len uint32
+ Ilocalsym uint32
+ Nlocalsym uint32
+ Iextdefsym uint32
+ Nextdefsym uint32
+ Iundefsym uint32
+ Nundefsym uint32
+ Tocoffset uint32
+ Ntoc uint32
+ Modtaboff uint32
+ Nmodtab uint32
+ Extrefsymoff uint32
+ Nextrefsyms uint32
+ Indirectsymoff uint32
+ Nindirectsyms uint32
+ Extreloff uint32
+ Nextrel uint32
+ Locreloff uint32
+ Nlocrel uint32
+}
+
+// An Nlist32 is a Mach-O 32-bit symbol table entry.
+type Nlist32 struct {
+ Name uint32
+ Type uint8
+ Sect uint8
+ Desc uint16
+ Value uint32
+}
+
+// An Nlist64 is a Mach-O 64-bit symbol table entry.
+type Nlist64 struct {
+ Name uint32
+ Type uint8
+ Sect uint8
+ Desc uint16
+ Value uint64
+}
+
+// A Symbol is a Mach-O 32-bit or 64-bit symbol table entry.
+type Symbol struct {
+ Name string
+ Type uint8
+ Sect uint8
+ Desc uint16
+ Value uint64
+}
+
+// A Thread is a Mach-O thread state command.
+type Thread struct {
+ Cmd LoadCmd
+ Len uint32
+ Type uint32
+ Data []uint32
+}
+
+// Regs386 is the Mach-O 386 register structure.
+type Regs386 struct {
+ AX uint32
+ BX uint32
+ CX uint32
+ DX uint32
+ DI uint32
+ SI uint32
+ BP uint32
+ SP uint32
+ SS uint32
+ FLAGS uint32
+ IP uint32
+ CS uint32
+ DS uint32
+ ES uint32
+ FS uint32
+ GS uint32
+}
+
+// RegsAMD64 is the Mach-O AMD64 register structure.
+type RegsAMD64 struct {
+ AX uint64
+ BX uint64
+ CX uint64
+ DX uint64
+ DI uint64
+ SI uint64
+ BP uint64
+ SP uint64
+ R8 uint64
+ R9 uint64
+ R10 uint64
+ R11 uint64
+ R12 uint64
+ R13 uint64
+ R14 uint64
+ R15 uint64
+ IP uint64
+ FLAGS uint64
+ CS uint64
+ FS uint64
+ GS uint64
+}
+
+type intName struct {
+ i uint32
+ s string
+}
+
+func stringName(i uint32, names []intName, goSyntax bool) string {
+ for _, n := range names {
+ if n.i == i {
+ if goSyntax {
+ return "macho." + n.s
+ }
+ return n.s
+ }
+ }
+ return strconv.Uitoa64(uint64(i))
+}
+
+func flagName(i uint32, names []intName, goSyntax bool) string {
+ s := ""
+ for _, n := range names {
+ if n.i&i == n.i {
+ if len(s) > 0 {
+ s += "+"
+ }
+ if goSyntax {
+ s += "macho."
+ }
+ s += n.s
+ i -= n.i
+ }
+ }
+ if len(s) == 0 {
+ return "0x" + strconv.Uitob64(uint64(i), 16)
+ }
+ if i != 0 {
+ s += "+0x" + strconv.Uitob64(uint64(i), 16)
+ }
+ return s
+}
diff --git a/libgo/go/debug/macho/testdata/gcc-386-darwin-exec b/libgo/go/debug/macho/testdata/gcc-386-darwin-exec
new file mode 100755
index 000000000..03ba1bafa
--- /dev/null
+++ b/libgo/go/debug/macho/testdata/gcc-386-darwin-exec
Binary files differ
diff --git a/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec b/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec
new file mode 100755
index 000000000..5155a5a26
--- /dev/null
+++ b/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec
Binary files differ
diff --git a/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec-debug b/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec-debug
new file mode 100644
index 000000000..a47d3aef7
--- /dev/null
+++ b/libgo/go/debug/macho/testdata/gcc-amd64-darwin-exec-debug
Binary files differ
diff --git a/libgo/go/debug/macho/testdata/hello.c b/libgo/go/debug/macho/testdata/hello.c
new file mode 100644
index 000000000..a689d3644
--- /dev/null
+++ b/libgo/go/debug/macho/testdata/hello.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int
+main(void)
+{
+ printf("hello, world\n");
+ return 0;
+}
diff --git a/libgo/go/debug/pe/file.go b/libgo/go/debug/pe/file.go
new file mode 100644
index 000000000..82c02407b
--- /dev/null
+++ b/libgo/go/debug/pe/file.go
@@ -0,0 +1,309 @@
+// 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 pe implements access to PE (Microsoft Windows Portable Executable) files.
+package pe
+
+import (
+ "debug/dwarf"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+)
+
+// A File represents an open PE file.
+type File struct {
+ FileHeader
+ Sections []*Section
+
+ closer io.Closer
+}
+
+type SectionHeader struct {
+ Name string
+ VirtualSize uint32
+ VirtualAddress uint32
+ Size uint32
+ Offset uint32
+ PointerToRelocations uint32
+ PointerToLineNumbers uint32
+ NumberOfRelocations uint16
+ NumberOfLineNumbers uint16
+ Characteristics uint32
+}
+
+
+type Section struct {
+ SectionHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+type ImportDirectory struct {
+ OriginalFirstThunk uint32
+ TimeDateStamp uint32
+ ForwarderChain uint32
+ Name uint32
+ FirstThunk uint32
+
+ dll string
+ rva []uint32
+}
+
+// Data reads and returns the contents of the PE section.
+func (s *Section) Data() ([]byte, os.Error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the PE section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+
+type FormatError struct {
+ off int64
+ msg string
+ val interface{}
+}
+
+func (e *FormatError) String() string {
+ msg := e.msg
+ if e.val != nil {
+ msg += fmt.Sprintf(" '%v'", e.val)
+ }
+ msg += fmt.Sprintf(" in record at byte %#x", e.off)
+ return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as a PE binary.
+func Open(name string) (*File, os.Error) {
+ f, err := os.Open(name, os.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ ff, err := NewFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() os.Error {
+ var err os.Error
+ if f.closer != nil {
+ err = f.closer.Close()
+ f.closer = nil
+ }
+ return err
+}
+
+// NewFile creates a new File for acecssing a PE binary in an underlying reader.
+func NewFile(r io.ReaderAt) (*File, os.Error) {
+ f := new(File)
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+ var dosheader [96]byte
+ if _, err := r.ReadAt(dosheader[0:], 0); err != nil {
+ return nil, err
+ }
+ var base int64
+ if dosheader[0] == 'M' && dosheader[1] == 'Z' {
+ var sign [4]byte
+ r.ReadAt(sign[0:], int64(dosheader[0x3c]))
+ if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
+ return nil, os.NewError("Invalid PE File Format.")
+ }
+ base = int64(dosheader[0x3c]) + 4
+ } else {
+ base = int64(0)
+ }
+ sr.Seek(base, 0)
+ if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
+ return nil, err
+ }
+ if f.FileHeader.Machine != IMAGE_FILE_MACHINE_UNKNOWN && f.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && f.FileHeader.Machine != IMAGE_FILE_MACHINE_I386 {
+ return nil, os.NewError("Invalid PE File Format.")
+ }
+ // get symbol string table
+ sr.Seek(int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols), 0)
+ var l uint32
+ if err := binary.Read(sr, binary.LittleEndian, &l); err != nil {
+ return nil, err
+ }
+ ss := make([]byte, l)
+ if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols)); err != nil {
+ return nil, err
+ }
+ sr.Seek(base, 0)
+ binary.Read(sr, binary.LittleEndian, &f.FileHeader)
+ sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), 1) //Skip OptionalHeader
+ f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
+ for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
+ sh := new(SectionHeader32)
+ if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
+ return nil, err
+ }
+ var name string
+ if sh.Name[0] == '\x2F' {
+ si, _ := strconv.Atoi(cstring(sh.Name[1:]))
+ name, _ = getString(ss, si)
+ } else {
+ name = cstring(sh.Name[0:])
+ }
+ s := new(Section)
+ s.SectionHeader = SectionHeader{
+ Name: name,
+ VirtualSize: uint32(sh.VirtualSize),
+ VirtualAddress: uint32(sh.VirtualAddress),
+ Size: uint32(sh.SizeOfRawData),
+ Offset: uint32(sh.PointerToRawData),
+ PointerToRelocations: uint32(sh.PointerToRelocations),
+ PointerToLineNumbers: uint32(sh.PointerToLineNumbers),
+ NumberOfRelocations: uint16(sh.NumberOfRelocations),
+ NumberOfLineNumbers: uint16(sh.NumberOfLineNumbers),
+ Characteristics: uint32(sh.Characteristics),
+ }
+ s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
+ s.ReaderAt = s.sr
+ f.Sections[i] = s
+ }
+ return f, nil
+}
+
+func cstring(b []byte) string {
+ var i int
+ for i = 0; i < len(b) && b[i] != 0; i++ {
+ }
+ return string(b[0:i])
+}
+
+// getString extracts a string from symbol string table.
+func getString(section []byte, start int) (string, bool) {
+ if start < 0 || start >= len(section) {
+ return "", false
+ }
+
+ for end := start; end < len(section); end++ {
+ if section[end] == 0 {
+ return string(section[start:end]), true
+ }
+ }
+ return "", false
+}
+
+// Section returns the first section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+ for _, s := range f.Sections {
+ if s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
+
+func (f *File) DWARF() (*dwarf.Data, os.Error) {
+ // There are many other DWARF sections, but these
+ // are the required ones, and the debug/dwarf package
+ // does not use the others, so don't bother loading them.
+ var names = [...]string{"abbrev", "info", "str"}
+ var dat [len(names)][]byte
+ for i, name := range names {
+ name = ".debug_" + name
+ s := f.Section(name)
+ if s == nil {
+ continue
+ }
+ b, err := s.Data()
+ if err != nil && uint32(len(b)) < s.Size {
+ return nil, err
+ }
+ dat[i] = b
+ }
+
+ abbrev, info, str := dat[0], dat[1], dat[2]
+ return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+}
+
+// ImportedSymbols returns the names of all symbols
+// referred to by the binary f that are expected to be
+// satisfied by other libraries at dynamic load time.
+// It does not return weak symbols.
+func (f *File) ImportedSymbols() ([]string, os.Error) {
+ ds := f.Section(".idata")
+ if ds == nil {
+ // not dynamic, so no libraries
+ return nil, nil
+ }
+ d, err := ds.Data()
+ if err != nil {
+ return nil, err
+ }
+ var ida []ImportDirectory
+ for len(d) > 0 {
+ var dt ImportDirectory
+ dt.OriginalFirstThunk = binary.LittleEndian.Uint32(d[0:4])
+ dt.Name = binary.LittleEndian.Uint32(d[12:16])
+ dt.FirstThunk = binary.LittleEndian.Uint32(d[16:20])
+ d = d[20:]
+ if dt.OriginalFirstThunk == 0 {
+ break
+ }
+ ida = append(ida, dt)
+ }
+ for i, _ := range ida {
+ for len(d) > 0 {
+ va := binary.LittleEndian.Uint32(d[0:4])
+ d = d[4:]
+ if va == 0 {
+ break
+ }
+ ida[i].rva = append(ida[i].rva, va)
+ }
+ }
+ for _, _ = range ida {
+ for len(d) > 0 {
+ va := binary.LittleEndian.Uint32(d[0:4])
+ d = d[4:]
+ if va == 0 {
+ break
+ }
+ }
+ }
+ names, _ := ds.Data()
+ var all []string
+ for _, dt := range ida {
+ dt.dll, _ = getString(names, int(dt.Name-ds.VirtualAddress))
+ for _, va := range dt.rva {
+ fn, _ := getString(names, int(va-ds.VirtualAddress+2))
+ all = append(all, fn+":"+dt.dll)
+ }
+ }
+
+ return all, nil
+}
+
+// ImportedLibraries returns the names of all libraries
+// referred to by the binary f that are expected to be
+// linked with the binary at dynamic link time.
+func (f *File) ImportedLibraries() ([]string, os.Error) {
+ // TODO
+ // cgo -dynimport don't use this for windows PE, so just return.
+ return nil, nil
+}
diff --git a/libgo/go/debug/pe/file_test.go b/libgo/go/debug/pe/file_test.go
new file mode 100644
index 000000000..2c5c25b8c
--- /dev/null
+++ b/libgo/go/debug/pe/file_test.go
@@ -0,0 +1,99 @@
+// 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 pe
+
+import (
+ "reflect"
+ "testing"
+)
+
+type fileTest struct {
+ file string
+ hdr FileHeader
+ sections []*SectionHeader
+}
+
+var fileTests = []fileTest{
+ {
+ "testdata/gcc-386-mingw-obj",
+ FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
+ []*SectionHeader{
+ &SectionHeader{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
+ &SectionHeader{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
+ &SectionHeader{".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
+ &SectionHeader{".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000},
+ &SectionHeader{".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832},
+ &SectionHeader{".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832},
+ &SectionHeader{".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616},
+ &SectionHeader{".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984},
+ &SectionHeader{".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832},
+ &SectionHeader{".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832},
+ &SectionHeader{".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
+ &SectionHeader{".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
+ },
+ },
+ {
+ "testdata/gcc-386-mingw-exec",
+ FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
+ []*SectionHeader{
+ &SectionHeader{Name: ".text", VirtualSize: 0xcd8, VirtualAddress: 0x1000, Size: 0xe00, Offset: 0x400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060},
+ &SectionHeader{Name: ".data", VirtualSize: 0x10, VirtualAddress: 0x2000, Size: 0x200, Offset: 0x1200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ &SectionHeader{Name: ".rdata", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x1400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40300040},
+ &SectionHeader{Name: ".bss", VirtualSize: 0xdc, VirtualAddress: 0x4000, Size: 0x0, Offset: 0x0, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0400080},
+ &SectionHeader{Name: ".idata", VirtualSize: 0x3c8, VirtualAddress: 0x5000, Size: 0x400, Offset: 0x1600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ &SectionHeader{Name: ".CRT", VirtualSize: 0x18, VirtualAddress: 0x6000, Size: 0x200, Offset: 0x1a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ &SectionHeader{Name: ".tls", VirtualSize: 0x20, VirtualAddress: 0x7000, Size: 0x200, Offset: 0x1c00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ &SectionHeader{Name: ".debug_aranges", VirtualSize: 0x20, VirtualAddress: 0x8000, Size: 0x200, Offset: 0x1e00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_pubnames", VirtualSize: 0x51, VirtualAddress: 0x9000, Size: 0x200, Offset: 0x2000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_pubtypes", VirtualSize: 0x91, VirtualAddress: 0xa000, Size: 0x200, Offset: 0x2200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_info", VirtualSize: 0xe22, VirtualAddress: 0xb000, Size: 0x1000, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_abbrev", VirtualSize: 0x157, VirtualAddress: 0xc000, Size: 0x200, Offset: 0x3400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_line", VirtualSize: 0x144, VirtualAddress: 0xd000, Size: 0x200, Offset: 0x3600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_frame", VirtualSize: 0x34, VirtualAddress: 0xe000, Size: 0x200, Offset: 0x3800, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42300000},
+ &SectionHeader{Name: ".debug_loc", VirtualSize: 0x38, VirtualAddress: 0xf000, Size: 0x200, Offset: 0x3a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ },
+ },
+}
+
+func TestOpen(t *testing.T) {
+ for i := range fileTests {
+ tt := &fileTests[i]
+
+ f, err := Open(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+ continue
+ }
+
+ for i, sh := range f.Sections {
+ if i >= len(tt.sections) {
+ break
+ }
+ have := &sh.SectionHeader
+ want := tt.sections[i]
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+ }
+ tn := len(tt.sections)
+ fn := len(f.Sections)
+ if tn != fn {
+ t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+ }
+
+ }
+}
+
+func TestOpenFailure(t *testing.T) {
+ filename := "file.go" // not a PE file
+ _, err := Open(filename) // don't crash
+ if err == nil {
+ t.Errorf("open %s: succeeded unexpectedly", filename)
+ }
+}
diff --git a/libgo/go/debug/pe/pe.go b/libgo/go/debug/pe/pe.go
new file mode 100644
index 000000000..b3dab739a
--- /dev/null
+++ b/libgo/go/debug/pe/pe.go
@@ -0,0 +1,51 @@
+// 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 pe
+
+type FileHeader struct {
+ Machine uint16
+ NumberOfSections uint16
+ TimeDateStamp uint32
+ PointerToSymbolTable uint32
+ NumberOfSymbols uint32
+ SizeOfOptionalHeader uint16
+ Characteristics uint16
+}
+
+type SectionHeader32 struct {
+ Name [8]uint8
+ VirtualSize uint32
+ VirtualAddress uint32
+ SizeOfRawData uint32
+ PointerToRawData uint32
+ PointerToRelocations uint32
+ PointerToLineNumbers uint32
+ NumberOfRelocations uint16
+ NumberOfLineNumbers uint16
+ Characteristics uint32
+}
+
+const (
+ IMAGE_FILE_MACHINE_UNKNOWN = 0x0
+ IMAGE_FILE_MACHINE_AM33 = 0x1d3
+ IMAGE_FILE_MACHINE_AMD64 = 0x8664
+ IMAGE_FILE_MACHINE_ARM = 0x1c0
+ IMAGE_FILE_MACHINE_EBC = 0xebc
+ IMAGE_FILE_MACHINE_I386 = 0x14c
+ IMAGE_FILE_MACHINE_IA64 = 0x200
+ IMAGE_FILE_MACHINE_M32R = 0x9041
+ IMAGE_FILE_MACHINE_MIPS16 = 0x266
+ IMAGE_FILE_MACHINE_MIPSFPU = 0x366
+ IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466
+ IMAGE_FILE_MACHINE_POWERPC = 0x1f0
+ IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1
+ IMAGE_FILE_MACHINE_R4000 = 0x166
+ IMAGE_FILE_MACHINE_SH3 = 0x1a2
+ IMAGE_FILE_MACHINE_SH3DSP = 0x1a3
+ IMAGE_FILE_MACHINE_SH4 = 0x1a6
+ IMAGE_FILE_MACHINE_SH5 = 0x1a8
+ IMAGE_FILE_MACHINE_THUMB = 0x1c2
+ IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169
+)
diff --git a/libgo/go/debug/pe/testdata/gcc-386-mingw-exec b/libgo/go/debug/pe/testdata/gcc-386-mingw-exec
new file mode 100644
index 000000000..4b808d043
--- /dev/null
+++ b/libgo/go/debug/pe/testdata/gcc-386-mingw-exec
Binary files differ
diff --git a/libgo/go/debug/pe/testdata/gcc-386-mingw-obj b/libgo/go/debug/pe/testdata/gcc-386-mingw-obj
new file mode 100644
index 000000000..0c84d898d
--- /dev/null
+++ b/libgo/go/debug/pe/testdata/gcc-386-mingw-obj
Binary files differ
diff --git a/libgo/go/debug/pe/testdata/hello.c b/libgo/go/debug/pe/testdata/hello.c
new file mode 100644
index 000000000..a689d3644
--- /dev/null
+++ b/libgo/go/debug/pe/testdata/hello.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int
+main(void)
+{
+ printf("hello, world\n");
+ return 0;
+}
diff --git a/libgo/go/debug/proc/proc.go b/libgo/go/debug/proc/proc.go
new file mode 100644
index 000000000..d89649cf8
--- /dev/null
+++ b/libgo/go/debug/proc/proc.go
@@ -0,0 +1,222 @@
+// 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 proc provides a platform-independent interface for
+// tracing and controlling running processes. It supports
+// multi-threaded processes and provides typical low-level debugging
+// controls such as breakpoints, single stepping, and manipulating
+// memory and registers.
+package proc
+
+// TODO(rsc): Have to import everything that proc_linux.go
+// and proc_darwin.go do, because deps.bash only looks at
+// this file.
+import (
+ _ "container/vector"
+ _ "fmt"
+ _ "io"
+ "os"
+ _ "runtime"
+ "strconv"
+ _ "strings"
+ _ "sync"
+ _ "syscall"
+)
+
+type Word uint64
+
+// A Cause explains why a thread is stopped.
+type Cause interface {
+ String() string
+}
+
+// Regs is a set of named machine registers, including a program
+// counter, link register, and stack pointer.
+//
+// TODO(austin) There's quite a proliferation of methods here. We
+// could make a Reg interface with Get and Set and make this just PC,
+// Link, SP, Names, and Reg. We could also put Index in Reg and that
+// makes it easy to get the index of things like the PC (currently
+// there's just no way to know that). This would also let us include
+// other per-register information like how to print it.
+type Regs interface {
+ // PC returns the value of the program counter.
+ PC() Word
+
+ // SetPC sets the program counter to val.
+ SetPC(val Word) os.Error
+
+ // Link returns the link register, if any.
+ Link() Word
+
+ // SetLink sets the link register to val.
+ SetLink(val Word) os.Error
+
+ // SP returns the value of the stack pointer.
+ SP() Word
+
+ // SetSP sets the stack pointer register to val.
+ SetSP(val Word) os.Error
+
+ // Names returns the names of all of the registers.
+ Names() []string
+
+ // Get returns the value of a register, where i corresponds to
+ // the index of the register's name in the array returned by
+ // Names.
+ Get(i int) Word
+
+ // Set sets the value of a register.
+ Set(i int, val Word) os.Error
+}
+
+// Thread is a thread in the process being traced.
+type Thread interface {
+ // Step steps this thread by a single instruction. The thread
+ // must be stopped. If the thread is currently stopped on a
+ // breakpoint, this will step over the breakpoint.
+ //
+ // XXX What if it's stopped because of a signal?
+ Step() os.Error
+
+ // Stopped returns the reason that this thread is stopped. It
+ // is an error is the thread not stopped.
+ Stopped() (Cause, os.Error)
+
+ // Regs retrieves the current register values from this
+ // thread. The thread must be stopped.
+ Regs() (Regs, os.Error)
+
+ // Peek reads len(out) bytes from the address addr in this
+ // thread into out. The thread must be stopped. It returns
+ // the number of bytes successfully read. If an error occurs,
+ // such as attempting to read unmapped memory, this count
+ // could be short and an error will be returned. If this does
+ // encounter unmapped memory, it will read up to the byte
+ // preceding the unmapped area.
+ Peek(addr Word, out []byte) (int, os.Error)
+
+ // Poke writes b to the address addr in this thread. The
+ // thread must be stopped. It returns the number of bytes
+ // successfully written. If an error occurs, such as
+ // attempting to write to unmapped memory, this count could be
+ // short and an error will be returned. If this does
+ // encounter unmapped memory, it will write up to the byte
+ // preceding the unmapped area.
+ Poke(addr Word, b []byte) (int, os.Error)
+}
+
+// Process is a process being traced. It consists of a set of
+// threads. A process can be running, stopped, or terminated. The
+// process's state extends to all of its threads.
+type Process interface {
+ // Threads returns an array of all threads in this process.
+ Threads() []Thread
+
+ // AddBreakpoint creates a new breakpoint at program counter
+ // pc. Breakpoints can only be created when the process is
+ // stopped. It is an error if a breakpoint already exists at
+ // pc.
+ AddBreakpoint(pc Word) os.Error
+
+ // RemoveBreakpoint removes the breakpoint at the program
+ // counter pc. It is an error if no breakpoint exists at pc.
+ RemoveBreakpoint(pc Word) os.Error
+
+ // Stop stops all running threads in this process before
+ // returning.
+ Stop() os.Error
+
+ // Continue resumes execution of all threads in this process.
+ // Any thread that is stopped on a breakpoint will be stepped
+ // over that breakpoint. Any thread that is stopped because
+ // of a signal (other than SIGSTOP or SIGTRAP) will receive
+ // the pending signal.
+ Continue() os.Error
+
+ // WaitStop waits until all threads in process p are stopped
+ // as a result of some thread hitting a breakpoint, receiving
+ // a signal, creating a new thread, or exiting.
+ WaitStop() os.Error
+
+ // Detach detaches from this process. All stopped threads
+ // will be resumed.
+ Detach() os.Error
+}
+
+// Stopped is a stop cause used for threads that are stopped either by
+// user request (e.g., from the Stop method or after single stepping),
+// or that are stopped because some other thread caused the program to
+// stop.
+type Stopped struct{}
+
+func (c Stopped) String() string { return "stopped" }
+
+// Breakpoint is a stop cause resulting from a thread reaching a set
+// breakpoint.
+type Breakpoint Word
+
+// PC returns the program counter that the program is stopped at.
+func (c Breakpoint) PC() Word { return Word(c) }
+
+func (c Breakpoint) String() string {
+ return "breakpoint at 0x" + strconv.Uitob64(uint64(c.PC()), 16)
+}
+
+// Signal is a stop cause resulting from a thread receiving a signal.
+// When the process is continued, the signal will be delivered.
+type Signal string
+
+// Signal returns the signal being delivered to the thread.
+func (c Signal) Name() string { return string(c) }
+
+func (c Signal) String() string { return c.Name() }
+
+// ThreadCreate is a stop cause returned from an existing thread when
+// it creates a new thread. The new thread exists in a primordial
+// form at this point and will begin executing in earnest when the
+// process is continued.
+type ThreadCreate struct {
+ thread Thread
+}
+
+func (c *ThreadCreate) NewThread() Thread { return c.thread }
+
+func (c *ThreadCreate) String() string { return "thread create" }
+
+// ThreadExit is a stop cause resulting from a thread exiting. When
+// this cause first arises, the thread will still be in the list of
+// process threads and its registers and memory will still be
+// accessible.
+type ThreadExit struct {
+ exitStatus int
+ signal string
+}
+
+// Exited returns true if the thread exited normally.
+func (c *ThreadExit) Exited() bool { return c.exitStatus != -1 }
+
+// ExitStatus returns the exit status of the thread if it exited
+// normally or -1 otherwise.
+func (c *ThreadExit) ExitStatus() int { return c.exitStatus }
+
+// Signaled returns true if the thread was terminated by a signal.
+func (c *ThreadExit) Signaled() bool { return c.exitStatus == -1 }
+
+// StopSignal returns the signal that terminated the thread, or "" if
+// it was not terminated by a signal.
+func (c *ThreadExit) StopSignal() string { return c.signal }
+
+func (c *ThreadExit) String() string {
+ res := "thread exited "
+ switch {
+ case c.Exited():
+ res += "with status " + strconv.Itoa(c.ExitStatus())
+ case c.Signaled():
+ res += "from signal " + c.StopSignal()
+ default:
+ res += "from unknown cause"
+ }
+ return res
+}
diff --git a/libgo/go/debug/proc/proc_darwin.go b/libgo/go/debug/proc/proc_darwin.go
new file mode 100644
index 000000000..7caf3a21a
--- /dev/null
+++ b/libgo/go/debug/proc/proc_darwin.go
@@ -0,0 +1,17 @@
+// 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 proc
+
+import "os"
+
+// Process tracing is not supported on OS X yet.
+
+func Attach(pid int) (Process, os.Error) {
+ return nil, os.NewError("debug/proc not implemented on OS X")
+}
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+ return Attach(0)
+}
diff --git a/libgo/go/debug/proc/proc_freebsd.go b/libgo/go/debug/proc/proc_freebsd.go
new file mode 100644
index 000000000..f6474ce80
--- /dev/null
+++ b/libgo/go/debug/proc/proc_freebsd.go
@@ -0,0 +1,17 @@
+// 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 proc
+
+import "os"
+
+// Process tracing is not supported on FreeBSD yet.
+
+func Attach(pid int) (Process, os.Error) {
+ return nil, os.NewError("debug/proc not implemented on FreeBSD")
+}
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+ return Attach(0)
+}
diff --git a/libgo/go/debug/proc/proc_linux.go b/libgo/go/debug/proc/proc_linux.go
new file mode 100644
index 000000000..f0cc43a10
--- /dev/null
+++ b/libgo/go/debug/proc/proc_linux.go
@@ -0,0 +1,1316 @@
+// 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 proc
+
+// TODO(rsc): Imports here after to be in proc.go too in order
+// for deps.bash to get the right answer.
+import (
+ "container/vector"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+ "syscall"
+)
+
+// This is an implementation of the process tracing interface using
+// Linux's ptrace(2) interface. The implementation is multi-threaded.
+// Each attached process has an associated monitor thread, and each
+// running attached thread has an associated "wait" thread. The wait
+// thread calls wait4 on the thread's TID and reports any wait events
+// or errors via "debug events". The monitor thread consumes these
+// wait events and updates the internally maintained state of each
+// thread. All ptrace calls must run in the monitor thread, so the
+// monitor executes closures received on the debugReq channel.
+//
+// As ptrace's documentation is somewhat light, this is heavily based
+// on information gleaned from the implementation of ptrace found at
+// http://lxr.linux.no/linux+v2.6.30/kernel/ptrace.c
+// http://lxr.linux.no/linux+v2.6.30/arch/x86/kernel/ptrace.c#L854
+// as well as experimentation and examination of gdb's behavior.
+
+const (
+ trace = false
+ traceIP = false
+ traceMem = false
+)
+
+/*
+ * Thread state
+ */
+
+// Each thread can be in one of the following set of states.
+// Each state satisfies
+// isRunning() || isStopped() || isZombie() || isTerminal().
+//
+// Running threads can be sent signals and must be waited on, but they
+// cannot be inspected using ptrace.
+//
+// Stopped threads can be inspected and continued, but cannot be
+// meaningfully waited on. They can be sent signals, but the signals
+// will be queued until they are running again.
+//
+// Zombie threads cannot be inspected, continued, or sent signals (and
+// therefore they cannot be stopped), but they must be waited on.
+//
+// Terminal threads no longer exist in the OS and thus you can't do
+// anything with them.
+type threadState string
+
+const (
+ running threadState = "Running"
+ singleStepping threadState = "SingleStepping" // Transient
+ stopping threadState = "Stopping" // Transient
+ stopped threadState = "Stopped"
+ stoppedBreakpoint threadState = "StoppedBreakpoint"
+ stoppedSignal threadState = "StoppedSignal"
+ stoppedThreadCreate threadState = "StoppedThreadCreate"
+ stoppedExiting threadState = "StoppedExiting"
+ exiting threadState = "Exiting" // Transient (except main thread)
+ exited threadState = "Exited"
+ detached threadState = "Detached"
+)
+
+func (ts threadState) isRunning() bool {
+ return ts == running || ts == singleStepping || ts == stopping
+}
+
+func (ts threadState) isStopped() bool {
+ return ts == stopped || ts == stoppedBreakpoint || ts == stoppedSignal || ts == stoppedThreadCreate || ts == stoppedExiting
+}
+
+func (ts threadState) isZombie() bool { return ts == exiting }
+
+func (ts threadState) isTerminal() bool { return ts == exited || ts == detached }
+
+func (ts threadState) String() string { return string(ts) }
+
+/*
+ * Basic types
+ */
+
+// A breakpoint stores information about a single breakpoint,
+// including its program counter, the overwritten text if the
+// breakpoint is installed.
+type breakpoint struct {
+ pc uintptr
+ olddata []byte
+}
+
+func (bp *breakpoint) String() string {
+ if bp == nil {
+ return "<nil>"
+ }
+ return fmt.Sprintf("%#x", bp.pc)
+}
+
+// bpinst386 is the breakpoint instruction used on 386 and amd64.
+var bpinst386 = []byte{0xcc}
+
+// A debugEvent represents a reason a thread stopped or a wait error.
+type debugEvent struct {
+ *os.Waitmsg
+ t *thread
+ err os.Error
+}
+
+// A debugReq is a request to execute a closure in the monitor thread.
+type debugReq struct {
+ f func() os.Error
+ res chan os.Error
+}
+
+// A transitionHandler specifies a function to be called when a thread
+// changes state and a function to be called when an error occurs in
+// the monitor. Both run in the monitor thread. Before the monitor
+// invokes a handler, it removes the handler from the handler queue.
+// The handler should re-add itself if needed.
+type transitionHandler struct {
+ handle func(*thread, threadState, threadState)
+ onErr func(os.Error)
+}
+
+// A process is a Linux process, which consists of a set of threads.
+// Each running process has one monitor thread, which processes
+// messages from the debugEvents, debugReqs, and stopReq channels and
+// calls transition handlers.
+//
+// To send a message to the monitor thread, first receive from the
+// ready channel. If the ready channel returns true, the monitor is
+// still running and will accept a message. If the ready channel
+// returns false, the monitor is not running (the ready channel has
+// been closed), and the reason it is not running will be stored in err.
+type process struct {
+ pid int
+ threads map[int]*thread
+ breakpoints map[uintptr]*breakpoint
+ ready chan bool
+ debugEvents chan *debugEvent
+ debugReqs chan *debugReq
+ stopReq chan os.Error
+ transitionHandlers vector.Vector
+ err os.Error
+}
+
+// A thread represents a Linux thread in another process that is being
+// debugged. Each running thread has an associated goroutine that
+// waits for thread updates and sends them to the process monitor.
+type thread struct {
+ tid int
+ proc *process
+ // Whether to ignore the next SIGSTOP received by wait.
+ ignoreNextSigstop bool
+
+ // Thread state. Only modified via setState.
+ state threadState
+ // If state == StoppedBreakpoint
+ breakpoint *breakpoint
+ // If state == StoppedSignal or state == Exited
+ signal int
+ // If state == StoppedThreadCreate
+ newThread *thread
+ // If state == Exited
+ exitStatus int
+}
+
+/*
+ * Errors
+ */
+
+type badState struct {
+ thread *thread
+ message string
+ state threadState
+}
+
+func (e *badState) String() string {
+ return fmt.Sprintf("Thread %d %s from state %v", e.thread.tid, e.message, e.state)
+}
+
+type breakpointExistsError Word
+
+func (e breakpointExistsError) String() string {
+ return fmt.Sprintf("breakpoint already exists at PC %#x", e)
+}
+
+type noBreakpointError Word
+
+func (e noBreakpointError) String() string { return fmt.Sprintf("no breakpoint at PC %#x", e) }
+
+type newThreadError struct {
+ *os.Waitmsg
+ wantPid int
+ wantSig int
+}
+
+func (e *newThreadError) String() string {
+ return fmt.Sprintf("newThread wait wanted pid %v and signal %v, got %v and %v", e.Pid, e.StopSignal(), e.wantPid, e.wantSig)
+}
+
+type ProcessExited struct{}
+
+func (p ProcessExited) String() string { return "process exited" }
+
+/*
+ * Ptrace wrappers
+ */
+
+func (t *thread) ptracePeekText(addr uintptr, out []byte) (int, os.Error) {
+ c, err := syscall.PtracePeekText(t.tid, addr, out)
+ if traceMem {
+ fmt.Printf("peek(%#x) => %v, %v\n", addr, out, err)
+ }
+ return c, os.NewSyscallError("ptrace(PEEKTEXT)", err)
+}
+
+func (t *thread) ptracePokeText(addr uintptr, out []byte) (int, os.Error) {
+ c, err := syscall.PtracePokeText(t.tid, addr, out)
+ if traceMem {
+ fmt.Printf("poke(%#x, %v) => %v\n", addr, out, err)
+ }
+ return c, os.NewSyscallError("ptrace(POKETEXT)", err)
+}
+
+func (t *thread) ptraceGetRegs(regs *syscall.PtraceRegs) os.Error {
+ err := syscall.PtraceGetRegs(t.tid, regs)
+ return os.NewSyscallError("ptrace(GETREGS)", err)
+}
+
+func (t *thread) ptraceSetRegs(regs *syscall.PtraceRegs) os.Error {
+ err := syscall.PtraceSetRegs(t.tid, regs)
+ return os.NewSyscallError("ptrace(SETREGS)", err)
+}
+
+func (t *thread) ptraceSetOptions(options int) os.Error {
+ err := syscall.PtraceSetOptions(t.tid, options)
+ return os.NewSyscallError("ptrace(SETOPTIONS)", err)
+}
+
+func (t *thread) ptraceGetEventMsg() (uint, os.Error) {
+ msg, err := syscall.PtraceGetEventMsg(t.tid)
+ return msg, os.NewSyscallError("ptrace(GETEVENTMSG)", err)
+}
+
+func (t *thread) ptraceCont() os.Error {
+ err := syscall.PtraceCont(t.tid, 0)
+ return os.NewSyscallError("ptrace(CONT)", err)
+}
+
+func (t *thread) ptraceContWithSignal(sig int) os.Error {
+ err := syscall.PtraceCont(t.tid, sig)
+ return os.NewSyscallError("ptrace(CONT)", err)
+}
+
+func (t *thread) ptraceStep() os.Error {
+ err := syscall.PtraceSingleStep(t.tid)
+ return os.NewSyscallError("ptrace(SINGLESTEP)", err)
+}
+
+func (t *thread) ptraceDetach() os.Error {
+ err := syscall.PtraceDetach(t.tid)
+ return os.NewSyscallError("ptrace(DETACH)", err)
+}
+
+/*
+ * Logging utilties
+ */
+
+var logLock sync.Mutex
+
+func (t *thread) logTrace(format string, args ...interface{}) {
+ if !trace {
+ return
+ }
+ logLock.Lock()
+ defer logLock.Unlock()
+ fmt.Fprintf(os.Stderr, "Thread %d", t.tid)
+ if traceIP {
+ var regs syscall.PtraceRegs
+ err := t.ptraceGetRegs(&regs)
+ if err == nil {
+ fmt.Fprintf(os.Stderr, "@%x", regs.PC())
+ }
+ }
+ fmt.Fprint(os.Stderr, ": ")
+ fmt.Fprintf(os.Stderr, format, args...)
+ fmt.Fprint(os.Stderr, "\n")
+}
+
+func (t *thread) warn(format string, args ...interface{}) {
+ logLock.Lock()
+ defer logLock.Unlock()
+ fmt.Fprintf(os.Stderr, "Thread %d: WARNING ", t.tid)
+ fmt.Fprintf(os.Stderr, format, args...)
+ fmt.Fprint(os.Stderr, "\n")
+}
+
+func (p *process) logTrace(format string, args ...interface{}) {
+ if !trace {
+ return
+ }
+ logLock.Lock()
+ defer logLock.Unlock()
+ fmt.Fprintf(os.Stderr, "Process %d: ", p.pid)
+ fmt.Fprintf(os.Stderr, format, args...)
+ fmt.Fprint(os.Stderr, "\n")
+}
+
+/*
+ * State utilities
+ */
+
+// someStoppedThread returns a stopped thread from the process.
+// Returns nil if no threads are stopped.
+//
+// Must be called from the monitor thread.
+func (p *process) someStoppedThread() *thread {
+ for _, t := range p.threads {
+ if t.state.isStopped() {
+ return t
+ }
+ }
+ return nil
+}
+
+// someRunningThread returns a running thread from the process.
+// Returns nil if no threads are running.
+//
+// Must be called from the monitor thread.
+func (p *process) someRunningThread() *thread {
+ for _, t := range p.threads {
+ if t.state.isRunning() {
+ return t
+ }
+ }
+ return nil
+}
+
+/*
+ * Breakpoint utilities
+ */
+
+// installBreakpoints adds breakpoints to the attached process.
+//
+// Must be called from the monitor thread.
+func (p *process) installBreakpoints() os.Error {
+ n := 0
+ main := p.someStoppedThread()
+ for _, b := range p.breakpoints {
+ if b.olddata != nil {
+ continue
+ }
+
+ b.olddata = make([]byte, len(bpinst386))
+ _, err := main.ptracePeekText(uintptr(b.pc), b.olddata)
+ if err != nil {
+ b.olddata = nil
+ return err
+ }
+
+ _, err = main.ptracePokeText(uintptr(b.pc), bpinst386)
+ if err != nil {
+ b.olddata = nil
+ return err
+ }
+ n++
+ }
+ if n > 0 {
+ p.logTrace("installed %d/%d breakpoints", n, len(p.breakpoints))
+ }
+
+ return nil
+}
+
+// uninstallBreakpoints removes the installed breakpoints from p.
+//
+// Must be called from the monitor thread.
+func (p *process) uninstallBreakpoints() os.Error {
+ if len(p.threads) == 0 {
+ return nil
+ }
+ n := 0
+ main := p.someStoppedThread()
+ for _, b := range p.breakpoints {
+ if b.olddata == nil {
+ continue
+ }
+
+ _, err := main.ptracePokeText(uintptr(b.pc), b.olddata)
+ if err != nil {
+ return err
+ }
+ b.olddata = nil
+ n++
+ }
+ if n > 0 {
+ p.logTrace("uninstalled %d/%d breakpoints", n, len(p.breakpoints))
+ }
+
+ return nil
+}
+
+/*
+ * Debug event handling
+ */
+
+// wait waits for a wait event from this thread and sends it on the
+// debug events channel for this thread's process. This should be
+// started in its own goroutine when the attached thread enters a
+// running state. The goroutine will exit as soon as it sends a debug
+// event.
+func (t *thread) wait() {
+ for {
+ var ev debugEvent
+ ev.t = t
+ t.logTrace("beginning wait")
+ ev.Waitmsg, ev.err = os.Wait(t.tid, syscall.WALL)
+ if ev.err == nil && ev.Pid != t.tid {
+ panic(fmt.Sprint("Wait returned pid ", ev.Pid, " wanted ", t.tid))
+ }
+ if ev.StopSignal() == syscall.SIGSTOP && t.ignoreNextSigstop {
+ // Spurious SIGSTOP. See Thread.Stop().
+ t.ignoreNextSigstop = false
+ err := t.ptraceCont()
+ if err == nil {
+ continue
+ }
+ // If we failed to continue, just let
+ // the stop go through so we can
+ // update the thread's state.
+ }
+ if !<-t.proc.ready {
+ // The monitor exited
+ break
+ }
+ t.proc.debugEvents <- &ev
+ break
+ }
+}
+
+// setState sets this thread's state, starts a wait thread if
+// necessary, and invokes state transition handlers.
+//
+// Must be called from the monitor thread.
+func (t *thread) setState(newState threadState) {
+ oldState := t.state
+ t.state = newState
+ t.logTrace("state %v -> %v", oldState, newState)
+
+ if !oldState.isRunning() && (newState.isRunning() || newState.isZombie()) {
+ // Start waiting on this thread
+ go t.wait()
+ }
+
+ // Invoke state change handlers
+ handlers := t.proc.transitionHandlers
+ if handlers.Len() == 0 {
+ return
+ }
+
+ t.proc.transitionHandlers = nil
+ for _, h := range handlers {
+ h := h.(*transitionHandler)
+ h.handle(t, oldState, newState)
+ }
+}
+
+// sendSigstop sends a SIGSTOP to this thread.
+func (t *thread) sendSigstop() os.Error {
+ t.logTrace("sending SIGSTOP")
+ err := syscall.Tgkill(t.proc.pid, t.tid, syscall.SIGSTOP)
+ return os.NewSyscallError("tgkill", err)
+}
+
+// stopAsync sends SIGSTOP to all threads in state 'running'.
+//
+// Must be called from the monitor thread.
+func (p *process) stopAsync() os.Error {
+ for _, t := range p.threads {
+ if t.state == running {
+ err := t.sendSigstop()
+ if err != nil {
+ return err
+ }
+ t.setState(stopping)
+ }
+ }
+ return nil
+}
+
+// doTrap handles SIGTRAP debug events with a cause of 0. These can
+// be caused either by an installed breakpoint, a breakpoint in the
+// program text, or by single stepping.
+//
+// TODO(austin) I think we also get this on an execve syscall.
+func (ev *debugEvent) doTrap() (threadState, os.Error) {
+ t := ev.t
+
+ if t.state == singleStepping {
+ return stopped, nil
+ }
+
+ // Hit a breakpoint. Linux leaves the program counter after
+ // the breakpoint. If this is an installed breakpoint, we
+ // need to back the PC up to the breakpoint PC.
+ var regs syscall.PtraceRegs
+ err := t.ptraceGetRegs(&regs)
+ if err != nil {
+ return stopped, err
+ }
+
+ b, ok := t.proc.breakpoints[uintptr(regs.PC())-uintptr(len(bpinst386))]
+ if !ok {
+ // We must have hit a breakpoint that was actually in
+ // the program. Leave the IP where it is so we don't
+ // re-execute the breakpoint instruction. Expose the
+ // fact that we stopped with a SIGTRAP.
+ return stoppedSignal, nil
+ }
+
+ t.breakpoint = b
+ t.logTrace("at breakpoint %v, backing up PC from %#x", b, regs.PC())
+
+ regs.SetPC(uint64(b.pc))
+ err = t.ptraceSetRegs(&regs)
+ if err != nil {
+ return stopped, err
+ }
+ return stoppedBreakpoint, nil
+}
+
+// doPtraceClone handles SIGTRAP debug events with a PTRACE_EVENT_CLONE
+// cause. It initializes the new thread, adds it to the process, and
+// returns the appropriate thread state for the existing thread.
+func (ev *debugEvent) doPtraceClone() (threadState, os.Error) {
+ t := ev.t
+
+ // Get the TID of the new thread
+ tid, err := t.ptraceGetEventMsg()
+ if err != nil {
+ return stopped, err
+ }
+
+ nt, err := t.proc.newThread(int(tid), syscall.SIGSTOP, true)
+ if err != nil {
+ return stopped, err
+ }
+
+ // Remember the thread
+ t.newThread = nt
+
+ return stoppedThreadCreate, nil
+}
+
+// doPtraceExit handles SIGTRAP debug events with a PTRACE_EVENT_EXIT
+// cause. It sets up the thread's state, but does not remove it from
+// the process. A later WIFEXITED debug event will remove it from the
+// process.
+func (ev *debugEvent) doPtraceExit() (threadState, os.Error) {
+ t := ev.t
+
+ // Get exit status
+ exitStatus, err := t.ptraceGetEventMsg()
+ if err != nil {
+ return stopped, err
+ }
+ ws := syscall.WaitStatus(exitStatus)
+ t.logTrace("exited with %v", ws)
+ switch {
+ case ws.Exited():
+ t.exitStatus = ws.ExitStatus()
+ case ws.Signaled():
+ t.signal = ws.Signal()
+ }
+
+ // We still need to continue this thread and wait on this
+ // thread's WIFEXITED event. We'll delete it then.
+ return stoppedExiting, nil
+}
+
+// process handles a debug event. It modifies any thread or process
+// state as necessary, uninstalls breakpoints if necessary, and stops
+// any running threads.
+func (ev *debugEvent) process() os.Error {
+ if ev.err != nil {
+ return ev.err
+ }
+
+ t := ev.t
+ t.exitStatus = -1
+ t.signal = -1
+
+ // Decode wait status.
+ var state threadState
+ switch {
+ case ev.Stopped():
+ state = stoppedSignal
+ t.signal = ev.StopSignal()
+ t.logTrace("stopped with %v", ev)
+ if ev.StopSignal() == syscall.SIGTRAP {
+ // What caused the debug trap?
+ var err os.Error
+ switch cause := ev.TrapCause(); cause {
+ case 0:
+ // Breakpoint or single stepping
+ state, err = ev.doTrap()
+
+ case syscall.PTRACE_EVENT_CLONE:
+ state, err = ev.doPtraceClone()
+
+ case syscall.PTRACE_EVENT_EXIT:
+ state, err = ev.doPtraceExit()
+
+ default:
+ t.warn("Unknown trap cause %d", cause)
+ }
+
+ if err != nil {
+ t.setState(stopped)
+ t.warn("failed to handle trap %v: %v", ev, err)
+ }
+ }
+
+ case ev.Exited():
+ state = exited
+ t.proc.threads[t.tid] = nil, false
+ t.logTrace("exited %v", ev)
+ // We should have gotten the exit status in
+ // PTRACE_EVENT_EXIT, but just in case.
+ t.exitStatus = ev.ExitStatus()
+
+ case ev.Signaled():
+ state = exited
+ t.proc.threads[t.tid] = nil, false
+ t.logTrace("signaled %v", ev)
+ // Again, this should be redundant.
+ t.signal = ev.Signal()
+
+ default:
+ panic(fmt.Sprintf("Unexpected wait status %v", ev.Waitmsg))
+ }
+
+ // If we sent a SIGSTOP to the thread (indicated by state
+ // Stopping), we might have raced with a different type of
+ // stop. If we didn't get the stop we expected, then the
+ // SIGSTOP we sent is now queued up, so we should ignore the
+ // next one we get.
+ if t.state == stopping && ev.StopSignal() != syscall.SIGSTOP {
+ t.ignoreNextSigstop = true
+ }
+
+ // TODO(austin) If we're in state stopping and get a SIGSTOP,
+ // set state stopped instead of stoppedSignal.
+
+ t.setState(state)
+
+ if t.proc.someRunningThread() == nil {
+ // Nothing is running, uninstall breakpoints
+ return t.proc.uninstallBreakpoints()
+ }
+ // Stop any other running threads
+ return t.proc.stopAsync()
+}
+
+// onStop adds a handler for state transitions from running to
+// non-running states. The handler will be called from the monitor
+// thread.
+//
+// Must be called from the monitor thread.
+func (t *thread) onStop(handle func(), onErr func(os.Error)) {
+ // TODO(austin) This is rather inefficient for things like
+ // stepping all threads during a continue. Maybe move
+ // transitionHandlers to the thread, or have both per-thread
+ // and per-process transition handlers.
+ h := &transitionHandler{nil, onErr}
+ h.handle = func(st *thread, old, new threadState) {
+ if t == st && old.isRunning() && !new.isRunning() {
+ handle()
+ } else {
+ t.proc.transitionHandlers.Push(h)
+ }
+ }
+ t.proc.transitionHandlers.Push(h)
+}
+
+/*
+ * Event monitor
+ */
+
+// monitor handles debug events and debug requests for p, exiting when
+// there are no threads left in p.
+func (p *process) monitor() {
+ var err os.Error
+
+ // Linux requires that all ptrace calls come from the thread
+ // that originally attached. Prevent the Go scheduler from
+ // migrating us to other OS threads.
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ hadThreads := false
+ for err == nil {
+ p.ready <- true
+ select {
+ case event := <-p.debugEvents:
+ err = event.process()
+
+ case req := <-p.debugReqs:
+ req.res <- req.f()
+
+ case err = <-p.stopReq:
+ break
+ }
+
+ if len(p.threads) == 0 {
+ if err == nil && hadThreads {
+ p.logTrace("no more threads; monitor exiting")
+ err = ProcessExited{}
+ }
+ } else {
+ hadThreads = true
+ }
+ }
+
+ // Abort waiting handlers
+ // TODO(austin) How do I stop the wait threads?
+ for _, h := range p.transitionHandlers {
+ h := h.(*transitionHandler)
+ h.onErr(err)
+ }
+
+ // Indicate that the monitor cannot receive any more messages
+ p.err = err
+ close(p.ready)
+}
+
+// do executes f in the monitor thread (and, thus, atomically with
+// respect to thread state changes). f must not block.
+//
+// Must NOT be called from the monitor thread.
+func (p *process) do(f func() os.Error) os.Error {
+ if !<-p.ready {
+ return p.err
+ }
+ req := &debugReq{f, make(chan os.Error)}
+ p.debugReqs <- req
+ return <-req.res
+}
+
+// stopMonitor stops the monitor with the given error. If the monitor
+// is already stopped, does nothing.
+func (p *process) stopMonitor(err os.Error) {
+ if err == nil {
+ panic("cannot stop the monitor with no error")
+ }
+ if <-p.ready {
+ p.stopReq <- err
+ }
+}
+
+/*
+ * Public thread interface
+ */
+
+func (t *thread) Regs() (Regs, os.Error) {
+ var regs syscall.PtraceRegs
+
+ err := t.proc.do(func() os.Error {
+ if !t.state.isStopped() {
+ return &badState{t, "cannot get registers", t.state}
+ }
+ return t.ptraceGetRegs(&regs)
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ setter := func(r *syscall.PtraceRegs) os.Error {
+ return t.proc.do(func() os.Error {
+ if !t.state.isStopped() {
+ return &badState{t, "cannot get registers", t.state}
+ }
+ return t.ptraceSetRegs(r)
+ })
+ }
+ return newRegs(&regs, setter), nil
+}
+
+func (t *thread) Peek(addr Word, out []byte) (int, os.Error) {
+ var c int
+
+ err := t.proc.do(func() os.Error {
+ if !t.state.isStopped() {
+ return &badState{t, "cannot peek text", t.state}
+ }
+
+ var err os.Error
+ c, err = t.ptracePeekText(uintptr(addr), out)
+ return err
+ })
+
+ return c, err
+}
+
+func (t *thread) Poke(addr Word, out []byte) (int, os.Error) {
+ var c int
+
+ err := t.proc.do(func() os.Error {
+ if !t.state.isStopped() {
+ return &badState{t, "cannot poke text", t.state}
+ }
+
+ var err os.Error
+ c, err = t.ptracePokeText(uintptr(addr), out)
+ return err
+ })
+
+ return c, err
+}
+
+// stepAsync starts this thread single stepping. When the single step
+// is complete, it will send nil on the given channel. If an error
+// occurs while setting up the single step, it returns that error. If
+// an error occurs while waiting for the single step to complete, it
+// sends that error on the channel.
+func (t *thread) stepAsync(ready chan os.Error) os.Error {
+ if err := t.ptraceStep(); err != nil {
+ return err
+ }
+ t.setState(singleStepping)
+ t.onStop(func() { ready <- nil },
+ func(err os.Error) { ready <- err })
+ return nil
+}
+
+func (t *thread) Step() os.Error {
+ t.logTrace("Step {")
+ defer t.logTrace("}")
+
+ ready := make(chan os.Error)
+
+ err := t.proc.do(func() os.Error {
+ if !t.state.isStopped() {
+ return &badState{t, "cannot single step", t.state}
+ }
+ return t.stepAsync(ready)
+ })
+ if err != nil {
+ return err
+ }
+
+ err = <-ready
+ return err
+}
+
+// TODO(austin) We should probably get this via C's strsignal.
+var sigNames = [...]string{
+ "SIGEXIT", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL",
+ "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL",
+ "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM",
+ "SIGTERM", "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP",
+ "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU",
+ "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGPOLL",
+ "SIGPWR", "SIGSYS",
+}
+
+// sigName returns the symbolic name for the given signal number. If
+// the signal number is invalid, returns "<invalid>".
+func sigName(signal int) string {
+ if signal < 0 || signal >= len(sigNames) {
+ return "<invalid>"
+ }
+ return sigNames[signal]
+}
+
+func (t *thread) Stopped() (Cause, os.Error) {
+ var c Cause
+ err := t.proc.do(func() os.Error {
+ switch t.state {
+ case stopped:
+ c = Stopped{}
+
+ case stoppedBreakpoint:
+ c = Breakpoint(t.breakpoint.pc)
+
+ case stoppedSignal:
+ c = Signal(sigName(t.signal))
+
+ case stoppedThreadCreate:
+ c = &ThreadCreate{t.newThread}
+
+ case stoppedExiting, exiting, exited:
+ if t.signal == -1 {
+ c = &ThreadExit{t.exitStatus, ""}
+ } else {
+ c = &ThreadExit{t.exitStatus, sigName(t.signal)}
+ }
+
+ default:
+ return &badState{t, "cannot get stop cause", t.state}
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return c, nil
+}
+
+func (p *process) Threads() []Thread {
+ var res []Thread
+
+ p.do(func() os.Error {
+ res = make([]Thread, len(p.threads))
+ i := 0
+ for _, t := range p.threads {
+ // Exclude zombie threads.
+ st := t.state
+ if st == exiting || st == exited || st == detached {
+ continue
+ }
+
+ res[i] = t
+ i++
+ }
+ res = res[0:i]
+ return nil
+ })
+ return res
+}
+
+func (p *process) AddBreakpoint(pc Word) os.Error {
+ return p.do(func() os.Error {
+ if t := p.someRunningThread(); t != nil {
+ return &badState{t, "cannot add breakpoint", t.state}
+ }
+ if _, ok := p.breakpoints[uintptr(pc)]; ok {
+ return breakpointExistsError(pc)
+ }
+ p.breakpoints[uintptr(pc)] = &breakpoint{pc: uintptr(pc)}
+ return nil
+ })
+}
+
+func (p *process) RemoveBreakpoint(pc Word) os.Error {
+ return p.do(func() os.Error {
+ if t := p.someRunningThread(); t != nil {
+ return &badState{t, "cannot remove breakpoint", t.state}
+ }
+ if _, ok := p.breakpoints[uintptr(pc)]; !ok {
+ return noBreakpointError(pc)
+ }
+ p.breakpoints[uintptr(pc)] = nil, false
+ return nil
+ })
+}
+
+func (p *process) Continue() os.Error {
+ // Single step any threads that are stopped at breakpoints so
+ // we can reinstall breakpoints.
+ var ready chan os.Error
+ count := 0
+
+ err := p.do(func() os.Error {
+ // We make the ready channel big enough to hold all
+ // ready message so we don't jam up the monitor if we
+ // stop listening (e.g., if there's an error).
+ ready = make(chan os.Error, len(p.threads))
+
+ for _, t := range p.threads {
+ if !t.state.isStopped() {
+ continue
+ }
+
+ // We use the breakpoint map directly here
+ // instead of checking the stop cause because
+ // it could have been stopped at a breakpoint
+ // for some other reason, or the breakpoint
+ // could have been added since it was stopped.
+ var regs syscall.PtraceRegs
+ err := t.ptraceGetRegs(&regs)
+ if err != nil {
+ return err
+ }
+ if b, ok := p.breakpoints[uintptr(regs.PC())]; ok {
+ t.logTrace("stepping over breakpoint %v", b)
+ if err := t.stepAsync(ready); err != nil {
+ return err
+ }
+ count++
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ p.stopMonitor(err)
+ return err
+ }
+
+ // Wait for single stepping threads
+ for count > 0 {
+ err = <-ready
+ if err != nil {
+ p.stopMonitor(err)
+ return err
+ }
+ count--
+ }
+
+ // Continue all threads
+ err = p.do(func() os.Error {
+ if err := p.installBreakpoints(); err != nil {
+ return err
+ }
+
+ for _, t := range p.threads {
+ var err os.Error
+ switch {
+ case !t.state.isStopped():
+ continue
+
+ case t.state == stoppedSignal && t.signal != syscall.SIGSTOP && t.signal != syscall.SIGTRAP:
+ t.logTrace("continuing with signal %d", t.signal)
+ err = t.ptraceContWithSignal(t.signal)
+
+ default:
+ t.logTrace("continuing")
+ err = t.ptraceCont()
+ }
+ if err != nil {
+ return err
+ }
+ if t.state == stoppedExiting {
+ t.setState(exiting)
+ } else {
+ t.setState(running)
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ // TODO(austin) Do we need to stop the monitor with
+ // this error atomically with the do-routine above?
+ p.stopMonitor(err)
+ return err
+ }
+
+ return nil
+}
+
+func (p *process) WaitStop() os.Error {
+ // We need a non-blocking ready channel for the case where all
+ // threads are already stopped.
+ ready := make(chan os.Error, 1)
+
+ err := p.do(func() os.Error {
+ // Are all of the threads already stopped?
+ if p.someRunningThread() == nil {
+ ready <- nil
+ return nil
+ }
+
+ // Monitor state transitions
+ h := &transitionHandler{}
+ h.handle = func(st *thread, old, new threadState) {
+ if !new.isRunning() {
+ if p.someRunningThread() == nil {
+ ready <- nil
+ return
+ }
+ }
+ p.transitionHandlers.Push(h)
+ }
+ h.onErr = func(err os.Error) { ready <- err }
+ p.transitionHandlers.Push(h)
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+
+ return <-ready
+}
+
+func (p *process) Stop() os.Error {
+ err := p.do(func() os.Error { return p.stopAsync() })
+ if err != nil {
+ return err
+ }
+
+ return p.WaitStop()
+}
+
+func (p *process) Detach() os.Error {
+ if err := p.Stop(); err != nil {
+ return err
+ }
+
+ err := p.do(func() os.Error {
+ if err := p.uninstallBreakpoints(); err != nil {
+ return err
+ }
+
+ for pid, t := range p.threads {
+ if t.state.isStopped() {
+ // We can't detach from zombies.
+ if err := t.ptraceDetach(); err != nil {
+ return err
+ }
+ }
+ t.setState(detached)
+ p.threads[pid] = nil, false
+ }
+ return nil
+ })
+ // TODO(austin) Wait for monitor thread to exit?
+ return err
+}
+
+// newThread creates a new thread object and waits for its initial
+// signal. If cloned is true, this thread was cloned from a thread we
+// are already attached to.
+//
+// Must be run from the monitor thread.
+func (p *process) newThread(tid int, signal int, cloned bool) (*thread, os.Error) {
+ t := &thread{tid: tid, proc: p, state: stopped}
+
+ // Get the signal from the thread
+ // TODO(austin) Thread might already be stopped if we're attaching.
+ w, err := os.Wait(tid, syscall.WALL)
+ if err != nil {
+ return nil, err
+ }
+ if w.Pid != tid || w.StopSignal() != signal {
+ return nil, &newThreadError{w, tid, signal}
+ }
+
+ if !cloned {
+ err = t.ptraceSetOptions(syscall.PTRACE_O_TRACECLONE | syscall.PTRACE_O_TRACEEXIT)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ p.threads[tid] = t
+
+ return t, nil
+}
+
+// attachThread attaches a running thread to the process.
+//
+// Must NOT be run from the monitor thread.
+func (p *process) attachThread(tid int) (*thread, os.Error) {
+ p.logTrace("attaching to thread %d", tid)
+ var thr *thread
+ err := p.do(func() os.Error {
+ errno := syscall.PtraceAttach(tid)
+ if errno != 0 {
+ return os.NewSyscallError("ptrace(ATTACH)", errno)
+ }
+
+ var err os.Error
+ thr, err = p.newThread(tid, syscall.SIGSTOP, false)
+ return err
+ })
+ return thr, err
+}
+
+// attachAllThreads attaches to all threads in a process.
+func (p *process) attachAllThreads() os.Error {
+ taskPath := "/proc/" + strconv.Itoa(p.pid) + "/task"
+ taskDir, err := os.Open(taskPath, os.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer taskDir.Close()
+
+ // We stop threads as we attach to them; however, because new
+ // threads can appear while we're looping over all of them, we
+ // have to repeatly scan until we know we're attached to all
+ // of them.
+ for again := true; again; {
+ again = false
+
+ tids, err := taskDir.Readdirnames(-1)
+ if err != nil {
+ return err
+ }
+
+ for _, tidStr := range tids {
+ tid, err := strconv.Atoi(tidStr)
+ if err != nil {
+ return err
+ }
+ if _, ok := p.threads[tid]; ok {
+ continue
+ }
+
+ _, err = p.attachThread(tid)
+ if err != nil {
+ // There could have been a race, or
+ // this process could be a zobmie.
+ statFile, err2 := ioutil.ReadFile(taskPath + "/" + tidStr + "/stat")
+ if err2 != nil {
+ switch err2 := err2.(type) {
+ case *os.PathError:
+ if err2.Error == os.ENOENT {
+ // Raced with thread exit
+ p.logTrace("raced with thread %d exit", tid)
+ continue
+ }
+ }
+ // Return the original error
+ return err
+ }
+
+ statParts := strings.Split(string(statFile), " ", 4)
+ if len(statParts) > 2 && statParts[2] == "Z" {
+ // tid is a zombie
+ p.logTrace("thread %d is a zombie", tid)
+ continue
+ }
+
+ // Return the original error
+ return err
+ }
+ again = true
+ }
+ }
+
+ return nil
+}
+
+// newProcess creates a new process object and starts its monitor thread.
+func newProcess(pid int) *process {
+ p := &process{
+ pid: pid,
+ threads: make(map[int]*thread),
+ breakpoints: make(map[uintptr]*breakpoint),
+ ready: make(chan bool, 1),
+ debugEvents: make(chan *debugEvent),
+ debugReqs: make(chan *debugReq),
+ stopReq: make(chan os.Error),
+ }
+
+ go p.monitor()
+
+ return p
+}
+
+// Attach attaches to process pid and stops all of its threads.
+func Attach(pid int) (Process, os.Error) {
+ p := newProcess(pid)
+
+ // Attach to all threads
+ err := p.attachAllThreads()
+ if err != nil {
+ p.Detach()
+ // TODO(austin) Detach stopped the monitor already
+ //p.stopMonitor(err);
+ return nil, err
+ }
+
+ return p, nil
+}
+
+// ForkExec forks the current process and execs argv0, stopping the
+// new process after the exec syscall. See os.ForkExec for additional
+// details.
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+ p := newProcess(-1)
+
+ // Create array of integer (system) fds.
+ intfd := make([]int, len(fd))
+ for i, f := range fd {
+ if f == nil {
+ intfd[i] = -1
+ } else {
+ intfd[i] = f.Fd()
+ }
+ }
+
+ // Fork from the monitor thread so we get the right tracer pid.
+ err := p.do(func() os.Error {
+ pid, errno := syscall.PtraceForkExec(argv0, argv, envv, dir, intfd)
+ if errno != 0 {
+ return &os.PathError{"fork/exec", argv0, os.Errno(errno)}
+ }
+ p.pid = pid
+
+ // The process will raise SIGTRAP when it reaches execve.
+ _, err := p.newThread(pid, syscall.SIGTRAP, false)
+ return err
+ })
+ if err != nil {
+ p.stopMonitor(err)
+ return nil, err
+ }
+
+ return p, nil
+}
diff --git a/libgo/go/debug/proc/proc_rtems.go b/libgo/go/debug/proc/proc_rtems.go
new file mode 100644
index 000000000..5311a63ba
--- /dev/null
+++ b/libgo/go/debug/proc/proc_rtems.go
@@ -0,0 +1,17 @@
+// 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 proc
+
+import "os"
+
+// Process tracing is not supported on RTEMS yet.
+
+func Attach(pid int) (Process, os.Error) {
+ return nil, os.NewError("debug/proc not implemented on RTEMS")
+}
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+ return Attach(0)
+}
diff --git a/libgo/go/debug/proc/proc_solaris.go b/libgo/go/debug/proc/proc_solaris.go
new file mode 100644
index 000000000..a72c59237
--- /dev/null
+++ b/libgo/go/debug/proc/proc_solaris.go
@@ -0,0 +1,17 @@
+// 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 proc
+
+import "os"
+
+// Process tracing is not supported on Solaris yet.
+
+func Attach(pid int) (Process, os.Error) {
+ return nil, os.NewError("debug/proc not implemented on Solaris")
+}
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+ return Attach(0)
+}
diff --git a/libgo/go/debug/proc/proc_windows.go b/libgo/go/debug/proc/proc_windows.go
new file mode 100644
index 000000000..dc22faef8
--- /dev/null
+++ b/libgo/go/debug/proc/proc_windows.go
@@ -0,0 +1,17 @@
+// 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 proc
+
+import "os"
+
+// Process tracing is not supported on windows yet.
+
+func Attach(pid int) (Process, os.Error) {
+ return nil, os.NewError("debug/proc not implemented on windows")
+}
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+ return Attach(0)
+}
diff --git a/libgo/go/debug/proc/ptrace-nptl.txt b/libgo/go/debug/proc/ptrace-nptl.txt
new file mode 100644
index 000000000..62cbf7700
--- /dev/null
+++ b/libgo/go/debug/proc/ptrace-nptl.txt
@@ -0,0 +1,132 @@
+// 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.
+
+ptrace and NTPL, the missing manpage
+
+== Signals ==
+
+A signal sent to a ptrace'd process or thread causes only the thread
+that receives it to stop and report to the attached process.
+
+Use tgkill to target a signal (for example, SIGSTOP) at a particular
+thread. If you use kill, the signal could be delivered to another
+thread in the same process.
+
+Note that SIGSTOP differs from its usual behavior when a process is
+being traced. Usually, a SIGSTOP sent to any thread in a thread group
+will stop all threads in the thread group. When a thread is traced,
+however, a SIGSTOP affects only the receiving thread (and any other
+threads in the thread group that are not traced).
+
+SIGKILL behaves like it does for non-traced processes. It affects all
+threads in the process and terminates them without the WSTOPSIG event
+generated by other signals. However, if PTRACE_O_TRACEEXIT is set,
+the attached process will still receive PTRACE_EVENT_EXIT events
+before receiving WIFSIGNALED events.
+
+See "Following thread death" for a caveat regarding signal delivery to
+zombie threads.
+
+== Waiting on threads ==
+
+Cloned threads in ptrace'd processes are treated similarly to cloned
+threads in your own process. Thus, you must use the __WALL option in
+order to receive notifications from threads created by the child
+process. Similarly, the __WCLONE option will wait only on
+notifications from threads created by the child process and *not* on
+notifications from the initial child thread.
+
+Even when waiting on a specific thread's PID using waitpid or similar,
+__WALL or __WCLONE is necessary or waitpid will return ECHILD.
+
+== Attaching to existing threads ==
+
+libthread_db (which gdb uses), attaches to existing threads by pulling
+the pthread data structures out of the traced process. The much
+easier way is to traverse the /proc/PID/task directory, though it's
+unclear how the semantics of these two approaches differ.
+
+Unfortunately, if the main thread has exited (but the overall process
+has not), it sticks around as a zombie process. This zombie will
+appear in the /proc/PID/task directory, but trying to attach to it
+will yield EPERM. In this case, the third field of the
+/proc/PID/task/PID/stat file will be "Z". Attempting to open the stat
+file is also a convenient way to detect races between listing the task
+directory and the thread exiting. Coincidentally, gdb will simply
+fail to attach to a process whose main thread is a zombie.
+
+Because new threads may be created while the debugger is in the
+process of attaching to existing threads, the debugger must repeatedly
+re-list the task directory until it has attached to (and thus stopped)
+every thread listed.
+
+In order to follow new threads created by existing threads,
+PTRACE_O_TRACECLONE must be set on each thread attached to.
+
+== Following new threads ==
+
+With the child process stopped, use PTRACE_SETOPTIONS to set the
+PTRACE_O_TRACECLONE option. This option is per-thread, and thus must
+be set on each existing thread individually. When an existing thread
+with PTRACE_O_TRACECLONE set spawns a new thread, the existing thread
+will stop with (SIGTRAP | PTRACE_EVENT_CLONE << 8) and the PID of the
+new thread can be retrieved with PTRACE_GETEVENTMSG on the creating
+thread. At this time, the new thread will exist, but will initially
+be stopped with a SIGSTOP. The new thread will automatically be
+traced and will inherit the PTRACE_O_TRACECLONE option from its
+parent. The attached process should wait on the new thread to receive
+the SIGSTOP notification.
+
+When using waitpid(-1, ...), don't rely on the parent thread reporting
+a SIGTRAP before receiving the SIGSTOP from the new child thread.
+
+Without PTRACE_O_TRACECLONE, newly cloned threads will not be
+ptrace'd. As a result, signals received by new threads will be
+handled in the usual way, which may affect the parent and in turn
+appear to the attached process, but attributed to the parent (possibly
+in unexpected ways).
+
+== Following thread death ==
+
+If any thread with the PTRACE_O_TRACEEXIT option set exits (either by
+returning or pthread_exit'ing), the tracing process will receive an
+immediate PTRACE_EVENT_EXIT. At this point, the thread will still
+exist. The exit status, encoded as for wait, can be queried using
+PTRACE_GETEVENTMSG on the exiting thread's PID. The thread should be
+continued so it can actually exit, after which its wait behavior is
+the same as for a thread without the PTRACE_O_TRACEEXIT option.
+
+If a non-main thread exits (either by returning or pthread_exit'ing),
+its corresponding process will also exit, producing a WIFEXITED event
+(after the process is continued from a possible PTRACE_EVENT_EXIT
+event). It is *not* necessary for another thread to ptrace_join for
+this to happen.
+
+If the main thread exits by returning, then all threads will exit,
+first generating a PTRACE_EVENT_EXIT event for each thread if
+appropriate, then producing a WIFEXITED event for each thread.
+
+If the main thread exits using pthread_exit, then it enters a
+non-waitable zombie state. It will still produce an immediate
+PTRACE_O_TRACEEXIT event, but the WIFEXITED event will be delayed
+until the entire process exits. This state exists so that shells
+don't think the process is done until all of the threads have exited.
+Unfortunately, signals cannot be delivered to non-waitable zombies.
+Most notably, SIGSTOP cannot be delivered; as a result, when you
+broadcast SIGSTOP to all of the threads, you must not wait for
+non-waitable zombies to stop. Furthermore, any ptrace command on a
+non-waitable zombie, including PTRACE_DETACH, will return ESRCH.
+
+== Multi-threaded debuggers ==
+
+If the debugger itself is multi-threaded, ptrace calls must come from
+the same thread that originally attached to the remote thread. The
+kernel simply compares the PID of the caller of ptrace against the
+tracer PID of the process passed to ptrace. Because each debugger
+thread has a different PID, calling ptrace from a different thread
+might as well be calling it from a different process and the kernel
+will return ESRCH.
+
+wait, on the other hand, does not have this restriction. Any debugger
+thread can wait on any thread in the attached process.
diff --git a/libgo/go/debug/proc/regs_darwin_386.go b/libgo/go/debug/proc/regs_darwin_386.go
new file mode 100644
index 000000000..60c9ac719
--- /dev/null
+++ b/libgo/go/debug/proc/regs_darwin_386.go
@@ -0,0 +1,5 @@
+// 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 proc
diff --git a/libgo/go/debug/proc/regs_darwin_amd64.go b/libgo/go/debug/proc/regs_darwin_amd64.go
new file mode 100644
index 000000000..60c9ac719
--- /dev/null
+++ b/libgo/go/debug/proc/regs_darwin_amd64.go
@@ -0,0 +1,5 @@
+// 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 proc
diff --git a/libgo/go/debug/proc/regs_freebsd_386.go b/libgo/go/debug/proc/regs_freebsd_386.go
new file mode 100644
index 000000000..60c9ac719
--- /dev/null
+++ b/libgo/go/debug/proc/regs_freebsd_386.go
@@ -0,0 +1,5 @@
+// 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 proc
diff --git a/libgo/go/debug/proc/regs_freebsd_amd64.go b/libgo/go/debug/proc/regs_freebsd_amd64.go
new file mode 100644
index 000000000..60c9ac719
--- /dev/null
+++ b/libgo/go/debug/proc/regs_freebsd_amd64.go
@@ -0,0 +1,5 @@
+// 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 proc
diff --git a/libgo/go/debug/proc/regs_linux_386.go b/libgo/go/debug/proc/regs_linux_386.go
new file mode 100644
index 000000000..b4a9769db
--- /dev/null
+++ b/libgo/go/debug/proc/regs_linux_386.go
@@ -0,0 +1,143 @@
+// 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 proc
+
+import (
+ "os"
+ "strconv"
+ "syscall"
+)
+
+type _386Regs struct {
+ syscall.PtraceRegs
+ setter func(*syscall.PtraceRegs) os.Error
+}
+
+var names = []string{
+ "eax",
+ "ebx",
+ "ecx",
+ "edx",
+ "esi",
+ "edi",
+ "ebp",
+ "esp",
+ "eip",
+ "eflags",
+ "cs",
+ "ss",
+ "ds",
+ "es",
+ "fs",
+ "gs",
+}
+
+func (r *_386Regs) PC() Word { return Word(r.Eip) }
+
+func (r *_386Regs) SetPC(val Word) os.Error {
+ r.Eip = int32(val)
+ return r.setter(&r.PtraceRegs)
+}
+
+func (r *_386Regs) Link() Word {
+ // TODO(austin)
+ panic("No link register")
+}
+
+func (r *_386Regs) SetLink(val Word) os.Error { panic("No link register") }
+
+func (r *_386Regs) SP() Word { return Word(r.Esp) }
+
+func (r *_386Regs) SetSP(val Word) os.Error {
+ r.Esp = int32(val)
+ return r.setter(&r.PtraceRegs)
+}
+
+func (r *_386Regs) Names() []string { return names }
+
+func (r *_386Regs) Get(i int) Word {
+ switch i {
+ case 0:
+ return Word(uint32(r.Eax))
+ case 1:
+ return Word(uint32(r.Ebx))
+ case 2:
+ return Word(uint32(r.Ecx))
+ case 3:
+ return Word(uint32(r.Edx))
+ case 4:
+ return Word(uint32(r.Esi))
+ case 5:
+ return Word(uint32(r.Edi))
+ case 6:
+ return Word(uint32(r.Ebp))
+ case 7:
+ return Word(uint32(r.Esp))
+ case 8:
+ return Word(uint32(r.Eip))
+ case 9:
+ return Word(uint32(r.Eflags))
+ case 10:
+ return Word(r.Xcs)
+ case 11:
+ return Word(r.Xss)
+ case 12:
+ return Word(r.Xds)
+ case 13:
+ return Word(r.Xes)
+ case 14:
+ return Word(r.Xfs)
+ case 15:
+ return Word(r.Xgs)
+ }
+ panic("invalid register index " + strconv.Itoa(i))
+}
+
+func (r *_386Regs) Set(i int, val Word) os.Error {
+ switch i {
+ case 0:
+ r.Eax = int32(val)
+ case 1:
+ r.Ebx = int32(val)
+ case 2:
+ r.Ecx = int32(val)
+ case 3:
+ r.Edx = int32(val)
+ case 4:
+ r.Esi = int32(val)
+ case 5:
+ r.Edi = int32(val)
+ case 6:
+ r.Ebp = int32(val)
+ case 7:
+ r.Esp = int32(val)
+ case 8:
+ r.Eip = int32(val)
+ case 9:
+ r.Eflags = int32(val)
+ case 10:
+ r.Xcs = int32(val)
+ case 11:
+ r.Xss = int32(val)
+ case 12:
+ r.Xds = int32(val)
+ case 13:
+ r.Xes = int32(val)
+ case 14:
+ r.Xfs = int32(val)
+ case 15:
+ r.Xgs = int32(val)
+ default:
+ panic("invalid register index " + strconv.Itoa(i))
+ }
+ return r.setter(&r.PtraceRegs)
+}
+
+func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs {
+ res := _386Regs{}
+ res.PtraceRegs = *regs
+ res.setter = setter
+ return &res
+}
diff --git a/libgo/go/debug/proc/regs_linux_amd64.go b/libgo/go/debug/proc/regs_linux_amd64.go
new file mode 100644
index 000000000..381be29b1
--- /dev/null
+++ b/libgo/go/debug/proc/regs_linux_amd64.go
@@ -0,0 +1,191 @@
+// 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 proc
+
+import (
+ "os"
+ "strconv"
+ "syscall"
+)
+
+type amd64Regs struct {
+ syscall.PtraceRegs
+ setter func(*syscall.PtraceRegs) os.Error
+}
+
+var names = [...]string{
+ "rax",
+ "rbx",
+ "rcx",
+ "rdx",
+ "rsi",
+ "rdi",
+ "rbp",
+ "rsp",
+ "r8",
+ "r9",
+ "r10",
+ "r11",
+ "r12",
+ "r13",
+ "r14",
+ "r15",
+ "rip",
+ "eflags",
+ "cs",
+ "ss",
+ "ds",
+ "es",
+ "fs",
+ "gs",
+
+ // PtraceRegs contains these registers, but I don't think
+ // they're actually meaningful.
+ //"orig_rax",
+ //"fs_base",
+ //"gs_base",
+}
+
+func (r *amd64Regs) PC() Word { return Word(r.Rip) }
+
+func (r *amd64Regs) SetPC(val Word) os.Error {
+ r.Rip = uint64(val)
+ return r.setter(&r.PtraceRegs)
+}
+
+func (r *amd64Regs) Link() Word {
+ // TODO(austin)
+ panic("No link register")
+}
+
+func (r *amd64Regs) SetLink(val Word) os.Error {
+ panic("No link register")
+}
+
+func (r *amd64Regs) SP() Word { return Word(r.Rsp) }
+
+func (r *amd64Regs) SetSP(val Word) os.Error {
+ r.Rsp = uint64(val)
+ return r.setter(&r.PtraceRegs)
+}
+
+func (r *amd64Regs) Names() []string { return names[0:] }
+
+func (r *amd64Regs) Get(i int) Word {
+ switch i {
+ case 0:
+ return Word(r.Rax)
+ case 1:
+ return Word(r.Rbx)
+ case 2:
+ return Word(r.Rcx)
+ case 3:
+ return Word(r.Rdx)
+ case 4:
+ return Word(r.Rsi)
+ case 5:
+ return Word(r.Rdi)
+ case 6:
+ return Word(r.Rbp)
+ case 7:
+ return Word(r.Rsp)
+ case 8:
+ return Word(r.R8)
+ case 9:
+ return Word(r.R9)
+ case 10:
+ return Word(r.R10)
+ case 11:
+ return Word(r.R11)
+ case 12:
+ return Word(r.R12)
+ case 13:
+ return Word(r.R13)
+ case 14:
+ return Word(r.R14)
+ case 15:
+ return Word(r.R15)
+ case 16:
+ return Word(r.Rip)
+ case 17:
+ return Word(r.Eflags)
+ case 18:
+ return Word(r.Cs)
+ case 19:
+ return Word(r.Ss)
+ case 20:
+ return Word(r.Ds)
+ case 21:
+ return Word(r.Es)
+ case 22:
+ return Word(r.Fs)
+ case 23:
+ return Word(r.Gs)
+ }
+ panic("invalid register index " + strconv.Itoa(i))
+}
+
+func (r *amd64Regs) Set(i int, val Word) os.Error {
+ switch i {
+ case 0:
+ r.Rax = uint64(val)
+ case 1:
+ r.Rbx = uint64(val)
+ case 2:
+ r.Rcx = uint64(val)
+ case 3:
+ r.Rdx = uint64(val)
+ case 4:
+ r.Rsi = uint64(val)
+ case 5:
+ r.Rdi = uint64(val)
+ case 6:
+ r.Rbp = uint64(val)
+ case 7:
+ r.Rsp = uint64(val)
+ case 8:
+ r.R8 = uint64(val)
+ case 9:
+ r.R9 = uint64(val)
+ case 10:
+ r.R10 = uint64(val)
+ case 11:
+ r.R11 = uint64(val)
+ case 12:
+ r.R12 = uint64(val)
+ case 13:
+ r.R13 = uint64(val)
+ case 14:
+ r.R14 = uint64(val)
+ case 15:
+ r.R15 = uint64(val)
+ case 16:
+ r.Rip = uint64(val)
+ case 17:
+ r.Eflags = uint64(val)
+ case 18:
+ r.Cs = uint64(val)
+ case 19:
+ r.Ss = uint64(val)
+ case 20:
+ r.Ds = uint64(val)
+ case 21:
+ r.Es = uint64(val)
+ case 22:
+ r.Fs = uint64(val)
+ case 23:
+ r.Gs = uint64(val)
+ default:
+ panic("invalid register index " + strconv.Itoa(i))
+ }
+ return r.setter(&r.PtraceRegs)
+}
+
+func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs {
+ res := amd64Regs{}
+ res.PtraceRegs = *regs
+ res.setter = setter
+ return &res
+}
diff --git a/libgo/go/debug/proc/regs_linux_arm.go b/libgo/go/debug/proc/regs_linux_arm.go
new file mode 100644
index 000000000..ec78cbcf2
--- /dev/null
+++ b/libgo/go/debug/proc/regs_linux_arm.go
@@ -0,0 +1,39 @@
+// 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 proc
+
+import (
+ "os"
+ "syscall"
+)
+
+// TODO(kaib): add support
+
+type armRegs struct{}
+
+func (r *armRegs) PC() Word { return Word(0) }
+
+func (r *armRegs) SetPC(val Word) os.Error { return nil }
+
+func (r *armRegs) Link() Word { return Word(0) }
+
+func (r *armRegs) SetLink(val Word) os.Error { return nil }
+
+func (r *armRegs) SP() Word { return Word(0) }
+
+func (r *armRegs) SetSP(val Word) os.Error { return nil }
+
+func (r *armRegs) Names() []string { return nil }
+
+func (r *armRegs) Get(i int) Word { return Word(0) }
+
+func (r *armRegs) Set(i int, val Word) os.Error {
+ return nil
+}
+
+func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs {
+ res := armRegs{}
+ return &res
+}
diff --git a/libgo/go/debug/proc/regs_windows_386.go b/libgo/go/debug/proc/regs_windows_386.go
new file mode 100644
index 000000000..60c9ac719
--- /dev/null
+++ b/libgo/go/debug/proc/regs_windows_386.go
@@ -0,0 +1,5 @@
+// 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 proc
diff --git a/libgo/go/debug/proc/regs_windows_amd64.go b/libgo/go/debug/proc/regs_windows_amd64.go
new file mode 100644
index 000000000..60c9ac719
--- /dev/null
+++ b/libgo/go/debug/proc/regs_windows_amd64.go
@@ -0,0 +1,5 @@
+// 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 proc
diff --git a/libgo/go/ebnf/ebnf.go b/libgo/go/ebnf/ebnf.go
new file mode 100644
index 000000000..e5aabd582
--- /dev/null
+++ b/libgo/go/ebnf/ebnf.go
@@ -0,0 +1,248 @@
+// 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 library for EBNF grammars. The input is text ([]byte) satisfying
+// the following grammar (represented itself in EBNF):
+//
+// Production = name "=" Expression "." .
+// Expression = Alternative { "|" Alternative } .
+// Alternative = Term { Term } .
+// Term = name | token [ "..." token ] | Group | Option | Repetition .
+// Group = "(" Expression ")" .
+// Option = "[" Expression "]" .
+// Repetition = "{" Expression "}" .
+//
+// A name is a Go identifier, a token is a Go string, and comments
+// and white space follow the same rules as for the Go language.
+// Production names starting with an uppercase Unicode letter denote
+// non-terminal productions (i.e., productions which allow white-space
+// and comments between tokens); all other production names denote
+// lexical productions.
+//
+package ebnf
+
+import (
+ "go/scanner"
+ "go/token"
+ "os"
+ "unicode"
+ "utf8"
+)
+
+
+// ----------------------------------------------------------------------------
+// Internal representation
+
+type (
+ // An Expression node represents a production expression.
+ Expression interface {
+ // Pos is the position of the first character of the syntactic construct
+ Pos() token.Pos
+ }
+
+ // An Alternative node represents a non-empty list of alternative expressions.
+ Alternative []Expression // x | y | z
+
+ // A Sequence node represents a non-empty list of sequential expressions.
+ Sequence []Expression // x y z
+
+ // A Name node represents a production name.
+ Name struct {
+ StringPos token.Pos
+ String string
+ }
+
+ // A Token node represents a literal.
+ Token struct {
+ StringPos token.Pos
+ String string
+ }
+
+ // A List node represents a range of characters.
+ Range struct {
+ Begin, End *Token // begin ... end
+ }
+
+ // A Group node represents a grouped expression.
+ Group struct {
+ Lparen token.Pos
+ Body Expression // (body)
+ }
+
+ // An Option node represents an optional expression.
+ Option struct {
+ Lbrack token.Pos
+ Body Expression // [body]
+ }
+
+ // A Repetition node represents a repeated expression.
+ Repetition struct {
+ Lbrace token.Pos
+ Body Expression // {body}
+ }
+
+ // A Production node represents an EBNF production.
+ Production struct {
+ Name *Name
+ Expr Expression
+ }
+
+ // A Grammar is a set of EBNF productions. The map
+ // is indexed by production name.
+ //
+ Grammar map[string]*Production
+)
+
+
+func (x Alternative) Pos() token.Pos { return x[0].Pos() } // the parser always generates non-empty Alternative
+func (x Sequence) Pos() token.Pos { return x[0].Pos() } // the parser always generates non-empty Sequences
+func (x *Name) Pos() token.Pos { return x.StringPos }
+func (x *Token) Pos() token.Pos { return x.StringPos }
+func (x *Range) Pos() token.Pos { return x.Begin.Pos() }
+func (x *Group) Pos() token.Pos { return x.Lparen }
+func (x *Option) Pos() token.Pos { return x.Lbrack }
+func (x *Repetition) Pos() token.Pos { return x.Lbrace }
+func (x *Production) Pos() token.Pos { return x.Name.Pos() }
+
+
+// ----------------------------------------------------------------------------
+// Grammar verification
+
+func isLexical(name string) bool {
+ ch, _ := utf8.DecodeRuneInString(name)
+ return !unicode.IsUpper(ch)
+}
+
+
+type verifier struct {
+ fset *token.FileSet
+ scanner.ErrorVector
+ worklist []*Production
+ reached Grammar // set of productions reached from (and including) the root production
+ grammar Grammar
+}
+
+
+func (v *verifier) error(pos token.Pos, msg string) {
+ v.Error(v.fset.Position(pos), msg)
+}
+
+
+func (v *verifier) push(prod *Production) {
+ name := prod.Name.String
+ if _, found := v.reached[name]; !found {
+ v.worklist = append(v.worklist, prod)
+ v.reached[name] = prod
+ }
+}
+
+
+func (v *verifier) verifyChar(x *Token) int {
+ s := x.String
+ if utf8.RuneCountInString(s) != 1 {
+ v.error(x.Pos(), "single char expected, found "+s)
+ return 0
+ }
+ ch, _ := utf8.DecodeRuneInString(s)
+ return ch
+}
+
+
+func (v *verifier) verifyExpr(expr Expression, lexical bool) {
+ switch x := expr.(type) {
+ case nil:
+ // empty expression
+ case Alternative:
+ for _, e := range x {
+ v.verifyExpr(e, lexical)
+ }
+ case Sequence:
+ for _, e := range x {
+ v.verifyExpr(e, lexical)
+ }
+ case *Name:
+ // a production with this name must exist;
+ // add it to the worklist if not yet processed
+ if prod, found := v.grammar[x.String]; found {
+ v.push(prod)
+ } else {
+ v.error(x.Pos(), "missing production "+x.String)
+ }
+ // within a lexical production references
+ // to non-lexical productions are invalid
+ if lexical && !isLexical(x.String) {
+ v.error(x.Pos(), "reference to non-lexical production "+x.String)
+ }
+ case *Token:
+ // nothing to do for now
+ case *Range:
+ i := v.verifyChar(x.Begin)
+ j := v.verifyChar(x.End)
+ if i >= j {
+ v.error(x.Pos(), "decreasing character range")
+ }
+ case *Group:
+ v.verifyExpr(x.Body, lexical)
+ case *Option:
+ v.verifyExpr(x.Body, lexical)
+ case *Repetition:
+ v.verifyExpr(x.Body, lexical)
+ default:
+ panic("unreachable")
+ }
+}
+
+
+func (v *verifier) verify(fset *token.FileSet, grammar Grammar, start string) {
+ // find root production
+ root, found := grammar[start]
+ if !found {
+ // token.NoPos doesn't require a file set;
+ // ok to set v.fset only afterwards
+ v.error(token.NoPos, "no start production "+start)
+ return
+ }
+
+ // initialize verifier
+ v.fset = fset
+ v.ErrorVector.Reset()
+ v.worklist = v.worklist[0:0]
+ v.reached = make(Grammar)
+ v.grammar = grammar
+
+ // work through the worklist
+ v.push(root)
+ for {
+ n := len(v.worklist) - 1
+ if n < 0 {
+ break
+ }
+ prod := v.worklist[n]
+ v.worklist = v.worklist[0:n]
+ v.verifyExpr(prod.Expr, isLexical(prod.Name.String))
+ }
+
+ // check if all productions were reached
+ if len(v.reached) < len(v.grammar) {
+ for name, prod := range v.grammar {
+ if _, found := v.reached[name]; !found {
+ v.error(prod.Pos(), name+" is unreachable")
+ }
+ }
+ }
+}
+
+
+// Verify checks that:
+// - all productions used are defined
+// - all productions defined are used when beginning at start
+// - lexical productions refer only to other lexical productions
+//
+// Position information is interpreted relative to the file set fset.
+//
+func Verify(fset *token.FileSet, grammar Grammar, start string) os.Error {
+ var v verifier
+ v.verify(fset, grammar, start)
+ return v.GetError(scanner.Sorted)
+}
diff --git a/libgo/go/ebnf/ebnf_test.go b/libgo/go/ebnf/ebnf_test.go
new file mode 100644
index 000000000..bbe530c27
--- /dev/null
+++ b/libgo/go/ebnf/ebnf_test.go
@@ -0,0 +1,77 @@
+// 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 ebnf
+
+import (
+ "go/token"
+ "io/ioutil"
+ "testing"
+)
+
+
+var fset = token.NewFileSet()
+
+
+var grammars = []string{
+ `Program = .
+ `,
+
+ `Program = foo .
+ foo = "foo" .
+ `,
+
+ `Program = "a" | "b" "c" .
+ `,
+
+ `Program = "a" ... "z" .
+ `,
+
+ `Program = Song .
+ Song = { Note } .
+ Note = Do | (Re | Mi | Fa | So | La) | Ti .
+ Do = "c" .
+ Re = "d" .
+ Mi = "e" .
+ Fa = "f" .
+ So = "g" .
+ La = "a" .
+ Ti = ti .
+ ti = "b" .
+ `,
+}
+
+
+func check(t *testing.T, filename string, src []byte) {
+ grammar, err := Parse(fset, filename, src)
+ if err != nil {
+ t.Errorf("Parse(%s) failed: %v", src, err)
+ }
+ if err = Verify(fset, grammar, "Program"); err != nil {
+ t.Errorf("Verify(%s) failed: %v", src, err)
+ }
+}
+
+
+func TestGrammars(t *testing.T) {
+ for _, src := range grammars {
+ check(t, "", []byte(src))
+ }
+}
+
+
+var files = []string{
+// TODO(gri) add some test files
+}
+
+
+func TestFiles(t *testing.T) {
+ for _, filename := range files {
+ src, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Fatal(err)
+ }
+ check(t, filename, src)
+ }
+}
diff --git a/libgo/go/ebnf/parser.go b/libgo/go/ebnf/parser.go
new file mode 100644
index 000000000..c38530177
--- /dev/null
+++ b/libgo/go/ebnf/parser.go
@@ -0,0 +1,208 @@
+// 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 ebnf
+
+import (
+ "go/scanner"
+ "go/token"
+ "os"
+ "strconv"
+)
+
+
+type parser struct {
+ fset *token.FileSet
+ scanner.ErrorVector
+ scanner scanner.Scanner
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit []byte // token literal
+}
+
+
+func (p *parser) next() {
+ p.pos, p.tok, p.lit = p.scanner.Scan()
+ if p.tok.IsKeyword() {
+ // TODO Should keyword mapping always happen outside scanner?
+ // Or should there be a flag to scanner to enable keyword mapping?
+ p.tok = token.IDENT
+ }
+}
+
+
+func (p *parser) error(pos token.Pos, msg string) {
+ p.Error(p.fset.Position(pos), msg)
+}
+
+
+func (p *parser) errorExpected(pos token.Pos, msg string) {
+ msg = "expected " + msg
+ if pos == p.pos {
+ // the error happened at the current position;
+ // make the error message more specific
+ msg += ", found '" + p.tok.String() + "'"
+ if p.tok.IsLiteral() {
+ msg += " " + string(p.lit)
+ }
+ }
+ p.error(pos, msg)
+}
+
+
+func (p *parser) expect(tok token.Token) token.Pos {
+ pos := p.pos
+ if p.tok != tok {
+ p.errorExpected(pos, "'"+tok.String()+"'")
+ }
+ p.next() // make progress in any case
+ return pos
+}
+
+
+func (p *parser) parseIdentifier() *Name {
+ pos := p.pos
+ name := string(p.lit)
+ p.expect(token.IDENT)
+ return &Name{pos, name}
+}
+
+
+func (p *parser) parseToken() *Token {
+ pos := p.pos
+ value := ""
+ if p.tok == token.STRING {
+ value, _ = strconv.Unquote(string(p.lit))
+ // Unquote may fail with an error, but only if the scanner found
+ // an illegal string in the first place. In this case the error
+ // has already been reported.
+ p.next()
+ } else {
+ p.expect(token.STRING)
+ }
+ return &Token{pos, value}
+}
+
+
+func (p *parser) parseTerm() (x Expression) {
+ pos := p.pos
+
+ switch p.tok {
+ case token.IDENT:
+ x = p.parseIdentifier()
+
+ case token.STRING:
+ tok := p.parseToken()
+ x = tok
+ if p.tok == token.ELLIPSIS {
+ p.next()
+ x = &Range{tok, p.parseToken()}
+ }
+
+ case token.LPAREN:
+ p.next()
+ x = &Group{pos, p.parseExpression()}
+ p.expect(token.RPAREN)
+
+ case token.LBRACK:
+ p.next()
+ x = &Option{pos, p.parseExpression()}
+ p.expect(token.RBRACK)
+
+ case token.LBRACE:
+ p.next()
+ x = &Repetition{pos, p.parseExpression()}
+ p.expect(token.RBRACE)
+ }
+
+ return x
+}
+
+
+func (p *parser) parseSequence() Expression {
+ var list Sequence
+
+ for x := p.parseTerm(); x != nil; x = p.parseTerm() {
+ list = append(list, x)
+ }
+
+ // no need for a sequence if list.Len() < 2
+ switch len(list) {
+ case 0:
+ return nil
+ case 1:
+ return list[0]
+ }
+
+ return list
+}
+
+
+func (p *parser) parseExpression() Expression {
+ var list Alternative
+
+ for {
+ if x := p.parseSequence(); x != nil {
+ list = append(list, x)
+ }
+ if p.tok != token.OR {
+ break
+ }
+ p.next()
+ }
+
+ // no need for an Alternative node if list.Len() < 2
+ switch len(list) {
+ case 0:
+ return nil
+ case 1:
+ return list[0]
+ }
+
+ return list
+}
+
+
+func (p *parser) parseProduction() *Production {
+ name := p.parseIdentifier()
+ p.expect(token.ASSIGN)
+ expr := p.parseExpression()
+ p.expect(token.PERIOD)
+ return &Production{name, expr}
+}
+
+
+func (p *parser) parse(fset *token.FileSet, filename string, src []byte) Grammar {
+ // initialize parser
+ p.fset = fset
+ p.ErrorVector.Reset()
+ p.scanner.Init(fset.AddFile(filename, fset.Base(), len(src)), src, p, 0)
+ p.next() // initializes pos, tok, lit
+
+ grammar := make(Grammar)
+ for p.tok != token.EOF {
+ prod := p.parseProduction()
+ name := prod.Name.String
+ if _, found := grammar[name]; !found {
+ grammar[name] = prod
+ } else {
+ p.error(prod.Pos(), name+" declared already")
+ }
+ }
+
+ return grammar
+}
+
+
+// Parse parses a set of EBNF productions from source src.
+// It returns a set of productions. Errors are reported
+// for incorrect syntax and if a production is declared
+// more than once. Position information is recorded relative
+// to the file set fset.
+//
+func Parse(fset *token.FileSet, filename string, src []byte) (Grammar, os.Error) {
+ var p parser
+ grammar := p.parse(fset, filename, src)
+ return grammar, p.GetError(scanner.Sorted)
+}
diff --git a/libgo/go/encoding/ascii85/ascii85.go b/libgo/go/encoding/ascii85/ascii85.go
new file mode 100644
index 000000000..ead0c2475
--- /dev/null
+++ b/libgo/go/encoding/ascii85/ascii85.go
@@ -0,0 +1,300 @@
+// 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 ascii85 implements the ascii85 data encoding
+// as used in the btoa tool and Adobe's PostScript and PDF document formats.
+package ascii85
+
+import (
+ "io"
+ "os"
+ "strconv"
+)
+
+/*
+ * Encoder
+ */
+
+// Encode encodes src into at most MaxEncodedLen(len(src))
+// bytes of dst, returning the actual number of bytes written.
+//
+// The encoding handles 4-byte chunks, using a special encoding
+// for the last fragment, so Encode is not appropriate for use on
+// individual blocks of a large data stream. Use NewEncoder() instead.
+//
+// Often, ascii85-encoded data is wrapped in <~ and ~> symbols.
+// Encode does not add these.
+func Encode(dst, src []byte) int {
+ if len(src) == 0 {
+ return 0
+ }
+
+ n := 0
+ for len(src) > 0 {
+ dst[0] = 0
+ dst[1] = 0
+ dst[2] = 0
+ dst[3] = 0
+ dst[4] = 0
+
+ // Unpack 4 bytes into uint32 to repack into base 85 5-byte.
+ var v uint32
+ switch len(src) {
+ default:
+ v |= uint32(src[3])
+ fallthrough
+ case 3:
+ v |= uint32(src[2]) << 8
+ fallthrough
+ case 2:
+ v |= uint32(src[1]) << 16
+ fallthrough
+ case 1:
+ v |= uint32(src[0]) << 24
+ }
+
+ // Special case: zero (!!!!!) shortens to z.
+ if v == 0 && len(src) >= 4 {
+ dst[0] = 'z'
+ dst = dst[1:]
+ n++
+ continue
+ }
+
+ // Otherwise, 5 base 85 digits starting at !.
+ for i := 4; i >= 0; i-- {
+ dst[i] = '!' + byte(v%85)
+ v /= 85
+ }
+
+ // If src was short, discard the low destination bytes.
+ m := 5
+ if len(src) < 4 {
+ m -= 4 - len(src)
+ src = nil
+ } else {
+ src = src[4:]
+ }
+ dst = dst[m:]
+ n += m
+ }
+ return n
+}
+
+// MaxEncodedLen returns the maximum length of an encoding of n source bytes.
+func MaxEncodedLen(n int) int { return (n + 3) / 4 * 5 }
+
+// NewEncoder returns a new ascii85 stream encoder. Data written to
+// the returned writer will be encoded and then written to w.
+// Ascii85 encodings operate in 32-bit blocks; when finished
+// writing, the caller must Close the returned encoder to flush any
+// trailing partial block.
+func NewEncoder(w io.Writer) io.WriteCloser { return &encoder{w: w} }
+
+type encoder struct {
+ err os.Error
+ w io.Writer
+ buf [4]byte // buffered data waiting to be encoded
+ nbuf int // number of bytes in buf
+ out [1024]byte // output buffer
+}
+
+func (e *encoder) Write(p []byte) (n int, err os.Error) {
+ if e.err != nil {
+ return 0, e.err
+ }
+
+ // Leading fringe.
+ if e.nbuf > 0 {
+ var i int
+ for i = 0; i < len(p) && e.nbuf < 4; i++ {
+ e.buf[e.nbuf] = p[i]
+ e.nbuf++
+ }
+ n += i
+ p = p[i:]
+ if e.nbuf < 4 {
+ return
+ }
+ nout := Encode(e.out[0:], e.buf[0:])
+ if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+ return n, e.err
+ }
+ e.nbuf = 0
+ }
+
+ // Large interior chunks.
+ for len(p) >= 4 {
+ nn := len(e.out) / 5 * 4
+ if nn > len(p) {
+ nn = len(p)
+ }
+ nn -= nn % 4
+ if nn > 0 {
+ nout := Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+ return n, e.err
+ }
+ }
+ n += nn
+ p = p[nn:]
+ }
+
+ // Trailing fringe.
+ for i := 0; i < len(p); i++ {
+ e.buf[i] = p[i]
+ }
+ e.nbuf = len(p)
+ n += len(p)
+ return
+}
+
+// Close flushes any pending output from the encoder.
+// It is an error to call Write after calling Close.
+func (e *encoder) Close() os.Error {
+ // If there's anything left in the buffer, flush it out
+ if e.err == nil && e.nbuf > 0 {
+ nout := Encode(e.out[0:], e.buf[0:e.nbuf])
+ e.nbuf = 0
+ _, e.err = e.w.Write(e.out[0:nout])
+ }
+ return e.err
+}
+
+/*
+ * Decoder
+ */
+
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+ return "illegal ascii85 data at input byte " + strconv.Itoa64(int64(e))
+}
+
+// Decode decodes src into dst, returning both the number
+// of bytes written to dst and the number consumed from src.
+// If src contains invalid ascii85 data, Decode will return the
+// number of bytes successfully written and a CorruptInputError.
+// Decode ignores space and control characters in src.
+// Often, ascii85-encoded data is wrapped in <~ and ~> symbols.
+// Decode expects these to have been stripped by the caller.
+//
+// If flush is true, Decode assumes that src represents the
+// end of the input stream and processes it completely rather
+// than wait for the completion of another 32-bit block.
+//
+// NewDecoder wraps an io.Reader interface around Decode.
+//
+func Decode(dst, src []byte, flush bool) (ndst, nsrc int, err os.Error) {
+ var v uint32
+ var nb int
+ for i, b := range src {
+ if len(dst)-ndst < 4 {
+ return
+ }
+ switch {
+ case b <= ' ':
+ continue
+ case b == 'z' && nb == 0:
+ nb = 5
+ v = 0
+ case '!' <= b && b <= 'u':
+ v = v*85 + uint32(b-'!')
+ nb++
+ default:
+ return 0, 0, CorruptInputError(i)
+ }
+ if nb == 5 {
+ nsrc = i + 1
+ dst[ndst] = byte(v >> 24)
+ dst[ndst+1] = byte(v >> 16)
+ dst[ndst+2] = byte(v >> 8)
+ dst[ndst+3] = byte(v)
+ ndst += 4
+ nb = 0
+ v = 0
+ }
+ }
+ if flush {
+ nsrc = len(src)
+ if nb > 0 {
+ // The number of output bytes in the last fragment
+ // is the number of leftover input bytes - 1:
+ // the extra byte provides enough bits to cover
+ // the inefficiency of the encoding for the block.
+ if nb == 1 {
+ return 0, 0, CorruptInputError(len(src))
+ }
+ for i := nb; i < 5; i++ {
+ // The short encoding truncated the output value.
+ // We have to assume the worst case values (digit 84)
+ // in order to ensure that the top bits are correct.
+ v = v*85 + 84
+ }
+ for i := 0; i < nb-1; i++ {
+ dst[ndst] = byte(v >> 24)
+ v <<= 8
+ ndst++
+ }
+ }
+ }
+ return
+}
+
+// NewDecoder constructs a new ascii85 stream decoder.
+func NewDecoder(r io.Reader) io.Reader { return &decoder{r: r} }
+
+type decoder struct {
+ err os.Error
+ readErr os.Error
+ r io.Reader
+ end bool // saw end of message
+ buf [1024]byte // leftover input
+ nbuf int
+ out []byte // leftover decoded output
+ outbuf [1024]byte
+}
+
+func (d *decoder) Read(p []byte) (n int, err os.Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
+ if d.err != nil {
+ return 0, d.err
+ }
+
+ for {
+ // Copy leftover output from last decode.
+ if len(d.out) > 0 {
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ return
+ }
+
+ // Decode leftover input from last read.
+ var nn, nsrc, ndst int
+ if d.nbuf > 0 {
+ ndst, nsrc, d.err = Decode(d.outbuf[0:], d.buf[0:d.nbuf], d.readErr != nil)
+ if ndst > 0 {
+ d.out = d.outbuf[0:ndst]
+ d.nbuf = copy(d.buf[0:], d.buf[nsrc:d.nbuf])
+ continue // copy out and return
+ }
+ }
+
+ // Out of input, out of decoded output. Check errors.
+ if d.err != nil {
+ return 0, d.err
+ }
+ if d.readErr != nil {
+ d.err = d.readErr
+ return 0, d.err
+ }
+
+ // Read more data.
+ nn, d.readErr = d.r.Read(d.buf[d.nbuf:])
+ d.nbuf += nn
+ }
+ panic("unreachable")
+}
diff --git a/libgo/go/encoding/ascii85/ascii85_test.go b/libgo/go/encoding/ascii85/ascii85_test.go
new file mode 100644
index 000000000..fdfeb889f
--- /dev/null
+++ b/libgo/go/encoding/ascii85/ascii85_test.go
@@ -0,0 +1,188 @@
+// 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 ascii85
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type testpair struct {
+ decoded, encoded string
+}
+
+var pairs = []testpair{
+ // Wikipedia example
+ {
+ "Man is distinguished, not only by his reason, but by this singular passion from " +
+ "other animals, which is a lust of the mind, that by a perseverance of delight in " +
+ "the continued and indefatigable generation of knowledge, exceeds the short " +
+ "vehemence of any carnal pleasure.",
+ "9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKF<GL>Cj@.4Gp$d7F!,L7@<6@)/0JDEF<G%<+EV:2F!,\n" +
+ "O<DJ+*.@<*K0@<6L(Df-\\0Ec5e;DffZ(EZee.Bl.9pF\"AGXBPCsi+DGm>@3BB/F*&OCAfu2/AKY\n" +
+ "i(DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF<G:8+EV:.+Cf>-FD5W8ARlolDIa\n" +
+ "l(DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G\n" +
+ ">uD.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c\n",
+ },
+}
+
+var bigtest = pairs[len(pairs)-1]
+
+func testEqual(t *testing.T, msg string, args ...interface{}) bool {
+ if args[len(args)-2] != args[len(args)-1] {
+ t.Errorf(msg, args...)
+ return false
+ }
+ return true
+}
+
+func strip85(s string) string {
+ t := make([]byte, len(s))
+ w := 0
+ for r := 0; r < len(s); r++ {
+ c := s[r]
+ if c > ' ' {
+ t[w] = c
+ w++
+ }
+ }
+ return string(t[0:w])
+}
+
+func TestEncode(t *testing.T) {
+ for _, p := range pairs {
+ buf := make([]byte, MaxEncodedLen(len(p.decoded)))
+ n := Encode(buf, []byte(p.decoded))
+ buf = buf[0:n]
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, strip85(string(buf)), strip85(p.encoded))
+ }
+}
+
+func TestEncoder(t *testing.T) {
+ for _, p := range pairs {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(bb)
+ encoder.Write([]byte(p.decoded))
+ encoder.Close()
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, strip85(bb.String()), strip85(p.encoded))
+ }
+}
+
+func TestEncoderBuffering(t *testing.T) {
+ input := []byte(bigtest.decoded)
+ for bs := 1; bs <= 12; bs++ {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(bb)
+ for pos := 0; pos < len(input); pos += bs {
+ end := pos + bs
+ if end > len(input) {
+ end = len(input)
+ }
+ n, err := encoder.Write(input[pos:end])
+ testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+ testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
+ }
+ err := encoder.Close()
+ testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+ testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, strip85(bb.String()), strip85(bigtest.encoded))
+ }
+}
+
+func TestDecode(t *testing.T) {
+ for _, p := range pairs {
+ dbuf := make([]byte, 4*len(p.encoded))
+ ndst, nsrc, err := Decode(dbuf, []byte(p.encoded), true)
+ testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "Decode(%q) = nsrc %v, want %v", p.encoded, nsrc, len(p.encoded))
+ testEqual(t, "Decode(%q) = ndst %v, want %v", p.encoded, ndst, len(p.decoded))
+ testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:ndst]), p.decoded)
+ }
+}
+
+func TestDecoder(t *testing.T) {
+ for _, p := range pairs {
+ decoder := NewDecoder(bytes.NewBufferString(p.encoded))
+ dbuf, err := ioutil.ReadAll(decoder)
+ if err != nil {
+ t.Fatal("Read failed", err)
+ }
+ testEqual(t, "Read from %q = length %v, want %v", p.encoded, len(dbuf), len(p.decoded))
+ testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf), p.decoded)
+ if err != nil {
+ testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+ }
+ }
+}
+
+func TestDecoderBuffering(t *testing.T) {
+ for bs := 1; bs <= 12; bs++ {
+ decoder := NewDecoder(bytes.NewBufferString(bigtest.encoded))
+ buf := make([]byte, len(bigtest.decoded)+12)
+ var total int
+ for total = 0; total < len(bigtest.decoded); {
+ n, err := decoder.Read(buf[total : total+bs])
+ testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil))
+ total += n
+ }
+ testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
+ }
+}
+
+func TestDecodeCorrupt(t *testing.T) {
+ type corrupt struct {
+ e string
+ p int
+ }
+ examples := []corrupt{
+ {"v", 0},
+ {"!z!!!!!!!!!", 1},
+ }
+
+ for _, e := range examples {
+ dbuf := make([]byte, 4*len(e.e))
+ _, _, err := Decode(dbuf, []byte(e.e), true)
+ switch err := err.(type) {
+ case CorruptInputError:
+ testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ default:
+ t.Error("Decoder failed to detect corruption in", e)
+ }
+ }
+}
+
+func TestBig(t *testing.T) {
+ n := 3*1000 + 1
+ raw := make([]byte, n)
+ const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ for i := 0; i < n; i++ {
+ raw[i] = alpha[i%len(alpha)]
+ }
+ encoded := new(bytes.Buffer)
+ w := NewEncoder(encoded)
+ nn, err := w.Write(raw)
+ if nn != n || err != nil {
+ t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
+ }
+ err = w.Close()
+ if err != nil {
+ t.Fatalf("Encoder.Close() = %v want nil", err)
+ }
+ decoded, err := ioutil.ReadAll(NewDecoder(encoded))
+ if err != nil {
+ t.Fatalf("io.ReadAll(NewDecoder(...)): %v", err)
+ }
+
+ if !bytes.Equal(raw, decoded) {
+ var i int
+ for i = 0; i < len(decoded) && i < len(raw); i++ {
+ if decoded[i] != raw[i] {
+ break
+ }
+ }
+ t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
+ }
+}
diff --git a/libgo/go/encoding/base32/base32.go b/libgo/go/encoding/base32/base32.go
new file mode 100644
index 000000000..acace30d6
--- /dev/null
+++ b/libgo/go/encoding/base32/base32.go
@@ -0,0 +1,368 @@
+// 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 base32 implements base32 encoding as specified by RFC 4648.
+package base32
+
+import (
+ "io"
+ "os"
+ "strconv"
+)
+
+/*
+ * Encodings
+ */
+
+// An Encoding is a radix 32 encoding/decoding scheme, defined by a
+// 32-character alphabet. The most common is the "base32" encoding
+// introduced for SASL GSSAPI and standardized in RFC 4648.
+// The alternate "base32hex" encoding is used in DNSSEC.
+type Encoding struct {
+ encode string
+ decodeMap [256]byte
+}
+
+const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
+const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
+
+// NewEncoding returns a new Encoding defined by the given alphabet,
+// which must be a 32-byte string.
+func NewEncoding(encoder string) *Encoding {
+ e := new(Encoding)
+ e.encode = encoder
+ for i := 0; i < len(e.decodeMap); i++ {
+ e.decodeMap[i] = 0xFF
+ }
+ for i := 0; i < len(encoder); i++ {
+ e.decodeMap[encoder[i]] = byte(i)
+ }
+ return e
+}
+
+// StdEncoding is the standard base32 encoding, as defined in
+// RFC 4648.
+var StdEncoding = NewEncoding(encodeStd)
+
+// HexEncoding is the ``Extended Hex Alphabet'' defined in RFC 4648.
+// It is typically used in DNS.
+var HexEncoding = NewEncoding(encodeHex)
+
+/*
+ * Encoder
+ */
+
+// Encode encodes src using the encoding enc, writing
+// EncodedLen(len(src)) bytes to dst.
+//
+// The encoding pads the output to a multiple of 8 bytes,
+// so Encode is not appropriate for use on individual blocks
+// of a large data stream. Use NewEncoder() instead.
+func (enc *Encoding) Encode(dst, src []byte) {
+ if len(src) == 0 {
+ return
+ }
+
+ for len(src) > 0 {
+ dst[0] = 0
+ dst[1] = 0
+ dst[2] = 0
+ dst[3] = 0
+ dst[4] = 0
+ dst[5] = 0
+ dst[6] = 0
+ dst[7] = 0
+
+ // Unpack 8x 5-bit source blocks into a 5 byte
+ // destination quantum
+ switch len(src) {
+ default:
+ dst[7] |= src[4] & 0x1F
+ dst[6] |= src[4] >> 5
+ fallthrough
+ case 4:
+ dst[6] |= (src[3] << 3) & 0x1F
+ dst[5] |= (src[3] >> 2) & 0x1F
+ dst[4] |= src[3] >> 7
+ fallthrough
+ case 3:
+ dst[4] |= (src[2] << 1) & 0x1F
+ dst[3] |= (src[2] >> 4) & 0x1F
+ fallthrough
+ case 2:
+ dst[3] |= (src[1] << 4) & 0x1F
+ dst[2] |= (src[1] >> 1) & 0x1F
+ dst[1] |= (src[1] >> 6) & 0x1F
+ fallthrough
+ case 1:
+ dst[1] |= (src[0] << 2) & 0x1F
+ dst[0] |= src[0] >> 3
+ }
+
+ // Encode 5-bit blocks using the base32 alphabet
+ for j := 0; j < 8; j++ {
+ dst[j] = enc.encode[dst[j]]
+ }
+
+ // Pad the final quantum
+ if len(src) < 5 {
+ dst[7] = '='
+ if len(src) < 4 {
+ dst[6] = '='
+ dst[5] = '='
+ if len(src) < 3 {
+ dst[4] = '='
+ if len(src) < 2 {
+ dst[3] = '='
+ dst[2] = '='
+ }
+ }
+ }
+ break
+ }
+ src = src[5:]
+ dst = dst[8:]
+ }
+}
+
+type encoder struct {
+ err os.Error
+ enc *Encoding
+ w io.Writer
+ buf [5]byte // buffered data waiting to be encoded
+ nbuf int // number of bytes in buf
+ out [1024]byte // output buffer
+}
+
+func (e *encoder) Write(p []byte) (n int, err os.Error) {
+ if e.err != nil {
+ return 0, e.err
+ }
+
+ // Leading fringe.
+ if e.nbuf > 0 {
+ var i int
+ for i = 0; i < len(p) && e.nbuf < 5; i++ {
+ e.buf[e.nbuf] = p[i]
+ e.nbuf++
+ }
+ n += i
+ p = p[i:]
+ if e.nbuf < 5 {
+ return
+ }
+ e.enc.Encode(e.out[0:], e.buf[0:])
+ if _, e.err = e.w.Write(e.out[0:8]); e.err != nil {
+ return n, e.err
+ }
+ e.nbuf = 0
+ }
+
+ // Large interior chunks.
+ for len(p) >= 5 {
+ nn := len(e.out) / 8 * 5
+ if nn > len(p) {
+ nn = len(p)
+ }
+ nn -= nn % 5
+ if nn > 0 {
+ e.enc.Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
+ return n, e.err
+ }
+ }
+ n += nn
+ p = p[nn:]
+ }
+
+ // Trailing fringe.
+ for i := 0; i < len(p); i++ {
+ e.buf[i] = p[i]
+ }
+ e.nbuf = len(p)
+ n += len(p)
+ return
+}
+
+// Close flushes any pending output from the encoder.
+// It is an error to call Write after calling Close.
+func (e *encoder) Close() os.Error {
+ // If there's anything left in the buffer, flush it out
+ if e.err == nil && e.nbuf > 0 {
+ e.enc.Encode(e.out[0:], e.buf[0:e.nbuf])
+ e.nbuf = 0
+ _, e.err = e.w.Write(e.out[0:8])
+ }
+ return e.err
+}
+
+// NewEncoder returns a new base32 stream encoder. Data written to
+// the returned writer will be encoded using enc and then written to w.
+// Base32 encodings operate in 5-byte blocks; when finished
+// writing, the caller must Close the returned encoder to flush any
+// partially written blocks.
+func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser {
+ return &encoder{enc: enc, w: w}
+}
+
+// EncodedLen returns the length in bytes of the base32 encoding
+// of an input buffer of length n.
+func (enc *Encoding) EncodedLen(n int) int { return (n + 4) / 5 * 8 }
+
+/*
+ * Decoder
+ */
+
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+ return "illegal base32 data at input byte " + strconv.Itoa64(int64(e))
+}
+
+// decode is like Decode but returns an additional 'end' value, which
+// indicates if end-of-message padding was encountered and thus any
+// additional data is an error. decode also assumes len(src)%8==0,
+// since it is meant for internal use.
+func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) {
+ for i := 0; i < len(src)/8 && !end; i++ {
+ // Decode quantum using the base32 alphabet
+ var dbuf [8]byte
+ dlen := 8
+
+ // do the top bytes contain any data?
+ dbufloop:
+ for j := 0; j < 8; j++ {
+ in := src[i*8+j]
+ if in == '=' && j >= 2 && i == len(src)/8-1 {
+ // We've reached the end and there's
+ // padding, the rest should be padded
+ for k := j; k < 8; k++ {
+ if src[i*8+k] != '=' {
+ return n, false, CorruptInputError(i*8 + j)
+ }
+ }
+ dlen = j
+ end = true
+ break dbufloop
+ }
+ dbuf[j] = enc.decodeMap[in]
+ if dbuf[j] == 0xFF {
+ return n, false, CorruptInputError(i*8 + j)
+ }
+ }
+
+ // Pack 8x 5-bit source blocks into 5 byte destination
+ // quantum
+ switch dlen {
+ case 7, 8:
+ dst[i*5+4] = dbuf[6]<<5 | dbuf[7]
+ fallthrough
+ case 6, 5:
+ dst[i*5+3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3
+ fallthrough
+ case 4:
+ dst[i*5+2] = dbuf[3]<<4 | dbuf[4]>>1
+ fallthrough
+ case 3:
+ dst[i*5+1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4
+ fallthrough
+ case 2:
+ dst[i*5+0] = dbuf[0]<<3 | dbuf[1]>>2
+ }
+ switch dlen {
+ case 2:
+ n += 1
+ case 3, 4:
+ n += 2
+ case 5:
+ n += 3
+ case 6, 7:
+ n += 4
+ case 8:
+ n += 5
+ }
+ }
+ return n, end, nil
+}
+
+// Decode decodes src using the encoding enc. It writes at most
+// DecodedLen(len(src)) bytes to dst and returns the number of bytes
+// written. If src contains invalid base32 data, it will return the
+// number of bytes successfully written and CorruptInputError.
+func (enc *Encoding) Decode(dst, src []byte) (n int, err os.Error) {
+ if len(src)%8 != 0 {
+ return 0, CorruptInputError(len(src) / 8 * 8)
+ }
+
+ n, _, err = enc.decode(dst, src)
+ return
+}
+
+type decoder struct {
+ err os.Error
+ enc *Encoding
+ r io.Reader
+ end bool // saw end of message
+ buf [1024]byte // leftover input
+ nbuf int
+ out []byte // leftover decoded output
+ outbuf [1024 / 8 * 5]byte
+}
+
+func (d *decoder) Read(p []byte) (n int, err os.Error) {
+ if d.err != nil {
+ return 0, d.err
+ }
+
+ // Use leftover decoded output from last read.
+ if len(d.out) > 0 {
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ return n, nil
+ }
+
+ // Read a chunk.
+ nn := len(p) / 5 * 8
+ if nn < 8 {
+ nn = 8
+ }
+ if nn > len(d.buf) {
+ nn = len(d.buf)
+ }
+ nn, d.err = io.ReadAtLeast(d.r, d.buf[d.nbuf:nn], 8-d.nbuf)
+ d.nbuf += nn
+ if d.nbuf < 8 {
+ return 0, d.err
+ }
+
+ // Decode chunk into p, or d.out and then p if p is too small.
+ nr := d.nbuf / 8 * 8
+ nw := d.nbuf / 8 * 5
+ if nw > len(p) {
+ nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
+ d.out = d.outbuf[0:nw]
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ } else {
+ n, d.end, d.err = d.enc.decode(p, d.buf[0:nr])
+ }
+ d.nbuf -= nr
+ for i := 0; i < d.nbuf; i++ {
+ d.buf[i] = d.buf[i+nr]
+ }
+
+ if d.err == nil {
+ d.err = err
+ }
+ return n, d.err
+}
+
+// NewDecoder constructs a new base32 stream decoder.
+func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
+ return &decoder{enc: enc, r: r}
+}
+
+// DecodedLen returns the maximum length in bytes of the decoded data
+// corresponding to n bytes of base32-encoded data.
+func (enc *Encoding) DecodedLen(n int) int { return n / 8 * 5 }
diff --git a/libgo/go/encoding/base32/base32_test.go b/libgo/go/encoding/base32/base32_test.go
new file mode 100644
index 000000000..792e4dc63
--- /dev/null
+++ b/libgo/go/encoding/base32/base32_test.go
@@ -0,0 +1,194 @@
+// 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 base32
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type testpair struct {
+ decoded, encoded string
+}
+
+var pairs = []testpair{
+ // RFC 4648 examples
+ {"", ""},
+ {"f", "MY======"},
+ {"fo", "MZXQ===="},
+ {"foo", "MZXW6==="},
+ {"foob", "MZXW6YQ="},
+ {"fooba", "MZXW6YTB"},
+ {"foobar", "MZXW6YTBOI======"},
+
+
+ // Wikipedia examples, converted to base32
+ {"sure.", "ON2XEZJO"},
+ {"sure", "ON2XEZI="},
+ {"sur", "ON2XE==="},
+ {"su", "ON2Q===="},
+ {"leasure.", "NRSWC43VOJSS4==="},
+ {"easure.", "MVQXG5LSMUXA===="},
+ {"asure.", "MFZXK4TFFY======"},
+ {"sure.", "ON2XEZJO"},
+}
+
+var bigtest = testpair{
+ "Twas brillig, and the slithy toves",
+ "KR3WC4ZAMJZGS3DMNFTSYIDBNZSCA5DIMUQHG3DJORUHSIDUN53GK4Y=",
+}
+
+func testEqual(t *testing.T, msg string, args ...interface{}) bool {
+ if args[len(args)-2] != args[len(args)-1] {
+ t.Errorf(msg, args...)
+ return false
+ }
+ return true
+}
+
+func TestEncode(t *testing.T) {
+ for _, p := range pairs {
+ buf := make([]byte, StdEncoding.EncodedLen(len(p.decoded)))
+ StdEncoding.Encode(buf, []byte(p.decoded))
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
+ }
+}
+
+func TestEncoder(t *testing.T) {
+ for _, p := range pairs {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(StdEncoding, bb)
+ encoder.Write([]byte(p.decoded))
+ encoder.Close()
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
+ }
+}
+
+func TestEncoderBuffering(t *testing.T) {
+ input := []byte(bigtest.decoded)
+ for bs := 1; bs <= 12; bs++ {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(StdEncoding, bb)
+ for pos := 0; pos < len(input); pos += bs {
+ end := pos + bs
+ if end > len(input) {
+ end = len(input)
+ }
+ n, err := encoder.Write(input[pos:end])
+ testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+ testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
+ }
+ err := encoder.Close()
+ testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+ testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded)
+ }
+}
+
+func TestDecode(t *testing.T) {
+ for _, p := range pairs {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
+ count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded))
+ testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded))
+ if len(p.encoded) > 0 {
+ testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '='))
+ }
+ testEqual(t, "Decode(%q) = %q, want %q", p.encoded,
+ string(dbuf[0:count]),
+ p.decoded)
+ }
+}
+
+func TestDecoder(t *testing.T) {
+ for _, p := range pairs {
+ decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
+ count, err := decoder.Read(dbuf)
+ if err != nil && err != os.EOF {
+ t.Fatal("Read failed", err)
+ }
+ testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded))
+ testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
+ if err != os.EOF {
+ count, err = decoder.Read(dbuf)
+ }
+ testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+ }
+}
+
+func TestDecoderBuffering(t *testing.T) {
+ for bs := 1; bs <= 12; bs++ {
+ decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
+ buf := make([]byte, len(bigtest.decoded)+12)
+ var total int
+ for total = 0; total < len(bigtest.decoded); {
+ n, err := decoder.Read(buf[total : total+bs])
+ testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil))
+ total += n
+ }
+ testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
+ }
+}
+
+func TestDecodeCorrupt(t *testing.T) {
+ type corrupt struct {
+ e string
+ p int
+ }
+ examples := []corrupt{
+ {"!!!!", 0},
+ {"x===", 0},
+ {"AA=A====", 2},
+ {"AAA=AAAA", 3},
+ {"MMMMMMMMM", 8},
+ {"MMMMMM", 0},
+ }
+
+ for _, e := range examples {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
+ _, err := StdEncoding.Decode(dbuf, []byte(e.e))
+ switch err := err.(type) {
+ case CorruptInputError:
+ testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ default:
+ t.Error("Decoder failed to detect corruption in", e)
+ }
+ }
+}
+
+func TestBig(t *testing.T) {
+ n := 3*1000 + 1
+ raw := make([]byte, n)
+ const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ for i := 0; i < n; i++ {
+ raw[i] = alpha[i%len(alpha)]
+ }
+ encoded := new(bytes.Buffer)
+ w := NewEncoder(StdEncoding, encoded)
+ nn, err := w.Write(raw)
+ if nn != n || err != nil {
+ t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
+ }
+ err = w.Close()
+ if err != nil {
+ t.Fatalf("Encoder.Close() = %v want nil", err)
+ }
+ decoded, err := ioutil.ReadAll(NewDecoder(StdEncoding, encoded))
+ if err != nil {
+ t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err)
+ }
+
+ if !bytes.Equal(raw, decoded) {
+ var i int
+ for i = 0; i < len(decoded) && i < len(raw); i++ {
+ if decoded[i] != raw[i] {
+ break
+ }
+ }
+ t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
+ }
+}
diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go
new file mode 100644
index 000000000..496129798
--- /dev/null
+++ b/libgo/go/encoding/base64/base64.go
@@ -0,0 +1,329 @@
+// 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 base64 implements base64 encoding as specified by RFC 4648.
+package base64
+
+import (
+ "io"
+ "os"
+ "strconv"
+)
+
+/*
+ * Encodings
+ */
+
+// An Encoding is a radix 64 encoding/decoding scheme, defined by a
+// 64-character alphabet. The most common encoding is the "base64"
+// encoding defined in RFC 4648 and used in MIME (RFC 2045) and PEM
+// (RFC 1421). RFC 4648 also defines an alternate encoding, which is
+// the standard encoding with - and _ substituted for + and /.
+type Encoding struct {
+ encode string
+ decodeMap [256]byte
+}
+
+const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
+
+// NewEncoding returns a new Encoding defined by the given alphabet,
+// which must be a 64-byte string.
+func NewEncoding(encoder string) *Encoding {
+ e := new(Encoding)
+ e.encode = encoder
+ for i := 0; i < len(e.decodeMap); i++ {
+ e.decodeMap[i] = 0xFF
+ }
+ for i := 0; i < len(encoder); i++ {
+ e.decodeMap[encoder[i]] = byte(i)
+ }
+ return e
+}
+
+// StdEncoding is the standard base64 encoding, as defined in
+// RFC 4648.
+var StdEncoding = NewEncoding(encodeStd)
+
+// URLEncoding is the alternate base64 encoding defined in RFC 4648.
+// It is typically used in URLs and file names.
+var URLEncoding = NewEncoding(encodeURL)
+
+/*
+ * Encoder
+ */
+
+// Encode encodes src using the encoding enc, writing
+// EncodedLen(len(src)) bytes to dst.
+//
+// The encoding pads the output to a multiple of 4 bytes,
+// so Encode is not appropriate for use on individual blocks
+// of a large data stream. Use NewEncoder() instead.
+func (enc *Encoding) Encode(dst, src []byte) {
+ if len(src) == 0 {
+ return
+ }
+
+ for len(src) > 0 {
+ dst[0] = 0
+ dst[1] = 0
+ dst[2] = 0
+ dst[3] = 0
+
+ // Unpack 4x 6-bit source blocks into a 4 byte
+ // destination quantum
+ switch len(src) {
+ default:
+ dst[3] |= src[2] & 0x3F
+ dst[2] |= src[2] >> 6
+ fallthrough
+ case 2:
+ dst[2] |= (src[1] << 2) & 0x3F
+ dst[1] |= src[1] >> 4
+ fallthrough
+ case 1:
+ dst[1] |= (src[0] << 4) & 0x3F
+ dst[0] |= src[0] >> 2
+ }
+
+ // Encode 6-bit blocks using the base64 alphabet
+ for j := 0; j < 4; j++ {
+ dst[j] = enc.encode[dst[j]]
+ }
+
+ // Pad the final quantum
+ if len(src) < 3 {
+ dst[3] = '='
+ if len(src) < 2 {
+ dst[2] = '='
+ }
+ break
+ }
+
+ src = src[3:]
+ dst = dst[4:]
+ }
+}
+
+type encoder struct {
+ err os.Error
+ enc *Encoding
+ w io.Writer
+ buf [3]byte // buffered data waiting to be encoded
+ nbuf int // number of bytes in buf
+ out [1024]byte // output buffer
+}
+
+func (e *encoder) Write(p []byte) (n int, err os.Error) {
+ if e.err != nil {
+ return 0, e.err
+ }
+
+ // Leading fringe.
+ if e.nbuf > 0 {
+ var i int
+ for i = 0; i < len(p) && e.nbuf < 3; i++ {
+ e.buf[e.nbuf] = p[i]
+ e.nbuf++
+ }
+ n += i
+ p = p[i:]
+ if e.nbuf < 3 {
+ return
+ }
+ e.enc.Encode(e.out[0:], e.buf[0:])
+ if _, e.err = e.w.Write(e.out[0:4]); e.err != nil {
+ return n, e.err
+ }
+ e.nbuf = 0
+ }
+
+ // Large interior chunks.
+ for len(p) >= 3 {
+ nn := len(e.out) / 4 * 3
+ if nn > len(p) {
+ nn = len(p)
+ }
+ nn -= nn % 3
+ if nn > 0 {
+ e.enc.Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
+ return n, e.err
+ }
+ }
+ n += nn
+ p = p[nn:]
+ }
+
+ // Trailing fringe.
+ for i := 0; i < len(p); i++ {
+ e.buf[i] = p[i]
+ }
+ e.nbuf = len(p)
+ n += len(p)
+ return
+}
+
+// Close flushes any pending output from the encoder.
+// It is an error to call Write after calling Close.
+func (e *encoder) Close() os.Error {
+ // If there's anything left in the buffer, flush it out
+ if e.err == nil && e.nbuf > 0 {
+ e.enc.Encode(e.out[0:], e.buf[0:e.nbuf])
+ e.nbuf = 0
+ _, e.err = e.w.Write(e.out[0:4])
+ }
+ return e.err
+}
+
+// NewEncoder returns a new base64 stream encoder. Data written to
+// the returned writer will be encoded using enc and then written to w.
+// Base64 encodings operate in 4-byte blocks; when finished
+// writing, the caller must Close the returned encoder to flush any
+// partially written blocks.
+func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser {
+ return &encoder{enc: enc, w: w}
+}
+
+// EncodedLen returns the length in bytes of the base64 encoding
+// of an input buffer of length n.
+func (enc *Encoding) EncodedLen(n int) int { return (n + 2) / 3 * 4 }
+
+/*
+ * Decoder
+ */
+
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+ return "illegal base64 data at input byte " + strconv.Itoa64(int64(e))
+}
+
+// decode is like Decode but returns an additional 'end' value, which
+// indicates if end-of-message padding was encountered and thus any
+// additional data is an error. decode also assumes len(src)%4==0,
+// since it is meant for internal use.
+func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) {
+ for i := 0; i < len(src)/4 && !end; i++ {
+ // Decode quantum using the base64 alphabet
+ var dbuf [4]byte
+ dlen := 4
+
+ dbufloop:
+ for j := 0; j < 4; j++ {
+ in := src[i*4+j]
+ if in == '=' && j >= 2 && i == len(src)/4-1 {
+ // We've reached the end and there's
+ // padding
+ if src[i*4+3] != '=' {
+ return n, false, CorruptInputError(i*4 + 2)
+ }
+ dlen = j
+ end = true
+ break dbufloop
+ }
+ dbuf[j] = enc.decodeMap[in]
+ if dbuf[j] == 0xFF {
+ return n, false, CorruptInputError(i*4 + j)
+ }
+ }
+
+ // Pack 4x 6-bit source blocks into 3 byte destination
+ // quantum
+ switch dlen {
+ case 4:
+ dst[i*3+2] = dbuf[2]<<6 | dbuf[3]
+ fallthrough
+ case 3:
+ dst[i*3+1] = dbuf[1]<<4 | dbuf[2]>>2
+ fallthrough
+ case 2:
+ dst[i*3+0] = dbuf[0]<<2 | dbuf[1]>>4
+ }
+ n += dlen - 1
+ }
+
+ return n, end, nil
+}
+
+// Decode decodes src using the encoding enc. It writes at most
+// DecodedLen(len(src)) bytes to dst and returns the number of bytes
+// written. If src contains invalid base64 data, it will return the
+// number of bytes successfully written and CorruptInputError.
+func (enc *Encoding) Decode(dst, src []byte) (n int, err os.Error) {
+ if len(src)%4 != 0 {
+ return 0, CorruptInputError(len(src) / 4 * 4)
+ }
+
+ n, _, err = enc.decode(dst, src)
+ return
+}
+
+type decoder struct {
+ err os.Error
+ enc *Encoding
+ r io.Reader
+ end bool // saw end of message
+ buf [1024]byte // leftover input
+ nbuf int
+ out []byte // leftover decoded output
+ outbuf [1024 / 4 * 3]byte
+}
+
+func (d *decoder) Read(p []byte) (n int, err os.Error) {
+ if d.err != nil {
+ return 0, d.err
+ }
+
+ // Use leftover decoded output from last read.
+ if len(d.out) > 0 {
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ return n, nil
+ }
+
+ // Read a chunk.
+ nn := len(p) / 3 * 4
+ if nn < 4 {
+ nn = 4
+ }
+ if nn > len(d.buf) {
+ nn = len(d.buf)
+ }
+ nn, d.err = io.ReadAtLeast(d.r, d.buf[d.nbuf:nn], 4-d.nbuf)
+ d.nbuf += nn
+ if d.nbuf < 4 {
+ return 0, d.err
+ }
+
+ // Decode chunk into p, or d.out and then p if p is too small.
+ nr := d.nbuf / 4 * 4
+ nw := d.nbuf / 4 * 3
+ if nw > len(p) {
+ nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
+ d.out = d.outbuf[0:nw]
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ } else {
+ n, d.end, d.err = d.enc.decode(p, d.buf[0:nr])
+ }
+ d.nbuf -= nr
+ for i := 0; i < d.nbuf; i++ {
+ d.buf[i] = d.buf[i+nr]
+ }
+
+ if d.err == nil {
+ d.err = err
+ }
+ return n, d.err
+}
+
+// NewDecoder constructs a new base64 stream decoder.
+func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
+ return &decoder{enc: enc, r: r}
+}
+
+// DecodedLen returns the maximum length in bytes of the decoded data
+// corresponding to n bytes of base64-encoded data.
+func (enc *Encoding) DecodedLen(n int) int { return n / 4 * 3 }
diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go
new file mode 100644
index 000000000..de41e704b
--- /dev/null
+++ b/libgo/go/encoding/base64/base64_test.go
@@ -0,0 +1,196 @@
+// 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 base64
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type testpair struct {
+ decoded, encoded string
+}
+
+var pairs = []testpair{
+ // RFC 3548 examples
+ {"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+"},
+ {"\x14\xfb\x9c\x03\xd9", "FPucA9k="},
+ {"\x14\xfb\x9c\x03", "FPucAw=="},
+
+ // RFC 4648 examples
+ {"", ""},
+ {"f", "Zg=="},
+ {"fo", "Zm8="},
+ {"foo", "Zm9v"},
+ {"foob", "Zm9vYg=="},
+ {"fooba", "Zm9vYmE="},
+ {"foobar", "Zm9vYmFy"},
+
+ // Wikipedia examples
+ {"sure.", "c3VyZS4="},
+ {"sure", "c3VyZQ=="},
+ {"sur", "c3Vy"},
+ {"su", "c3U="},
+ {"leasure.", "bGVhc3VyZS4="},
+ {"easure.", "ZWFzdXJlLg=="},
+ {"asure.", "YXN1cmUu"},
+ {"sure.", "c3VyZS4="},
+}
+
+var bigtest = testpair{
+ "Twas brillig, and the slithy toves",
+ "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==",
+}
+
+func testEqual(t *testing.T, msg string, args ...interface{}) bool {
+ if args[len(args)-2] != args[len(args)-1] {
+ t.Errorf(msg, args...)
+ return false
+ }
+ return true
+}
+
+func TestEncode(t *testing.T) {
+ for _, p := range pairs {
+ buf := make([]byte, StdEncoding.EncodedLen(len(p.decoded)))
+ StdEncoding.Encode(buf, []byte(p.decoded))
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
+ }
+}
+
+func TestEncoder(t *testing.T) {
+ for _, p := range pairs {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(StdEncoding, bb)
+ encoder.Write([]byte(p.decoded))
+ encoder.Close()
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
+ }
+}
+
+func TestEncoderBuffering(t *testing.T) {
+ input := []byte(bigtest.decoded)
+ for bs := 1; bs <= 12; bs++ {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(StdEncoding, bb)
+ for pos := 0; pos < len(input); pos += bs {
+ end := pos + bs
+ if end > len(input) {
+ end = len(input)
+ }
+ n, err := encoder.Write(input[pos:end])
+ testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+ testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
+ }
+ err := encoder.Close()
+ testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+ testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded)
+ }
+}
+
+func TestDecode(t *testing.T) {
+ for _, p := range pairs {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
+ count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded))
+ testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded))
+ if len(p.encoded) > 0 {
+ testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '='))
+ }
+ testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
+ }
+}
+
+func TestDecoder(t *testing.T) {
+ for _, p := range pairs {
+ decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
+ count, err := decoder.Read(dbuf)
+ if err != nil && err != os.EOF {
+ t.Fatal("Read failed", err)
+ }
+ testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded))
+ testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
+ if err != os.EOF {
+ count, err = decoder.Read(dbuf)
+ }
+ testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+ }
+}
+
+func TestDecoderBuffering(t *testing.T) {
+ for bs := 1; bs <= 12; bs++ {
+ decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
+ buf := make([]byte, len(bigtest.decoded)+12)
+ var total int
+ for total = 0; total < len(bigtest.decoded); {
+ n, err := decoder.Read(buf[total : total+bs])
+ testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil))
+ total += n
+ }
+ testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
+ }
+}
+
+func TestDecodeCorrupt(t *testing.T) {
+ type corrupt struct {
+ e string
+ p int
+ }
+ examples := []corrupt{
+ {"!!!!", 0},
+ {"x===", 1},
+ {"AA=A", 2},
+ {"AAA=AAAA", 3},
+ {"AAAAA", 4},
+ {"AAAAAA", 4},
+ }
+
+ for _, e := range examples {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
+ _, err := StdEncoding.Decode(dbuf, []byte(e.e))
+ switch err := err.(type) {
+ case CorruptInputError:
+ testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ default:
+ t.Error("Decoder failed to detect corruption in", e)
+ }
+ }
+}
+
+func TestBig(t *testing.T) {
+ n := 3*1000 + 1
+ raw := make([]byte, n)
+ const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ for i := 0; i < n; i++ {
+ raw[i] = alpha[i%len(alpha)]
+ }
+ encoded := new(bytes.Buffer)
+ w := NewEncoder(StdEncoding, encoded)
+ nn, err := w.Write(raw)
+ if nn != n || err != nil {
+ t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
+ }
+ err = w.Close()
+ if err != nil {
+ t.Fatalf("Encoder.Close() = %v want nil", err)
+ }
+ decoded, err := ioutil.ReadAll(NewDecoder(StdEncoding, encoded))
+ if err != nil {
+ t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err)
+ }
+
+ if !bytes.Equal(raw, decoded) {
+ var i int
+ for i = 0; i < len(decoded) && i < len(raw); i++ {
+ if decoded[i] != raw[i] {
+ break
+ }
+ }
+ t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
+ }
+}
diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go
new file mode 100644
index 000000000..77ff3a9f3
--- /dev/null
+++ b/libgo/go/encoding/binary/binary.go
@@ -0,0 +1,409 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements translation between
+// unsigned integer values and byte sequences.
+package binary
+
+import (
+ "math"
+ "io"
+ "os"
+ "reflect"
+)
+
+// A ByteOrder specifies how to convert byte sequences into
+// 16-, 32-, or 64-bit unsigned integers.
+type ByteOrder interface {
+ Uint16(b []byte) uint16
+ Uint32(b []byte) uint32
+ Uint64(b []byte) uint64
+ PutUint16([]byte, uint16)
+ PutUint32([]byte, uint32)
+ PutUint64([]byte, uint64)
+ String() string
+}
+
+// This is byte instead of struct{} so that it can be compared,
+// allowing, e.g., order == binary.LittleEndian.
+type unused byte
+
+// LittleEndian is the little-endian implementation of ByteOrder.
+var LittleEndian littleEndian
+
+// BigEndian is the big-endian implementation of ByteOrder.
+var BigEndian bigEndian
+
+type littleEndian unused
+
+func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
+
+func (littleEndian) PutUint16(b []byte, v uint16) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+}
+
+func (littleEndian) Uint32(b []byte) uint32 {
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func (littleEndian) PutUint32(b []byte, v uint32) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+}
+
+func (littleEndian) Uint64(b []byte) uint64 {
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+func (littleEndian) PutUint64(b []byte, v uint64) {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+ b[4] = byte(v >> 32)
+ b[5] = byte(v >> 40)
+ b[6] = byte(v >> 48)
+ b[7] = byte(v >> 56)
+}
+
+func (littleEndian) String() string { return "LittleEndian" }
+
+func (littleEndian) GoString() string { return "binary.LittleEndian" }
+
+type bigEndian unused
+
+func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
+
+func (bigEndian) PutUint16(b []byte, v uint16) {
+ b[0] = byte(v >> 8)
+ b[1] = byte(v)
+}
+
+func (bigEndian) Uint32(b []byte) uint32 {
+ return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+}
+
+func (bigEndian) PutUint32(b []byte, v uint32) {
+ b[0] = byte(v >> 24)
+ b[1] = byte(v >> 16)
+ b[2] = byte(v >> 8)
+ b[3] = byte(v)
+}
+
+func (bigEndian) Uint64(b []byte) uint64 {
+ return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+}
+
+func (bigEndian) PutUint64(b []byte, v uint64) {
+ b[0] = byte(v >> 56)
+ b[1] = byte(v >> 48)
+ b[2] = byte(v >> 40)
+ b[3] = byte(v >> 32)
+ b[4] = byte(v >> 24)
+ b[5] = byte(v >> 16)
+ b[6] = byte(v >> 8)
+ b[7] = byte(v)
+}
+
+func (bigEndian) String() string { return "BigEndian" }
+
+func (bigEndian) GoString() string { return "binary.BigEndian" }
+
+// Read reads structured binary data from r into data.
+// Data must be a pointer to a fixed-size value or a slice
+// of fixed-size values.
+// A fixed-size value is either a fixed-size arithmetic
+// type (int8, uint8, int16, float32, complex64, ...)
+// or an array or struct containing only fixed-size values.
+// Bytes read from r are decoded using the specified byte order
+// and written to successive fields of the data.
+func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
+ var v reflect.Value
+ switch d := reflect.NewValue(data).(type) {
+ case *reflect.PtrValue:
+ v = d.Elem()
+ case *reflect.SliceValue:
+ v = d
+ default:
+ return os.NewError("binary.Read: invalid type " + d.Type().String())
+ }
+ size := TotalSize(v)
+ if size < 0 {
+ return os.NewError("binary.Read: invalid type " + v.Type().String())
+ }
+ d := &decoder{order: order, buf: make([]byte, size)}
+ if _, err := io.ReadFull(r, d.buf); err != nil {
+ return err
+ }
+ d.value(v)
+ return nil
+}
+
+// Write writes the binary representation of data into w.
+// Data must be a fixed-size value or a pointer to
+// a fixed-size value.
+// A fixed-size value is either a fixed-size arithmetic
+// type (int8, uint8, int16, float32, complex64, ...)
+// or an array or struct containing only fixed-size values.
+// Bytes written to w are encoded using the specified byte order
+// and read from successive fields of the data.
+func Write(w io.Writer, order ByteOrder, data interface{}) os.Error {
+ v := reflect.Indirect(reflect.NewValue(data))
+ size := TotalSize(v)
+ if size < 0 {
+ return os.NewError("binary.Write: invalid type " + v.Type().String())
+ }
+ buf := make([]byte, size)
+ e := &encoder{order: order, buf: buf}
+ e.value(v)
+ _, err := w.Write(buf)
+ return err
+}
+
+func TotalSize(v reflect.Value) int {
+ if sv, ok := v.(*reflect.SliceValue); ok {
+ elem := sizeof(v.Type().(*reflect.SliceType).Elem())
+ if elem < 0 {
+ return -1
+ }
+ return sv.Len() * elem
+ }
+ return sizeof(v.Type())
+}
+
+func sizeof(v reflect.Type) int {
+ switch t := v.(type) {
+ case *reflect.ArrayType:
+ n := sizeof(t.Elem())
+ if n < 0 {
+ return -1
+ }
+ return t.Len() * n
+
+ case *reflect.StructType:
+ sum := 0
+ for i, n := 0, t.NumField(); i < n; i++ {
+ s := sizeof(t.Field(i).Type)
+ if s < 0 {
+ return -1
+ }
+ sum += s
+ }
+ return sum
+
+ case *reflect.UintType, *reflect.IntType, *reflect.FloatType, *reflect.ComplexType:
+ switch t := t.Kind(); t {
+ case reflect.Int, reflect.Uint, reflect.Uintptr:
+ return -1
+ }
+ return int(v.Size())
+ }
+ return -1
+}
+
+type decoder struct {
+ order ByteOrder
+ buf []byte
+}
+
+type encoder struct {
+ order ByteOrder
+ buf []byte
+}
+
+func (d *decoder) uint8() uint8 {
+ x := d.buf[0]
+ d.buf = d.buf[1:]
+ return x
+}
+
+func (e *encoder) uint8(x uint8) {
+ e.buf[0] = x
+ e.buf = e.buf[1:]
+}
+
+func (d *decoder) uint16() uint16 {
+ x := d.order.Uint16(d.buf[0:2])
+ d.buf = d.buf[2:]
+ return x
+}
+
+func (e *encoder) uint16(x uint16) {
+ e.order.PutUint16(e.buf[0:2], x)
+ e.buf = e.buf[2:]
+}
+
+func (d *decoder) uint32() uint32 {
+ x := d.order.Uint32(d.buf[0:4])
+ d.buf = d.buf[4:]
+ return x
+}
+
+func (e *encoder) uint32(x uint32) {
+ e.order.PutUint32(e.buf[0:4], x)
+ e.buf = e.buf[4:]
+}
+
+func (d *decoder) uint64() uint64 {
+ x := d.order.Uint64(d.buf[0:8])
+ d.buf = d.buf[8:]
+ return x
+}
+
+func (e *encoder) uint64(x uint64) {
+ e.order.PutUint64(e.buf[0:8], x)
+ e.buf = e.buf[8:]
+}
+
+func (d *decoder) int8() int8 { return int8(d.uint8()) }
+
+func (e *encoder) int8(x int8) { e.uint8(uint8(x)) }
+
+func (d *decoder) int16() int16 { return int16(d.uint16()) }
+
+func (e *encoder) int16(x int16) { e.uint16(uint16(x)) }
+
+func (d *decoder) int32() int32 { return int32(d.uint32()) }
+
+func (e *encoder) int32(x int32) { e.uint32(uint32(x)) }
+
+func (d *decoder) int64() int64 { return int64(d.uint64()) }
+
+func (e *encoder) int64(x int64) { e.uint64(uint64(x)) }
+
+func (d *decoder) value(v reflect.Value) {
+ switch v := v.(type) {
+ case *reflect.ArrayValue:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ d.value(v.Elem(i))
+ }
+ case *reflect.StructValue:
+ l := v.NumField()
+ for i := 0; i < l; i++ {
+ d.value(v.Field(i))
+ }
+
+ case *reflect.SliceValue:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ d.value(v.Elem(i))
+ }
+
+ case *reflect.IntValue:
+ switch v.Type().Kind() {
+ case reflect.Int8:
+ v.Set(int64(d.int8()))
+ case reflect.Int16:
+ v.Set(int64(d.int16()))
+ case reflect.Int32:
+ v.Set(int64(d.int32()))
+ case reflect.Int64:
+ v.Set(d.int64())
+ }
+
+ case *reflect.UintValue:
+ switch v.Type().Kind() {
+ case reflect.Uint8:
+ v.Set(uint64(d.uint8()))
+ case reflect.Uint16:
+ v.Set(uint64(d.uint16()))
+ case reflect.Uint32:
+ v.Set(uint64(d.uint32()))
+ case reflect.Uint64:
+ v.Set(d.uint64())
+ }
+
+ case *reflect.FloatValue:
+ switch v.Type().Kind() {
+ case reflect.Float32:
+ v.Set(float64(math.Float32frombits(d.uint32())))
+ case reflect.Float64:
+ v.Set(math.Float64frombits(d.uint64()))
+ }
+
+ case *reflect.ComplexValue:
+ switch v.Type().Kind() {
+ case reflect.Complex64:
+ v.Set(complex(
+ float64(math.Float32frombits(d.uint32())),
+ float64(math.Float32frombits(d.uint32())),
+ ))
+ case reflect.Complex128:
+ v.Set(complex(
+ math.Float64frombits(d.uint64()),
+ math.Float64frombits(d.uint64()),
+ ))
+ }
+ }
+}
+
+func (e *encoder) value(v reflect.Value) {
+ switch v := v.(type) {
+ case *reflect.ArrayValue:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ e.value(v.Elem(i))
+ }
+ case *reflect.StructValue:
+ l := v.NumField()
+ for i := 0; i < l; i++ {
+ e.value(v.Field(i))
+ }
+ case *reflect.SliceValue:
+ l := v.Len()
+ for i := 0; i < l; i++ {
+ e.value(v.Elem(i))
+ }
+
+ case *reflect.IntValue:
+ switch v.Type().Kind() {
+ case reflect.Int8:
+ e.int8(int8(v.Get()))
+ case reflect.Int16:
+ e.int16(int16(v.Get()))
+ case reflect.Int32:
+ e.int32(int32(v.Get()))
+ case reflect.Int64:
+ e.int64(v.Get())
+ }
+
+ case *reflect.UintValue:
+ switch v.Type().Kind() {
+ case reflect.Uint8:
+ e.uint8(uint8(v.Get()))
+ case reflect.Uint16:
+ e.uint16(uint16(v.Get()))
+ case reflect.Uint32:
+ e.uint32(uint32(v.Get()))
+ case reflect.Uint64:
+ e.uint64(v.Get())
+ }
+
+ case *reflect.FloatValue:
+ switch v.Type().Kind() {
+ case reflect.Float32:
+ e.uint32(math.Float32bits(float32(v.Get())))
+ case reflect.Float64:
+ e.uint64(math.Float64bits(v.Get()))
+ }
+
+ case *reflect.ComplexValue:
+ switch v.Type().Kind() {
+ case reflect.Complex64:
+ x := v.Get()
+ e.uint32(math.Float32bits(float32(real(x))))
+ e.uint32(math.Float32bits(float32(imag(x))))
+ case reflect.Complex128:
+ x := v.Get()
+ e.uint64(math.Float64bits(real(x)))
+ e.uint64(math.Float64bits(imag(x)))
+ }
+ }
+}
diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go
new file mode 100644
index 000000000..e09ec489f
--- /dev/null
+++ b/libgo/go/encoding/binary/binary_test.go
@@ -0,0 +1,162 @@
+// 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 binary
+
+import (
+ "os"
+ "bytes"
+ "math"
+ "reflect"
+ "testing"
+)
+
+type Struct struct {
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ Float32 float32
+ Float64 float64
+ Complex64 complex64
+ Complex128 complex128
+ Array [4]uint8
+}
+
+type T struct {
+ Int int
+ Uint uint
+ Uintptr uintptr
+ Array [4]int
+}
+
+var s = Struct{
+ 0x01,
+ 0x0203,
+ 0x04050607,
+ 0x08090a0b0c0d0e0f,
+ 0x10,
+ 0x1112,
+ 0x13141516,
+ 0x1718191a1b1c1d1e,
+
+ math.Float32frombits(0x1f202122),
+ math.Float64frombits(0x232425262728292a),
+ complex(
+ math.Float32frombits(0x2b2c2d2e),
+ math.Float32frombits(0x2f303132),
+ ),
+ complex(
+ math.Float64frombits(0x333435363738393a),
+ math.Float64frombits(0x3b3c3d3e3f404142),
+ ),
+
+ [4]uint8{0x43, 0x44, 0x45, 0x46},
+}
+
+var big = []byte{
+ 1,
+ 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16,
+ 17, 18,
+ 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30,
+
+ 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+
+ 67, 68, 69, 70,
+}
+
+var little = []byte{
+ 1,
+ 3, 2,
+ 7, 6, 5, 4,
+ 15, 14, 13, 12, 11, 10, 9, 8,
+ 16,
+ 18, 17,
+ 22, 21, 20, 19,
+ 30, 29, 28, 27, 26, 25, 24, 23,
+
+ 34, 33, 32, 31,
+ 42, 41, 40, 39, 38, 37, 36, 35,
+ 46, 45, 44, 43, 50, 49, 48, 47,
+ 58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59,
+
+ 67, 68, 69, 70,
+}
+
+var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
+var res = []int32{0x01020304, 0x05060708}
+
+func checkResult(t *testing.T, dir string, order, err os.Error, have, want interface{}) {
+ if err != nil {
+ t.Errorf("%v %v: %v", dir, order, err)
+ return
+ }
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("%v %v:\n\thave %+v\n\twant %+v", dir, order, have, want)
+ }
+}
+
+func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
+ var s2 Struct
+ err := Read(bytes.NewBuffer(b), order, &s2)
+ checkResult(t, "Read", order, err, s2, s1)
+}
+
+func testWrite(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
+ buf := new(bytes.Buffer)
+ err := Write(buf, order, s1)
+ checkResult(t, "Write", order, err, buf.Bytes(), b)
+}
+
+func TestBigEndianRead(t *testing.T) { testRead(t, BigEndian, big, s) }
+
+func TestLittleEndianRead(t *testing.T) { testRead(t, LittleEndian, little, s) }
+
+func TestBigEndianWrite(t *testing.T) { testWrite(t, BigEndian, big, s) }
+
+func TestLittleEndianWrite(t *testing.T) { testWrite(t, LittleEndian, little, s) }
+
+func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) }
+
+func TestLittleEndianPtrWrite(t *testing.T) { testWrite(t, LittleEndian, little, &s) }
+
+func TestReadSlice(t *testing.T) {
+ slice := make([]int32, 2)
+ err := Read(bytes.NewBuffer(src), BigEndian, slice)
+ checkResult(t, "ReadSlice", BigEndian, err, slice, res)
+}
+
+func TestWriteSlice(t *testing.T) {
+ buf := new(bytes.Buffer)
+ err := Write(buf, BigEndian, res)
+ checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src)
+}
+
+func TestWriteT(t *testing.T) {
+ buf := new(bytes.Buffer)
+ ts := T{}
+ err := Write(buf, BigEndian, ts)
+ if err == nil {
+ t.Errorf("WriteT: have nil, want non-nil")
+ }
+
+ tv := reflect.Indirect(reflect.NewValue(ts)).(*reflect.StructValue)
+ for i, n := 0, tv.NumField(); i < n; i++ {
+ err = Write(buf, BigEndian, tv.Field(i).Interface())
+ if err == nil {
+ t.Errorf("WriteT.%v: have nil, want non-nil", tv.Field(i).Type())
+ }
+ }
+}
diff --git a/libgo/go/encoding/git85/git.go b/libgo/go/encoding/git85/git.go
new file mode 100644
index 000000000..09a45cd3c
--- /dev/null
+++ b/libgo/go/encoding/git85/git.go
@@ -0,0 +1,277 @@
+// 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 git85 implements the radix 85 data encoding
+// used in the Git version control system.
+package git85
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+)
+
+type CorruptInputError int64
+
+func (e CorruptInputError) String() string {
+ return "illegal git85 data at input byte " + strconv.Itoa64(int64(e))
+}
+
+const encode = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
+
+// The decodings are 1+ the actual value, so that the
+// default zero value can be used to mean "not valid".
+var decode = [256]uint8{
+ '0': 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 'A': 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 'a': 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+ '!': 63,
+ '#': 64, 65, 66, 67,
+ '(': 68, 69, 70, 71,
+ '-': 72,
+ ';': 73,
+ '<': 74, 75, 76, 77,
+ '@': 78,
+ '^': 79, 80, 81,
+ '{': 82, 83, 84, 85,
+}
+
+// Encode encodes src into EncodedLen(len(src))
+// bytes of dst. As a convenience, it returns the number
+// of bytes written to dst, but this value is always EncodedLen(len(src)).
+// Encode implements the radix 85 encoding used in the
+// Git version control tool.
+//
+// The encoding splits src into chunks of at most 52 bytes
+// and encodes each chunk on its own line.
+func Encode(dst, src []byte) int {
+ ndst := 0
+ for len(src) > 0 {
+ n := len(src)
+ if n > 52 {
+ n = 52
+ }
+ if n <= 27 {
+ dst[ndst] = byte('A' + n - 1)
+ } else {
+ dst[ndst] = byte('a' + n - 26 - 1)
+ }
+ ndst++
+ for i := 0; i < n; i += 4 {
+ var v uint32
+ for j := 0; j < 4 && i+j < n; j++ {
+ v |= uint32(src[i+j]) << uint(24-j*8)
+ }
+ for j := 4; j >= 0; j-- {
+ dst[ndst+j] = encode[v%85]
+ v /= 85
+ }
+ ndst += 5
+ }
+ dst[ndst] = '\n'
+ ndst++
+ src = src[n:]
+ }
+ return ndst
+}
+
+// EncodedLen returns the length of an encoding of n source bytes.
+func EncodedLen(n int) int {
+ if n == 0 {
+ return 0
+ }
+ // 5 bytes per 4 bytes of input, rounded up.
+ // 2 extra bytes for each line of 52 src bytes, rounded up.
+ return (n+3)/4*5 + (n+51)/52*2
+}
+
+var newline = []byte{'\n'}
+
+// Decode decodes src into at most MaxDecodedLen(len(src))
+// bytes, returning the actual number of bytes written to dst.
+//
+// If Decode encounters invalid input, it returns a CorruptInputError.
+//
+func Decode(dst, src []byte) (n int, err os.Error) {
+ ndst := 0
+ nsrc := 0
+ for nsrc < len(src) {
+ var l int
+ switch ch := int(src[nsrc]); {
+ case 'A' <= ch && ch <= 'Z':
+ l = ch - 'A' + 1
+ case 'a' <= ch && ch <= 'z':
+ l = ch - 'a' + 26 + 1
+ default:
+ return ndst, CorruptInputError(nsrc)
+ }
+ if nsrc+1+l > len(src) {
+ return ndst, CorruptInputError(nsrc)
+ }
+ el := (l + 3) / 4 * 5 // encoded len
+ if nsrc+1+el+1 > len(src) || src[nsrc+1+el] != '\n' {
+ return ndst, CorruptInputError(nsrc)
+ }
+ line := src[nsrc+1 : nsrc+1+el]
+ for i := 0; i < el; i += 5 {
+ var v uint32
+ for j := 0; j < 5; j++ {
+ ch := decode[line[i+j]]
+ if ch == 0 {
+ return ndst, CorruptInputError(nsrc + 1 + i + j)
+ }
+ v = v*85 + uint32(ch-1)
+ }
+ for j := 0; j < 4; j++ {
+ dst[ndst] = byte(v >> 24)
+ v <<= 8
+ ndst++
+ }
+ }
+ // Last fragment may have run too far (but there was room in dst).
+ // Back up.
+ if l%4 != 0 {
+ ndst -= 4 - l%4
+ }
+ nsrc += 1 + el + 1
+ }
+ return ndst, nil
+}
+
+func MaxDecodedLen(n int) int { return n / 5 * 4 }
+
+// NewEncoder returns a new Git base85 stream encoder. Data written to
+// the returned writer will be encoded and then written to w.
+// The Git encoding operates on 52-byte blocks; when finished
+// writing, the caller must Close the returned encoder to flush any
+// partially written blocks.
+func NewEncoder(w io.Writer) io.WriteCloser { return &encoder{w: w} }
+
+type encoder struct {
+ w io.Writer
+ err os.Error
+ buf [52]byte
+ nbuf int
+ out [1024]byte
+ nout int
+}
+
+func (e *encoder) Write(p []byte) (n int, err os.Error) {
+ if e.err != nil {
+ return 0, e.err
+ }
+
+ // Leading fringe.
+ if e.nbuf > 0 {
+ var i int
+ for i = 0; i < len(p) && e.nbuf < 52; i++ {
+ e.buf[e.nbuf] = p[i]
+ e.nbuf++
+ }
+ n += i
+ p = p[i:]
+ if e.nbuf < 52 {
+ return
+ }
+ nout := Encode(e.out[0:], e.buf[0:])
+ if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+ return n, e.err
+ }
+ e.nbuf = 0
+ }
+
+ // Large interior chunks.
+ for len(p) >= 52 {
+ nn := len(e.out) / (1 + 52/4*5 + 1) * 52
+ if nn > len(p) {
+ nn = len(p) / 52 * 52
+ }
+ if nn > 0 {
+ nout := Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
+ return n, e.err
+ }
+ }
+ n += nn
+ p = p[nn:]
+ }
+
+ // Trailing fringe.
+ for i := 0; i < len(p); i++ {
+ e.buf[i] = p[i]
+ }
+ e.nbuf = len(p)
+ n += len(p)
+ return
+}
+
+func (e *encoder) Close() os.Error {
+ // If there's anything left in the buffer, flush it out
+ if e.err == nil && e.nbuf > 0 {
+ nout := Encode(e.out[0:], e.buf[0:e.nbuf])
+ e.nbuf = 0
+ _, e.err = e.w.Write(e.out[0:nout])
+ }
+ return e.err
+}
+
+// NewDecoder returns a new Git base85 stream decoder.
+func NewDecoder(r io.Reader) io.Reader { return &decoder{r: r} }
+
+type decoder struct {
+ r io.Reader
+ err os.Error
+ readErr os.Error
+ buf [1024]byte
+ nbuf int
+ out []byte
+ outbuf [1024]byte
+ off int64
+}
+
+func (d *decoder) Read(p []byte) (n int, err os.Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
+
+ for {
+ // Copy leftover output from last decode.
+ if len(d.out) > 0 {
+ n = copy(p, d.out)
+ d.out = d.out[n:]
+ return
+ }
+
+ // Out of decoded output. Check errors.
+ if d.err != nil {
+ return 0, d.err
+ }
+ if d.readErr != nil {
+ d.err = d.readErr
+ return 0, d.err
+ }
+
+ // Read and decode more input.
+ var nn int
+ nn, d.readErr = d.r.Read(d.buf[d.nbuf:])
+ d.nbuf += nn
+
+ // Send complete lines to Decode.
+ nl := bytes.LastIndex(d.buf[0:d.nbuf], newline)
+ if nl < 0 {
+ continue
+ }
+ nn, d.err = Decode(d.outbuf[0:], d.buf[0:nl+1])
+ if e, ok := d.err.(CorruptInputError); ok {
+ d.err = CorruptInputError(int64(e) + d.off)
+ }
+ d.out = d.outbuf[0:nn]
+ d.nbuf = copy(d.buf[0:], d.buf[nl+1:d.nbuf])
+ d.off += int64(nl + 1)
+ }
+ panic("unreacahable")
+}
diff --git a/libgo/go/encoding/git85/git_test.go b/libgo/go/encoding/git85/git_test.go
new file mode 100644
index 000000000..c76385c35
--- /dev/null
+++ b/libgo/go/encoding/git85/git_test.go
@@ -0,0 +1,194 @@
+// 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 git85
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type testpair struct {
+ decoded, encoded string
+}
+
+func testEqual(t *testing.T, msg string, args ...interface{}) bool {
+ if args[len(args)-2] != args[len(args)-1] {
+ t.Errorf(msg, args...)
+ return false
+ }
+ return true
+}
+
+func TestGitTable(t *testing.T) {
+ var saw [256]bool
+ for i, c := range encode {
+ if decode[c] != uint8(i+1) {
+ t.Errorf("decode['%c'] = %d, want %d", c, decode[c], i+1)
+ }
+ saw[c] = true
+ }
+ for i, b := range saw {
+ if !b && decode[i] != 0 {
+ t.Errorf("decode[%d] = %d, want 0", i, decode[i])
+ }
+ }
+}
+
+var gitPairs = []testpair{
+ // Wikipedia example, adapted.
+ {
+ "Man is distinguished, not only by his reason, but by this singular passion from " +
+ "other animals, which is a lust of the mind, that by a perseverance of delight in " +
+ "the continued and indefatigable generation of knowledge, exceeds the short " +
+ "vehemence of any carnal pleasure.",
+
+ "zO<`^zX>%ZCX>)XGZfA9Ab7*B`EFf-gbRchTY<VDJc_3(Mb0BhMVRLV8EFfZabRc4R\n" +
+ "zAarPHb0BkRZfA9DVR9gFVRLh7Z*CxFa&K)QZ**v7av))DX>DO_b1WctXlY|;AZc?T\n" +
+ "zVIXXEb95kYW*~HEWgu;7Ze%PVbZB98AYyqSVIXj2a&u*NWpZI|V`U(3W*}r`Y-wj`\n" +
+ "zbRcPNAarPDAY*TCbZKsNWn>^>Ze$>7Ze(R<VRUI{VPb4$AZKN6WpZJ3X>V>IZ)PBC\n" +
+ "zZf|#NWn^b%EFfigV`XJzb0BnRWgv5CZ*p`Xc4cT~ZDnp_Wgu^6AYpEKAY);2ZeeU7\n" +
+ "IaBO8^b9HiME&u=k\n",
+ },
+}
+
+var gitBigtest = gitPairs[len(gitPairs)-1]
+
+func TestEncode(t *testing.T) {
+ for _, p := range gitPairs {
+ buf := make([]byte, EncodedLen(len(p.decoded)))
+ n := Encode(buf, []byte(p.decoded))
+ if n != len(buf) {
+ t.Errorf("EncodedLen does not agree with Encode")
+ }
+ buf = buf[0:n]
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
+ }
+}
+
+func TestEncoder(t *testing.T) {
+ for _, p := range gitPairs {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(bb)
+ encoder.Write([]byte(p.decoded))
+ encoder.Close()
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
+ }
+}
+
+func TestEncoderBuffering(t *testing.T) {
+ input := []byte(gitBigtest.decoded)
+ for bs := 1; bs <= 12; bs++ {
+ bb := &bytes.Buffer{}
+ encoder := NewEncoder(bb)
+ for pos := 0; pos < len(input); pos += bs {
+ end := pos + bs
+ if end > len(input) {
+ end = len(input)
+ }
+ n, err := encoder.Write(input[pos:end])
+ testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+ testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
+ }
+ err := encoder.Close()
+ testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+ testEqual(t, "Encoding/%d of %q = %q, want %q", bs, gitBigtest.decoded, bb.String(), gitBigtest.encoded)
+ }
+}
+
+func TestDecode(t *testing.T) {
+ for _, p := range gitPairs {
+ dbuf := make([]byte, 4*len(p.encoded))
+ ndst, err := Decode(dbuf, []byte(p.encoded))
+ testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "Decode(%q) = ndst %v, want %v", p.encoded, ndst, len(p.decoded))
+ testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:ndst]), p.decoded)
+ }
+}
+
+func TestDecoder(t *testing.T) {
+ for _, p := range gitPairs {
+ decoder := NewDecoder(bytes.NewBufferString(p.encoded))
+ dbuf, err := ioutil.ReadAll(decoder)
+ if err != nil {
+ t.Fatal("Read failed", err)
+ }
+ testEqual(t, "Read from %q = length %v, want %v", p.encoded, len(dbuf), len(p.decoded))
+ testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf), p.decoded)
+ if err != nil {
+ testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+ }
+ }
+}
+
+func TestDecoderBuffering(t *testing.T) {
+ for bs := 1; bs <= 12; bs++ {
+ decoder := NewDecoder(bytes.NewBufferString(gitBigtest.encoded))
+ buf := make([]byte, len(gitBigtest.decoded)+12)
+ var total int
+ for total = 0; total < len(gitBigtest.decoded); {
+ n, err := decoder.Read(buf[total : total+bs])
+ testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", gitBigtest.encoded, total, n, err, os.Error(nil))
+ total += n
+ }
+ testEqual(t, "Decoding/%d of %q = %q, want %q", bs, gitBigtest.encoded, string(buf[0:total]), gitBigtest.decoded)
+ }
+}
+
+func TestDecodeCorrupt(t *testing.T) {
+ type corrupt struct {
+ e string
+ p int
+ }
+ examples := []corrupt{
+ {"v", 0},
+ {"!z!!!!!!!!!", 0},
+ }
+
+ for _, e := range examples {
+ dbuf := make([]byte, 2*len(e.e))
+ _, err := Decode(dbuf, []byte(e.e))
+ switch err := err.(type) {
+ case CorruptInputError:
+ testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ default:
+ t.Error("Decoder failed to detect corruption in", e)
+ }
+ }
+}
+
+func TestGitBig(t *testing.T) {
+ n := 3*1000 + 1
+ raw := make([]byte, n)
+ const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ for i := 0; i < n; i++ {
+ raw[i] = alpha[i%len(alpha)]
+ }
+ encoded := new(bytes.Buffer)
+ w := NewEncoder(encoded)
+ nn, err := w.Write(raw)
+ if nn != n || err != nil {
+ t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
+ }
+ err = w.Close()
+ if err != nil {
+ t.Fatalf("Encoder.Close() = %v want nil", err)
+ }
+ decoded, err := ioutil.ReadAll(NewDecoder(encoded))
+ if err != nil {
+ t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err)
+ }
+
+ if !bytes.Equal(raw, decoded) {
+ var i int
+ for i = 0; i < len(decoded) && i < len(raw); i++ {
+ if decoded[i] != raw[i] {
+ break
+ }
+ }
+ t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
+ }
+}
diff --git a/libgo/go/encoding/hex/hex.go b/libgo/go/encoding/hex/hex.go
new file mode 100644
index 000000000..292d917eb
--- /dev/null
+++ b/libgo/go/encoding/hex/hex.go
@@ -0,0 +1,101 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements hexadecimal encoding and decoding.
+package hex
+
+import (
+ "os"
+ "strconv"
+)
+
+const hextable = "0123456789abcdef"
+
+// EncodedLen returns the length of an encoding of n source bytes.
+func EncodedLen(n int) int { return n * 2 }
+
+// Encode encodes src into EncodedLen(len(src))
+// bytes of dst. As a convenience, it returns the number
+// of bytes written to dst, but this value is always EncodedLen(len(src)).
+// Encode implements hexadecimal encoding.
+func Encode(dst, src []byte) int {
+ for i, v := range src {
+ dst[i*2] = hextable[v>>4]
+ dst[i*2+1] = hextable[v&0x0f]
+ }
+
+ return len(src) * 2
+}
+
+// OddLengthInputError results from decoding an odd length slice.
+type OddLengthInputError struct{}
+
+func (OddLengthInputError) String() string { return "odd length hex string" }
+
+// InvalidHexCharError results from finding an invalid character in a hex string.
+type InvalidHexCharError byte
+
+func (e InvalidHexCharError) String() string {
+ return "invalid hex char: " + strconv.Itoa(int(e))
+}
+
+
+func DecodedLen(x int) int { return x / 2 }
+
+// Decode decodes src into DecodedLen(len(src)) bytes, returning the actual
+// number of bytes written to dst.
+//
+// If Decode encounters invalid input, it returns an OddLengthInputError or an
+// InvalidHexCharError.
+func Decode(dst, src []byte) (int, os.Error) {
+ if len(src)%2 == 1 {
+ return 0, OddLengthInputError{}
+ }
+
+ for i := 0; i < len(src)/2; i++ {
+ a, ok := fromHexChar(src[i*2])
+ if !ok {
+ return 0, InvalidHexCharError(src[i*2])
+ }
+ b, ok := fromHexChar(src[i*2+1])
+ if !ok {
+ return 0, InvalidHexCharError(src[i*2+1])
+ }
+ dst[i] = (a << 4) | b
+ }
+
+ return len(src) / 2, nil
+}
+
+// fromHexChar converts a hex character into its value and a success flag.
+func fromHexChar(c byte) (byte, bool) {
+ switch {
+ case '0' <= c && c <= '9':
+ return c - '0', true
+ case 'a' <= c && c <= 'f':
+ return c - 'a' + 10, true
+ case 'A' <= c && c <= 'F':
+ return c - 'A' + 10, true
+ }
+
+ return 0, false
+}
+
+// EncodeToString returns the hexadecimal encoding of src.
+func EncodeToString(src []byte) string {
+ dst := make([]byte, EncodedLen(len(src)))
+ Encode(dst, src)
+ return string(dst)
+}
+
+// DecodeString returns the bytes represented by the hexadecimal string s.
+func DecodeString(s string) ([]byte, os.Error) {
+ src := []byte(s)
+ dst := make([]byte, DecodedLen(len(src)))
+ _, err := Decode(dst, src)
+ if err != nil {
+ return nil, err
+ }
+ return dst, nil
+}
diff --git a/libgo/go/encoding/hex/hex_test.go b/libgo/go/encoding/hex/hex_test.go
new file mode 100644
index 000000000..a14c9d4f4
--- /dev/null
+++ b/libgo/go/encoding/hex/hex_test.go
@@ -0,0 +1,149 @@
+// 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 hex
+
+import (
+ "bytes"
+ "testing"
+)
+
+type encodeTest struct {
+ in, out []byte
+}
+
+var encodeTests = []encodeTest{
+ {[]byte{}, []byte{}},
+ {[]byte{0x01}, []byte{'0', '1'}},
+ {[]byte{0xff}, []byte{'f', 'f'}},
+ {[]byte{0xff, 00}, []byte{'f', 'f', '0', '0'}},
+ {[]byte{0}, []byte{'0', '0'}},
+ {[]byte{1}, []byte{'0', '1'}},
+ {[]byte{2}, []byte{'0', '2'}},
+ {[]byte{3}, []byte{'0', '3'}},
+ {[]byte{4}, []byte{'0', '4'}},
+ {[]byte{5}, []byte{'0', '5'}},
+ {[]byte{6}, []byte{'0', '6'}},
+ {[]byte{7}, []byte{'0', '7'}},
+ {[]byte{8}, []byte{'0', '8'}},
+ {[]byte{9}, []byte{'0', '9'}},
+ {[]byte{10}, []byte{'0', 'a'}},
+ {[]byte{11}, []byte{'0', 'b'}},
+ {[]byte{12}, []byte{'0', 'c'}},
+ {[]byte{13}, []byte{'0', 'd'}},
+ {[]byte{14}, []byte{'0', 'e'}},
+ {[]byte{15}, []byte{'0', 'f'}},
+}
+
+func TestEncode(t *testing.T) {
+ for i, test := range encodeTests {
+ dst := make([]byte, EncodedLen(len(test.in)))
+ n := Encode(dst, test.in)
+ if n != len(dst) {
+ t.Errorf("#%d: bad return value: got: %d want: %d", i, n, len(dst))
+ }
+ if bytes.Compare(dst, test.out) != 0 {
+ t.Errorf("#%d: got: %#v want: %#v", i, dst, test.out)
+ }
+ }
+}
+
+type decodeTest struct {
+ in, out []byte
+ ok bool
+}
+
+var decodeTests = []decodeTest{
+ {[]byte{}, []byte{}, true},
+ {[]byte{'0'}, []byte{}, false},
+ {[]byte{'0', 'g'}, []byte{}, false},
+ {[]byte{'0', '\x01'}, []byte{}, false},
+ {[]byte{'0', '0'}, []byte{0}, true},
+ {[]byte{'0', '1'}, []byte{1}, true},
+ {[]byte{'0', '2'}, []byte{2}, true},
+ {[]byte{'0', '3'}, []byte{3}, true},
+ {[]byte{'0', '4'}, []byte{4}, true},
+ {[]byte{'0', '5'}, []byte{5}, true},
+ {[]byte{'0', '6'}, []byte{6}, true},
+ {[]byte{'0', '7'}, []byte{7}, true},
+ {[]byte{'0', '8'}, []byte{8}, true},
+ {[]byte{'0', '9'}, []byte{9}, true},
+ {[]byte{'0', 'a'}, []byte{10}, true},
+ {[]byte{'0', 'b'}, []byte{11}, true},
+ {[]byte{'0', 'c'}, []byte{12}, true},
+ {[]byte{'0', 'd'}, []byte{13}, true},
+ {[]byte{'0', 'e'}, []byte{14}, true},
+ {[]byte{'0', 'f'}, []byte{15}, true},
+ {[]byte{'0', 'A'}, []byte{10}, true},
+ {[]byte{'0', 'B'}, []byte{11}, true},
+ {[]byte{'0', 'C'}, []byte{12}, true},
+ {[]byte{'0', 'D'}, []byte{13}, true},
+ {[]byte{'0', 'E'}, []byte{14}, true},
+ {[]byte{'0', 'F'}, []byte{15}, true},
+}
+
+func TestDecode(t *testing.T) {
+ for i, test := range decodeTests {
+ dst := make([]byte, DecodedLen(len(test.in)))
+ n, err := Decode(dst, test.in)
+ if err == nil && n != len(dst) {
+ t.Errorf("#%d: bad return value: got:%d want:%d", i, n, len(dst))
+ }
+ if test.ok != (err == nil) {
+ t.Errorf("#%d: unexpected err value: %s", i, err)
+ }
+ if err == nil && bytes.Compare(dst, test.out) != 0 {
+ t.Errorf("#%d: got: %#v want: %#v", i, dst, test.out)
+ }
+ }
+}
+
+type encodeStringTest struct {
+ in []byte
+ out string
+}
+
+var encodeStringTests = []encodeStringTest{
+ {[]byte{}, ""},
+ {[]byte{0}, "00"},
+ {[]byte{0, 1}, "0001"},
+ {[]byte{0, 1, 255}, "0001ff"},
+}
+
+func TestEncodeToString(t *testing.T) {
+ for i, test := range encodeStringTests {
+ s := EncodeToString(test.in)
+ if s != test.out {
+ t.Errorf("#%d got:%s want:%s", i, s, test.out)
+ }
+ }
+}
+
+type decodeStringTest struct {
+ in string
+ out []byte
+ ok bool
+}
+
+var decodeStringTests = []decodeStringTest{
+ {"", []byte{}, true},
+ {"0", []byte{}, false},
+ {"00", []byte{0}, true},
+ {"0\x01", []byte{}, false},
+ {"0g", []byte{}, false},
+ {"00ff00", []byte{0, 255, 0}, true},
+ {"0000ff", []byte{0, 0, 255}, true},
+}
+
+func TestDecodeString(t *testing.T) {
+ for i, test := range decodeStringTests {
+ dst, err := DecodeString(test.in)
+ if test.ok != (err == nil) {
+ t.Errorf("#%d: unexpected err value: %s", i, err)
+ }
+ if err == nil && bytes.Compare(dst, test.out) != 0 {
+ t.Errorf("#%d: got: %#v want: #%v", i, dst, test.out)
+ }
+ }
+}
diff --git a/libgo/go/encoding/line/line.go b/libgo/go/encoding/line/line.go
new file mode 100644
index 000000000..92dddcb99
--- /dev/null
+++ b/libgo/go/encoding/line/line.go
@@ -0,0 +1,95 @@
+// 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.
+
+// This package implements a Reader which handles reading \r and \r\n
+// deliminated lines.
+package line
+
+import (
+ "io"
+ "os"
+)
+
+// Reader reads lines from an io.Reader (which may use either '\n' or
+// '\r\n').
+type Reader struct {
+ buf []byte
+ consumed int
+ in io.Reader
+ err os.Error
+}
+
+func NewReader(in io.Reader, maxLineLength int) *Reader {
+ return &Reader{
+ buf: make([]byte, 0, maxLineLength),
+ consumed: 0,
+ in: in,
+ }
+}
+
+// ReadLine tries to return a single line, not including the end-of-line bytes.
+// If the line was found to be longer than the maximum length then isPrefix is
+// set and the beginning of the line is returned. The rest of the line will be
+// returned from future calls. isPrefix will be false when returning the last
+// fragment of the line. The returned buffer points into the internal state of
+// the Reader and is only valid until the next call to ReadLine. ReadLine
+// either returns a non-nil line or it returns an error, never both.
+func (l *Reader) ReadLine() (line []byte, isPrefix bool, err os.Error) {
+ if l.consumed > 0 {
+ n := copy(l.buf, l.buf[l.consumed:])
+ l.buf = l.buf[:n]
+ l.consumed = 0
+ }
+
+ if len(l.buf) == 0 && l.err != nil {
+ err = l.err
+ return
+ }
+
+ scannedTo := 0
+
+ for {
+ i := scannedTo
+ for ; i < len(l.buf); i++ {
+ if l.buf[i] == '\r' && len(l.buf) > i+1 && l.buf[i+1] == '\n' {
+ line = l.buf[:i]
+ l.consumed = i + 2
+ return
+ } else if l.buf[i] == '\n' {
+ line = l.buf[:i]
+ l.consumed = i + 1
+ return
+ }
+ }
+
+ if i == cap(l.buf) {
+ line = l.buf[:i]
+ l.consumed = i
+ isPrefix = true
+ return
+ }
+
+ if l.err != nil {
+ line = l.buf
+ l.consumed = i
+ return
+ }
+
+ // We don't want to rescan the input that we just scanned.
+ // However, we need to back up one byte because the last byte
+ // could have been a '\r' and we do need to rescan that.
+ scannedTo = i
+ if scannedTo > 0 {
+ scannedTo--
+ }
+ oldLen := len(l.buf)
+ l.buf = l.buf[:cap(l.buf)]
+ n, readErr := l.in.Read(l.buf[oldLen:])
+ l.buf = l.buf[:oldLen+n]
+ if readErr != nil {
+ l.err = readErr
+ }
+ }
+ panic("unreachable")
+}
diff --git a/libgo/go/encoding/line/line_test.go b/libgo/go/encoding/line/line_test.go
new file mode 100644
index 000000000..68d13b586
--- /dev/null
+++ b/libgo/go/encoding/line/line_test.go
@@ -0,0 +1,89 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package line
+
+import (
+ "bytes"
+ "os"
+ "testing"
+)
+
+var testOutput = []byte("0123456789abcdefghijklmnopqrstuvwxy")
+var testInput = []byte("012\n345\n678\n9ab\ncde\nfgh\nijk\nlmn\nopq\nrst\nuvw\nxy")
+var testInputrn = []byte("012\r\n345\r\n678\r\n9ab\r\ncde\r\nfgh\r\nijk\r\nlmn\r\nopq\r\nrst\r\nuvw\r\nxy\r\n\n\r\n")
+
+// TestReader wraps a []byte and returns reads of a specific length.
+type testReader struct {
+ data []byte
+ stride int
+}
+
+func (t *testReader) Read(buf []byte) (n int, err os.Error) {
+ n = t.stride
+ if n > len(t.data) {
+ n = len(t.data)
+ }
+ if n > len(buf) {
+ n = len(buf)
+ }
+ copy(buf, t.data)
+ t.data = t.data[n:]
+ if len(t.data) == 0 {
+ err = os.EOF
+ }
+ return
+}
+
+func testLineReader(t *testing.T, input []byte) {
+ for stride := 1; stride < len(input); stride++ {
+ done := 0
+ reader := testReader{input, stride}
+ l := NewReader(&reader, len(input)+1)
+ for {
+ line, isPrefix, err := l.ReadLine()
+ if len(line) > 0 && err != nil {
+ t.Errorf("ReadLine returned both data and error: %s", err)
+ }
+ if isPrefix {
+ t.Errorf("ReadLine returned prefix")
+ }
+ if err != nil {
+ if err != os.EOF {
+ t.Fatalf("Got unknown error: %s", err)
+ }
+ break
+ }
+ if want := testOutput[done : done+len(line)]; !bytes.Equal(want, line) {
+ t.Errorf("Bad line at stride %d: want: %x got: %x", stride, want, line)
+ }
+ done += len(line)
+ }
+ if done != len(testOutput) {
+ t.Error("ReadLine didn't return everything")
+ }
+ }
+}
+
+func TestReader(t *testing.T) {
+ testLineReader(t, testInput)
+ testLineReader(t, testInputrn)
+}
+
+func TestLineTooLong(t *testing.T) {
+ buf := bytes.NewBuffer([]byte("aaabbbcc\n"))
+ l := NewReader(buf, 3)
+ line, isPrefix, err := l.ReadLine()
+ if !isPrefix || !bytes.Equal(line, []byte("aaa")) || err != nil {
+ t.Errorf("bad result for first line: %x %s", line, err)
+ }
+ line, isPrefix, err = l.ReadLine()
+ if !isPrefix || !bytes.Equal(line, []byte("bbb")) || err != nil {
+ t.Errorf("bad result for second line: %x", line)
+ }
+ line, isPrefix, err = l.ReadLine()
+ if isPrefix || !bytes.Equal(line, []byte("cc")) || err != nil {
+ t.Errorf("bad result for third line: %x", line)
+ }
+}
diff --git a/libgo/go/encoding/pem/pem.go b/libgo/go/encoding/pem/pem.go
new file mode 100644
index 000000000..5653aeb77
--- /dev/null
+++ b/libgo/go/encoding/pem/pem.go
@@ -0,0 +1,257 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the PEM data encoding, which originated in Privacy
+// Enhanced Mail. The most common use of PEM encoding today is in TLS keys and
+// certificates. See RFC 1421.
+package pem
+
+import (
+ "bytes"
+ "encoding/base64"
+ "io"
+ "os"
+)
+
+// A Block represents a PEM encoded structure.
+//
+// The encoded form is:
+// -----BEGIN Type-----
+// Headers
+// base64-encoded Bytes
+// -----END Type-----
+// where Headers is a possibly empty sequence of Key: Value lines.
+type Block struct {
+ Type string // The type, taken from the preamble (i.e. "RSA PRIVATE KEY").
+ Headers map[string]string // Optional headers.
+ Bytes []byte // The decoded bytes of the contents. Typically a DER encoded ASN.1 structure.
+}
+
+// getLine results the first \r\n or \n delineated line from the given byte
+// array. The line does not include the \r\n or \n. The remainder of the byte
+// array (also not including the new line bytes) is also returned and this will
+// always be smaller than the original argument.
+func getLine(data []byte) (line, rest []byte) {
+ i := bytes.Index(data, []byte{'\n'})
+ var j int
+ if i < 0 {
+ i = len(data)
+ j = i
+ } else {
+ j = i + 1
+ if i > 0 && data[i-1] == '\r' {
+ i--
+ }
+ }
+ return data[0:i], data[j:]
+}
+
+// removeWhitespace returns a copy of its input with all spaces, tab and
+// newline characters removed.
+func removeWhitespace(data []byte) []byte {
+ result := make([]byte, len(data))
+ n := 0
+
+ for _, b := range data {
+ if b == ' ' || b == '\t' || b == '\r' || b == '\n' {
+ continue
+ }
+ result[n] = b
+ n++
+ }
+
+ return result[0:n]
+}
+
+var pemStart = []byte("\n-----BEGIN ")
+var pemEnd = []byte("\n-----END ")
+var pemEndOfLine = []byte("-----")
+
+// Decode will find the next PEM formatted block (certificate, private key
+// etc) in the input. It returns that block and the remainder of the input. If
+// no PEM data is found, p is nil and the whole of the input is returned in
+// rest.
+func Decode(data []byte) (p *Block, rest []byte) {
+ // pemStart begins with a newline. However, at the very beginning of
+ // the byte array, we'll accept the start string without it.
+ rest = data
+ if bytes.HasPrefix(data, pemStart[1:]) {
+ rest = rest[len(pemStart)-1 : len(data)]
+ } else if i := bytes.Index(data, pemStart); i >= 0 {
+ rest = rest[i+len(pemStart) : len(data)]
+ } else {
+ return nil, data
+ }
+
+ typeLine, rest := getLine(rest)
+ if !bytes.HasSuffix(typeLine, pemEndOfLine) {
+ goto Error
+ }
+ typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)]
+
+ p = &Block{
+ Headers: make(map[string]string),
+ Type: string(typeLine),
+ }
+
+ for {
+ // This loop terminates because getLine's second result is
+ // always smaller than it's argument.
+ if len(rest) == 0 {
+ return nil, data
+ }
+ line, next := getLine(rest)
+
+ i := bytes.Index(line, []byte{':'})
+ if i == -1 {
+ break
+ }
+
+ // TODO(agl): need to cope with values that spread across lines.
+ key, val := line[0:i], line[i+1:]
+ key = bytes.TrimSpace(key)
+ val = bytes.TrimSpace(val)
+ p.Headers[string(key)] = string(val)
+ rest = next
+ }
+
+ i := bytes.Index(rest, pemEnd)
+ if i < 0 {
+ goto Error
+ }
+ 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
+ }
+ p.Bytes = p.Bytes[0:n]
+
+ _, rest = getLine(rest[i+len(pemEnd):])
+
+ return
+
+Error:
+ // 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
+ // any lines which could be header lines. However, a valid preamble
+ // line is not a valid header line, therefore we cannot have consumed
+ // the preamble line for the any subsequent block. Thus, we will always
+ // find any valid block, no matter what bytes preceed it.
+ //
+ // For example, if the input is
+ //
+ // -----BEGIN MALFORMED BLOCK-----
+ // junk that may look like header lines
+ // or data lines, but no END line
+ //
+ // -----BEGIN ACTUAL BLOCK-----
+ // realdata
+ // -----END ACTUAL BLOCK-----
+ //
+ // we've failed to parse using the first BEGIN line
+ // and now will try again, using the second BEGIN line.
+ p, rest = Decode(rest)
+ if p == nil {
+ rest = data
+ }
+ return
+}
+
+const pemLineLength = 64
+
+type lineBreaker struct {
+ line [pemLineLength]byte
+ used int
+ out io.Writer
+}
+
+func (l *lineBreaker) Write(b []byte) (n int, err os.Error) {
+ if l.used+len(b) < pemLineLength {
+ copy(l.line[l.used:], b)
+ l.used += len(b)
+ return len(b), nil
+ }
+
+ n, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ excess := pemLineLength - l.used
+ l.used = 0
+
+ n, err = l.out.Write(b[0:excess])
+ if err != nil {
+ return
+ }
+
+ n, err = l.out.Write([]byte{'\n'})
+ if err != nil {
+ return
+ }
+
+ return l.Write(b[excess:])
+}
+
+func (l *lineBreaker) Close() (err os.Error) {
+ if l.used > 0 {
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ _, err = l.out.Write([]byte{'\n'})
+ }
+
+ return
+}
+
+func Encode(out io.Writer, b *Block) (err os.Error) {
+ _, err = out.Write(pemStart[1:])
+ if err != nil {
+ return
+ }
+ _, err = out.Write([]byte(b.Type + "-----\n"))
+ if err != nil {
+ return
+ }
+
+ if len(b.Headers) > 0 {
+ for k, v := range b.Headers {
+ _, err = out.Write([]byte(k + ": " + v + "\n"))
+ if err != nil {
+ return
+ }
+ }
+ _, err = out.Write([]byte{'\n'})
+ if err != nil {
+ return
+ }
+ }
+
+ var breaker lineBreaker
+ breaker.out = out
+
+ b64 := base64.NewEncoder(base64.StdEncoding, &breaker)
+ _, err = b64.Write(b.Bytes)
+ if err != nil {
+ return
+ }
+ b64.Close()
+ breaker.Close()
+
+ _, err = out.Write(pemEnd[1:])
+ if err != nil {
+ return
+ }
+ _, err = out.Write([]byte(b.Type + "-----\n"))
+ return
+}
+
+func EncodeToMemory(b *Block) []byte {
+ buf := bytes.NewBuffer(nil)
+ Encode(buf, b)
+ return buf.Bytes()
+}
diff --git a/libgo/go/encoding/pem/pem_test.go b/libgo/go/encoding/pem/pem_test.go
new file mode 100644
index 000000000..11efe5544
--- /dev/null
+++ b/libgo/go/encoding/pem/pem_test.go
@@ -0,0 +1,390 @@
+// 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 pem
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+)
+
+type GetLineTest struct {
+ in, out1, out2 string
+}
+
+var getLineTests = []GetLineTest{
+ {"abc", "abc", ""},
+ {"abc\r", "abc\r", ""},
+ {"abc\n", "abc", ""},
+ {"abc\r\n", "abc", ""},
+ {"abc\nd", "abc", "d"},
+ {"abc\r\nd", "abc", "d"},
+ {"\nabc", "", "abc"},
+ {"\r\nabc", "", "abc"},
+}
+
+func TestGetLine(t *testing.T) {
+ for i, test := range getLineTests {
+ x, y := getLine([]byte(test.in))
+ if string(x) != test.out1 || string(y) != test.out2 {
+ t.Errorf("#%d got:%+v,%+v want:%s,%s", i, x, y, test.out1, test.out2)
+ }
+ }
+}
+
+func TestDecode(t *testing.T) {
+ result, remainder := Decode([]byte(pemData))
+ if !reflect.DeepEqual(result, certificate) {
+ t.Errorf("#0 got:%#v want:%#v", result, certificate)
+ }
+ result, remainder = Decode(remainder)
+ if !reflect.DeepEqual(result, privateKey) {
+ t.Errorf("#1 got:%#v want:%#v", result, privateKey)
+ }
+ result, _ = Decode([]byte(pemPrivateKey))
+ if !reflect.DeepEqual(result, privateKey2) {
+ t.Errorf("#2 got:%#v want:%#v", result, privateKey2)
+ }
+}
+
+func TestEncode(t *testing.T) {
+ r := EncodeToMemory(privateKey2)
+ if string(r) != pemPrivateKey {
+ t.Errorf("got:%s want:%s", r, pemPrivateKey)
+ }
+}
+
+type lineBreakerTest struct {
+ in, out string
+}
+
+const sixtyFourCharString = "0123456789012345678901234567890123456789012345678901234567890123"
+
+var lineBreakerTests = []lineBreakerTest{
+ {"", ""},
+ {"a", "a\n"},
+ {"ab", "ab\n"},
+ {sixtyFourCharString, sixtyFourCharString + "\n"},
+ {sixtyFourCharString + "X", sixtyFourCharString + "\nX\n"},
+ {sixtyFourCharString + sixtyFourCharString, sixtyFourCharString + "\n" + sixtyFourCharString + "\n"},
+}
+
+func TestLineBreaker(t *testing.T) {
+ for i, test := range lineBreakerTests {
+ buf := bytes.NewBuffer(nil)
+ var breaker lineBreaker
+ breaker.out = buf
+ _, err := breaker.Write([]byte(test.in))
+ if err != nil {
+ t.Errorf("#%d: error from Write: %s", i, err)
+ continue
+ }
+ err = breaker.Close()
+ if err != nil {
+ t.Errorf("#%d: error from Close: %s", i, err)
+ continue
+ }
+
+ if string(buf.Bytes()) != test.out {
+ t.Errorf("#%d: got:%s want:%s", i, string(buf.Bytes()), test.out)
+ }
+ }
+
+ for i, test := range lineBreakerTests {
+ buf := bytes.NewBuffer(nil)
+ var breaker lineBreaker
+ breaker.out = buf
+
+ for i := 0; i < len(test.in); i++ {
+ _, err := breaker.Write([]byte(test.in[i : i+1]))
+ if err != nil {
+ t.Errorf("#%d: error from Write (byte by byte): %s", i, err)
+ continue
+ }
+ }
+ err := breaker.Close()
+ if err != nil {
+ t.Errorf("#%d: error from Close (byte by byte): %s", i, err)
+ continue
+ }
+
+ if string(buf.Bytes()) != test.out {
+ t.Errorf("#%d: (byte by byte) got:%s want:%s", i, string(buf.Bytes()), test.out)
+ }
+ }
+}
+
+var pemData = `verify return:0
+-----BEGIN CERTIFICATE-----
+sdlfkjskldfj
+ -----BEGIN CERTIFICATE-----
+---
+Certificate chain
+ 0 s:/C=AU/ST=Somewhere/L=Someplace/O=Foo Bar/CN=foo.example.com
+ i:/C=ZA/O=CA Inc./CN=CA Inc
+-----BEGIN CERTIFICATE-----
+testing
+-----BEGIN CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID6TCCA1ICAQEwDQYJKoZIhvcNAQEFBQAwgYsxCzAJBgNVBAYTAlVTMRMwEQYD
+VQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQK
+EwtHb29nbGUgSW5jLjEMMAoGA1UECxMDRW5nMQwwCgYDVQQDEwNhZ2wxHTAbBgkq
+hkiG9w0BCQEWDmFnbEBnb29nbGUuY29tMB4XDTA5MDkwOTIyMDU0M1oXDTEwMDkw
+OTIyMDU0M1owajELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAf
+BgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEjMCEGA1UEAxMaZXVyb3Bh
+LnNmby5jb3JwLmdvb2dsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQC6pgYt7/EibBDumASF+S0qvqdL/f+nouJw2T1Qc8GmXF/iiUcrsgzh/Fd8
+pDhz/T96Qg9IyR4ztuc2MXrmPra+zAuSf5bevFReSqvpIt8Duv0HbDbcqs/XKPfB
+uMDe+of7a9GCywvAZ4ZUJcp0thqD9fKTTjUWOBzHY1uNE4RitrhmJCrbBGXbJ249
+bvgmb7jgdInH2PU7PT55hujvOoIsQW2osXBFRur4pF1wmVh4W4lTLD6pjfIMUcML
+ICHEXEN73PDic8KS3EtNYCwoIld+tpIBjE1QOb1KOyuJBNW6Esw9ALZn7stWdYcE
+qAwvv20egN2tEXqj7Q4/1ccyPZc3PQgC3FJ8Be2mtllM+80qf4dAaQ/fWvCtOrQ5
+pnfe9juQvCo8Y0VGlFcrSys/MzSg9LJ/24jZVgzQved/Qupsp89wVidwIzjt+WdS
+fyWfH0/v1aQLvu5cMYuW//C0W2nlYziL5blETntM8My2ybNARy3ICHxCBv2RNtPI
+WQVm+E9/W5rwh2IJR4DHn2LHwUVmT/hHNTdBLl5Uhwr4Wc7JhE7AVqb14pVNz1lr
+5jxsp//ncIwftb7mZQ3DF03Yna+jJhpzx8CQoeLT6aQCHyzmH68MrHHT4MALPyUs
+Pomjn71GNTtDeWAXibjCgdL6iHACCF6Htbl0zGlG0OAK+bdn0QIDAQABMA0GCSqG
+SIb3DQEBBQUAA4GBAOKnQDtqBV24vVqvesL5dnmyFpFPXBn3WdFfwD6DzEb21UVG
+5krmJiu+ViipORJPGMkgoL6BjU21XI95VQbun5P8vvg8Z+FnFsvRFY3e1CCzAVQY
+ZsUkLw2I7zI/dNlWdB8Xp7v+3w9sX5N3J/WuJ1KOO5m26kRlHQo7EzT3974g
+-----END CERTIFICATE-----
+ 1 s:/C=ZA/O=Ca Inc./CN=CA Inc
+
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,80C7C7A09690757A
+
+eQp5ZkH6CyHBz7BZfUPxyLCCmftsBJ7HlqGb8Ld21cSwnzWZ4/SIlhyrUtsfw7VR
+2TTwA+odo9ex7GdxOTaH8oZFumIRoiEjHsk8U7Bhntp+ekkPP79xunnN7hb7hkhr
+yGDQZgA7s2cQHQ71v3gwT2BACAft26jCjbM1wgNzBnJ8M0Rzn68YWqaPtdBu8qb/
+zVR5JB1mnqvTSbFsfF5yMc6o2WQ9jJCl6KypnMl+BpL+dlvdjYVK4l9lYsB1Hs3d
++zDBbWxos818zzhS8/y6eIfiSG27cqrbhURbmgiSfDXjncK4m/pLcQ7mmBL6mFOr
+3Pj4jepzgOiFRL6MKE//h62fZvI1ErYr8VunHEykgKNhChDvb1RO6LEfqKBu+Ivw
+TB6fBhW3TCLMnVPYVoYwA+fHNTmZZm8BEonlIMfI+KktjWUg4Oia+NI6vKcPpFox
+hSnlGgCtvfEaq5/H4kHJp95eOpnFsLviw2seHNkz/LxJMRP1X428+DpYW/QD/0JU
+tJSuC/q9FUHL6RI3u/Asrv8pCb4+D7i1jW/AMIdJTtycOGsbPxQA7yHMWujHmeb1
+BTiHcL3s3KrJu1vDVrshvxfnz71KTeNnZH8UbOqT5i7fPGyXtY1XJddcbI/Q6tXf
+wHFsZc20TzSdsVLBtwksUacpbDogcEVMctnNrB8FIrB3vZEv9Q0Z1VeY7nmTpF+6
+a+z2P7acL7j6A6Pr3+q8P9CPiPC7zFonVzuVPyB8GchGR2hytyiOVpuD9+k8hcuw
+ZWAaUoVtWIQ52aKS0p19G99hhb+IVANC4akkdHV4SP8i7MVNZhfUmg==
+-----END RSA PRIVATE KEY-----`
+
+var certificate = &Block{Type: "CERTIFICATE",
+ Headers: map[string]string{},
+ Bytes: []uint8{0x30, 0x82, 0x3, 0xe9, 0x30, 0x82, 0x3, 0x52, 0x2, 0x1,
+ 0x1, 0x30, 0xd, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd,
+ 0x1, 0x1, 0x5, 0x5, 0x0, 0x30, 0x81, 0x8b, 0x31, 0xb, 0x30,
+ 0x9, 0x6, 0x3, 0x55, 0x4, 0x6, 0x13, 0x2, 0x55, 0x53, 0x31,
+ 0x13, 0x30, 0x11, 0x6, 0x3, 0x55, 0x4, 0x8, 0x13, 0xa, 0x43,
+ 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31,
+ 0x16, 0x30, 0x14, 0x6, 0x3, 0x55, 0x4, 0x7, 0x13, 0xd, 0x53,
+ 0x61, 0x6e, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x73,
+ 0x63, 0x6f, 0x31, 0x14, 0x30, 0x12, 0x6, 0x3, 0x55, 0x4, 0xa,
+ 0x13, 0xb, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49,
+ 0x6e, 0x63, 0x2e, 0x31, 0xc, 0x30, 0xa, 0x6, 0x3, 0x55, 0x4,
+ 0xb, 0x13, 0x3, 0x45, 0x6e, 0x67, 0x31, 0xc, 0x30, 0xa, 0x6,
+ 0x3, 0x55, 0x4, 0x3, 0x13, 0x3, 0x61, 0x67, 0x6c, 0x31, 0x1d,
+ 0x30, 0x1b, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1,
+ 0x9, 0x1, 0x16, 0xe, 0x61, 0x67, 0x6c, 0x40, 0x67, 0x6f, 0x6f,
+ 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17,
+ 0xd, 0x30, 0x39, 0x30, 0x39, 0x30, 0x39, 0x32, 0x32, 0x30,
+ 0x35, 0x34, 0x33, 0x5a, 0x17, 0xd, 0x31, 0x30, 0x30, 0x39,
+ 0x30, 0x39, 0x32, 0x32, 0x30, 0x35, 0x34, 0x33, 0x5a, 0x30,
+ 0x6a, 0x31, 0xb, 0x30, 0x9, 0x6, 0x3, 0x55, 0x4, 0x6, 0x13,
+ 0x2, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x6, 0x3, 0x55, 0x4,
+ 0x8, 0x13, 0xa, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
+ 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x6, 0x3, 0x55, 0x4, 0xa,
+ 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
+ 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x23, 0x30, 0x21,
+ 0x6, 0x3, 0x55, 0x4, 0x3, 0x13, 0x1a, 0x65, 0x75, 0x72, 0x6f,
+ 0x70, 0x61, 0x2e, 0x73, 0x66, 0x6f, 0x2e, 0x63, 0x6f, 0x72,
+ 0x70, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x30, 0x82, 0x2, 0x22, 0x30, 0xd, 0x6, 0x9, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1, 0x1, 0x1, 0x5, 0x0, 0x3,
+ 0x82, 0x2, 0xf, 0x0, 0x30, 0x82, 0x2, 0xa, 0x2, 0x82, 0x2, 0x1,
+ 0x0, 0xba, 0xa6, 0x6, 0x2d, 0xef, 0xf1, 0x22, 0x6c, 0x10, 0xee,
+ 0x98, 0x4, 0x85, 0xf9, 0x2d, 0x2a, 0xbe, 0xa7, 0x4b, 0xfd,
+ 0xff, 0xa7, 0xa2, 0xe2, 0x70, 0xd9, 0x3d, 0x50, 0x73, 0xc1,
+ 0xa6, 0x5c, 0x5f, 0xe2, 0x89, 0x47, 0x2b, 0xb2, 0xc, 0xe1,
+ 0xfc, 0x57, 0x7c, 0xa4, 0x38, 0x73, 0xfd, 0x3f, 0x7a, 0x42,
+ 0xf, 0x48, 0xc9, 0x1e, 0x33, 0xb6, 0xe7, 0x36, 0x31, 0x7a,
+ 0xe6, 0x3e, 0xb6, 0xbe, 0xcc, 0xb, 0x92, 0x7f, 0x96, 0xde,
+ 0xbc, 0x54, 0x5e, 0x4a, 0xab, 0xe9, 0x22, 0xdf, 0x3, 0xba,
+ 0xfd, 0x7, 0x6c, 0x36, 0xdc, 0xaa, 0xcf, 0xd7, 0x28, 0xf7,
+ 0xc1, 0xb8, 0xc0, 0xde, 0xfa, 0x87, 0xfb, 0x6b, 0xd1, 0x82,
+ 0xcb, 0xb, 0xc0, 0x67, 0x86, 0x54, 0x25, 0xca, 0x74, 0xb6,
+ 0x1a, 0x83, 0xf5, 0xf2, 0x93, 0x4e, 0x35, 0x16, 0x38, 0x1c,
+ 0xc7, 0x63, 0x5b, 0x8d, 0x13, 0x84, 0x62, 0xb6, 0xb8, 0x66,
+ 0x24, 0x2a, 0xdb, 0x4, 0x65, 0xdb, 0x27, 0x6e, 0x3d, 0x6e,
+ 0xf8, 0x26, 0x6f, 0xb8, 0xe0, 0x74, 0x89, 0xc7, 0xd8, 0xf5,
+ 0x3b, 0x3d, 0x3e, 0x79, 0x86, 0xe8, 0xef, 0x3a, 0x82, 0x2c,
+ 0x41, 0x6d, 0xa8, 0xb1, 0x70, 0x45, 0x46, 0xea, 0xf8, 0xa4,
+ 0x5d, 0x70, 0x99, 0x58, 0x78, 0x5b, 0x89, 0x53, 0x2c, 0x3e,
+ 0xa9, 0x8d, 0xf2, 0xc, 0x51, 0xc3, 0xb, 0x20, 0x21, 0xc4, 0x5c,
+ 0x43, 0x7b, 0xdc, 0xf0, 0xe2, 0x73, 0xc2, 0x92, 0xdc, 0x4b,
+ 0x4d, 0x60, 0x2c, 0x28, 0x22, 0x57, 0x7e, 0xb6, 0x92, 0x1,
+ 0x8c, 0x4d, 0x50, 0x39, 0xbd, 0x4a, 0x3b, 0x2b, 0x89, 0x4,
+ 0xd5, 0xba, 0x12, 0xcc, 0x3d, 0x0, 0xb6, 0x67, 0xee, 0xcb,
+ 0x56, 0x75, 0x87, 0x4, 0xa8, 0xc, 0x2f, 0xbf, 0x6d, 0x1e, 0x80,
+ 0xdd, 0xad, 0x11, 0x7a, 0xa3, 0xed, 0xe, 0x3f, 0xd5, 0xc7,
+ 0x32, 0x3d, 0x97, 0x37, 0x3d, 0x8, 0x2, 0xdc, 0x52, 0x7c, 0x5,
+ 0xed, 0xa6, 0xb6, 0x59, 0x4c, 0xfb, 0xcd, 0x2a, 0x7f, 0x87,
+ 0x40, 0x69, 0xf, 0xdf, 0x5a, 0xf0, 0xad, 0x3a, 0xb4, 0x39,
+ 0xa6, 0x77, 0xde, 0xf6, 0x3b, 0x90, 0xbc, 0x2a, 0x3c, 0x63,
+ 0x45, 0x46, 0x94, 0x57, 0x2b, 0x4b, 0x2b, 0x3f, 0x33, 0x34,
+ 0xa0, 0xf4, 0xb2, 0x7f, 0xdb, 0x88, 0xd9, 0x56, 0xc, 0xd0,
+ 0xbd, 0xe7, 0x7f, 0x42, 0xea, 0x6c, 0xa7, 0xcf, 0x70, 0x56,
+ 0x27, 0x70, 0x23, 0x38, 0xed, 0xf9, 0x67, 0x52, 0x7f, 0x25,
+ 0x9f, 0x1f, 0x4f, 0xef, 0xd5, 0xa4, 0xb, 0xbe, 0xee, 0x5c,
+ 0x31, 0x8b, 0x96, 0xff, 0xf0, 0xb4, 0x5b, 0x69, 0xe5, 0x63,
+ 0x38, 0x8b, 0xe5, 0xb9, 0x44, 0x4e, 0x7b, 0x4c, 0xf0, 0xcc,
+ 0xb6, 0xc9, 0xb3, 0x40, 0x47, 0x2d, 0xc8, 0x8, 0x7c, 0x42, 0x6,
+ 0xfd, 0x91, 0x36, 0xd3, 0xc8, 0x59, 0x5, 0x66, 0xf8, 0x4f,
+ 0x7f, 0x5b, 0x9a, 0xf0, 0x87, 0x62, 0x9, 0x47, 0x80, 0xc7,
+ 0x9f, 0x62, 0xc7, 0xc1, 0x45, 0x66, 0x4f, 0xf8, 0x47, 0x35,
+ 0x37, 0x41, 0x2e, 0x5e, 0x54, 0x87, 0xa, 0xf8, 0x59, 0xce,
+ 0xc9, 0x84, 0x4e, 0xc0, 0x56, 0xa6, 0xf5, 0xe2, 0x95, 0x4d,
+ 0xcf, 0x59, 0x6b, 0xe6, 0x3c, 0x6c, 0xa7, 0xff, 0xe7, 0x70,
+ 0x8c, 0x1f, 0xb5, 0xbe, 0xe6, 0x65, 0xd, 0xc3, 0x17, 0x4d,
+ 0xd8, 0x9d, 0xaf, 0xa3, 0x26, 0x1a, 0x73, 0xc7, 0xc0, 0x90,
+ 0xa1, 0xe2, 0xd3, 0xe9, 0xa4, 0x2, 0x1f, 0x2c, 0xe6, 0x1f,
+ 0xaf, 0xc, 0xac, 0x71, 0xd3, 0xe0, 0xc0, 0xb, 0x3f, 0x25, 0x2c,
+ 0x3e, 0x89, 0xa3, 0x9f, 0xbd, 0x46, 0x35, 0x3b, 0x43, 0x79,
+ 0x60, 0x17, 0x89, 0xb8, 0xc2, 0x81, 0xd2, 0xfa, 0x88, 0x70,
+ 0x2, 0x8, 0x5e, 0x87, 0xb5, 0xb9, 0x74, 0xcc, 0x69, 0x46, 0xd0,
+ 0xe0, 0xa, 0xf9, 0xb7, 0x67, 0xd1, 0x2, 0x3, 0x1, 0x0, 0x1,
+ 0x30, 0xd, 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0xd, 0x1,
+ 0x1, 0x5, 0x5, 0x0, 0x3, 0x81, 0x81, 0x0, 0xe2, 0xa7, 0x40,
+ 0x3b, 0x6a, 0x5, 0x5d, 0xb8, 0xbd, 0x5a, 0xaf, 0x7a, 0xc2,
+ 0xf9, 0x76, 0x79, 0xb2, 0x16, 0x91, 0x4f, 0x5c, 0x19, 0xf7,
+ 0x59, 0xd1, 0x5f, 0xc0, 0x3e, 0x83, 0xcc, 0x46, 0xf6, 0xd5,
+ 0x45, 0x46, 0xe6, 0x4a, 0xe6, 0x26, 0x2b, 0xbe, 0x56, 0x28,
+ 0xa9, 0x39, 0x12, 0x4f, 0x18, 0xc9, 0x20, 0xa0, 0xbe, 0x81,
+ 0x8d, 0x4d, 0xb5, 0x5c, 0x8f, 0x79, 0x55, 0x6, 0xee, 0x9f,
+ 0x93, 0xfc, 0xbe, 0xf8, 0x3c, 0x67, 0xe1, 0x67, 0x16, 0xcb,
+ 0xd1, 0x15, 0x8d, 0xde, 0xd4, 0x20, 0xb3, 0x1, 0x54, 0x18,
+ 0x66, 0xc5, 0x24, 0x2f, 0xd, 0x88, 0xef, 0x32, 0x3f, 0x74,
+ 0xd9, 0x56, 0x74, 0x1f, 0x17, 0xa7, 0xbb, 0xfe, 0xdf, 0xf,
+ 0x6c, 0x5f, 0x93, 0x77, 0x27, 0xf5, 0xae, 0x27, 0x52, 0x8e,
+ 0x3b, 0x99, 0xb6, 0xea, 0x44, 0x65, 0x1d, 0xa, 0x3b, 0x13,
+ 0x34, 0xf7, 0xf7, 0xbe, 0x20,
+ },
+}
+
+var privateKey = &Block{Type: "RSA PRIVATE KEY",
+ Headers: map[string]string{"DEK-Info": "DES-EDE3-CBC,80C7C7A09690757A", "Proc-Type": "4,ENCRYPTED"},
+ Bytes: []uint8{0x79, 0xa, 0x79, 0x66, 0x41, 0xfa, 0xb,
+ 0x21, 0xc1, 0xcf, 0xb0, 0x59, 0x7d, 0x43, 0xf1, 0xc8, 0xb0,
+ 0x82, 0x99, 0xfb, 0x6c, 0x4, 0x9e, 0xc7, 0x96, 0xa1, 0x9b,
+ 0xf0, 0xb7, 0x76, 0xd5, 0xc4, 0xb0, 0x9f, 0x35, 0x99, 0xe3,
+ 0xf4, 0x88, 0x96, 0x1c, 0xab, 0x52, 0xdb, 0x1f, 0xc3, 0xb5,
+ 0x51, 0xd9, 0x34, 0xf0, 0x3, 0xea, 0x1d, 0xa3, 0xd7, 0xb1,
+ 0xec, 0x67, 0x71, 0x39, 0x36, 0x87, 0xf2, 0x86, 0x45, 0xba,
+ 0x62, 0x11, 0xa2, 0x21, 0x23, 0x1e, 0xc9, 0x3c, 0x53, 0xb0,
+ 0x61, 0x9e, 0xda, 0x7e, 0x7a, 0x49, 0xf, 0x3f, 0xbf, 0x71,
+ 0xba, 0x79, 0xcd, 0xee, 0x16, 0xfb, 0x86, 0x48, 0x6b, 0xc8,
+ 0x60, 0xd0, 0x66, 0x0, 0x3b, 0xb3, 0x67, 0x10, 0x1d, 0xe,
+ 0xf5, 0xbf, 0x78, 0x30, 0x4f, 0x60, 0x40, 0x8, 0x7, 0xed,
+ 0xdb, 0xa8, 0xc2, 0x8d, 0xb3, 0x35, 0xc2, 0x3, 0x73, 0x6,
+ 0x72, 0x7c, 0x33, 0x44, 0x73, 0x9f, 0xaf, 0x18, 0x5a, 0xa6,
+ 0x8f, 0xb5, 0xd0, 0x6e, 0xf2, 0xa6, 0xff, 0xcd, 0x54, 0x79,
+ 0x24, 0x1d, 0x66, 0x9e, 0xab, 0xd3, 0x49, 0xb1, 0x6c, 0x7c,
+ 0x5e, 0x72, 0x31, 0xce, 0xa8, 0xd9, 0x64, 0x3d, 0x8c, 0x90,
+ 0xa5, 0xe8, 0xac, 0xa9, 0x9c, 0xc9, 0x7e, 0x6, 0x92, 0xfe,
+ 0x76, 0x5b, 0xdd, 0x8d, 0x85, 0x4a, 0xe2, 0x5f, 0x65, 0x62,
+ 0xc0, 0x75, 0x1e, 0xcd, 0xdd, 0xfb, 0x30, 0xc1, 0x6d, 0x6c,
+ 0x68, 0xb3, 0xcd, 0x7c, 0xcf, 0x38, 0x52, 0xf3, 0xfc, 0xba,
+ 0x78, 0x87, 0xe2, 0x48, 0x6d, 0xbb, 0x72, 0xaa, 0xdb, 0x85,
+ 0x44, 0x5b, 0x9a, 0x8, 0x92, 0x7c, 0x35, 0xe3, 0x9d, 0xc2,
+ 0xb8, 0x9b, 0xfa, 0x4b, 0x71, 0xe, 0xe6, 0x98, 0x12, 0xfa,
+ 0x98, 0x53, 0xab, 0xdc, 0xf8, 0xf8, 0x8d, 0xea, 0x73, 0x80,
+ 0xe8, 0x85, 0x44, 0xbe, 0x8c, 0x28, 0x4f, 0xff, 0x87, 0xad,
+ 0x9f, 0x66, 0xf2, 0x35, 0x12, 0xb6, 0x2b, 0xf1, 0x5b, 0xa7,
+ 0x1c, 0x4c, 0xa4, 0x80, 0xa3, 0x61, 0xa, 0x10, 0xef, 0x6f,
+ 0x54, 0x4e, 0xe8, 0xb1, 0x1f, 0xa8, 0xa0, 0x6e, 0xf8, 0x8b,
+ 0xf0, 0x4c, 0x1e, 0x9f, 0x6, 0x15, 0xb7, 0x4c, 0x22, 0xcc,
+ 0x9d, 0x53, 0xd8, 0x56, 0x86, 0x30, 0x3, 0xe7, 0xc7, 0x35,
+ 0x39, 0x99, 0x66, 0x6f, 0x1, 0x12, 0x89, 0xe5, 0x20, 0xc7,
+ 0xc8, 0xf8, 0xa9, 0x2d, 0x8d, 0x65, 0x20, 0xe0, 0xe8, 0x9a,
+ 0xf8, 0xd2, 0x3a, 0xbc, 0xa7, 0xf, 0xa4, 0x5a, 0x31, 0x85,
+ 0x29, 0xe5, 0x1a, 0x0, 0xad, 0xbd, 0xf1, 0x1a, 0xab, 0x9f,
+ 0xc7, 0xe2, 0x41, 0xc9, 0xa7, 0xde, 0x5e, 0x3a, 0x99, 0xc5,
+ 0xb0, 0xbb, 0xe2, 0xc3, 0x6b, 0x1e, 0x1c, 0xd9, 0x33, 0xfc,
+ 0xbc, 0x49, 0x31, 0x13, 0xf5, 0x5f, 0x8d, 0xbc, 0xf8, 0x3a,
+ 0x58, 0x5b, 0xf4, 0x3, 0xff, 0x42, 0x54, 0xb4, 0x94, 0xae,
+ 0xb, 0xfa, 0xbd, 0x15, 0x41, 0xcb, 0xe9, 0x12, 0x37, 0xbb,
+ 0xf0, 0x2c, 0xae, 0xff, 0x29, 0x9, 0xbe, 0x3e, 0xf, 0xb8,
+ 0xb5, 0x8d, 0x6f, 0xc0, 0x30, 0x87, 0x49, 0x4e, 0xdc, 0x9c,
+ 0x38, 0x6b, 0x1b, 0x3f, 0x14, 0x0, 0xef, 0x21, 0xcc, 0x5a,
+ 0xe8, 0xc7, 0x99, 0xe6, 0xf5, 0x5, 0x38, 0x87, 0x70, 0xbd,
+ 0xec, 0xdc, 0xaa, 0xc9, 0xbb, 0x5b, 0xc3, 0x56, 0xbb, 0x21,
+ 0xbf, 0x17, 0xe7, 0xcf, 0xbd, 0x4a, 0x4d, 0xe3, 0x67, 0x64,
+ 0x7f, 0x14, 0x6c, 0xea, 0x93, 0xe6, 0x2e, 0xdf, 0x3c, 0x6c,
+ 0x97, 0xb5, 0x8d, 0x57, 0x25, 0xd7, 0x5c, 0x6c, 0x8f, 0xd0,
+ 0xea, 0xd5, 0xdf, 0xc0, 0x71, 0x6c, 0x65, 0xcd, 0xb4, 0x4f,
+ 0x34, 0x9d, 0xb1, 0x52, 0xc1, 0xb7, 0x9, 0x2c, 0x51, 0xa7,
+ 0x29, 0x6c, 0x3a, 0x20, 0x70, 0x45, 0x4c, 0x72, 0xd9, 0xcd,
+ 0xac, 0x1f, 0x5, 0x22, 0xb0, 0x77, 0xbd, 0x91, 0x2f, 0xf5,
+ 0xd, 0x19, 0xd5, 0x57, 0x98, 0xee, 0x79, 0x93, 0xa4, 0x5f,
+ 0xba, 0x6b, 0xec, 0xf6, 0x3f, 0xb6, 0x9c, 0x2f, 0xb8, 0xfa,
+ 0x3, 0xa3, 0xeb, 0xdf, 0xea, 0xbc, 0x3f, 0xd0, 0x8f, 0x88,
+ 0xf0, 0xbb, 0xcc, 0x5a, 0x27, 0x57, 0x3b, 0x95, 0x3f, 0x20,
+ 0x7c, 0x19, 0xc8, 0x46, 0x47, 0x68, 0x72, 0xb7, 0x28, 0x8e,
+ 0x56, 0x9b, 0x83, 0xf7, 0xe9, 0x3c, 0x85, 0xcb, 0xb0, 0x65,
+ 0x60, 0x1a, 0x52, 0x85, 0x6d, 0x58, 0x84, 0x39, 0xd9, 0xa2,
+ 0x92, 0xd2, 0x9d, 0x7d, 0x1b, 0xdf, 0x61, 0x85, 0xbf, 0x88,
+ 0x54, 0x3, 0x42, 0xe1, 0xa9, 0x24, 0x74, 0x75, 0x78, 0x48,
+ 0xff, 0x22, 0xec, 0xc5, 0x4d, 0x66, 0x17, 0xd4, 0x9a,
+ },
+}
+
+var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
+ Headers: map[string]string{},
+ Bytes: []uint8{0x30, 0x82, 0x1, 0x3a, 0x2, 0x1, 0x0, 0x2,
+ 0x41, 0x0, 0xb2, 0x99, 0xf, 0x49, 0xc4, 0x7d, 0xfa, 0x8c,
+ 0xd4, 0x0, 0xae, 0x6a, 0x4d, 0x1b, 0x8a, 0x3b, 0x6a, 0x13,
+ 0x64, 0x2b, 0x23, 0xf2, 0x8b, 0x0, 0x3b, 0xfb, 0x97, 0x79,
+ 0xa, 0xde, 0x9a, 0x4c, 0xc8, 0x2b, 0x8b, 0x2a, 0x81, 0x74,
+ 0x7d, 0xde, 0xc0, 0x8b, 0x62, 0x96, 0xe5, 0x3a, 0x8, 0xc3,
+ 0x31, 0x68, 0x7e, 0xf2, 0x5c, 0x4b, 0xf4, 0x93, 0x6b, 0xa1,
+ 0xc0, 0xe6, 0x4, 0x1e, 0x9d, 0x15, 0x2, 0x3, 0x1, 0x0, 0x1,
+ 0x2, 0x41, 0x0, 0x8a, 0xbd, 0x6a, 0x69, 0xf4, 0xd1, 0xa4,
+ 0xb4, 0x87, 0xf0, 0xab, 0x8d, 0x7a, 0xae, 0xfd, 0x38, 0x60,
+ 0x94, 0x5, 0xc9, 0x99, 0x98, 0x4e, 0x30, 0xf5, 0x67, 0xe1,
+ 0xe8, 0xae, 0xef, 0xf4, 0x4e, 0x8b, 0x18, 0xbd, 0xb1, 0xec,
+ 0x78, 0xdf, 0xa3, 0x1a, 0x55, 0xe3, 0x2a, 0x48, 0xd7, 0xfb,
+ 0x13, 0x1f, 0x5a, 0xf1, 0xf4, 0x4d, 0x7d, 0x6b, 0x2c, 0xed,
+ 0x2a, 0x9d, 0xf5, 0xe5, 0xae, 0x45, 0x35, 0x2, 0x21, 0x0,
+ 0xda, 0xb2, 0xf1, 0x80, 0x48, 0xba, 0xa6, 0x8d, 0xe7, 0xdf,
+ 0x4, 0xd2, 0xd3, 0x5d, 0x5d, 0x80, 0xe6, 0xe, 0x2d, 0xfa,
+ 0x42, 0xd5, 0xa, 0x9b, 0x4, 0x21, 0x90, 0x32, 0x71, 0x5e,
+ 0x46, 0xb3, 0x2, 0x21, 0x0, 0xd1, 0xf, 0x2e, 0x66, 0xb1,
+ 0xd0, 0xc1, 0x3f, 0x10, 0xef, 0x99, 0x27, 0xbf, 0x53, 0x24,
+ 0xa3, 0x79, 0xca, 0x21, 0x81, 0x46, 0xcb, 0xf9, 0xca, 0xfc,
+ 0x79, 0x52, 0x21, 0xf1, 0x6a, 0x31, 0x17, 0x2, 0x20, 0x21,
+ 0x2, 0x89, 0x79, 0x37, 0x81, 0x14, 0xca, 0xae, 0x88, 0xf7,
+ 0xd, 0x6b, 0x61, 0xd8, 0x4f, 0x30, 0x6a, 0x4b, 0x7e, 0x4e,
+ 0xc0, 0x21, 0x4d, 0xac, 0x9d, 0xf4, 0x49, 0xe8, 0xda, 0xb6,
+ 0x9, 0x2, 0x20, 0x16, 0xb3, 0xec, 0x59, 0x10, 0xa4, 0x57,
+ 0xe8, 0xe, 0x61, 0xc6, 0xa3, 0xf, 0x5e, 0xeb, 0x12, 0xa9,
+ 0xae, 0x2e, 0xb7, 0x48, 0x45, 0xec, 0x69, 0x83, 0xc3, 0x75,
+ 0xc, 0xe4, 0x97, 0xa0, 0x9f, 0x2, 0x20, 0x69, 0x52, 0xb4,
+ 0x6, 0xe8, 0x50, 0x60, 0x71, 0x4c, 0x3a, 0xb7, 0x66, 0xba,
+ 0xd, 0x8a, 0xc9, 0xb7, 0xd, 0xa3, 0x8, 0x6c, 0xa3, 0xf2,
+ 0x62, 0xb0, 0x2a, 0x84, 0xaa, 0x2f, 0xd6, 0x1e, 0x55,
+ },
+}
+
+var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA PRIVATE KEY-----
+`
diff --git a/libgo/go/exec/exec.go b/libgo/go/exec/exec.go
new file mode 100644
index 000000000..ba9bd2472
--- /dev/null
+++ b/libgo/go/exec/exec.go
@@ -0,0 +1,183 @@
+// 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.
+
+// The exec package runs external commands.
+package exec
+
+import (
+ "os"
+)
+
+// Arguments to Run.
+const (
+ DevNull = iota
+ PassThrough
+ Pipe
+ MergeWithStdout
+)
+
+// A Cmd represents a running command.
+// Stdin, Stdout, and Stderr are Files representing pipes
+// connected to the running command's standard input, output, and error,
+// or else nil, depending on the arguments to Run.
+// Pid is the running command's operating system process ID.
+type Cmd struct {
+ Stdin *os.File
+ Stdout *os.File
+ Stderr *os.File
+ Pid int
+}
+
+// Given mode (DevNull, etc), return file for child
+// and file to record in Cmd structure.
+func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
+ switch mode {
+ case DevNull:
+ rw := os.O_WRONLY
+ if fd == 0 {
+ rw = os.O_RDONLY
+ }
+ f, err := os.Open(os.DevNull, rw, 0)
+ return f, nil, err
+ case PassThrough:
+ switch fd {
+ case 0:
+ return os.Stdin, nil, nil
+ case 1:
+ return os.Stdout, nil, nil
+ case 2:
+ return os.Stderr, nil, nil
+ }
+ case Pipe:
+ r, w, err := os.Pipe()
+ if err != nil {
+ return nil, nil, err
+ }
+ if fd == 0 {
+ return r, w, nil
+ }
+ return w, r, nil
+ }
+ return nil, nil, os.EINVAL
+}
+
+// Run starts the named binary running with
+// arguments argv and environment envv.
+// It returns a pointer to a new Cmd representing
+// the command or an error.
+//
+// The parameters stdin, stdout, and stderr
+// specify how to handle standard input, output, and error.
+// The choices are DevNull (connect to /dev/null),
+// PassThrough (connect to the current process's standard stream),
+// Pipe (connect to an operating system pipe), and
+// MergeWithStdout (only for standard error; use the same
+// file descriptor as was used for standard output).
+// If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr)
+// of the returned Cmd is the other end of the pipe.
+// Otherwise the field in Cmd is nil.
+func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
+ p = new(Cmd)
+ var fd [3]*os.File
+
+ if fd[0], p.Stdin, err = modeToFiles(stdin, 0); err != nil {
+ goto Error
+ }
+ if fd[1], p.Stdout, err = modeToFiles(stdout, 1); err != nil {
+ goto Error
+ }
+ if stderr == MergeWithStdout {
+ fd[2] = fd[1]
+ } else if fd[2], p.Stderr, err = modeToFiles(stderr, 2); err != nil {
+ goto Error
+ }
+
+ // Run command.
+ p.Pid, err = os.ForkExec(name, argv, envv, dir, fd[0:])
+ if err != nil {
+ goto Error
+ }
+ if fd[0] != os.Stdin {
+ fd[0].Close()
+ }
+ if fd[1] != os.Stdout {
+ fd[1].Close()
+ }
+ if fd[2] != os.Stderr && fd[2] != fd[1] {
+ fd[2].Close()
+ }
+ return p, nil
+
+Error:
+ if fd[0] != os.Stdin && fd[0] != nil {
+ fd[0].Close()
+ }
+ if fd[1] != os.Stdout && fd[1] != nil {
+ fd[1].Close()
+ }
+ if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] {
+ fd[2].Close()
+ }
+ if p.Stdin != nil {
+ p.Stdin.Close()
+ }
+ if p.Stdout != nil {
+ p.Stdout.Close()
+ }
+ if p.Stderr != nil {
+ p.Stderr.Close()
+ }
+ return nil, err
+}
+
+// Wait waits for the running command p,
+// returning the Waitmsg returned by os.Wait and an error.
+// The options are passed through to os.Wait.
+// Setting options to 0 waits for p to exit;
+// other options cause Wait to return for other
+// process events; see package os for details.
+func (p *Cmd) Wait(options int) (*os.Waitmsg, os.Error) {
+ if p.Pid <= 0 {
+ return nil, os.ErrorString("exec: invalid use of Cmd.Wait")
+ }
+ w, err := os.Wait(p.Pid, options)
+ if w != nil && (w.Exited() || w.Signaled()) {
+ p.Pid = -1
+ }
+ return w, err
+}
+
+// Close waits for the running command p to exit,
+// if it hasn't already, and then closes the non-nil file descriptors
+// p.Stdin, p.Stdout, and p.Stderr.
+func (p *Cmd) Close() os.Error {
+ if p.Pid > 0 {
+ // Loop on interrupt, but
+ // ignore other errors -- maybe
+ // caller has already waited for pid.
+ _, err := p.Wait(0)
+ for err == os.EINTR {
+ _, err = p.Wait(0)
+ }
+ }
+
+ // Close the FDs that are still open.
+ var err os.Error
+ if p.Stdin != nil && p.Stdin.Fd() >= 0 {
+ if err1 := p.Stdin.Close(); err1 != nil {
+ err = err1
+ }
+ }
+ if p.Stdout != nil && p.Stdout.Fd() >= 0 {
+ if err1 := p.Stdout.Close(); err1 != nil && err != nil {
+ err = err1
+ }
+ }
+ if p.Stderr != nil && p.Stderr != p.Stdout && p.Stderr.Fd() >= 0 {
+ if err1 := p.Stderr.Close(); err1 != nil && err != nil {
+ err = err1
+ }
+ }
+ return err
+}
diff --git a/libgo/go/exec/exec_test.go b/libgo/go/exec/exec_test.go
new file mode 100644
index 000000000..3a3d3b1a5
--- /dev/null
+++ b/libgo/go/exec/exec_test.go
@@ -0,0 +1,120 @@
+// 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 exec
+
+import (
+ "io"
+ "io/ioutil"
+ "testing"
+ "os"
+ "runtime"
+)
+
+func run(argv []string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
+ if runtime.GOOS == "windows" {
+ argv = append([]string{"cmd", "/c"}, argv...)
+ }
+ exe, err := LookPath(argv[0])
+ if err != nil {
+ return nil, err
+ }
+ p, err = Run(exe, argv, nil, "", stdin, stdout, stderr)
+ return p, err
+}
+
+func TestRunCat(t *testing.T) {
+ cmd, err := run([]string{"cat"}, Pipe, Pipe, DevNull)
+ if err != nil {
+ t.Fatal("run:", err)
+ }
+ io.WriteString(cmd.Stdin, "hello, world\n")
+ cmd.Stdin.Close()
+ buf, err := ioutil.ReadAll(cmd.Stdout)
+ if err != nil {
+ t.Fatal("read:", err)
+ }
+ if string(buf) != "hello, world\n" {
+ t.Fatalf("read: got %q", buf)
+ }
+ if err = cmd.Close(); err != nil {
+ t.Fatal("close:", err)
+ }
+}
+
+func TestRunEcho(t *testing.T) {
+ cmd, err := run([]string{"sh", "-c", "echo hello world"},
+ DevNull, Pipe, DevNull)
+ if err != nil {
+ t.Fatal("run:", err)
+ }
+ buf, err := ioutil.ReadAll(cmd.Stdout)
+ if err != nil {
+ t.Fatal("read:", err)
+ }
+ if string(buf) != "hello world\n" {
+ t.Fatalf("read: got %q", buf)
+ }
+ if err = cmd.Close(); err != nil {
+ t.Fatal("close:", err)
+ }
+}
+
+func TestStderr(t *testing.T) {
+ cmd, err := run([]string{"sh", "-c", "echo hello world 1>&2"},
+ DevNull, DevNull, Pipe)
+ if err != nil {
+ t.Fatal("run:", err)
+ }
+ buf, err := ioutil.ReadAll(cmd.Stderr)
+ if err != nil {
+ t.Fatal("read:", err)
+ }
+ if string(buf) != "hello world\n" {
+ t.Fatalf("read: got %q", buf)
+ }
+ if err = cmd.Close(); err != nil {
+ t.Fatal("close:", err)
+ }
+}
+
+func TestMergeWithStdout(t *testing.T) {
+ cmd, err := run([]string{"sh", "-c", "echo hello world 1>&2"},
+ DevNull, Pipe, MergeWithStdout)
+ if err != nil {
+ t.Fatal("run:", err)
+ }
+ buf, err := ioutil.ReadAll(cmd.Stdout)
+ if err != nil {
+ t.Fatal("read:", err)
+ }
+ if string(buf) != "hello world\n" {
+ t.Fatalf("read: got %q", buf)
+ }
+ if err = cmd.Close(); err != nil {
+ t.Fatal("close:", err)
+ }
+}
+
+func TestAddEnvVar(t *testing.T) {
+ err := os.Setenv("NEWVAR", "hello world")
+ if err != nil {
+ t.Fatal("setenv:", err)
+ }
+ cmd, err := run([]string{"sh", "-c", "echo $NEWVAR"},
+ DevNull, Pipe, DevNull)
+ if err != nil {
+ t.Fatal("run:", err)
+ }
+ buf, err := ioutil.ReadAll(cmd.Stdout)
+ if err != nil {
+ t.Fatal("read:", err)
+ }
+ if string(buf) != "hello world\n" {
+ t.Fatalf("read: got %q", buf)
+ }
+ if err = cmd.Close(); err != nil {
+ t.Fatal("close:", err)
+ }
+}
diff --git a/libgo/go/exec/lp_unix.go b/libgo/go/exec/lp_unix.go
new file mode 100644
index 000000000..292e24fcc
--- /dev/null
+++ b/libgo/go/exec/lp_unix.go
@@ -0,0 +1,45 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+ "os"
+ "strings"
+)
+
+func canExec(file string) bool {
+ d, err := os.Stat(file)
+ if err != nil {
+ return false
+ }
+ return d.IsRegular() && d.Permission()&0111 != 0
+}
+
+// LookPath searches for an executable binary named file
+// in the directories named by the PATH environment variable.
+// If file contains a slash, it is tried directly and the PATH is not consulted.
+func LookPath(file string) (string, os.Error) {
+ // NOTE(rsc): I wish we could use the Plan 9 behavior here
+ // (only bypass the path if file begins with / or ./ or ../)
+ // but that would not match all the Unix shells.
+
+ if strings.Contains(file, "/") {
+ if canExec(file) {
+ return file, nil
+ }
+ return "", &os.PathError{"lookpath", file, os.ENOENT}
+ }
+ pathenv := os.Getenv("PATH")
+ for _, dir := range strings.Split(pathenv, ":", -1) {
+ if dir == "" {
+ // Unix shell semantics: path element "" means "."
+ dir = "."
+ }
+ if canExec(dir + "/" + file) {
+ return dir + "/" + file, nil
+ }
+ }
+ return "", &os.PathError{"lookpath", file, os.ENOENT}
+}
diff --git a/libgo/go/exec/lp_windows.go b/libgo/go/exec/lp_windows.go
new file mode 100644
index 000000000..7b56afa85
--- /dev/null
+++ b/libgo/go/exec/lp_windows.go
@@ -0,0 +1,66 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+ "os"
+ "strings"
+)
+
+func chkStat(file string) bool {
+ d, err := os.Stat(file)
+ if err != nil {
+ return false
+ }
+ return d.IsRegular()
+}
+
+func canExec(file string, exts []string) (string, bool) {
+ if len(exts) == 0 {
+ return file, chkStat(file)
+ }
+ f := strings.ToLower(file)
+ for _, e := range exts {
+ if strings.HasSuffix(f, e) {
+ return file, chkStat(file)
+ }
+ }
+ for _, e := range exts {
+ if f := file + e; chkStat(f) {
+ return f, true
+ }
+ }
+ return ``, false
+}
+
+func LookPath(file string) (string, os.Error) {
+ 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
+ }
+ }
+ }
+ if strings.Contains(file, `\`) || strings.Contains(file, `/`) {
+ if f, ok := canExec(file, exts); ok {
+ return f, nil
+ }
+ return ``, &os.PathError{"lookpath", file, os.ENOENT}
+ }
+ if pathenv := os.Getenv(`PATH`); pathenv == `` {
+ if f, ok := canExec(`.\`+file, exts); ok {
+ return f, nil
+ }
+ } else {
+ for _, dir := range strings.Split(pathenv, `;`, -1) {
+ if f, ok := canExec(dir+`\`+file, exts); ok {
+ return f, nil
+ }
+ }
+ }
+ return ``, &os.PathError{"lookpath", file, os.ENOENT}
+}
diff --git a/libgo/go/exp/README b/libgo/go/exp/README
new file mode 100644
index 000000000..e602e3ac9
--- /dev/null
+++ b/libgo/go/exp/README
@@ -0,0 +1,3 @@
+This directory tree contains experimental packages and
+unfinished code that is subject to even more change than the
+rest of the Go tree.
diff --git a/libgo/go/exp/datafmt/datafmt.go b/libgo/go/exp/datafmt/datafmt.go
new file mode 100644
index 000000000..46c412342
--- /dev/null
+++ b/libgo/go/exp/datafmt/datafmt.go
@@ -0,0 +1,731 @@
+// 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.
+
+/* The datafmt package implements syntax-directed, type-driven formatting
+ of arbitrary data structures. Formatting a data structure consists of
+ two phases: first, a parser reads a format specification and builds a
+ "compiled" format. Then, the format can be applied repeatedly to
+ arbitrary values. Applying a format to a value evaluates to a []byte
+ containing the formatted value bytes, or nil.
+
+ A format specification is a set of package declarations and format rules:
+
+ Format = [ Entry { ";" Entry } [ ";" ] ] .
+ Entry = PackageDecl | FormatRule .
+
+ (The syntax of a format specification is presented in the same EBNF
+ notation as used in the Go language specification. The syntax of white
+ space, comments, identifiers, and string literals is the same as in Go.)
+
+ A package declaration binds a package name (such as 'ast') to a
+ package import path (such as '"go/ast"'). Each package used (in
+ a type name, see below) must be declared once before use.
+
+ PackageDecl = PackageName ImportPath .
+ PackageName = identifier .
+ ImportPath = string .
+
+ A format rule binds a rule name to a format expression. A rule name
+ may be a type name or one of the special names 'default' or '/'.
+ A type name may be the name of a predeclared type (for example, 'int',
+ 'float32', etc.), the package-qualified name of a user-defined type
+ (for example, 'ast.MapType'), or an identifier indicating the structure
+ of unnamed composite types ('array', 'chan', 'func', 'interface', 'map',
+ or 'ptr'). Each rule must have a unique name; rules can be declared in
+ any order.
+
+ FormatRule = RuleName "=" Expression .
+ RuleName = TypeName | "default" | "/" .
+ TypeName = [ PackageName "." ] identifier .
+
+ To format a value, the value's type name is used to select the format rule
+ (there is an override mechanism, see below). The format expression of the
+ selected rule specifies how the value is formatted. Each format expression,
+ when applied to a value, evaluates to a byte sequence or nil.
+
+ In its most general form, a format expression is a list of alternatives,
+ each of which is a sequence of operands:
+
+ Expression = [ Sequence ] { "|" [ Sequence ] } .
+ Sequence = Operand { Operand } .
+
+ The formatted result produced by an expression is the result of the first
+ alternative sequence that evaluates to a non-nil result; if there is no
+ such alternative, the expression evaluates to nil. The result produced by
+ an operand sequence is the concatenation of the results of its operands.
+ If any operand in the sequence evaluates to nil, the entire sequence
+ evaluates to nil.
+
+ There are five kinds of operands:
+
+ Operand = Literal | Field | Group | Option | Repetition .
+
+ Literals evaluate to themselves, with two substitutions. First,
+ %-formats expand in the manner of fmt.Printf, with the current value
+ passed as the parameter. Second, the current indentation (see below)
+ is inserted after every newline or form feed character.
+
+ Literal = string .
+
+ This table shows string literals applied to the value 42 and the
+ corresponding formatted result:
+
+ "foo" foo
+ "%x" 2a
+ "x = %d" x = 42
+ "%#x = %d" 0x2a = 42
+
+ A field operand is a field name optionally followed by an alternate
+ rule name. The field name may be an identifier or one of the special
+ names @ or *.
+
+ Field = FieldName [ ":" RuleName ] .
+ FieldName = identifier | "@" | "*" .
+
+ If the field name is an identifier, the current value must be a struct,
+ and there must be a field with that name in the struct. The same lookup
+ rules apply as in the Go language (for instance, the name of an anonymous
+ field is the unqualified type name). The field name denotes the field
+ value in the struct. If the field is not found, formatting is aborted
+ and an error message is returned. (TODO consider changing the semantics
+ such that if a field is not found, it evaluates to nil).
+
+ The special name '@' denotes the current value.
+
+ The meaning of the special name '*' depends on the type of the current
+ value:
+
+ array, slice types array, slice element (inside {} only, see below)
+ interfaces value stored in interface
+ pointers value pointed to by pointer
+
+ (Implementation restriction: channel, function and map types are not
+ supported due to missing reflection support).
+
+ Fields are evaluated as follows: If the field value is nil, or an array
+ or slice element does not exist, the result is nil (see below for details
+ on array/slice elements). If the value is not nil the field value is
+ formatted (recursively) using the rule corresponding to its type name,
+ or the alternate rule name, if given.
+
+ The following example shows a complete format specification for a
+ struct 'myPackage.Point'. Assume the package
+
+ package myPackage // in directory myDir/myPackage
+ type Point struct {
+ name string;
+ x, y int;
+ }
+
+ Applying the format specification
+
+ myPackage "myDir/myPackage";
+ int = "%d";
+ hexInt = "0x%x";
+ string = "---%s---";
+ myPackage.Point = name "{" x ", " y:hexInt "}";
+
+ to the value myPackage.Point{"foo", 3, 15} results in
+
+ ---foo---{3, 0xf}
+
+ Finally, an operand may be a grouped, optional, or repeated expression.
+ A grouped expression ("group") groups a more complex expression (body)
+ so that it can be used in place of a single operand:
+
+ Group = "(" [ Indentation ">>" ] Body ")" .
+ Indentation = Expression .
+ Body = Expression .
+
+ A group body may be prefixed by an indentation expression followed by '>>'.
+ The indentation expression is applied to the current value like any other
+ expression and the result, if not nil, is appended to the current indentation
+ during the evaluation of the body (see also formatting state, below).
+
+ An optional expression ("option") is enclosed in '[]' brackets.
+
+ Option = "[" Body "]" .
+
+ An option evaluates to its body, except that if the body evaluates to nil,
+ the option expression evaluates to an empty []byte. Thus an option's purpose
+ is to protect the expression containing the option from a nil operand.
+
+ A repeated expression ("repetition") is enclosed in '{}' braces.
+
+ Repetition = "{" Body [ "/" Separator ] "}" .
+ Separator = Expression .
+
+ A repeated expression is evaluated as follows: The body is evaluated
+ repeatedly and its results are concatenated until the body evaluates
+ to nil. The result of the repetition is the (possibly empty) concatenation,
+ but it is never nil. An implicit index is supplied for the evaluation of
+ the body: that index is used to address elements of arrays or slices. If
+ the corresponding elements do not exist, the field denoting the element
+ evaluates to nil (which in turn may terminate the repetition).
+
+ The body of a repetition may be followed by a '/' and a "separator"
+ expression. If the separator is present, it is invoked between repetitions
+ of the body.
+
+ The following example shows a complete format specification for formatting
+ a slice of unnamed type. Applying the specification
+
+ int = "%b";
+ array = { * / ", " }; // array is the type name for an unnamed slice
+
+ to the value '[]int{2, 3, 5, 7}' results in
+
+ 10, 11, 101, 111
+
+ Default rule: If a format rule named 'default' is present, it is used for
+ formatting a value if no other rule was found. A common default rule is
+
+ default = "%v"
+
+ to provide default formatting for basic types without having to specify
+ a specific rule for each basic type.
+
+ Global separator rule: If a format rule named '/' is present, it is
+ invoked with the current value between literals. If the separator
+ expression evaluates to nil, it is ignored.
+
+ For instance, a global separator rule may be used to punctuate a sequence
+ of values with commas. The rules:
+
+ default = "%v";
+ / = ", ";
+
+ will format an argument list by printing each one in its default format,
+ separated by a comma and a space.
+*/
+package datafmt
+
+import (
+ "bytes"
+ "fmt"
+ "go/token"
+ "io"
+ "os"
+ "reflect"
+ "runtime"
+)
+
+
+// ----------------------------------------------------------------------------
+// Format representation
+
+// Custom formatters implement the Formatter function type.
+// A formatter is invoked with the current formatting state, the
+// value to format, and the rule name under which the formatter
+// was installed (the same formatter function may be installed
+// under different names). The formatter may access the current state
+// to guide formatting and use State.Write to append to the state's
+// output.
+//
+// A formatter must return a boolean value indicating if it evaluated
+// to a non-nil value (true), or a nil value (false).
+//
+type Formatter func(state *State, value interface{}, ruleName string) bool
+
+
+// A FormatterMap is a set of custom formatters.
+// It maps a rule name to a formatter function.
+//
+type FormatterMap map[string]Formatter
+
+
+// A parsed format expression is built from the following nodes.
+//
+type (
+ expr interface{}
+
+ alternatives []expr // x | y | z
+
+ sequence []expr // x y z
+
+ literal [][]byte // a list of string segments, possibly starting with '%'
+
+ field struct {
+ fieldName string // including "@", "*"
+ ruleName string // "" if no rule name specified
+ }
+
+ group struct {
+ indent, body expr // (indent >> body)
+ }
+
+ option struct {
+ body expr // [body]
+ }
+
+ repetition struct {
+ body, separator expr // {body / separator}
+ }
+
+ custom struct {
+ ruleName string
+ fun Formatter
+ }
+)
+
+
+// A Format is the result of parsing a format specification.
+// The format may be applied repeatedly to format values.
+//
+type Format map[string]expr
+
+
+// ----------------------------------------------------------------------------
+// Formatting
+
+// An application-specific environment may be provided to Format.Apply;
+// the environment is available inside custom formatters via State.Env().
+// Environments must implement copying; the Copy method must return an
+// complete copy of the receiver. This is necessary so that the formatter
+// can save and restore an environment (in case of an absent expression).
+//
+// If the Environment doesn't change during formatting (this is under
+// control of the custom formatters), the Copy function can simply return
+// the receiver, and thus can be very light-weight.
+//
+type Environment interface {
+ Copy() Environment
+}
+
+
+// State represents the current formatting state.
+// It is provided as argument to custom formatters.
+//
+type State struct {
+ fmt Format // format in use
+ env Environment // user-supplied environment
+ errors chan os.Error // not chan *Error (errors <- nil would be wrong!)
+ hasOutput bool // true after the first literal has been written
+ indent bytes.Buffer // current indentation
+ output bytes.Buffer // format output
+ linePos token.Position // position of line beginning (Column == 0)
+ default_ expr // possibly nil
+ separator expr // possibly nil
+}
+
+
+func newState(fmt Format, env Environment, errors chan os.Error) *State {
+ s := new(State)
+ s.fmt = fmt
+ s.env = env
+ s.errors = errors
+ s.linePos = token.Position{Line: 1}
+
+ // if we have a default rule, cache it's expression for fast access
+ if x, found := fmt["default"]; found {
+ s.default_ = x
+ }
+
+ // if we have a global separator rule, cache it's expression for fast access
+ if x, found := fmt["/"]; found {
+ s.separator = x
+ }
+
+ return s
+}
+
+
+// Env returns the environment passed to Format.Apply.
+func (s *State) Env() interface{} { return s.env }
+
+
+// LinePos returns the position of the current line beginning
+// in the state's output buffer. Line numbers start at 1.
+//
+func (s *State) LinePos() token.Position { return s.linePos }
+
+
+// Pos returns the position of the next byte to be written to the
+// output buffer. Line numbers start at 1.
+//
+func (s *State) Pos() token.Position {
+ offs := s.output.Len()
+ return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs}
+}
+
+
+// Write writes data to the output buffer, inserting the indentation
+// string after each newline or form feed character. It cannot return an error.
+//
+func (s *State) Write(data []byte) (int, os.Error) {
+ n := 0
+ i0 := 0
+ for i, ch := range data {
+ if ch == '\n' || ch == '\f' {
+ // write text segment and indentation
+ n1, _ := s.output.Write(data[i0 : i+1])
+ n2, _ := s.output.Write(s.indent.Bytes())
+ n += n1 + n2
+ i0 = i + 1
+ s.linePos.Offset = s.output.Len()
+ s.linePos.Line++
+ }
+ }
+ n3, _ := s.output.Write(data[i0:])
+ return n + n3, nil
+}
+
+
+type checkpoint struct {
+ env Environment
+ hasOutput bool
+ outputLen int
+ linePos token.Position
+}
+
+
+func (s *State) save() checkpoint {
+ saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos}
+ if s.env != nil {
+ saved.env = s.env.Copy()
+ }
+ return saved
+}
+
+
+func (s *State) restore(m checkpoint) {
+ s.env = m.env
+ s.output.Truncate(m.outputLen)
+}
+
+
+func (s *State) error(msg string) {
+ s.errors <- os.NewError(msg)
+ runtime.Goexit()
+}
+
+
+// TODO At the moment, unnamed types are simply mapped to the default
+// names below. For instance, all unnamed arrays are mapped to
+// 'array' which is not really sufficient. Eventually one may want
+// to be able to specify rules for say an unnamed slice of T.
+//
+
+func typename(typ reflect.Type) string {
+ switch typ.(type) {
+ case *reflect.ArrayType:
+ return "array"
+ case *reflect.SliceType:
+ return "array"
+ case *reflect.ChanType:
+ return "chan"
+ case *reflect.FuncType:
+ return "func"
+ case *reflect.InterfaceType:
+ return "interface"
+ case *reflect.MapType:
+ return "map"
+ case *reflect.PtrType:
+ return "ptr"
+ }
+ return typ.String()
+}
+
+func (s *State) getFormat(name string) expr {
+ if fexpr, found := s.fmt[name]; found {
+ return fexpr
+ }
+
+ if s.default_ != nil {
+ return s.default_
+ }
+
+ s.error(fmt.Sprintf("no format rule for type: '%s'", name))
+ return nil
+}
+
+
+// eval applies a format expression fexpr to a value. If the expression
+// evaluates internally to a non-nil []byte, that slice is appended to
+// the state's output buffer and eval returns true. Otherwise, eval
+// returns false and the state remains unchanged.
+//
+func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
+ // an empty format expression always evaluates
+ // to a non-nil (but empty) []byte
+ if fexpr == nil {
+ return true
+ }
+
+ switch t := fexpr.(type) {
+ case alternatives:
+ // append the result of the first alternative that evaluates to
+ // a non-nil []byte to the state's output
+ mark := s.save()
+ for _, x := range t {
+ if s.eval(x, value, index) {
+ return true
+ }
+ s.restore(mark)
+ }
+ return false
+
+ case sequence:
+ // append the result of all operands to the state's output
+ // unless a nil result is encountered
+ mark := s.save()
+ for _, x := range t {
+ if !s.eval(x, value, index) {
+ s.restore(mark)
+ return false
+ }
+ }
+ return true
+
+ case literal:
+ // write separator, if any
+ if s.hasOutput {
+ // not the first literal
+ if s.separator != nil {
+ sep := s.separator // save current separator
+ s.separator = nil // and disable it (avoid recursion)
+ mark := s.save()
+ if !s.eval(sep, value, index) {
+ s.restore(mark)
+ }
+ s.separator = sep // enable it again
+ }
+ }
+ s.hasOutput = true
+ // write literal segments
+ for _, lit := range t {
+ if len(lit) > 1 && lit[0] == '%' {
+ // segment contains a %-format at the beginning
+ if lit[1] == '%' {
+ // "%%" is printed as a single "%"
+ s.Write(lit[1:])
+ } else {
+ // use s instead of s.output to get indentation right
+ fmt.Fprintf(s, string(lit), value.Interface())
+ }
+ } else {
+ // segment contains no %-formats
+ s.Write(lit)
+ }
+ }
+ return true // a literal never evaluates to nil
+
+ case *field:
+ // determine field value
+ switch t.fieldName {
+ case "@":
+ // field value is current value
+
+ case "*":
+ // indirection: operation is type-specific
+ switch v := value.(type) {
+ case *reflect.ArrayValue:
+ if v.Len() <= index {
+ return false
+ }
+ value = v.Elem(index)
+
+ case *reflect.SliceValue:
+ if v.IsNil() || v.Len() <= index {
+ return false
+ }
+ value = v.Elem(index)
+
+ case *reflect.MapValue:
+ s.error("reflection support for maps incomplete")
+
+ case *reflect.PtrValue:
+ if v.IsNil() {
+ return false
+ }
+ value = v.Elem()
+
+ case *reflect.InterfaceValue:
+ if v.IsNil() {
+ return false
+ }
+ value = v.Elem()
+
+ case *reflect.ChanValue:
+ s.error("reflection support for chans incomplete")
+
+ case *reflect.FuncValue:
+ s.error("reflection support for funcs incomplete")
+
+ default:
+ s.error(fmt.Sprintf("error: * does not apply to `%s`", value.Type()))
+ }
+
+ default:
+ // value is value of named field
+ var field reflect.Value
+ if sval, ok := value.(*reflect.StructValue); ok {
+ field = sval.FieldByName(t.fieldName)
+ if field == nil {
+ // TODO consider just returning false in this case
+ s.error(fmt.Sprintf("error: no field `%s` in `%s`", t.fieldName, value.Type()))
+ }
+ }
+ value = field
+ }
+
+ // determine rule
+ ruleName := t.ruleName
+ if ruleName == "" {
+ // no alternate rule name, value type determines rule
+ ruleName = typename(value.Type())
+ }
+ fexpr = s.getFormat(ruleName)
+
+ mark := s.save()
+ if !s.eval(fexpr, value, index) {
+ s.restore(mark)
+ return false
+ }
+ return true
+
+ case *group:
+ // remember current indentation
+ indentLen := s.indent.Len()
+
+ // update current indentation
+ mark := s.save()
+ s.eval(t.indent, value, index)
+ // if the indentation evaluates to nil, the state's output buffer
+ // didn't change - either way it's ok to append the difference to
+ // the current identation
+ s.indent.Write(s.output.Bytes()[mark.outputLen:s.output.Len()])
+ s.restore(mark)
+
+ // format group body
+ mark = s.save()
+ b := true
+ if !s.eval(t.body, value, index) {
+ s.restore(mark)
+ b = false
+ }
+
+ // reset indentation
+ s.indent.Truncate(indentLen)
+ return b
+
+ case *option:
+ // evaluate the body and append the result to the state's output
+ // buffer unless the result is nil
+ mark := s.save()
+ if !s.eval(t.body, value, 0) { // TODO is 0 index correct?
+ s.restore(mark)
+ }
+ return true // an option never evaluates to nil
+
+ case *repetition:
+ // evaluate the body and append the result to the state's output
+ // buffer until a result is nil
+ for i := 0; ; i++ {
+ mark := s.save()
+ // write separator, if any
+ if i > 0 && t.separator != nil {
+ // nil result from separator is ignored
+ mark := s.save()
+ if !s.eval(t.separator, value, i) {
+ s.restore(mark)
+ }
+ }
+ if !s.eval(t.body, value, i) {
+ s.restore(mark)
+ break
+ }
+ }
+ return true // a repetition never evaluates to nil
+
+ case *custom:
+ // invoke the custom formatter to obtain the result
+ mark := s.save()
+ if !t.fun(s, value.Interface(), t.ruleName) {
+ s.restore(mark)
+ return false
+ }
+ return true
+ }
+
+ panic("unreachable")
+ return false
+}
+
+
+// Eval formats each argument according to the format
+// f and returns the resulting []byte and os.Error. If
+// an error occurred, the []byte contains the partially
+// formatted result. An environment env may be passed
+// in which is available in custom formatters through
+// the state parameter.
+//
+func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
+ if f == nil {
+ return nil, os.NewError("format is nil")
+ }
+
+ errors := make(chan os.Error)
+ s := newState(f, env, errors)
+
+ go func() {
+ for _, v := range args {
+ fld := reflect.NewValue(v)
+ if fld == nil {
+ errors <- os.NewError("nil argument")
+ return
+ }
+ mark := s.save()
+ if !s.eval(s.getFormat(typename(fld.Type())), fld, 0) { // TODO is 0 index correct?
+ s.restore(mark)
+ }
+ }
+ errors <- nil // no errors
+ }()
+
+ err := <-errors
+ return s.output.Bytes(), err
+}
+
+
+// ----------------------------------------------------------------------------
+// Convenience functions
+
+// Fprint formats each argument according to the format f
+// and writes to w. The result is the total number of bytes
+// written and an os.Error, if any.
+//
+func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int, os.Error) {
+ data, err := f.Eval(env, args...)
+ if err != nil {
+ // TODO should we print partial result in case of error?
+ return 0, err
+ }
+ return w.Write(data)
+}
+
+
+// Print formats each argument according to the format f
+// and writes to standard output. The result is the total
+// number of bytes written and an os.Error, if any.
+//
+func (f Format) Print(args ...interface{}) (int, os.Error) {
+ return f.Fprint(os.Stdout, nil, args...)
+}
+
+
+// Sprint formats each argument according to the format f
+// and returns the resulting string. If an error occurs
+// during formatting, the result string contains the
+// partially formatted result followed by an error message.
+//
+func (f Format) Sprint(args ...interface{}) string {
+ var buf bytes.Buffer
+ _, err := f.Fprint(&buf, nil, args...)
+ if err != nil {
+ var i interface{} = args
+ fmt.Fprintf(&buf, "--- Sprint(%s) failed: %v", fmt.Sprint(i), err)
+ }
+ return buf.String()
+}
diff --git a/libgo/go/exp/datafmt/datafmt_test.go b/libgo/go/exp/datafmt/datafmt_test.go
new file mode 100644
index 000000000..d7c70b21d
--- /dev/null
+++ b/libgo/go/exp/datafmt/datafmt_test.go
@@ -0,0 +1,351 @@
+// 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 datafmt
+
+import (
+ "fmt"
+ "testing"
+ "go/token"
+)
+
+
+var fset = token.NewFileSet()
+
+
+func parse(t *testing.T, form string, fmap FormatterMap) Format {
+ f, err := Parse(fset, "", []byte(form), fmap)
+ if err != nil {
+ t.Errorf("Parse(%s): %v", form, err)
+ return nil
+ }
+ return f
+}
+
+
+func verify(t *testing.T, f Format, expected string, args ...interface{}) {
+ if f == nil {
+ return // allow other tests to run
+ }
+ result := f.Sprint(args...)
+ if result != expected {
+ t.Errorf(
+ "result : `%s`\nexpected: `%s`\n\n",
+ result, expected)
+ }
+}
+
+
+func formatter(s *State, value interface{}, rule_name string) bool {
+ switch rule_name {
+ case "/":
+ fmt.Fprintf(s, "%d %d %d", s.Pos().Line, s.LinePos().Column, s.Pos().Column)
+ return true
+ case "blank":
+ s.Write([]byte{' '})
+ return true
+ case "int":
+ if value.(int)&1 == 0 {
+ fmt.Fprint(s, "even ")
+ } else {
+ fmt.Fprint(s, "odd ")
+ }
+ return true
+ case "nil":
+ return false
+ case "testing.T":
+ s.Write([]byte("testing.T"))
+ return true
+ }
+ panic("unreachable")
+ return false
+}
+
+
+func TestCustomFormatters(t *testing.T) {
+ fmap0 := FormatterMap{"/": formatter}
+ fmap1 := FormatterMap{"int": formatter, "blank": formatter, "nil": formatter}
+ fmap2 := FormatterMap{"testing.T": formatter}
+
+ f := parse(t, `int=`, fmap0)
+ verify(t, f, ``, 1, 2, 3)
+
+ f = parse(t, `int="#"`, nil)
+ verify(t, f, `###`, 1, 2, 3)
+
+ f = parse(t, `int="#";string="%s"`, fmap0)
+ verify(t, f, "#1 0 1#1 0 7#1 0 13\n2 0 0foo2 0 8\n", 1, 2, 3, "\n", "foo", "\n")
+
+ f = parse(t, ``, fmap1)
+ verify(t, f, `even odd even odd `, 0, 1, 2, 3)
+
+ f = parse(t, `/ =@:blank; float64="#"`, fmap1)
+ verify(t, f, `# # #`, 0.0, 1.0, 2.0)
+
+ f = parse(t, `float64=@:nil`, fmap1)
+ verify(t, f, ``, 0.0, 1.0, 2.0)
+
+ f = parse(t, `testing "testing"; ptr=*`, fmap2)
+ verify(t, f, `testing.T`, t)
+
+ // TODO needs more tests
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting of basic and simple composite types
+
+func check(t *testing.T, form, expected string, args ...interface{}) {
+ f := parse(t, form, nil)
+ if f == nil {
+ return // allow other tests to run
+ }
+ result := f.Sprint(args...)
+ if result != expected {
+ t.Errorf(
+ "format : %s\nresult : `%s`\nexpected: `%s`\n\n",
+ form, result, expected)
+ }
+}
+
+
+func TestBasicTypes(t *testing.T) {
+ check(t, ``, ``)
+ check(t, `bool=":%v"`, `:true:false`, true, false)
+ check(t, `int="%b %d %o 0x%x"`, `101010 42 52 0x2a`, 42)
+
+ check(t, `int="%"`, `%`, 42)
+ check(t, `int="%%"`, `%`, 42)
+ check(t, `int="**%%**"`, `**%**`, 42)
+ check(t, `int="%%%%%%"`, `%%%`, 42)
+ check(t, `int="%%%d%%"`, `%42%`, 42)
+
+ const i = -42
+ const is = `-42`
+ check(t, `int ="%d"`, is, i)
+ check(t, `int8 ="%d"`, is, int8(i))
+ check(t, `int16="%d"`, is, int16(i))
+ check(t, `int32="%d"`, is, int32(i))
+ check(t, `int64="%d"`, is, int64(i))
+
+ const u = 42
+ const us = `42`
+ check(t, `uint ="%d"`, us, uint(u))
+ check(t, `uint8 ="%d"`, us, uint8(u))
+ check(t, `uint16="%d"`, us, uint16(u))
+ check(t, `uint32="%d"`, us, uint32(u))
+ check(t, `uint64="%d"`, us, uint64(u))
+
+ const f = 3.141592
+ const fs = `3.141592`
+ check(t, `float64="%g"`, fs, f)
+ check(t, `float32="%g"`, fs, float32(f))
+ check(t, `float64="%g"`, fs, float64(f))
+}
+
+
+func TestArrayTypes(t *testing.T) {
+ var a0 [10]int
+ check(t, `array="array";`, `array`, a0)
+
+ a1 := [...]int{1, 2, 3}
+ check(t, `array="array";`, `array`, a1)
+ check(t, `array={*}; int="%d";`, `123`, a1)
+ check(t, `array={* / ", "}; int="%d";`, `1, 2, 3`, a1)
+ check(t, `array={* / *}; int="%d";`, `12233`, a1)
+
+ a2 := []interface{}{42, "foo", 3.14}
+ check(t, `array={* / ", "}; interface=*; string="bar"; default="%v";`, `42, bar, 3.14`, a2)
+}
+
+
+func TestChanTypes(t *testing.T) {
+ var c0 chan int
+ check(t, `chan="chan"`, `chan`, c0)
+
+ c1 := make(chan int)
+ go func() { c1 <- 42 }()
+ check(t, `chan="chan"`, `chan`, c1)
+ // check(t, `chan=*`, `42`, c1); // reflection support for chans incomplete
+}
+
+
+func TestFuncTypes(t *testing.T) {
+ var f0 func() int
+ check(t, `func="func"`, `func`, f0)
+
+ f1 := func() int { return 42 }
+ check(t, `func="func"`, `func`, f1)
+ // check(t, `func=*`, `42`, f1); // reflection support for funcs incomplete
+}
+
+
+func TestMapTypes(t *testing.T) {
+ var m0 map[string]int
+ check(t, `map="map"`, `map`, m0)
+
+ m1 := map[string]int{}
+ check(t, `map="map"`, `map`, m1)
+ // check(t, `map=*`, ``, m1); // reflection support for maps incomplete
+}
+
+
+func TestPointerTypes(t *testing.T) {
+ var p0 *int
+ check(t, `ptr="ptr"`, `ptr`, p0)
+ check(t, `ptr=*`, ``, p0)
+ check(t, `ptr=*|"nil"`, `nil`, p0)
+
+ x := 99991
+ p1 := &x
+ check(t, `ptr="ptr"`, `ptr`, p1)
+ check(t, `ptr=*; int="%d"`, `99991`, p1)
+}
+
+
+func TestDefaultRule(t *testing.T) {
+ check(t, `default="%v"`, `42foo3.14`, 42, "foo", 3.14)
+ check(t, `default="%v"; int="%x"`, `abcdef`, 10, 11, 12, 13, 14, 15)
+ check(t, `default="%v"; int="%x"`, `ab**ef`, 10, 11, "**", 14, 15)
+ check(t, `default="%x"; int=@:default`, `abcdef`, 10, 11, 12, 13, 14, 15)
+}
+
+
+func TestGlobalSeparatorRule(t *testing.T) {
+ check(t, `int="%d"; / ="-"`, `1-2-3-4`, 1, 2, 3, 4)
+ check(t, `int="%x%x"; / ="*"`, `aa*aa`, 10, 10)
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct
+
+type T1 struct {
+ a int
+}
+
+const F1 = `datafmt "datafmt";` +
+ `int = "%d";` +
+ `datafmt.T1 = "<" a ">";`
+
+func TestStruct1(t *testing.T) { check(t, F1, "<42>", T1{42}) }
+
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct with an optional field (ptr)
+
+type T2 struct {
+ s string
+ p *T1
+}
+
+const F2a = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+const F2b = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ("-" p "-" | "empty");`
+
+func TestStruct2(t *testing.T) {
+ check(t, F2a, "foo", T2{"foo", nil})
+ check(t, F2a, "bar-<17>-", T2{"bar", &T1{17}})
+ check(t, F2b, "fooempty", T2{"foo", nil})
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct with a repetitive field (slice)
+
+type T3 struct {
+ s string
+ a []int
+}
+
+const F3a = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+const F3b = `datafmt "datafmt";` +
+ `int = "%d";` +
+ `string = "%s";` +
+ `array = *;` +
+ `nil = ;` +
+ `empty = *:nil;` +
+ `datafmt.T3 = s [a:empty ": " {a / "-"}]`
+
+func TestStruct3(t *testing.T) {
+ check(t, F3a, "foo", T3{"foo", nil})
+ check(t, F3a, "foo 00, 11, 22", T3{"foo", []int{0, 1, 2}})
+ check(t, F3b, "bar", T3{"bar", nil})
+ check(t, F3b, "bal: 2-3-5", T3{"bal", []int{2, 3, 5}})
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting of a struct with alternative field
+
+type T4 struct {
+ x *int
+ a []int
+}
+
+const F4a = `datafmt "datafmt";` +
+ `int = "%d";` +
+ `ptr = *;` +
+ `array = *;` +
+ `nil = ;` +
+ `empty = *:nil;` +
+ `datafmt.T4 = "<" (x:empty x | "-") ">" `
+
+const F4b = `datafmt "datafmt";` +
+ `int = "%d";` +
+ `ptr = *;` +
+ `array = *;` +
+ `nil = ;` +
+ `empty = *:nil;` +
+ `datafmt.T4 = "<" (a:empty {a / ", "} | "-") ">" `
+
+func TestStruct4(t *testing.T) {
+ x := 7
+ check(t, F4a, "<->", T4{nil, nil})
+ check(t, F4a, "<7>", T4{&x, nil})
+ check(t, F4b, "<->", T4{nil, nil})
+ check(t, F4b, "<2, 3, 7>", T4{nil, []int{2, 3, 7}})
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting a struct (documentation example)
+
+type Point struct {
+ name string
+ x, y int
+}
+
+const FPoint = `datafmt "datafmt";` +
+ `int = "%d";` +
+ `hexInt = "0x%x";` +
+ `string = "---%s---";` +
+ `datafmt.Point = name "{" x ", " y:hexInt "}";`
+
+func TestStructPoint(t *testing.T) {
+ p := Point{"foo", 3, 15}
+ check(t, FPoint, "---foo---{3, 0xf}", p)
+}
+
+
+// ----------------------------------------------------------------------------
+// Formatting a slice (documentation example)
+
+const FSlice = `int = "%b";` +
+ `array = { * / ", " }`
+
+func TestSlice(t *testing.T) { check(t, FSlice, "10, 11, 101, 111", []int{2, 3, 5, 7}) }
+
+
+// TODO add more tests
diff --git a/libgo/go/exp/datafmt/parser.go b/libgo/go/exp/datafmt/parser.go
new file mode 100644
index 000000000..c6d140264
--- /dev/null
+++ b/libgo/go/exp/datafmt/parser.go
@@ -0,0 +1,386 @@
+// 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 datafmt
+
+import (
+ "container/vector"
+ "go/scanner"
+ "go/token"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// ----------------------------------------------------------------------------
+// Parsing
+
+type parser struct {
+ scanner.ErrorVector
+ scanner scanner.Scanner
+ file *token.File
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit []byte // token literal
+
+ packs map[string]string // PackageName -> ImportPath
+ rules map[string]expr // RuleName -> Expression
+}
+
+
+func (p *parser) next() {
+ p.pos, p.tok, p.lit = p.scanner.Scan()
+ switch p.tok {
+ case token.CHAN, token.FUNC, token.INTERFACE, token.MAP, token.STRUCT:
+ // Go keywords for composite types are type names
+ // returned by reflect. Accept them as identifiers.
+ p.tok = token.IDENT // p.lit is already set correctly
+ }
+}
+
+
+func (p *parser) init(fset *token.FileSet, filename string, src []byte) {
+ p.ErrorVector.Reset()
+ p.file = fset.AddFile(filename, fset.Base(), len(src))
+ p.scanner.Init(p.file, src, p, scanner.AllowIllegalChars) // return '@' as token.ILLEGAL w/o error message
+ p.next() // initializes pos, tok, lit
+ p.packs = make(map[string]string)
+ p.rules = make(map[string]expr)
+}
+
+
+func (p *parser) error(pos token.Pos, msg string) {
+ p.Error(p.file.Position(pos), msg)
+}
+
+
+func (p *parser) errorExpected(pos token.Pos, msg string) {
+ msg = "expected " + msg
+ if pos == p.pos {
+ // the error happened at the current position;
+ // make the error message more specific
+ msg += ", found '" + p.tok.String() + "'"
+ if p.tok.IsLiteral() {
+ msg += " " + string(p.lit)
+ }
+ }
+ p.error(pos, msg)
+}
+
+
+func (p *parser) expect(tok token.Token) token.Pos {
+ pos := p.pos
+ if p.tok != tok {
+ p.errorExpected(pos, "'"+tok.String()+"'")
+ }
+ p.next() // make progress in any case
+ return pos
+}
+
+
+func (p *parser) parseIdentifier() string {
+ name := string(p.lit)
+ p.expect(token.IDENT)
+ return name
+}
+
+
+func (p *parser) parseTypeName() (string, bool) {
+ pos := p.pos
+ name, isIdent := p.parseIdentifier(), true
+ if p.tok == token.PERIOD {
+ // got a package name, lookup package
+ if importPath, found := p.packs[name]; found {
+ name = importPath
+ } else {
+ p.error(pos, "package not declared: "+name)
+ }
+ p.next()
+ name, isIdent = name+"."+p.parseIdentifier(), false
+ }
+ return name, isIdent
+}
+
+
+// Parses a rule name and returns it. If the rule name is
+// a package-qualified type name, the package name is resolved.
+// The 2nd result value is true iff the rule name consists of a
+// single identifier only (and thus could be a package name).
+//
+func (p *parser) parseRuleName() (string, bool) {
+ name, isIdent := "", false
+ switch p.tok {
+ case token.IDENT:
+ name, isIdent = p.parseTypeName()
+ case token.DEFAULT:
+ name = "default"
+ p.next()
+ case token.QUO:
+ name = "/"
+ p.next()
+ default:
+ p.errorExpected(p.pos, "rule name")
+ p.next() // make progress in any case
+ }
+ return name, isIdent
+}
+
+
+func (p *parser) parseString() string {
+ s := ""
+ if p.tok == token.STRING {
+ s, _ = strconv.Unquote(string(p.lit))
+ // Unquote may fail with an error, but only if the scanner found
+ // an illegal string in the first place. In this case the error
+ // has already been reported.
+ p.next()
+ return s
+ } else {
+ p.expect(token.STRING)
+ }
+ return s
+}
+
+
+func (p *parser) parseLiteral() literal {
+ s := []byte(p.parseString())
+
+ // A string literal may contain %-format specifiers. To simplify
+ // and speed up printing of the literal, split it into segments
+ // that start with "%" possibly followed by a last segment that
+ // starts with some other character.
+ var list vector.Vector
+ i0 := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == '%' && i+1 < len(s) {
+ // the next segment starts with a % format
+ if i0 < i {
+ // the current segment is not empty, split it off
+ list.Push(s[i0:i])
+ i0 = i
+ }
+ i++ // skip %; let loop skip over char after %
+ }
+ }
+ // the final segment may start with any character
+ // (it is empty iff the string is empty)
+ list.Push(s[i0:])
+
+ // convert list into a literal
+ lit := make(literal, list.Len())
+ for i := 0; i < list.Len(); i++ {
+ lit[i] = list.At(i).([]byte)
+ }
+
+ return lit
+}
+
+
+func (p *parser) parseField() expr {
+ var fname string
+ switch p.tok {
+ case token.ILLEGAL:
+ if string(p.lit) != "@" {
+ return nil
+ }
+ fname = "@"
+ p.next()
+ case token.MUL:
+ fname = "*"
+ p.next()
+ case token.IDENT:
+ fname = p.parseIdentifier()
+ default:
+ return nil
+ }
+
+ var ruleName string
+ if p.tok == token.COLON {
+ p.next()
+ ruleName, _ = p.parseRuleName()
+ }
+
+ return &field{fname, ruleName}
+}
+
+
+func (p *parser) parseOperand() (x expr) {
+ switch p.tok {
+ case token.STRING:
+ x = p.parseLiteral()
+
+ case token.LPAREN:
+ p.next()
+ x = p.parseExpression()
+ if p.tok == token.SHR {
+ p.next()
+ x = &group{x, p.parseExpression()}
+ }
+ p.expect(token.RPAREN)
+
+ case token.LBRACK:
+ p.next()
+ x = &option{p.parseExpression()}
+ p.expect(token.RBRACK)
+
+ case token.LBRACE:
+ p.next()
+ x = p.parseExpression()
+ var div expr
+ if p.tok == token.QUO {
+ p.next()
+ div = p.parseExpression()
+ }
+ x = &repetition{x, div}
+ p.expect(token.RBRACE)
+
+ default:
+ x = p.parseField() // may be nil
+ }
+
+ return x
+}
+
+
+func (p *parser) parseSequence() expr {
+ var list vector.Vector
+
+ for x := p.parseOperand(); x != nil; x = p.parseOperand() {
+ list.Push(x)
+ }
+
+ // no need for a sequence if list.Len() < 2
+ switch list.Len() {
+ case 0:
+ return nil
+ case 1:
+ return list.At(0).(expr)
+ }
+
+ // convert list into a sequence
+ seq := make(sequence, list.Len())
+ for i := 0; i < list.Len(); i++ {
+ seq[i] = list.At(i).(expr)
+ }
+ return seq
+}
+
+
+func (p *parser) parseExpression() expr {
+ var list vector.Vector
+
+ for {
+ x := p.parseSequence()
+ if x != nil {
+ list.Push(x)
+ }
+ if p.tok != token.OR {
+ break
+ }
+ p.next()
+ }
+
+ // no need for an alternatives if list.Len() < 2
+ switch list.Len() {
+ case 0:
+ return nil
+ case 1:
+ return list.At(0).(expr)
+ }
+
+ // convert list into a alternatives
+ alt := make(alternatives, list.Len())
+ for i := 0; i < list.Len(); i++ {
+ alt[i] = list.At(i).(expr)
+ }
+ return alt
+}
+
+
+func (p *parser) parseFormat() {
+ for p.tok != token.EOF {
+ pos := p.pos
+
+ name, isIdent := p.parseRuleName()
+ switch p.tok {
+ case token.STRING:
+ // package declaration
+ importPath := p.parseString()
+
+ // add package declaration
+ if !isIdent {
+ p.error(pos, "illegal package name: "+name)
+ } else if _, found := p.packs[name]; !found {
+ p.packs[name] = importPath
+ } else {
+ p.error(pos, "package already declared: "+name)
+ }
+
+ case token.ASSIGN:
+ // format rule
+ p.next()
+ x := p.parseExpression()
+
+ // add rule
+ if _, found := p.rules[name]; !found {
+ p.rules[name] = x
+ } else {
+ p.error(pos, "format rule already declared: "+name)
+ }
+
+ default:
+ p.errorExpected(p.pos, "package declaration or format rule")
+ p.next() // make progress in any case
+ }
+
+ if p.tok == token.SEMICOLON {
+ p.next()
+ } else {
+ break
+ }
+ }
+ p.expect(token.EOF)
+}
+
+
+func remap(p *parser, name string) string {
+ i := strings.Index(name, ".")
+ if i >= 0 {
+ packageName, suffix := name[0:i], name[i:]
+ // lookup package
+ if importPath, found := p.packs[packageName]; found {
+ name = importPath + suffix
+ } else {
+ var invalidPos token.Position
+ p.Error(invalidPos, "package not declared: "+packageName)
+ }
+ }
+ return name
+}
+
+
+// Parse parses a set of format productions from source src. Custom
+// formatters may be provided via a map of formatter functions. If
+// there are no errors, the result is a Format and the error is nil.
+// Otherwise the format is nil and a non-empty ErrorList is returned.
+//
+func Parse(fset *token.FileSet, filename string, src []byte, fmap FormatterMap) (Format, os.Error) {
+ // parse source
+ var p parser
+ p.init(fset, filename, src)
+ p.parseFormat()
+
+ // add custom formatters, if any
+ for name, form := range fmap {
+ name = remap(&p, name)
+ if _, found := p.rules[name]; !found {
+ p.rules[name] = &custom{name, form}
+ } else {
+ var invalidPos token.Position
+ p.Error(invalidPos, "formatter already declared: "+name)
+ }
+ }
+
+ return p.rules, p.GetError(scanner.NoMultiples)
+}
diff --git a/libgo/go/exp/draw/draw.go b/libgo/go/exp/draw/draw.go
new file mode 100644
index 000000000..1d0729d92
--- /dev/null
+++ b/libgo/go/exp/draw/draw.go
@@ -0,0 +1,363 @@
+// 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 draw provides basic graphics and drawing primitives,
+// in the style of the Plan 9 graphics library
+// (see http://plan9.bell-labs.com/magic/man2html/2/draw)
+// and the X Render extension.
+package draw
+
+import "image"
+
+// m is the maximum color value returned by image.Color.RGBA.
+const m = 1<<16 - 1
+
+// A Porter-Duff compositing operator.
+type Op int
+
+const (
+ // Over specifies ``(src in mask) over dst''.
+ Over Op = iota
+ // Src specifies ``src in mask''.
+ Src
+)
+
+var zeroColor image.Color = image.AlphaColor{0}
+
+// A draw.Image is an image.Image with a Set method to change a single pixel.
+type Image interface {
+ image.Image
+ 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)
+}
+
+// DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r
+// in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque.
+func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
+ sb := src.Bounds()
+ dx, dy := sb.Max.X-sp.X, sb.Max.Y-sp.Y
+ if mask != nil {
+ mb := mask.Bounds()
+ if dx > mb.Max.X-mp.X {
+ dx = mb.Max.X - mp.X
+ }
+ if dy > mb.Max.Y-mp.Y {
+ dy = mb.Max.Y - mp.Y
+ }
+ }
+ if r.Dx() > dx {
+ r.Max.X = r.Min.X + dx
+ }
+ if r.Dy() > dy {
+ r.Max.Y = r.Min.Y + dy
+ }
+ r = r.Intersect(dst.Bounds())
+ if r.Empty() {
+ return
+ }
+
+ // Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation.
+ if dst0, ok := dst.(*image.RGBA); ok {
+ if op == Over {
+ if mask == nil {
+ if src0, ok := src.(*image.ColorImage); ok {
+ drawFillOver(dst0, r, src0)
+ return
+ }
+ if src0, ok := src.(*image.RGBA); ok {
+ drawCopyOver(dst0, r, src0, sp)
+ return
+ }
+ } else if mask0, ok := mask.(*image.Alpha); ok {
+ if src0, ok := src.(*image.ColorImage); ok {
+ drawGlyphOver(dst0, r, src0, mask0, mp)
+ return
+ }
+ }
+ } else {
+ if mask == nil {
+ if src0, ok := src.(*image.ColorImage); ok {
+ drawFillSrc(dst0, r, src0)
+ return
+ }
+ if src0, ok := src.(*image.RGBA); ok {
+ drawCopySrc(dst0, r, src0, sp)
+ return
+ }
+ }
+ }
+ drawRGBA(dst0, r, src, sp, mask, mp, op)
+ return
+ }
+
+ x0, x1, dx := r.Min.X, r.Max.X, 1
+ y0, y1, dy := r.Min.Y, r.Max.Y, 1
+ if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
+ // Rectangles overlap: process backward?
+ if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
+ x0, x1, dx = x1-1, x0-1, -1
+ y0, y1, dy = y1-1, y0-1, -1
+ }
+ }
+
+ var out *image.RGBA64Color
+ sy := sp.Y + y0 - r.Min.Y
+ my := mp.Y + y0 - r.Min.Y
+ for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+ sx := sp.X + x0 - r.Min.X
+ mx := mp.X + x0 - r.Min.X
+ for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
+ ma := uint32(m)
+ if mask != nil {
+ _, _, _, ma = mask.At(mx, my).RGBA()
+ }
+ switch {
+ case ma == 0:
+ if op == Over {
+ // No-op.
+ } else {
+ dst.Set(x, y, zeroColor)
+ }
+ case ma == m && op == Src:
+ dst.Set(x, y, src.At(sx, sy))
+ default:
+ sr, sg, sb, sa := src.At(sx, sy).RGBA()
+ if out == nil {
+ out = new(image.RGBA64Color)
+ }
+ if op == Over {
+ dr, dg, db, da := dst.At(x, y).RGBA()
+ a := m - (sa * ma / m)
+ out.R = uint16((dr*a + sr*ma) / m)
+ out.G = uint16((dg*a + sg*ma) / m)
+ out.B = uint16((db*a + sb*ma) / m)
+ out.A = uint16((da*a + sa*ma) / m)
+ } else {
+ out.R = uint16(sr * ma / m)
+ out.G = uint16(sg * ma / m)
+ out.B = uint16(sb * ma / m)
+ out.A = uint16(sa * ma / m)
+ }
+ dst.Set(x, y, out)
+ }
+ }
+ }
+}
+
+func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
+ cr, cg, cb, ca := src.RGBA()
+ // The 0x101 is here for the same reason as in drawRGBA.
+ a := (m - ca) * 0x101
+ x0, x1 := r.Min.X, r.Max.X
+ y0, y1 := r.Min.Y, r.Max.Y
+ for y := y0; y != y1; y++ {
+ dbase := y * dst.Stride
+ dpix := dst.Pix[dbase+x0 : dbase+x1]
+ for i, rgba := range dpix {
+ dr := (uint32(rgba.R)*a)/m + cr
+ dg := (uint32(rgba.G)*a)/m + cg
+ db := (uint32(rgba.B)*a)/m + cb
+ da := (uint32(rgba.A)*a)/m + ca
+ dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+ }
+ }
+}
+
+func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
+ dx0, dx1 := r.Min.X, r.Max.X
+ dy0, dy1 := r.Min.Y, r.Max.Y
+ nrows := dy1 - dy0
+ sx0, sx1 := sp.X, sp.X+dx1-dx0
+ d0 := dy0*dst.Stride + dx0
+ d1 := dy0*dst.Stride + dx1
+ s0 := sp.Y*src.Stride + sx0
+ s1 := sp.Y*src.Stride + sx1
+ var (
+ ddelta, sdelta int
+ i0, i1, idelta int
+ )
+ if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
+ ddelta = dst.Stride
+ sdelta = src.Stride
+ i0, i1, idelta = 0, d1-d0, +1
+ } else {
+ // If the source start point is higher than the destination start point, or equal height but to the left,
+ // then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
+ d0 += (nrows - 1) * dst.Stride
+ d1 += (nrows - 1) * dst.Stride
+ s0 += (nrows - 1) * src.Stride
+ s1 += (nrows - 1) * src.Stride
+ ddelta = -dst.Stride
+ sdelta = -src.Stride
+ i0, i1, idelta = d1-d0-1, -1, -1
+ }
+ for ; nrows > 0; nrows-- {
+ dpix := dst.Pix[d0:d1]
+ spix := src.Pix[s0:s1]
+ for i := i0; i != i1; i += idelta {
+ // For unknown reasons, even though both dpix[i] and spix[i] are
+ // image.RGBAColors, on an x86 CPU it seems fastest to call RGBA
+ // for the source but to do it manually for the destination.
+ sr, sg, sb, sa := spix[i].RGBA()
+ rgba := dpix[i]
+ dr := uint32(rgba.R)
+ dg := uint32(rgba.G)
+ db := uint32(rgba.B)
+ da := uint32(rgba.A)
+ // The 0x101 is here for the same reason as in drawRGBA.
+ a := (m - sa) * 0x101
+ dr = (dr*a)/m + sr
+ dg = (dg*a)/m + sg
+ db = (db*a)/m + sb
+ da = (da*a)/m + sa
+ dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+ }
+ d0 += ddelta
+ d1 += ddelta
+ s0 += sdelta
+ s1 += sdelta
+ }
+}
+
+func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
+ x0, x1 := r.Min.X, r.Max.X
+ y0, y1 := r.Min.Y, r.Max.Y
+ cr, cg, cb, ca := src.RGBA()
+ for y, my := y0, mp.Y; y != y1; y, my = y+1, my+1 {
+ dbase := y * dst.Stride
+ dpix := dst.Pix[dbase+x0 : dbase+x1]
+ mbase := my * mask.Stride
+ mpix := mask.Pix[mbase+mp.X:]
+ for i, rgba := range dpix {
+ ma := uint32(mpix[i].A)
+ if ma == 0 {
+ continue
+ }
+ ma |= ma << 8
+ dr := uint32(rgba.R)
+ dg := uint32(rgba.G)
+ db := uint32(rgba.B)
+ da := uint32(rgba.A)
+ // The 0x101 is here for the same reason as in drawRGBA.
+ a := (m - (ca * ma / m)) * 0x101
+ dr = (dr*a + cr*ma) / m
+ dg = (dg*a + cg*ma) / m
+ db = (db*a + cb*ma) / m
+ da = (da*a + ca*ma) / m
+ dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+ }
+ }
+}
+
+func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
+ if r.Dy() < 1 {
+ return
+ }
+ cr, cg, cb, ca := src.RGBA()
+ color := image.RGBAColor{uint8(cr >> 8), uint8(cg >> 8), uint8(cb >> 8), uint8(ca >> 8)}
+ // The built-in copy function is faster than a straightforward for loop to fill the destination with
+ // the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
+ // then use the first row as the slice source for the remaining rows.
+ dx0, dx1 := r.Min.X, r.Max.X
+ dy0, dy1 := r.Min.Y, r.Max.Y
+ dbase := dy0 * dst.Stride
+ i0, i1 := dbase+dx0, dbase+dx1
+ firstRow := dst.Pix[i0:i1]
+ for i := range firstRow {
+ firstRow[i] = color
+ }
+ for y := dy0 + 1; y < dy1; y++ {
+ i0 += dst.Stride
+ i1 += dst.Stride
+ copy(dst.Pix[i0:i1], firstRow)
+ }
+}
+
+func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
+ dx0, dx1 := r.Min.X, r.Max.X
+ dy0, dy1 := r.Min.Y, r.Max.Y
+ nrows := dy1 - dy0
+ sx0, sx1 := sp.X, sp.X+dx1-dx0
+ d0 := dy0*dst.Stride + dx0
+ d1 := dy0*dst.Stride + dx1
+ s0 := sp.Y*src.Stride + sx0
+ s1 := sp.Y*src.Stride + sx1
+ var ddelta, sdelta int
+ if r.Min.Y <= sp.Y {
+ ddelta = dst.Stride
+ sdelta = src.Stride
+ } else {
+ // If the source start point is higher than the destination start point, then we compose the rows
+ // in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
+ // check the x co-ordinates because the built-in copy function can handle overlapping slices.
+ d0 += (nrows - 1) * dst.Stride
+ d1 += (nrows - 1) * dst.Stride
+ s0 += (nrows - 1) * src.Stride
+ s1 += (nrows - 1) * src.Stride
+ ddelta = -dst.Stride
+ sdelta = -src.Stride
+ }
+ for ; nrows > 0; nrows-- {
+ copy(dst.Pix[d0:d1], src.Pix[s0:s1])
+ d0 += ddelta
+ d1 += ddelta
+ s0 += sdelta
+ s1 += sdelta
+ }
+}
+
+func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
+ x0, x1, dx := r.Min.X, r.Max.X, 1
+ y0, y1, dy := r.Min.Y, r.Max.Y, 1
+ if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
+ if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
+ x0, x1, dx = x1-1, x0-1, -1
+ y0, y1, dy = y1-1, y0-1, -1
+ }
+ }
+
+ sy := sp.Y + y0 - r.Min.Y
+ my := mp.Y + y0 - r.Min.Y
+ for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
+ sx := sp.X + x0 - r.Min.X
+ mx := mp.X + x0 - r.Min.X
+ dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
+ for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
+ ma := uint32(m)
+ if mask != nil {
+ _, _, _, ma = mask.At(mx, my).RGBA()
+ }
+ sr, sg, sb, sa := src.At(sx, sy).RGBA()
+ var dr, dg, db, da uint32
+ if op == Over {
+ rgba := dpix[x]
+ dr = uint32(rgba.R)
+ dg = uint32(rgba.G)
+ db = uint32(rgba.B)
+ da = uint32(rgba.A)
+ // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
+ // We work in 16-bit color, and so would normally do:
+ // dr |= dr << 8
+ // and similarly for dg, db and da, but instead we multiply a
+ // (which is a 16-bit color, ranging in [0,65535]) by 0x101.
+ // This yields the same result, but is fewer arithmetic operations.
+ a := (m - (sa * ma / m)) * 0x101
+ dr = (dr*a + sr*ma) / m
+ dg = (dg*a + sg*ma) / m
+ db = (db*a + sb*ma) / m
+ da = (da*a + sa*ma) / m
+ } else {
+ dr = sr * ma / m
+ dg = sg * ma / m
+ db = sb * ma / m
+ da = sa * ma / m
+ }
+ dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+ }
+ }
+}
diff --git a/libgo/go/exp/draw/draw_test.go b/libgo/go/exp/draw/draw_test.go
new file mode 100644
index 000000000..90c9e823d
--- /dev/null
+++ b/libgo/go/exp/draw/draw_test.go
@@ -0,0 +1,228 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+import (
+ "image"
+ "testing"
+)
+
+func eq(c0, c1 image.Color) bool {
+ r0, g0, b0, a0 := c0.RGBA()
+ r1, g1, b1, a1 := c1.RGBA()
+ return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1
+}
+
+func fillBlue(alpha int) image.Image {
+ return image.NewColorImage(image.RGBAColor{0, 0, uint8(alpha), uint8(alpha)})
+}
+
+func fillAlpha(alpha int) image.Image {
+ return image.NewColorImage(image.AlphaColor{uint8(alpha)})
+}
+
+func vgradGreen(alpha int) image.Image {
+ m := image.NewRGBA(16, 16)
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, image.RGBAColor{0, uint8(y * alpha / 15), 0, uint8(alpha)})
+ }
+ }
+ return m
+}
+
+func vgradAlpha(alpha int) image.Image {
+ m := image.NewAlpha(16, 16)
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, image.AlphaColor{uint8(y * alpha / 15)})
+ }
+ }
+ return m
+}
+
+func hgradRed(alpha int) Image {
+ m := image.NewRGBA(16, 16)
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), 0, 0, uint8(alpha)})
+ }
+ }
+ return m
+}
+
+func gradYellow(alpha int) Image {
+ m := image.NewRGBA(16, 16)
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), uint8(y * alpha / 15), 0, uint8(alpha)})
+ }
+ }
+ return m
+}
+
+type drawTest struct {
+ desc string
+ src image.Image
+ mask image.Image
+ op Op
+ expected image.Color
+}
+
+var drawTests = []drawTest{
+ // Uniform mask (0% opaque).
+ {"nop", vgradGreen(255), fillAlpha(0), Over, image.RGBAColor{136, 0, 0, 255}},
+ {"clear", vgradGreen(255), fillAlpha(0), Src, image.RGBAColor{0, 0, 0, 0}},
+ // Uniform mask (100%, 75%, nil) and uniform source.
+ // At (x, y) == (8, 8):
+ // The destination pixel is {136, 0, 0, 255}.
+ // The source pixel is {0, 0, 90, 90}.
+ {"fill", fillBlue(90), fillAlpha(255), Over, image.RGBAColor{88, 0, 90, 255}},
+ {"fillSrc", fillBlue(90), fillAlpha(255), Src, image.RGBAColor{0, 0, 90, 90}},
+ {"fillAlpha", fillBlue(90), fillAlpha(192), Over, image.RGBAColor{100, 0, 68, 255}},
+ {"fillAlphaSrc", fillBlue(90), fillAlpha(192), Src, image.RGBAColor{0, 0, 68, 68}},
+ {"fillNil", fillBlue(90), nil, Over, image.RGBAColor{88, 0, 90, 255}},
+ {"fillNilSrc", fillBlue(90), nil, Src, image.RGBAColor{0, 0, 90, 90}},
+ // Uniform mask (100%, 75%, nil) and variable source.
+ // At (x, y) == (8, 8):
+ // The destination pixel is {136, 0, 0, 255}.
+ // The source pixel is {0, 48, 0, 90}.
+ {"copy", vgradGreen(90), fillAlpha(255), Over, image.RGBAColor{88, 48, 0, 255}},
+ {"copySrc", vgradGreen(90), fillAlpha(255), Src, image.RGBAColor{0, 48, 0, 90}},
+ {"copyAlpha", vgradGreen(90), fillAlpha(192), Over, image.RGBAColor{100, 36, 0, 255}},
+ {"copyAlphaSrc", vgradGreen(90), fillAlpha(192), Src, image.RGBAColor{0, 36, 0, 68}},
+ {"copyNil", vgradGreen(90), nil, Over, image.RGBAColor{88, 48, 0, 255}},
+ {"copyNilSrc", vgradGreen(90), nil, Src, image.RGBAColor{0, 48, 0, 90}},
+ // Variable mask and variable source.
+ // At (x, y) == (8, 8):
+ // The destination pixel is {136, 0, 0, 255}.
+ // The source pixel is {0, 0, 255, 255}.
+ // The mask pixel's alpha is 102, or 40%.
+ {"generic", fillBlue(255), vgradAlpha(192), Over, image.RGBAColor{81, 0, 102, 255}},
+ {"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
+}
+
+func makeGolden(dst, src, mask image.Image, op Op) image.Image {
+ // Since golden is a newly allocated image, we don't have to check if the
+ // input source and mask images and the output golden image overlap.
+ b := dst.Bounds()
+ sx0 := src.Bounds().Min.X - b.Min.X
+ sy0 := src.Bounds().Min.Y - b.Min.Y
+ var mx0, my0 int
+ if mask != nil {
+ mx0 = mask.Bounds().Min.X - b.Min.X
+ my0 = mask.Bounds().Min.Y - b.Min.Y
+ }
+ golden := image.NewRGBA(b.Max.X, b.Max.Y)
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ my, sy := my0+y, sy0+y
+ for x := b.Min.X; x < b.Max.X; x++ {
+ mx, sx := mx0+x, sx0+x
+ const M = 1<<16 - 1
+ var dr, dg, db, da uint32
+ if op == Over {
+ dr, dg, db, da = dst.At(x, y).RGBA()
+ }
+ sr, sg, sb, sa := src.At(sx, sy).RGBA()
+ ma := uint32(M)
+ if mask != nil {
+ _, _, _, ma = mask.At(mx, my).RGBA()
+ }
+ a := M - (sa * ma / M)
+ golden.Set(x, y, image.RGBA64Color{
+ uint16((dr*a + sr*ma) / M),
+ uint16((dg*a + sg*ma) / M),
+ uint16((db*a + sb*ma) / M),
+ uint16((da*a + sa*ma) / M),
+ })
+ }
+ }
+ golden.Rect = b
+ return golden
+}
+
+func TestDraw(t *testing.T) {
+loop:
+ for _, test := range drawTests {
+ dst := hgradRed(255)
+ // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+ golden := makeGolden(dst, test.src, test.mask, test.op)
+ b := dst.Bounds()
+ if !b.Eq(golden.Bounds()) {
+ t.Errorf("draw %s: bounds %v versus %v", test.desc, dst.Bounds(), golden.Bounds())
+ continue
+ }
+ // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
+ DrawMask(dst, b, test.src, image.ZP, test.mask, image.ZP, test.op)
+ // Check that the resultant pixel at (8, 8) matches what we expect
+ // (the expected value can be verified by hand).
+ if !eq(dst.At(8, 8), test.expected) {
+ t.Errorf("draw %s: at (8, 8) %v versus %v", test.desc, dst.At(8, 8), test.expected)
+ continue
+ }
+ // Check that the resultant dst image matches the golden output.
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ if !eq(dst.At(x, y), golden.At(x, y)) {
+ t.Errorf("draw %s: at (%d, %d), %v versus golden %v", test.desc, x, y, dst.At(x, y), golden.At(x, y))
+ continue loop
+ }
+ }
+ }
+ }
+}
+
+func TestDrawOverlap(t *testing.T) {
+ for _, op := range []Op{Over, Src} {
+ for yoff := -2; yoff <= 2; yoff++ {
+ loop:
+ for xoff := -2; xoff <= 2; xoff++ {
+ m := gradYellow(127).(*image.RGBA)
+ dst := &image.RGBA{
+ Pix: m.Pix,
+ Stride: m.Stride,
+ Rect: image.Rect(5, 5, 10, 10),
+ }
+ src := &image.RGBA{
+ Pix: m.Pix,
+ Stride: m.Stride,
+ Rect: image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff),
+ }
+ // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+ golden := makeGolden(dst, src, nil, op)
+ b := dst.Bounds()
+ if !b.Eq(golden.Bounds()) {
+ t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds())
+ continue
+ }
+ // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
+ DrawMask(dst, b, src, src.Bounds().Min, nil, image.ZP, op)
+ // Check that the resultant dst image matches the golden output.
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ if !eq(dst.At(x, y), golden.At(x, y)) {
+ t.Errorf("drawOverlap xoff=%d,yoff=%d: at (%d, %d), %v versus golden %v", xoff, yoff, x, y, dst.At(x, y), golden.At(x, y))
+ continue loop
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// TestIssue836 verifies http://code.google.com/p/go/issues/detail?id=836.
+func TestIssue836(t *testing.T) {
+ a := image.NewRGBA(1, 1)
+ b := image.NewRGBA(2, 2)
+ b.Set(0, 0, image.RGBAColor{0, 0, 0, 5})
+ 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))
+ if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) {
+ t.Errorf("Issue 836: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
+ }
+}
diff --git a/libgo/go/exp/draw/event.go b/libgo/go/exp/draw/event.go
new file mode 100644
index 000000000..b777d912e
--- /dev/null
+++ b/libgo/go/exp/draw/event.go
@@ -0,0 +1,56 @@
+// 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 draw
+
+import (
+ "image"
+ "os"
+)
+
+// A Window represents a single graphics window.
+type Window interface {
+ // Screen returns an editable Image for the window.
+ Screen() Image
+ // FlushImage flushes changes made to Screen() back to screen.
+ FlushImage()
+ // EventChan returns a channel carrying UI events such as key presses,
+ // mouse movements and window resizes.
+ EventChan() <-chan interface{}
+ // Close closes the window.
+ Close() os.Error
+}
+
+// A KeyEvent is sent for a key press or release.
+type KeyEvent struct {
+ // The value k represents key k being pressed.
+ // The value -k represents key k being released.
+ // The specific set of key values is not specified,
+ // but ordinary characters represent themselves.
+ Key int
+}
+
+// A MouseEvent is sent for a button press or release or for a mouse movement.
+type MouseEvent struct {
+ // Buttons is a bit mask of buttons: 1<<0 is left, 1<<1 middle, 1<<2 right.
+ // It represents button state and not necessarily the state delta: bit 0
+ // being on means that the left mouse button is down, but does not imply
+ // that the same button was up in the previous MouseEvent.
+ Buttons int
+ // Loc is the location of the cursor.
+ Loc image.Point
+ // Nsec is the event's timestamp.
+ Nsec int64
+}
+
+// A ConfigEvent is sent each time the window's color model or size changes.
+// The client should respond by calling Window.Screen to obtain a new image.
+type ConfigEvent struct {
+ Config image.Config
+}
+
+// An ErrEvent is sent when an error occurs.
+type ErrEvent struct {
+ Err os.Error
+}
diff --git a/libgo/go/exp/draw/x11/auth.go b/libgo/go/exp/draw/x11/auth.go
new file mode 100644
index 000000000..896dedf05
--- /dev/null
+++ b/libgo/go/exp/draw/x11/auth.go
@@ -0,0 +1,93 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x11
+
+import (
+ "bufio"
+ "io"
+ "os"
+)
+
+// readU16BE reads a big-endian uint16 from r, using b as a scratch buffer.
+func readU16BE(r io.Reader, b []byte) (uint16, os.Error) {
+ _, err := io.ReadFull(r, b[0:2])
+ if err != nil {
+ return 0, err
+ }
+ return uint16(b[0])<<8 + uint16(b[1]), nil
+}
+
+// readStr reads a length-prefixed string from r, using b as a scratch buffer.
+func readStr(r io.Reader, b []byte) (string, os.Error) {
+ n, err := readU16BE(r, b)
+ if err != nil {
+ return "", err
+ }
+ if int(n) > len(b) {
+ return "", os.NewError("Xauthority entry too long for buffer")
+ }
+ _, err = io.ReadFull(r, b[0:n])
+ if err != nil {
+ return "", err
+ }
+ return string(b[0:n]), nil
+}
+
+// readAuth reads the X authority file and returns the name/data pair for the display.
+// displayStr is the "12" out of a $DISPLAY like ":12.0".
+func readAuth(displayStr string) (name, data string, err os.Error) {
+ // b is a scratch buffer to use and should be at least 256 bytes long
+ // (i.e. it should be able to hold a hostname).
+ var b [256]byte
+ // As per /usr/include/X11/Xauth.h.
+ const familyLocal = 256
+
+ fn := os.Getenv("XAUTHORITY")
+ if fn == "" {
+ home := os.Getenv("HOME")
+ if home == "" {
+ err = os.NewError("Xauthority not found: $XAUTHORITY, $HOME not set")
+ return
+ }
+ fn = home + "/.Xauthority"
+ }
+ r, err := os.Open(fn, os.O_RDONLY, 0444)
+ if err != nil {
+ return
+ }
+ defer r.Close()
+ br := bufio.NewReader(r)
+
+ hostname, err := os.Hostname()
+ if err != nil {
+ return
+ }
+ for {
+ family, err := readU16BE(br, b[0:2])
+ if err != nil {
+ return
+ }
+ addr, err := readStr(br, b[0:])
+ if err != nil {
+ return
+ }
+ disp, err := readStr(br, b[0:])
+ if err != nil {
+ return
+ }
+ name0, err := readStr(br, b[0:])
+ if err != nil {
+ return
+ }
+ data0, err := readStr(br, b[0:])
+ if err != nil {
+ return
+ }
+ if family == familyLocal && addr == hostname && disp == displayStr {
+ return name0, data0, nil
+ }
+ }
+ panic("unreachable")
+}
diff --git a/libgo/go/exp/draw/x11/conn.go b/libgo/go/exp/draw/x11/conn.go
new file mode 100644
index 000000000..da2181536
--- /dev/null
+++ b/libgo/go/exp/draw/x11/conn.go
@@ -0,0 +1,622 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements an X11 backend for the exp/draw package.
+//
+// The X protocol specification is at ftp://ftp.x.org/pub/X11R7.0/doc/PDF/proto.pdf.
+// A summary of the wire format can be found in XCB's xproto.xml.
+package x11
+
+import (
+ "bufio"
+ "exp/draw"
+ "image"
+ "io"
+ "log"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "time"
+)
+
+type resID uint32 // X resource IDs.
+
+// TODO(nigeltao): Handle window resizes.
+const (
+ windowHeight = 600
+ windowWidth = 800
+)
+
+const (
+ keymapLo = 8
+ keymapHi = 255
+)
+
+type conn struct {
+ c io.Closer
+ r *bufio.Reader
+ w *bufio.Writer
+
+ gc, window, root, visual resID
+
+ img *image.RGBA
+ eventc chan interface{}
+ mouseState draw.MouseEvent
+
+ buf [256]byte // General purpose scratch buffer.
+
+ flush chan bool
+ flushBuf0 [24]byte
+ flushBuf1 [4 * 1024]byte
+}
+
+// writeSocket runs in its own goroutine, serving both FlushImage calls
+// directly from the exp/draw client and indirectly from X expose events.
+// It paints c.img to the X server via PutImage requests.
+func (c *conn) writeSocket() {
+ defer c.c.Close()
+ for _ = range c.flush {
+ b := c.img.Bounds()
+ if b.Empty() {
+ continue
+ }
+ // Each X request has a 16-bit length (in terms of 4-byte units). To avoid going over
+ // this limit, we send PutImage for each row of the image, rather than trying to paint
+ // the entire image in one X request. This approach could easily be optimized (or the
+ // X protocol may have an escape sequence to delimit very large requests).
+ // TODO(nigeltao): See what XCB's xcb_put_image does in this situation.
+ units := 6 + b.Dx()
+ if units > 0xffff || b.Dy() > 0xffff {
+ log.Print("x11: window is too large for PutImage")
+ return
+ }
+
+ c.flushBuf0[0] = 0x48 // PutImage opcode.
+ c.flushBuf0[1] = 0x02 // XCB_IMAGE_FORMAT_Z_PIXMAP.
+ c.flushBuf0[2] = uint8(units)
+ c.flushBuf0[3] = uint8(units >> 8)
+ setU32LE(c.flushBuf0[4:8], uint32(c.window))
+ setU32LE(c.flushBuf0[8:12], uint32(c.gc))
+ setU32LE(c.flushBuf0[12:16], 1<<16|uint32(b.Dx()))
+ c.flushBuf0[21] = 0x18 // depth = 24 bits.
+
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ setU32LE(c.flushBuf0[16:20], uint32(y<<16))
+ if _, err := c.w.Write(c.flushBuf0[0:24]); err != nil {
+ if err != os.EOF {
+ log.Println("x11:", err.String())
+ }
+ return
+ }
+ p := c.img.Pix[y*c.img.Stride : (y+1)*c.img.Stride]
+ for x := b.Min.X; x < b.Max.X; {
+ nx := b.Max.X - x
+ if nx > len(c.flushBuf1)/4 {
+ nx = len(c.flushBuf1) / 4
+ }
+ for i, rgba := range p[x : x+nx] {
+ c.flushBuf1[4*i+0] = rgba.B
+ c.flushBuf1[4*i+1] = rgba.G
+ c.flushBuf1[4*i+2] = rgba.R
+ }
+ x += nx
+ if _, err := c.w.Write(c.flushBuf1[0 : 4*nx]); err != nil {
+ if err != os.EOF {
+ log.Println("x11:", err.String())
+ }
+ return
+ }
+ }
+ }
+ if err := c.w.Flush(); err != nil {
+ if err != os.EOF {
+ log.Println("x11:", err.String())
+ }
+ return
+ }
+ }
+}
+
+func (c *conn) Screen() draw.Image { return c.img }
+
+func (c *conn) FlushImage() {
+ // We do the send (the <- operator) in an expression context, rather than in
+ // a statement context, so that it does not block, and fails if the buffered
+ // channel is full (in which case there already is a flush request pending).
+ _ = c.flush <- false
+}
+
+func (c *conn) Close() os.Error {
+ // Shut down the writeSocket goroutine. This will close the socket to the
+ // X11 server, which will cause c.eventc to close.
+ close(c.flush)
+ for _ = range c.eventc {
+ // Drain the channel to allow the readSocket goroutine to shut down.
+ }
+ return nil
+}
+
+func (c *conn) EventChan() <-chan interface{} { return c.eventc }
+
+// readSocket runs in its own goroutine, reading X events and sending draw
+// events on c's EventChan.
+func (c *conn) readSocket() {
+ var (
+ keymap [256][]int
+ keysymsPerKeycode int
+ )
+ defer close(c.eventc)
+ for {
+ // X events are always 32 bytes long.
+ if _, err := io.ReadFull(c.r, c.buf[0:32]); err != nil {
+ if err != os.EOF {
+ c.eventc <- draw.ErrEvent{err}
+ }
+ return
+ }
+ switch c.buf[0] {
+ case 0x01: // Reply from a request (e.g. GetKeyboardMapping).
+ cookie := int(c.buf[3])<<8 | int(c.buf[2])
+ if cookie != 1 {
+ // We issued only one request (GetKeyboardMapping) with a cookie of 1,
+ // so we shouldn't get any other reply from the X server.
+ c.eventc <- draw.ErrEvent{os.NewError("x11: unexpected cookie")}
+ return
+ }
+ keysymsPerKeycode = int(c.buf[1])
+ b := make([]int, 256*keysymsPerKeycode)
+ for i := range keymap {
+ keymap[i] = b[i*keysymsPerKeycode : (i+1)*keysymsPerKeycode]
+ }
+ for i := keymapLo; i <= keymapHi; i++ {
+ m := keymap[i]
+ for j := range m {
+ u, err := readU32LE(c.r, c.buf[0:4])
+ if err != nil {
+ if err != os.EOF {
+ c.eventc <- draw.ErrEvent{err}
+ }
+ return
+ }
+ m[j] = int(u)
+ }
+ }
+ case 0x02, 0x03: // Key press, key release.
+ // X Keyboard Encoding is documented at http://tronche.com/gui/x/xlib/input/keyboard-encoding.html
+ // TODO(nigeltao): Do we need to implement the "MODE SWITCH / group modifier" feature
+ // or is that some no-longer-used X construct?
+ if keysymsPerKeycode < 2 {
+ // Either we haven't yet received the GetKeyboardMapping reply or
+ // the X server has sent one that's too short.
+ continue
+ }
+ keycode := int(c.buf[1])
+ shift := int(c.buf[28]) & 0x01
+ keysym := keymap[keycode][shift]
+ if keysym == 0 {
+ keysym = keymap[keycode][0]
+ }
+ // TODO(nigeltao): Should we send KeyEvents for Shift/Ctrl/Alt? Should Shift-A send
+ // the same int down the channel as the sent on just the A key?
+ // TODO(nigeltao): How should IME events (e.g. key presses that should generate CJK text) work? Or
+ // is that outside the scope of the draw.Window interface?
+ if c.buf[0] == 0x03 {
+ keysym = -keysym
+ }
+ c.eventc <- draw.KeyEvent{keysym}
+ case 0x04, 0x05: // Button press, button release.
+ mask := 1 << (c.buf[1] - 1)
+ if c.buf[0] == 0x04 {
+ c.mouseState.Buttons |= mask
+ } else {
+ c.mouseState.Buttons &^= mask
+ }
+ c.mouseState.Nsec = time.Nanoseconds()
+ c.eventc <- c.mouseState
+ case 0x06: // Motion notify.
+ c.mouseState.Loc.X = int(int16(c.buf[25])<<8 | int16(c.buf[24]))
+ c.mouseState.Loc.Y = int(int16(c.buf[27])<<8 | int16(c.buf[26]))
+ c.mouseState.Nsec = time.Nanoseconds()
+ c.eventc <- c.mouseState
+ case 0x0c: // Expose.
+ // A single user action could trigger multiple expose events (e.g. if moving another
+ // window with XShape'd rounded corners over our window). In that case, the X server will
+ // send a uint16 count (in bytes 16-17) of the number of additional expose events coming.
+ // We could parse each event for the (x, y, width, height) and maintain a minimal dirty
+ // rectangle, but for now, the simplest approach is to paint the entire window, when
+ // receiving the final event in the series.
+ if c.buf[17] == 0 && c.buf[16] == 0 {
+ // TODO(nigeltao): Should we ignore the very first expose event? A freshly mapped window
+ // will trigger expose, but until the first c.FlushImage call, there's probably nothing to
+ // paint but black. For an 800x600 window, at 4 bytes per pixel, each repaint writes about
+ // 2MB over the socket.
+ c.FlushImage()
+ }
+ // TODO(nigeltao): Should we listen to DestroyNotify (0x11) and ResizeRequest (0x19) events?
+ // What about EnterNotify (0x07) and LeaveNotify (0x08)?
+ }
+ }
+}
+
+// connect connects to the X server given by the full X11 display name (e.g.
+// ":12.0") and returns the connection as well as the portion of the full name
+// that is the display number (e.g. "12").
+// Examples:
+// connect(":1") // calls net.Dial("unix", "", "/tmp/.X11-unix/X1"), displayStr="1"
+// connect("/tmp/launch-123/:0") // calls net.Dial("unix", "", "/tmp/launch-123/:0"), displayStr="0"
+// connect("hostname:2.1") // calls net.Dial("tcp", "", "hostname:6002"), displayStr="2"
+// connect("tcp/hostname:1.0") // calls net.Dial("tcp", "", "hostname:6001"), displayStr="1"
+func connect(display string) (conn net.Conn, displayStr string, err os.Error) {
+ colonIdx := strings.LastIndex(display, ":")
+ if colonIdx < 0 {
+ return nil, "", os.NewError("bad display: " + display)
+ }
+ // Parse the section before the colon.
+ var protocol, host, socket string
+ if display[0] == '/' {
+ socket = display[0:colonIdx]
+ } else {
+ if i := strings.LastIndex(display, "/"); i < 0 {
+ // The default protocol is TCP.
+ protocol = "tcp"
+ host = display[0:colonIdx]
+ } else {
+ protocol = display[0:i]
+ host = display[i+1 : colonIdx]
+ }
+ }
+ // Parse the section after the colon.
+ after := display[colonIdx+1:]
+ if after == "" {
+ return nil, "", os.NewError("bad display: " + display)
+ }
+ if i := strings.LastIndex(after, "."); i < 0 {
+ displayStr = after
+ } else {
+ displayStr = after[0:i]
+ }
+ displayInt, err := strconv.Atoi(displayStr)
+ if err != nil || displayInt < 0 {
+ return nil, "", os.NewError("bad display: " + display)
+ }
+ // Make the connection.
+ if socket != "" {
+ conn, err = net.Dial("unix", "", socket+":"+displayStr)
+ } else if host != "" {
+ conn, err = net.Dial(protocol, "", host+":"+strconv.Itoa(6000+displayInt))
+ } else {
+ conn, err = net.Dial("unix", "", "/tmp/.X11-unix/X"+displayStr)
+ }
+ if err != nil {
+ return nil, "", os.NewError("cannot connect to " + display + ": " + err.String())
+ }
+ return
+}
+
+// authenticate authenticates ourselves with the X server.
+// displayStr is the "12" out of ":12.0".
+func authenticate(w *bufio.Writer, displayStr string) os.Error {
+ key, value, err := readAuth(displayStr)
+ if err != nil {
+ return err
+ }
+ // Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1".
+ if len(key) != 18 || len(value) != 16 {
+ return os.NewError("unsupported Xauth")
+ }
+ // 0x006c means little-endian. 0x000b, 0x0000 means X major version 11, minor version 0.
+ // 0x0012 and 0x0010 means the auth key and value have lenths 18 and 16.
+ // The final 0x0000 is padding, so that the string length is a multiple of 4.
+ _, err = io.WriteString(w, "\x6c\x00\x0b\x00\x00\x00\x12\x00\x10\x00\x00\x00")
+ if err != nil {
+ return err
+ }
+ _, err = io.WriteString(w, key)
+ if err != nil {
+ return err
+ }
+ // Again, the 0x0000 is padding.
+ _, err = io.WriteString(w, "\x00\x00")
+ if err != nil {
+ return err
+ }
+ _, err = io.WriteString(w, value)
+ if err != nil {
+ return err
+ }
+ err = w.Flush()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// readU8 reads a uint8 from r, using b as a scratch buffer.
+func readU8(r io.Reader, b []byte) (uint8, os.Error) {
+ _, err := io.ReadFull(r, b[0:1])
+ if err != nil {
+ return 0, err
+ }
+ return uint8(b[0]), nil
+}
+
+// readU16LE reads a little-endian uint16 from r, using b as a scratch buffer.
+func readU16LE(r io.Reader, b []byte) (uint16, os.Error) {
+ _, err := io.ReadFull(r, b[0:2])
+ if err != nil {
+ return 0, err
+ }
+ return uint16(b[0]) | uint16(b[1])<<8, nil
+}
+
+// readU32LE reads a little-endian uint32 from r, using b as a scratch buffer.
+func readU32LE(r io.Reader, b []byte) (uint32, os.Error) {
+ _, err := io.ReadFull(r, b[0:4])
+ if err != nil {
+ return 0, err
+ }
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, nil
+}
+
+// setU32LE sets b[0:4] to be the little-endian representation of u.
+func setU32LE(b []byte, u uint32) {
+ b[0] = byte((u >> 0) & 0xff)
+ b[1] = byte((u >> 8) & 0xff)
+ b[2] = byte((u >> 16) & 0xff)
+ b[3] = byte((u >> 24) & 0xff)
+}
+
+// checkPixmapFormats checks that we have an agreeable X pixmap Format.
+func checkPixmapFormats(r io.Reader, b []byte, n int) (agree bool, err os.Error) {
+ for i := 0; i < n; i++ {
+ _, err = io.ReadFull(r, b[0:8])
+ if err != nil {
+ return
+ }
+ // Byte 0 is depth, byte 1 is bits-per-pixel, byte 2 is scanline-pad, the rest (5) is padding.
+ if b[0] == 24 && b[1] == 32 {
+ agree = true
+ }
+ }
+ return
+}
+
+// checkDepths checks that we have an agreeable X Depth (i.e. one that has an agreeable X VisualType).
+func checkDepths(r io.Reader, b []byte, n int, visual uint32) (agree bool, err os.Error) {
+ for i := 0; i < n; i++ {
+ depth, err := readU16LE(r, b)
+ if err != nil {
+ return
+ }
+ depth &= 0xff
+ visualsLen, err := readU16LE(r, b)
+ if err != nil {
+ return
+ }
+ // Ignore 4 bytes of padding.
+ _, err = io.ReadFull(r, b[0:4])
+ if err != nil {
+ return
+ }
+ for j := 0; j < int(visualsLen); j++ {
+ // Read 24 bytes: visual(4), class(1), bits per rgb value(1), colormap entries(2),
+ // red mask(4), green mask(4), blue mask(4), padding(4).
+ v, err := readU32LE(r, b)
+ _, err = readU32LE(r, b)
+ rm, err := readU32LE(r, b)
+ gm, err := readU32LE(r, b)
+ bm, err := readU32LE(r, b)
+ _, err = readU32LE(r, b)
+ if err != nil {
+ return
+ }
+ if v == visual && rm == 0xff0000 && gm == 0xff00 && bm == 0xff && depth == 24 {
+ agree = true
+ }
+ }
+ }
+ return
+}
+
+// checkScreens checks that we have an agreeable X Screen.
+func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Error) {
+ for i := 0; i < n; i++ {
+ root0, err := readU32LE(r, b)
+ if err != nil {
+ return
+ }
+ // Ignore the next 7x4 bytes, which is: colormap, whitepixel, blackpixel, current input masks,
+ // width and height (pixels), width and height (mm), min and max installed maps.
+ _, err = io.ReadFull(r, b[0:28])
+ if err != nil {
+ return
+ }
+ visual0, err := readU32LE(r, b)
+ if err != nil {
+ return
+ }
+ // Next 4 bytes: backing stores, save unders, root depth, allowed depths length.
+ x, err := readU32LE(r, b)
+ if err != nil {
+ return
+ }
+ nDepths := int(x >> 24)
+ agree, err := checkDepths(r, b, nDepths, visual0)
+ if err != nil {
+ return
+ }
+ if agree && root == 0 {
+ root = root0
+ visual = visual0
+ }
+ }
+ return
+}
+
+// handshake performs the protocol handshake with the X server, and ensures
+// that the server provides a compatible Screen, Depth, etc.
+func (c *conn) handshake() os.Error {
+ _, err := io.ReadFull(c.r, c.buf[0:8])
+ if err != nil {
+ return err
+ }
+ // Byte 0:1 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0).
+ if c.buf[0] != 1 || c.buf[2] != 11 || c.buf[3] != 0 || c.buf[4] != 0 || c.buf[5] != 0 {
+ return os.NewError("unsupported X version")
+ }
+ // Ignore the release number.
+ _, err = io.ReadFull(c.r, c.buf[0:4])
+ if err != nil {
+ return err
+ }
+ // Read the resource ID base.
+ resourceIdBase, err := readU32LE(c.r, c.buf[0:4])
+ if err != nil {
+ return err
+ }
+ // Read the resource ID mask.
+ resourceIdMask, err := readU32LE(c.r, c.buf[0:4])
+ if err != nil {
+ return err
+ }
+ if resourceIdMask < 256 {
+ return os.NewError("X resource ID mask is too small")
+ }
+ // Ignore the motion buffer size.
+ _, err = io.ReadFull(c.r, c.buf[0:4])
+ if err != nil {
+ return err
+ }
+ // Read the vendor length and round it up to a multiple of 4,
+ // for X11 protocol alignment reasons.
+ vendorLen, err := readU16LE(c.r, c.buf[0:2])
+ if err != nil {
+ return err
+ }
+ vendorLen = (vendorLen + 3) &^ 3
+ // Read the maximum request length.
+ maxReqLen, err := readU16LE(c.r, c.buf[0:2])
+ if err != nil {
+ return err
+ }
+ if maxReqLen != 0xffff {
+ return os.NewError("unsupported X maximum request length")
+ }
+ // Read the roots length.
+ rootsLen, err := readU8(c.r, c.buf[0:1])
+ if err != nil {
+ return err
+ }
+ // Read the pixmap formats length.
+ pixmapFormatsLen, err := readU8(c.r, c.buf[0:1])
+ if err != nil {
+ return err
+ }
+ // Ignore some things that we don't care about (totalling 10 + vendorLen bytes):
+ // imageByteOrder(1), bitmapFormatBitOrder(1), bitmapFormatScanlineUnit(1) bitmapFormatScanlinePad(1),
+ // minKeycode(1), maxKeycode(1), padding(4), vendor (vendorLen).
+ if 10+int(vendorLen) > cap(c.buf) {
+ return os.NewError("unsupported X vendor")
+ }
+ _, err = io.ReadFull(c.r, c.buf[0:10+int(vendorLen)])
+ if err != nil {
+ return err
+ }
+ // Check that we have an agreeable pixmap format.
+ agree, err := checkPixmapFormats(c.r, c.buf[0:8], int(pixmapFormatsLen))
+ if err != nil {
+ return err
+ }
+ if !agree {
+ return os.NewError("unsupported X pixmap formats")
+ }
+ // Check that we have an agreeable screen.
+ root, visual, err := checkScreens(c.r, c.buf[0:24], int(rootsLen))
+ if err != nil {
+ return err
+ }
+ if root == 0 || visual == 0 {
+ return os.NewError("unsupported X screen")
+ }
+ c.gc = resID(resourceIdBase)
+ c.window = resID(resourceIdBase + 1)
+ c.root = resID(root)
+ c.visual = resID(visual)
+ return nil
+}
+
+// NewWindow calls NewWindowDisplay with $DISPLAY.
+func NewWindow() (draw.Window, os.Error) {
+ display := os.Getenv("DISPLAY")
+ if len(display) == 0 {
+ return nil, os.NewError("$DISPLAY not set")
+ }
+ return NewWindowDisplay(display)
+}
+
+// NewWindowDisplay returns a new draw.Window, backed by a newly created and
+// mapped X11 window. The X server to connect to is specified by the display
+// string, such as ":1".
+func NewWindowDisplay(display string) (draw.Window, os.Error) {
+ socket, displayStr, err := connect(display)
+ if err != nil {
+ return nil, err
+ }
+ c := new(conn)
+ c.c = socket
+ c.r = bufio.NewReader(socket)
+ c.w = bufio.NewWriter(socket)
+ err = authenticate(c.w, displayStr)
+ if err != nil {
+ return nil, err
+ }
+ err = c.handshake()
+ if err != nil {
+ return nil, err
+ }
+
+ // Now that we're connected, show a window, via three X protocol messages.
+ // First, issue a GetKeyboardMapping request. This is the first request, and
+ // will be associated with a cookie of 1.
+ setU32LE(c.buf[0:4], 0x00020065) // 0x65 is the GetKeyboardMapping opcode, and the message is 2 x 4 bytes long.
+ setU32LE(c.buf[4:8], uint32((keymapHi-keymapLo+1)<<8|keymapLo))
+ // Second, create a graphics context (GC).
+ setU32LE(c.buf[8:12], 0x00060037) // 0x37 is the CreateGC opcode, and the message is 6 x 4 bytes long.
+ setU32LE(c.buf[12:16], uint32(c.gc))
+ setU32LE(c.buf[16:20], uint32(c.root))
+ setU32LE(c.buf[20:24], 0x00010004) // Bit 2 is XCB_GC_FOREGROUND, bit 16 is XCB_GC_GRAPHICS_EXPOSURES.
+ setU32LE(c.buf[24:28], 0x00000000) // The Foreground is black.
+ setU32LE(c.buf[28:32], 0x00000000) // GraphicsExposures' value is unused.
+ // Third, create the window.
+ setU32LE(c.buf[32:36], 0x000a0001) // 0x01 is the CreateWindow opcode, and the message is 10 x 4 bytes long.
+ setU32LE(c.buf[36:40], uint32(c.window))
+ setU32LE(c.buf[40:44], uint32(c.root))
+ setU32LE(c.buf[44:48], 0x00000000) // Initial (x, y) is (0, 0).
+ setU32LE(c.buf[48:52], windowHeight<<16|windowWidth)
+ setU32LE(c.buf[52:56], 0x00010000) // Border width is 0, XCB_WINDOW_CLASS_INPUT_OUTPUT is 1.
+ setU32LE(c.buf[56:60], uint32(c.visual))
+ setU32LE(c.buf[60:64], 0x00000802) // Bit 1 is XCB_CW_BACK_PIXEL, bit 11 is XCB_CW_EVENT_MASK.
+ setU32LE(c.buf[64:68], 0x00000000) // The Back-Pixel is black.
+ setU32LE(c.buf[68:72], 0x0000804f) // Key/button press and release, pointer motion, and expose event masks.
+ // Fourth, map the window.
+ setU32LE(c.buf[72:76], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long.
+ setU32LE(c.buf[76:80], uint32(c.window))
+ // Write the bytes.
+ _, err = c.w.Write(c.buf[0:80])
+ if err != nil {
+ return nil, err
+ }
+ err = c.w.Flush()
+ if err != nil {
+ return nil, err
+ }
+
+ c.img = image.NewRGBA(windowWidth, windowHeight)
+ c.eventc = make(chan interface{}, 16)
+ c.flush = make(chan bool, 1)
+ go c.readSocket()
+ go c.writeSocket()
+ return c, nil
+}
diff --git a/libgo/go/exp/eval/abort.go b/libgo/go/exp/eval/abort.go
new file mode 100644
index 000000000..22e17cec4
--- /dev/null
+++ b/libgo/go/exp/eval/abort.go
@@ -0,0 +1,85 @@
+// 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 eval
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+)
+
+// Abort aborts the thread's current computation,
+// causing the innermost Try to return err.
+func (t *Thread) Abort(err os.Error) {
+ if t.abort == nil {
+ panic("abort: " + err.String())
+ }
+ t.abort <- err
+ runtime.Goexit()
+}
+
+// Try executes a computation; if the computation
+// Aborts, Try returns the error passed to abort.
+func (t *Thread) Try(f func(t *Thread)) os.Error {
+ oc := t.abort
+ c := make(chan os.Error)
+ t.abort = c
+ go func() {
+ f(t)
+ c <- nil
+ }()
+ err := <-c
+ t.abort = oc
+ return err
+}
+
+type DivByZeroError struct{}
+
+func (DivByZeroError) String() string { return "divide by zero" }
+
+type NilPointerError struct{}
+
+func (NilPointerError) String() string { return "nil pointer dereference" }
+
+type IndexError struct {
+ Idx, Len int64
+}
+
+func (e IndexError) String() string {
+ if e.Idx < 0 {
+ return fmt.Sprintf("negative index: %d", e.Idx)
+ }
+ return fmt.Sprintf("index %d exceeds length %d", e.Idx, e.Len)
+}
+
+type SliceError struct {
+ Lo, Hi, Cap int64
+}
+
+func (e SliceError) String() string {
+ return fmt.Sprintf("slice [%d:%d]; cap %d", e.Lo, e.Hi, e.Cap)
+}
+
+type KeyError struct {
+ Key interface{}
+}
+
+func (e KeyError) String() string { return fmt.Sprintf("key '%v' not found in map", e.Key) }
+
+type NegativeLengthError struct {
+ Len int64
+}
+
+func (e NegativeLengthError) String() string {
+ return fmt.Sprintf("negative length: %d", e.Len)
+}
+
+type NegativeCapacityError struct {
+ Len int64
+}
+
+func (e NegativeCapacityError) String() string {
+ return fmt.Sprintf("negative capacity: %d", e.Len)
+}
diff --git a/libgo/go/exp/eval/bridge.go b/libgo/go/exp/eval/bridge.go
new file mode 100644
index 000000000..12835c4c0
--- /dev/null
+++ b/libgo/go/exp/eval/bridge.go
@@ -0,0 +1,169 @@
+// 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 eval
+
+import (
+ "log"
+ "go/token"
+ "reflect"
+)
+
+/*
+ * Type bridging
+ */
+
+var (
+ evalTypes = make(map[reflect.Type]Type)
+ nativeTypes = make(map[Type]reflect.Type)
+)
+
+// TypeFromNative converts a regular Go type into a the corresponding
+// interpreter Type.
+func TypeFromNative(t reflect.Type) Type {
+ if et, ok := evalTypes[t]; ok {
+ return et
+ }
+
+ var nt *NamedType
+ if t.Name() != "" {
+ name := t.PkgPath() + "·" + t.Name()
+ nt = &NamedType{token.NoPos, name, nil, true, make(map[string]Method)}
+ evalTypes[t] = nt
+ }
+
+ var et Type
+ switch t := t.(type) {
+ case *reflect.BoolType:
+ et = BoolType
+ case *reflect.FloatType:
+ switch t.Kind() {
+ case reflect.Float32:
+ et = Float32Type
+ case reflect.Float64:
+ et = Float64Type
+ }
+ case *reflect.IntType:
+ switch t.Kind() {
+ case reflect.Int16:
+ et = Int16Type
+ case reflect.Int32:
+ et = Int32Type
+ case reflect.Int64:
+ et = Int64Type
+ case reflect.Int8:
+ et = Int8Type
+ case reflect.Int:
+ et = IntType
+ }
+ case *reflect.UintType:
+ switch t.Kind() {
+ case reflect.Uint16:
+ et = Uint16Type
+ case reflect.Uint32:
+ et = Uint32Type
+ case reflect.Uint64:
+ et = Uint64Type
+ case reflect.Uint8:
+ et = Uint8Type
+ case reflect.Uint:
+ et = UintType
+ case reflect.Uintptr:
+ et = UintptrType
+ }
+ case *reflect.StringType:
+ et = StringType
+ case *reflect.ArrayType:
+ et = NewArrayType(int64(t.Len()), TypeFromNative(t.Elem()))
+ case *reflect.ChanType:
+ log.Panicf("%T not implemented", t)
+ case *reflect.FuncType:
+ nin := t.NumIn()
+ // Variadic functions have DotDotDotType at the end
+ variadic := t.DotDotDot()
+ if variadic {
+ nin--
+ }
+ in := make([]Type, nin)
+ for i := range in {
+ in[i] = TypeFromNative(t.In(i))
+ }
+ out := make([]Type, t.NumOut())
+ for i := range out {
+ out[i] = TypeFromNative(t.Out(i))
+ }
+ et = NewFuncType(in, variadic, out)
+ case *reflect.InterfaceType:
+ log.Panicf("%T not implemented", t)
+ case *reflect.MapType:
+ log.Panicf("%T not implemented", t)
+ case *reflect.PtrType:
+ et = NewPtrType(TypeFromNative(t.Elem()))
+ case *reflect.SliceType:
+ et = NewSliceType(TypeFromNative(t.Elem()))
+ case *reflect.StructType:
+ n := t.NumField()
+ fields := make([]StructField, n)
+ for i := 0; i < n; i++ {
+ sf := t.Field(i)
+ // TODO(austin) What to do about private fields?
+ fields[i].Name = sf.Name
+ fields[i].Type = TypeFromNative(sf.Type)
+ fields[i].Anonymous = sf.Anonymous
+ }
+ et = NewStructType(fields)
+ case *reflect.UnsafePointerType:
+ log.Panicf("%T not implemented", t)
+ default:
+ log.Panicf("unexpected reflect.Type: %T", t)
+ }
+
+ if nt != nil {
+ if _, ok := et.(*NamedType); !ok {
+ nt.Complete(et)
+ et = nt
+ }
+ }
+
+ nativeTypes[et] = t
+ evalTypes[t] = et
+
+ return et
+}
+
+// TypeOfNative returns the interpreter Type of a regular Go value.
+func TypeOfNative(v interface{}) Type { return TypeFromNative(reflect.Typeof(v)) }
+
+/*
+ * Function bridging
+ */
+
+type nativeFunc struct {
+ fn func(*Thread, []Value, []Value)
+ in, out int
+}
+
+func (f *nativeFunc) NewFrame() *Frame {
+ vars := make([]Value, f.in+f.out)
+ return &Frame{nil, vars}
+}
+
+func (f *nativeFunc) Call(t *Thread) { f.fn(t, t.f.Vars[0:f.in], t.f.Vars[f.in:f.in+f.out]) }
+
+// FuncFromNative creates an interpreter function from a native
+// function that takes its in and out arguments as slices of
+// interpreter Value's. While somewhat inconvenient, this avoids
+// value marshalling.
+func FuncFromNative(fn func(*Thread, []Value, []Value), t *FuncType) FuncValue {
+ return &funcV{&nativeFunc{fn, len(t.In), len(t.Out)}}
+}
+
+// FuncFromNativeTyped is like FuncFromNative, but constructs the
+// function type from a function pointer using reflection. Typically,
+// the type will be given as a nil pointer to a function with the
+// desired signature.
+func FuncFromNativeTyped(fn func(*Thread, []Value, []Value), t interface{}) (*FuncType, FuncValue) {
+ ft := TypeOfNative(t).(*FuncType)
+ return ft, FuncFromNative(fn, ft)
+}
diff --git a/libgo/go/exp/eval/compiler.go b/libgo/go/exp/eval/compiler.go
new file mode 100644
index 000000000..9d2923bfc
--- /dev/null
+++ b/libgo/go/exp/eval/compiler.go
@@ -0,0 +1,92 @@
+// 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 eval
+
+import (
+ "fmt"
+ "go/scanner"
+ "go/token"
+)
+
+
+// A compiler captures information used throughout an entire
+// compilation. Currently it includes only the error handler.
+//
+// TODO(austin) This might actually represent package level, in which
+// case it should be package compiler.
+type compiler struct {
+ fset *token.FileSet
+ errors scanner.ErrorHandler
+ numErrors int
+ silentErrors int
+}
+
+func (a *compiler) diagAt(pos token.Pos, format string, args ...interface{}) {
+ a.errors.Error(a.fset.Position(pos), fmt.Sprintf(format, args...))
+ a.numErrors++
+}
+
+func (a *compiler) numError() int { return a.numErrors + a.silentErrors }
+
+// The universal scope
+func newUniverse() *Scope {
+ sc := &Scope{nil, 0}
+ sc.block = &block{
+ offset: 0,
+ scope: sc,
+ global: true,
+ defs: make(map[string]Def),
+ }
+ return sc
+}
+
+var universe *Scope = newUniverse()
+
+
+// TODO(austin) These can all go in stmt.go now
+type label struct {
+ name string
+ desc string
+ // The PC goto statements should jump to, or nil if this label
+ // cannot be goto'd (such as an anonymous for loop label).
+ gotoPC *uint
+ // The PC break statements should jump to, or nil if a break
+ // statement is invalid.
+ breakPC *uint
+ // The PC continue statements should jump to, or nil if a
+ // continue statement is invalid.
+ continuePC *uint
+ // The position where this label was resolved. If it has not
+ // been resolved yet, an invalid position.
+ resolved token.Pos
+ // The position where this label was first jumped to.
+ used token.Pos
+}
+
+// A funcCompiler captures information used throughout the compilation
+// of a single function body.
+type funcCompiler struct {
+ *compiler
+ fnType *FuncType
+ // Whether the out variables are named. This affects what
+ // kinds of return statements are legal.
+ outVarsNamed bool
+ *codeBuf
+ flow *flowBuf
+ labels map[string]*label
+}
+
+// A blockCompiler captures information used throughout the compilation
+// of a single block within a function.
+type blockCompiler struct {
+ *funcCompiler
+ block *block
+ // The label of this block, used for finding break and
+ // continue labels.
+ label *label
+ // The blockCompiler for the block enclosing this one, or nil
+ // for a function-level block.
+ parent *blockCompiler
+}
diff --git a/libgo/go/exp/eval/eval_test.go b/libgo/go/exp/eval/eval_test.go
new file mode 100644
index 000000000..ff28cf1a9
--- /dev/null
+++ b/libgo/go/exp/eval/eval_test.go
@@ -0,0 +1,259 @@
+// 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 eval
+
+import (
+ "big"
+ "flag"
+ "fmt"
+ "go/token"
+ "log"
+ "os"
+ "reflect"
+ "regexp"
+ "testing"
+)
+
+// All tests are done using the same file set.
+var fset = token.NewFileSet()
+
+// Print each statement or expression before parsing it
+var noisy = false
+
+func init() { flag.BoolVar(&noisy, "noisy", false, "chatter during eval tests") }
+
+/*
+ * Generic statement/expression test framework
+ */
+
+type test []job
+
+type job struct {
+ code string
+ cerr string
+ rterr string
+ val Value
+ noval bool
+}
+
+func runTests(t *testing.T, baseName string, tests []test) {
+ for i, test := range tests {
+ name := fmt.Sprintf("%s[%d]", baseName, i)
+ test.run(t, name)
+ }
+}
+
+func (a test) run(t *testing.T, name string) {
+ w := newTestWorld()
+ for _, j := range a {
+ src := j.code + ";" // trailing semicolon to finish statement
+ if noisy {
+ println("code:", src)
+ }
+
+ code, err := w.Compile(fset, src)
+ if err != nil {
+ if j.cerr == "" {
+ t.Errorf("%s: Compile %s: %v", name, src, err)
+ break
+ }
+ if !match(t, err, j.cerr) {
+ t.Errorf("%s: Compile %s = error %s; want %v", name, src, err, j.cerr)
+ break
+ }
+ continue
+ }
+ if j.cerr != "" {
+ t.Errorf("%s: Compile %s succeeded; want %s", name, src, j.cerr)
+ break
+ }
+
+ val, err := code.Run()
+ if err != nil {
+ if j.rterr == "" {
+ t.Errorf("%s: Run %s: %v", name, src, err)
+ break
+ }
+ if !match(t, err, j.rterr) {
+ t.Errorf("%s: Run %s = error %s; want %v", name, src, err, j.rterr)
+ break
+ }
+ continue
+ }
+ if j.rterr != "" {
+ t.Errorf("%s: Run %s succeeded; want %s", name, src, j.rterr)
+ break
+ }
+
+ if !j.noval && !reflect.DeepEqual(val, j.val) {
+ t.Errorf("%s: Run %s = %T(%v) want %T(%v)", name, src, val, val, j.val, j.val)
+ }
+ }
+}
+
+func match(t *testing.T, err os.Error, pat string) bool {
+ ok, err1 := regexp.MatchString(pat, err.String())
+ if err1 != nil {
+ t.Fatalf("compile regexp %s: %v", pat, err1)
+ }
+ return ok
+}
+
+
+/*
+ * Test constructors
+ */
+
+// Expression compile error
+func CErr(expr string, cerr string) test { return test([]job{{code: expr, cerr: cerr}}) }
+
+// Expression runtime error
+func RErr(expr string, rterr string) test { return test([]job{{code: expr, rterr: rterr}}) }
+
+// Expression value
+func Val(expr string, val interface{}) test {
+ return test([]job{{code: expr, val: toValue(val)}})
+}
+
+// Statement runs without error
+func Run(stmts string) test { return test([]job{{code: stmts, noval: true}}) }
+
+// Two statements without error.
+// TODO(rsc): Should be possible with Run but the parser
+// won't let us do both top-level and non-top-level statements.
+func Run2(stmt1, stmt2 string) test {
+ return test([]job{{code: stmt1, noval: true}, {code: stmt2, noval: true}})
+}
+
+// Statement runs and test one expression's value
+func Val1(stmts string, expr1 string, val1 interface{}) test {
+ return test([]job{
+ {code: stmts, noval: true},
+ {code: expr1, val: toValue(val1)},
+ })
+}
+
+// Statement runs and test two expressions' values
+func Val2(stmts string, expr1 string, val1 interface{}, expr2 string, val2 interface{}) test {
+ return test([]job{
+ {code: stmts, noval: true},
+ {code: expr1, val: toValue(val1)},
+ {code: expr2, val: toValue(val2)},
+ })
+}
+
+/*
+ * Value constructors
+ */
+
+type vstruct []interface{}
+
+type varray []interface{}
+
+type vslice struct {
+ arr varray
+ len, cap int
+}
+
+func toValue(val interface{}) Value {
+ switch val := val.(type) {
+ case bool:
+ r := boolV(val)
+ return &r
+ case uint8:
+ r := uint8V(val)
+ return &r
+ case uint:
+ r := uintV(val)
+ return &r
+ case int:
+ r := intV(val)
+ return &r
+ case *big.Int:
+ return &idealIntV{val}
+ case float64:
+ r := float64V(val)
+ return &r
+ case *big.Rat:
+ return &idealFloatV{val}
+ case string:
+ r := stringV(val)
+ return &r
+ case vstruct:
+ elems := make([]Value, len(val))
+ for i, e := range val {
+ elems[i] = toValue(e)
+ }
+ r := structV(elems)
+ return &r
+ case varray:
+ elems := make([]Value, len(val))
+ for i, e := range val {
+ elems[i] = toValue(e)
+ }
+ r := arrayV(elems)
+ return &r
+ case vslice:
+ return &sliceV{Slice{toValue(val.arr).(ArrayValue), int64(val.len), int64(val.cap)}}
+ case Func:
+ return &funcV{val}
+ }
+ log.Panicf("toValue(%T) not implemented", val)
+ panic("unreachable")
+}
+
+/*
+ * Default test scope
+ */
+
+type testFunc struct{}
+
+func (*testFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
+
+func (*testFunc) Call(t *Thread) {
+ n := t.f.Vars[0].(IntValue).Get(t)
+
+ res := n + 1
+
+ t.f.Vars[1].(IntValue).Set(t, res)
+}
+
+type oneTwoFunc struct{}
+
+func (*oneTwoFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
+
+func (*oneTwoFunc) Call(t *Thread) {
+ t.f.Vars[0].(IntValue).Set(t, 1)
+ t.f.Vars[1].(IntValue).Set(t, 2)
+}
+
+type voidFunc struct{}
+
+func (*voidFunc) NewFrame() *Frame { return &Frame{nil, []Value{}} }
+
+func (*voidFunc) Call(t *Thread) {}
+
+func newTestWorld() *World {
+ w := NewWorld()
+
+ def := func(name string, t Type, val interface{}) { w.DefineVar(name, t, toValue(val)) }
+
+ w.DefineConst("c", IdealIntType, toValue(big.NewInt(1)))
+ def("i", IntType, 1)
+ def("i2", IntType, 2)
+ def("u", UintType, uint(1))
+ def("f", Float64Type, 1.0)
+ def("s", StringType, "abc")
+ def("t", NewStructType([]StructField{{"a", IntType, false}}), vstruct{1})
+ def("ai", NewArrayType(2, IntType), varray{1, 2})
+ def("aai", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{1, 2}, varray{3, 4}})
+ def("aai2", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{5, 6}, varray{7, 8}})
+ def("fn", NewFuncType([]Type{IntType}, false, []Type{IntType}), &testFunc{})
+ def("oneTwo", NewFuncType([]Type{}, false, []Type{IntType, IntType}), &oneTwoFunc{})
+ def("void", NewFuncType([]Type{}, false, []Type{}), &voidFunc{})
+ def("sli", NewSliceType(IntType), vslice{varray{1, 2, 3}, 2, 3})
+
+ return w
+}
diff --git a/libgo/go/exp/eval/expr.go b/libgo/go/exp/eval/expr.go
new file mode 100644
index 000000000..e65f47617
--- /dev/null
+++ b/libgo/go/exp/eval/expr.go
@@ -0,0 +1,2015 @@
+// 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 eval
+
+import (
+ "big"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "log"
+ "strconv"
+ "strings"
+ "os"
+)
+
+var (
+ idealZero = big.NewInt(0)
+ idealOne = big.NewInt(1)
+)
+
+// An expr is the result of compiling an expression. It stores the
+// type of the expression and its evaluator function.
+type expr struct {
+ *exprInfo
+ t Type
+
+ // Evaluate this node as the given type.
+ eval interface{}
+
+ // Map index expressions permit special forms of assignment,
+ // for which we need to know the Map and key.
+ evalMapValue func(t *Thread) (Map, interface{})
+
+ // Evaluate to the "address of" this value; that is, the
+ // settable Value object. nil for expressions whose address
+ // cannot be taken.
+ evalAddr func(t *Thread) Value
+
+ // Execute this expression as a statement. Only expressions
+ // that are valid expression statements should set this.
+ exec func(t *Thread)
+
+ // If this expression is a type, this is its compiled type.
+ // This is only permitted in the function position of a call
+ // expression. In this case, t should be nil.
+ valType Type
+
+ // A short string describing this expression for error
+ // messages.
+ desc string
+}
+
+// exprInfo stores information needed to compile any expression node.
+// Each expr also stores its exprInfo so further expressions can be
+// compiled from it.
+type exprInfo struct {
+ *compiler
+ pos token.Pos
+}
+
+func (a *exprInfo) newExpr(t Type, desc string) *expr {
+ return &expr{exprInfo: a, t: t, desc: desc}
+}
+
+func (a *exprInfo) diag(format string, args ...interface{}) {
+ a.diagAt(a.pos, format, args...)
+}
+
+func (a *exprInfo) diagOpType(op token.Token, vt Type) {
+ a.diag("illegal operand type for '%v' operator\n\t%v", op, vt)
+}
+
+func (a *exprInfo) diagOpTypes(op token.Token, lt Type, rt Type) {
+ a.diag("illegal operand types for '%v' operator\n\t%v\n\t%v", op, lt, rt)
+}
+
+/*
+ * Common expression manipulations
+ */
+
+// a.convertTo(t) converts the value of the analyzed expression a,
+// which must be a constant, ideal number, to a new analyzed
+// expression with a constant value of type t.
+//
+// TODO(austin) Rename to resolveIdeal or something?
+func (a *expr) convertTo(t Type) *expr {
+ if !a.t.isIdeal() {
+ log.Panicf("attempted to convert from %v, expected ideal", a.t)
+ }
+
+ var rat *big.Rat
+
+ // XXX(Spec) The spec says "It is erroneous".
+ //
+ // It is an error to assign a value with a non-zero fractional
+ // part to an integer, or if the assignment would overflow or
+ // underflow, or in general if the value cannot be represented
+ // by the type of the variable.
+ switch a.t {
+ case IdealFloatType:
+ rat = a.asIdealFloat()()
+ if t.isInteger() && !rat.IsInt() {
+ a.diag("constant %v truncated to integer", rat.FloatString(6))
+ return nil
+ }
+ case IdealIntType:
+ i := a.asIdealInt()()
+ rat = new(big.Rat).SetInt(i)
+ default:
+ log.Panicf("unexpected ideal type %v", a.t)
+ }
+
+ // Check bounds
+ if t, ok := t.lit().(BoundedType); ok {
+ if rat.Cmp(t.minVal()) < 0 {
+ a.diag("constant %v underflows %v", rat.FloatString(6), t)
+ return nil
+ }
+ if rat.Cmp(t.maxVal()) > 0 {
+ a.diag("constant %v overflows %v", rat.FloatString(6), t)
+ return nil
+ }
+ }
+
+ // Convert rat to type t.
+ res := a.newExpr(t, a.desc)
+ switch t := t.lit().(type) {
+ case *uintType:
+ n, d := rat.Num(), rat.Denom()
+ f := new(big.Int).Quo(n, d)
+ f = f.Abs(f)
+ v := uint64(f.Int64())
+ res.eval = func(*Thread) uint64 { return v }
+ case *intType:
+ n, d := rat.Num(), rat.Denom()
+ f := new(big.Int).Quo(n, d)
+ v := f.Int64()
+ res.eval = func(*Thread) int64 { return v }
+ case *idealIntType:
+ n, d := rat.Num(), rat.Denom()
+ f := new(big.Int).Quo(n, d)
+ res.eval = func() *big.Int { return f }
+ case *floatType:
+ n, d := rat.Num(), rat.Denom()
+ v := float64(n.Int64()) / float64(d.Int64())
+ res.eval = func(*Thread) float64 { return v }
+ case *idealFloatType:
+ res.eval = func() *big.Rat { return rat }
+ default:
+ log.Panicf("cannot convert to type %T", t)
+ }
+
+ return res
+}
+
+// convertToInt converts this expression to an integer, if possible,
+// or produces an error if not. This accepts ideal ints, uints, and
+// ints. If max is not -1, produces an error if possible if the value
+// exceeds max. If negErr is not "", produces an error if possible if
+// the value is negative.
+func (a *expr) convertToInt(max int64, negErr string, errOp string) *expr {
+ switch a.t.lit().(type) {
+ case *idealIntType:
+ val := a.asIdealInt()()
+ if negErr != "" && val.Sign() < 0 {
+ a.diag("negative %s: %s", negErr, val)
+ return nil
+ }
+ bound := max
+ if negErr == "slice" {
+ bound++
+ }
+ if max != -1 && val.Cmp(big.NewInt(bound)) >= 0 {
+ a.diag("index %s exceeds length %d", val, max)
+ return nil
+ }
+ return a.convertTo(IntType)
+
+ case *uintType:
+ // Convert to int
+ na := a.newExpr(IntType, a.desc)
+ af := a.asUint()
+ na.eval = func(t *Thread) int64 { return int64(af(t)) }
+ return na
+
+ case *intType:
+ // Good as is
+ return a
+ }
+
+ a.diag("illegal operand type for %s\n\t%v", errOp, a.t)
+ return nil
+}
+
+// derefArray returns an expression of array type if the given
+// expression is a *array type. Otherwise, returns the given
+// expression.
+func (a *expr) derefArray() *expr {
+ if pt, ok := a.t.lit().(*PtrType); ok {
+ if _, ok := pt.Elem.lit().(*ArrayType); ok {
+ deref := a.compileStarExpr(a)
+ if deref == nil {
+ log.Panicf("failed to dereference *array")
+ }
+ return deref
+ }
+ }
+ return a
+}
+
+/*
+ * Assignments
+ */
+
+// An assignCompiler compiles assignment operations. Anything other
+// than short declarations should use the compileAssign wrapper.
+//
+// There are three valid types of assignment:
+// 1) T = T
+// Assigning a single expression with single-valued type to a
+// single-valued type.
+// 2) MT = T, T, ...
+// Assigning multiple expressions with single-valued types to a
+// multi-valued type.
+// 3) MT = MT
+// Assigning a single expression with multi-valued type to a
+// multi-valued type.
+type assignCompiler struct {
+ *compiler
+ pos token.Pos
+ // The RHS expressions. This may include nil's for
+ // expressions that failed to compile.
+ rs []*expr
+ // The (possibly unary) MultiType of the RHS.
+ rmt *MultiType
+ // Whether this is an unpack assignment (case 3).
+ isUnpack bool
+ // Whether map special assignment forms are allowed.
+ allowMap bool
+ // Whether this is a "r, ok = a[x]" assignment.
+ isMapUnpack bool
+ // The operation name to use in error messages, such as
+ // "assignment" or "function call".
+ errOp string
+ // The name to use for positions in error messages, such as
+ // "argument".
+ errPosName string
+}
+
+// Type check the RHS of an assignment, returning a new assignCompiler
+// and indicating if the type check succeeded. This always returns an
+// assignCompiler with rmt set, but if type checking fails, slots in
+// the MultiType may be nil. If rs contains nil's, type checking will
+// fail and these expressions given a nil type.
+func (a *compiler) checkAssign(pos token.Pos, rs []*expr, errOp, errPosName string) (*assignCompiler, bool) {
+ c := &assignCompiler{
+ compiler: a,
+ pos: pos,
+ rs: rs,
+ errOp: errOp,
+ errPosName: errPosName,
+ }
+
+ // Is this an unpack?
+ if len(rs) == 1 && rs[0] != nil {
+ if rmt, isUnpack := rs[0].t.(*MultiType); isUnpack {
+ c.rmt = rmt
+ c.isUnpack = true
+ return c, true
+ }
+ }
+
+ // Create MultiType for RHS and check that all RHS expressions
+ // are single-valued.
+ rts := make([]Type, len(rs))
+ ok := true
+ for i, r := range rs {
+ if r == nil {
+ ok = false
+ continue
+ }
+
+ if _, isMT := r.t.(*MultiType); isMT {
+ r.diag("multi-valued expression not allowed in %s", errOp)
+ ok = false
+ continue
+ }
+
+ rts[i] = r.t
+ }
+
+ c.rmt = NewMultiType(rts)
+ return c, ok
+}
+
+func (a *assignCompiler) allowMapForms(nls int) {
+ a.allowMap = true
+
+ // Update unpacking info if this is r, ok = a[x]
+ if nls == 2 && len(a.rs) == 1 && a.rs[0] != nil && a.rs[0].evalMapValue != nil {
+ a.isUnpack = true
+ a.rmt = NewMultiType([]Type{a.rs[0].t, BoolType})
+ a.isMapUnpack = true
+ }
+}
+
+// compile type checks and compiles an assignment operation, returning
+// a function that expects an l-value and the frame in which to
+// evaluate the RHS expressions. The l-value must have exactly the
+// type given by lt. Returns nil if type checking fails.
+func (a *assignCompiler) compile(b *block, lt Type) func(Value, *Thread) {
+ lmt, isMT := lt.(*MultiType)
+ rmt, isUnpack := a.rmt, a.isUnpack
+
+ // Create unary MultiType for single LHS
+ if !isMT {
+ lmt = NewMultiType([]Type{lt})
+ }
+
+ // Check that the assignment count matches
+ lcount := len(lmt.Elems)
+ rcount := len(rmt.Elems)
+ if lcount != rcount {
+ msg := "not enough"
+ pos := a.pos
+ if rcount > lcount {
+ msg = "too many"
+ if lcount > 0 {
+ pos = a.rs[lcount-1].pos
+ }
+ }
+ a.diagAt(pos, "%s %ss for %s\n\t%s\n\t%s", msg, a.errPosName, a.errOp, lt, rmt)
+ return nil
+ }
+
+ bad := false
+
+ // If this is an unpack, create a temporary to store the
+ // multi-value and replace the RHS with expressions to pull
+ // out values from the temporary. Technically, this is only
+ // necessary when we need to perform assignment conversions.
+ var effect func(*Thread)
+ if isUnpack {
+ // This leaks a slot, but is definitely safe.
+ temp := b.DefineTemp(a.rmt)
+ tempIdx := temp.Index
+ if tempIdx < 0 {
+ panic(fmt.Sprintln("tempidx", tempIdx))
+ }
+ if a.isMapUnpack {
+ rf := a.rs[0].evalMapValue
+ vt := a.rmt.Elems[0]
+ effect = func(t *Thread) {
+ m, k := rf(t)
+ v := m.Elem(t, k)
+ found := boolV(true)
+ if v == nil {
+ found = boolV(false)
+ v = vt.Zero()
+ }
+ t.f.Vars[tempIdx] = multiV([]Value{v, &found})
+ }
+ } else {
+ rf := a.rs[0].asMulti()
+ effect = func(t *Thread) { t.f.Vars[tempIdx] = multiV(rf(t)) }
+ }
+ orig := a.rs[0]
+ a.rs = make([]*expr, len(a.rmt.Elems))
+ for i, t := range a.rmt.Elems {
+ if t.isIdeal() {
+ log.Panicf("Right side of unpack contains ideal: %s", rmt)
+ }
+ a.rs[i] = orig.newExpr(t, orig.desc)
+ index := i
+ a.rs[i].genValue(func(t *Thread) Value { return t.f.Vars[tempIdx].(multiV)[index] })
+ }
+ }
+ // Now len(a.rs) == len(a.rmt) and we've reduced any unpacking
+ // to multi-assignment.
+
+ // TODO(austin) Deal with assignment special cases.
+
+ // Values of any type may always be assigned to variables of
+ // compatible static type.
+ for i, lt := range lmt.Elems {
+ rt := rmt.Elems[i]
+
+ // When [an ideal is] (used in an expression) assigned
+ // to a variable or typed constant, the destination
+ // must be able to represent the assigned value.
+ if rt.isIdeal() {
+ a.rs[i] = a.rs[i].convertTo(lmt.Elems[i])
+ if a.rs[i] == nil {
+ bad = true
+ continue
+ }
+ rt = a.rs[i].t
+ }
+
+ // A pointer p to an array can be assigned to a slice
+ // variable v with compatible element type if the type
+ // of p or v is unnamed.
+ if rpt, ok := rt.lit().(*PtrType); ok {
+ if at, ok := rpt.Elem.lit().(*ArrayType); ok {
+ if lst, ok := lt.lit().(*SliceType); ok {
+ if lst.Elem.compat(at.Elem, false) && (rt.lit() == Type(rt) || lt.lit() == Type(lt)) {
+ rf := a.rs[i].asPtr()
+ a.rs[i] = a.rs[i].newExpr(lt, a.rs[i].desc)
+ len := at.Len
+ a.rs[i].eval = func(t *Thread) Slice { return Slice{rf(t).(ArrayValue), len, len} }
+ rt = a.rs[i].t
+ }
+ }
+ }
+ }
+
+ if !lt.compat(rt, false) {
+ if len(a.rs) == 1 {
+ a.rs[0].diag("illegal operand types for %s\n\t%v\n\t%v", a.errOp, lt, rt)
+ } else {
+ a.rs[i].diag("illegal operand types in %s %d of %s\n\t%v\n\t%v", a.errPosName, i+1, a.errOp, lt, rt)
+ }
+ bad = true
+ }
+ }
+ if bad {
+ return nil
+ }
+
+ // Compile
+ if !isMT {
+ // Case 1
+ return genAssign(lt, a.rs[0])
+ }
+ // Case 2 or 3
+ as := make([]func(lv Value, t *Thread), len(a.rs))
+ for i, r := range a.rs {
+ as[i] = genAssign(lmt.Elems[i], r)
+ }
+ return func(lv Value, t *Thread) {
+ if effect != nil {
+ effect(t)
+ }
+ lmv := lv.(multiV)
+ for i, a := range as {
+ a(lmv[i], t)
+ }
+ }
+}
+
+// compileAssign compiles an assignment operation without the full
+// generality of an assignCompiler. See assignCompiler for a
+// description of the arguments.
+func (a *compiler) compileAssign(pos token.Pos, b *block, lt Type, rs []*expr, errOp, errPosName string) func(Value, *Thread) {
+ ac, ok := a.checkAssign(pos, rs, errOp, errPosName)
+ if !ok {
+ return nil
+ }
+ return ac.compile(b, lt)
+}
+
+/*
+ * Expression compiler
+ */
+
+// An exprCompiler stores information used throughout the compilation
+// of a single expression. It does not embed funcCompiler because
+// expressions can appear at top level.
+type exprCompiler struct {
+ *compiler
+ // The block this expression is being compiled in.
+ block *block
+ // Whether this expression is used in a constant context.
+ constant bool
+}
+
+// compile compiles an expression AST. callCtx should be true if this
+// AST is in the function position of a function call node; it allows
+// the returned expression to be a type or a built-in function (which
+// otherwise result in errors).
+func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
+ ei := &exprInfo{a.compiler, x.Pos()}
+
+ switch x := x.(type) {
+ // Literals
+ case *ast.BasicLit:
+ switch x.Kind {
+ case token.INT:
+ return ei.compileIntLit(string(x.Value))
+ case token.FLOAT:
+ return ei.compileFloatLit(string(x.Value))
+ case token.CHAR:
+ return ei.compileCharLit(string(x.Value))
+ case token.STRING:
+ return ei.compileStringLit(string(x.Value))
+ default:
+ log.Panicf("unexpected basic literal type %v", x.Kind)
+ }
+
+ case *ast.CompositeLit:
+ goto notimpl
+
+ case *ast.FuncLit:
+ decl := ei.compileFuncType(a.block, x.Type)
+ if decl == nil {
+ // TODO(austin) Try compiling the body,
+ // perhaps with dummy argument definitions
+ return nil
+ }
+ fn := ei.compileFunc(a.block, decl, x.Body)
+ if fn == nil {
+ return nil
+ }
+ if a.constant {
+ a.diagAt(x.Pos(), "function literal used in constant expression")
+ return nil
+ }
+ return ei.compileFuncLit(decl, fn)
+
+ // Types
+ case *ast.ArrayType:
+ // TODO(austin) Use a multi-type case
+ goto typeexpr
+
+ case *ast.ChanType:
+ goto typeexpr
+
+ case *ast.Ellipsis:
+ goto typeexpr
+
+ case *ast.FuncType:
+ goto typeexpr
+
+ case *ast.InterfaceType:
+ goto typeexpr
+
+ case *ast.MapType:
+ goto typeexpr
+
+ // Remaining expressions
+ case *ast.BadExpr:
+ // Error already reported by parser
+ a.silentErrors++
+ return nil
+
+ case *ast.BinaryExpr:
+ l, r := a.compile(x.X, false), a.compile(x.Y, false)
+ if l == nil || r == nil {
+ return nil
+ }
+ return ei.compileBinaryExpr(x.Op, l, r)
+
+ case *ast.CallExpr:
+ l := a.compile(x.Fun, true)
+ args := make([]*expr, len(x.Args))
+ bad := false
+ for i, arg := range x.Args {
+ if i == 0 && l != nil && (l.t == Type(makeType) || l.t == Type(newType)) {
+ argei := &exprInfo{a.compiler, arg.Pos()}
+ args[i] = argei.exprFromType(a.compileType(a.block, arg))
+ } else {
+ args[i] = a.compile(arg, false)
+ }
+ if args[i] == nil {
+ bad = true
+ }
+ }
+ if bad || l == nil {
+ return nil
+ }
+ if a.constant {
+ a.diagAt(x.Pos(), "function call in constant context")
+ return nil
+ }
+
+ if l.valType != nil {
+ a.diagAt(x.Pos(), "type conversions not implemented")
+ return nil
+ } else if ft, ok := l.t.(*FuncType); ok && ft.builtin != "" {
+ return ei.compileBuiltinCallExpr(a.block, ft, args)
+ } else {
+ return ei.compileCallExpr(a.block, l, args)
+ }
+
+ case *ast.Ident:
+ return ei.compileIdent(a.block, a.constant, callCtx, x.Name)
+
+ case *ast.IndexExpr:
+ l, r := a.compile(x.X, false), a.compile(x.Index, false)
+ if l == nil || r == nil {
+ return nil
+ }
+ return ei.compileIndexExpr(l, r)
+
+ case *ast.SliceExpr:
+ var lo, hi *expr
+ arr := a.compile(x.X, false)
+ if x.Low == nil {
+ // beginning was omitted, so we need to provide it
+ ei := &exprInfo{a.compiler, x.Pos()}
+ lo = ei.compileIntLit("0")
+ } else {
+ lo = a.compile(x.Low, false)
+ }
+ if x.High == nil {
+ // End was omitted, so we need to compute len(x.X)
+ ei := &exprInfo{a.compiler, x.Pos()}
+ hi = ei.compileBuiltinCallExpr(a.block, lenType, []*expr{arr})
+ } else {
+ hi = a.compile(x.High, false)
+ }
+ if arr == nil || lo == nil || hi == nil {
+ return nil
+ }
+ return ei.compileSliceExpr(arr, lo, hi)
+
+ case *ast.KeyValueExpr:
+ goto notimpl
+
+ case *ast.ParenExpr:
+ return a.compile(x.X, callCtx)
+
+ case *ast.SelectorExpr:
+ v := a.compile(x.X, false)
+ if v == nil {
+ return nil
+ }
+ return ei.compileSelectorExpr(v, x.Sel.Name)
+
+ case *ast.StarExpr:
+ // We pass down our call context because this could be
+ // a pointer type (and thus a type conversion)
+ v := a.compile(x.X, callCtx)
+ if v == nil {
+ return nil
+ }
+ if v.valType != nil {
+ // Turns out this was a pointer type, not a dereference
+ return ei.exprFromType(NewPtrType(v.valType))
+ }
+ return ei.compileStarExpr(v)
+
+ case *ast.StructType:
+ goto notimpl
+
+ case *ast.TypeAssertExpr:
+ goto notimpl
+
+ case *ast.UnaryExpr:
+ v := a.compile(x.X, false)
+ if v == nil {
+ return nil
+ }
+ return ei.compileUnaryExpr(x.Op, v)
+ }
+ log.Panicf("unexpected ast node type %T", x)
+ panic("unreachable")
+
+typeexpr:
+ if !callCtx {
+ a.diagAt(x.Pos(), "type used as expression")
+ return nil
+ }
+ return ei.exprFromType(a.compileType(a.block, x))
+
+notimpl:
+ a.diagAt(x.Pos(), "%T expression node not implemented", x)
+ return nil
+}
+
+func (a *exprInfo) exprFromType(t Type) *expr {
+ if t == nil {
+ return nil
+ }
+ expr := a.newExpr(nil, "type")
+ expr.valType = t
+ return expr
+}
+
+func (a *exprInfo) compileIdent(b *block, constant bool, callCtx bool, name string) *expr {
+ bl, level, def := b.Lookup(name)
+ if def == nil {
+ a.diag("%s: undefined", name)
+ return nil
+ }
+ switch def := def.(type) {
+ case *Constant:
+ expr := a.newExpr(def.Type, "constant")
+ if ft, ok := def.Type.(*FuncType); ok && ft.builtin != "" {
+ // XXX(Spec) I don't think anything says that
+ // built-in functions can't be used as values.
+ if !callCtx {
+ a.diag("built-in function %s cannot be used as a value", ft.builtin)
+ return nil
+ }
+ // Otherwise, we leave the evaluators empty
+ // because this is handled specially
+ } else {
+ expr.genConstant(def.Value)
+ }
+ return expr
+ case *Variable:
+ if constant {
+ a.diag("variable %s used in constant expression", name)
+ return nil
+ }
+ if bl.global {
+ return a.compileGlobalVariable(def)
+ }
+ return a.compileVariable(level, def)
+ case Type:
+ if callCtx {
+ return a.exprFromType(def)
+ }
+ a.diag("type %v used as expression", name)
+ return nil
+ }
+ log.Panicf("name %s has unknown type %T", name, def)
+ panic("unreachable")
+}
+
+func (a *exprInfo) compileVariable(level int, v *Variable) *expr {
+ if v.Type == nil {
+ // Placeholder definition from an earlier error
+ a.silentErrors++
+ return nil
+ }
+ expr := a.newExpr(v.Type, "variable")
+ expr.genIdentOp(level, v.Index)
+ return expr
+}
+
+func (a *exprInfo) compileGlobalVariable(v *Variable) *expr {
+ if v.Type == nil {
+ // Placeholder definition from an earlier error
+ a.silentErrors++
+ return nil
+ }
+ if v.Init == nil {
+ v.Init = v.Type.Zero()
+ }
+ expr := a.newExpr(v.Type, "variable")
+ val := v.Init
+ expr.genValue(func(t *Thread) Value { return val })
+ return expr
+}
+
+func (a *exprInfo) compileIdealInt(i *big.Int, desc string) *expr {
+ expr := a.newExpr(IdealIntType, desc)
+ expr.eval = func() *big.Int { return i }
+ return expr
+}
+
+func (a *exprInfo) compileIntLit(lit string) *expr {
+ i, _ := new(big.Int).SetString(lit, 0)
+ return a.compileIdealInt(i, "integer literal")
+}
+
+func (a *exprInfo) compileCharLit(lit string) *expr {
+ if lit[0] != '\'' {
+ // Caught by parser
+ a.silentErrors++
+ return nil
+ }
+ v, _, tail, err := strconv.UnquoteChar(lit[1:], '\'')
+ if err != nil || tail != "'" {
+ // Caught by parser
+ a.silentErrors++
+ return nil
+ }
+ return a.compileIdealInt(big.NewInt(int64(v)), "character literal")
+}
+
+func (a *exprInfo) compileFloatLit(lit string) *expr {
+ f, ok := new(big.Rat).SetString(lit)
+ if !ok {
+ log.Panicf("malformed float literal %s at %v passed parser", lit, a.pos)
+ }
+ expr := a.newExpr(IdealFloatType, "float literal")
+ expr.eval = func() *big.Rat { return f }
+ return expr
+}
+
+func (a *exprInfo) compileString(s string) *expr {
+ // Ideal strings don't have a named type but they are
+ // compatible with type string.
+
+ // TODO(austin) Use unnamed string type.
+ expr := a.newExpr(StringType, "string literal")
+ expr.eval = func(*Thread) string { return s }
+ return expr
+}
+
+func (a *exprInfo) compileStringLit(lit string) *expr {
+ s, err := strconv.Unquote(lit)
+ if err != nil {
+ a.diag("illegal string literal, %v", err)
+ return nil
+ }
+ return a.compileString(s)
+}
+
+func (a *exprInfo) compileStringList(list []*expr) *expr {
+ ss := make([]string, len(list))
+ for i, s := range list {
+ ss[i] = s.asString()(nil)
+ }
+ return a.compileString(strings.Join(ss, ""))
+}
+
+func (a *exprInfo) compileFuncLit(decl *FuncDecl, fn func(*Thread) Func) *expr {
+ expr := a.newExpr(decl.Type, "function literal")
+ expr.eval = fn
+ return expr
+}
+
+func (a *exprInfo) compileSelectorExpr(v *expr, name string) *expr {
+ // mark marks a field that matches the selector name. It
+ // tracks the best depth found so far and whether more than
+ // one field has been found at that depth.
+ bestDepth := -1
+ ambig := false
+ amberr := ""
+ mark := func(depth int, pathName string) {
+ switch {
+ case bestDepth == -1 || depth < bestDepth:
+ bestDepth = depth
+ ambig = false
+ amberr = ""
+
+ case depth == bestDepth:
+ ambig = true
+
+ default:
+ log.Panicf("Marked field at depth %d, but already found one at depth %d", depth, bestDepth)
+ }
+ amberr += "\n\t" + pathName[1:]
+ }
+
+ visited := make(map[Type]bool)
+
+ // find recursively searches for the named field, starting at
+ // type t. If it finds the named field, it returns a function
+ // which takes an expr that represents a value of type 't' and
+ // returns an expr that retrieves the named field. We delay
+ // expr construction to avoid producing lots of useless expr's
+ // as we search.
+ //
+ // TODO(austin) Now that the expression compiler works on
+ // semantic values instead of AST's, there should be a much
+ // better way of doing this.
+ var find func(Type, int, string) func(*expr) *expr
+ find = func(t Type, depth int, pathName string) func(*expr) *expr {
+ // Don't bother looking if we've found something shallower
+ if bestDepth != -1 && bestDepth < depth {
+ return nil
+ }
+
+ // Don't check the same type twice and avoid loops
+ if visited[t] {
+ return nil
+ }
+ visited[t] = true
+
+ // Implicit dereference
+ deref := false
+ if ti, ok := t.(*PtrType); ok {
+ deref = true
+ t = ti.Elem
+ }
+
+ // If it's a named type, look for methods
+ if ti, ok := t.(*NamedType); ok {
+ _, ok := ti.methods[name]
+ if ok {
+ mark(depth, pathName+"."+name)
+ log.Panic("Methods not implemented")
+ }
+ t = ti.Def
+ }
+
+ // If it's a struct type, check fields and embedded types
+ var builder func(*expr) *expr
+ if t, ok := t.(*StructType); ok {
+ for i, f := range t.Elems {
+ var sub func(*expr) *expr
+ switch {
+ case f.Name == name:
+ mark(depth, pathName+"."+name)
+ sub = func(e *expr) *expr { return e }
+
+ case f.Anonymous:
+ sub = find(f.Type, depth+1, pathName+"."+f.Name)
+ if sub == nil {
+ continue
+ }
+
+ default:
+ continue
+ }
+
+ // We found something. Create a
+ // builder for accessing this field.
+ ft := f.Type
+ index := i
+ builder = func(parent *expr) *expr {
+ if deref {
+ parent = a.compileStarExpr(parent)
+ }
+ expr := a.newExpr(ft, "selector expression")
+ pf := parent.asStruct()
+ evalAddr := func(t *Thread) Value { return pf(t).Field(t, index) }
+ expr.genValue(evalAddr)
+ return sub(expr)
+ }
+ }
+ }
+
+ return builder
+ }
+
+ builder := find(v.t, 0, "")
+ if builder == nil {
+ a.diag("type %v has no field or method %s", v.t, name)
+ return nil
+ }
+ if ambig {
+ a.diag("field %s is ambiguous in type %v%s", name, v.t, amberr)
+ return nil
+ }
+
+ return builder(v)
+}
+
+func (a *exprInfo) compileSliceExpr(arr, lo, hi *expr) *expr {
+ // Type check object
+ arr = arr.derefArray()
+
+ var at Type
+ var maxIndex int64 = -1
+
+ switch lt := arr.t.lit().(type) {
+ case *ArrayType:
+ at = NewSliceType(lt.Elem)
+ maxIndex = lt.Len
+
+ case *SliceType:
+ at = lt
+
+ case *stringType:
+ at = lt
+
+ default:
+ a.diag("cannot slice %v", arr.t)
+ return nil
+ }
+
+ // Type check index and convert to int
+ // XXX(Spec) It's unclear if ideal floats with no
+ // fractional part are allowed here. 6g allows it. I
+ // believe that's wrong.
+ lo = lo.convertToInt(maxIndex, "slice", "slice")
+ hi = hi.convertToInt(maxIndex, "slice", "slice")
+ if lo == nil || hi == nil {
+ return nil
+ }
+
+ expr := a.newExpr(at, "slice expression")
+
+ // Compile
+ lof := lo.asInt()
+ hif := hi.asInt()
+ switch lt := arr.t.lit().(type) {
+ case *ArrayType:
+ arrf := arr.asArray()
+ bound := lt.Len
+ expr.eval = func(t *Thread) Slice {
+ arr, lo, hi := arrf(t), lof(t), hif(t)
+ if lo > hi || hi > bound || lo < 0 {
+ t.Abort(SliceError{lo, hi, bound})
+ }
+ return Slice{arr.Sub(lo, bound-lo), hi - lo, bound - lo}
+ }
+
+ case *SliceType:
+ arrf := arr.asSlice()
+ expr.eval = func(t *Thread) Slice {
+ arr, lo, hi := arrf(t), lof(t), hif(t)
+ if lo > hi || hi > arr.Cap || lo < 0 {
+ t.Abort(SliceError{lo, hi, arr.Cap})
+ }
+ return Slice{arr.Base.Sub(lo, arr.Cap-lo), hi - lo, arr.Cap - lo}
+ }
+
+ case *stringType:
+ arrf := arr.asString()
+ // TODO(austin) This pulls over the whole string in a
+ // remote setting, instead of creating a substring backed
+ // by remote memory.
+ expr.eval = func(t *Thread) string {
+ arr, lo, hi := arrf(t), lof(t), hif(t)
+ if lo > hi || hi > int64(len(arr)) || lo < 0 {
+ t.Abort(SliceError{lo, hi, int64(len(arr))})
+ }
+ return arr[lo:hi]
+ }
+
+ default:
+ log.Panicf("unexpected left operand type %T", arr.t.lit())
+ }
+
+ return expr
+}
+
+func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
+ // Type check object
+ l = l.derefArray()
+
+ var at Type
+ intIndex := false
+ var maxIndex int64 = -1
+
+ switch lt := l.t.lit().(type) {
+ case *ArrayType:
+ at = lt.Elem
+ intIndex = true
+ maxIndex = lt.Len
+
+ case *SliceType:
+ at = lt.Elem
+ intIndex = true
+
+ case *stringType:
+ at = Uint8Type
+ intIndex = true
+
+ case *MapType:
+ at = lt.Elem
+ if r.t.isIdeal() {
+ r = r.convertTo(lt.Key)
+ if r == nil {
+ return nil
+ }
+ }
+ if !lt.Key.compat(r.t, false) {
+ a.diag("cannot use %s as index into %s", r.t, lt)
+ return nil
+ }
+
+ default:
+ a.diag("cannot index into %v", l.t)
+ return nil
+ }
+
+ // Type check index and convert to int if necessary
+ if intIndex {
+ // XXX(Spec) It's unclear if ideal floats with no
+ // fractional part are allowed here. 6g allows it. I
+ // believe that's wrong.
+ r = r.convertToInt(maxIndex, "index", "index")
+ if r == nil {
+ return nil
+ }
+ }
+
+ expr := a.newExpr(at, "index expression")
+
+ // Compile
+ switch lt := l.t.lit().(type) {
+ case *ArrayType:
+ lf := l.asArray()
+ rf := r.asInt()
+ bound := lt.Len
+ expr.genValue(func(t *Thread) Value {
+ l, r := lf(t), rf(t)
+ if r < 0 || r >= bound {
+ t.Abort(IndexError{r, bound})
+ }
+ return l.Elem(t, r)
+ })
+
+ case *SliceType:
+ lf := l.asSlice()
+ rf := r.asInt()
+ expr.genValue(func(t *Thread) Value {
+ l, r := lf(t), rf(t)
+ if l.Base == nil {
+ t.Abort(NilPointerError{})
+ }
+ if r < 0 || r >= l.Len {
+ t.Abort(IndexError{r, l.Len})
+ }
+ return l.Base.Elem(t, r)
+ })
+
+ case *stringType:
+ lf := l.asString()
+ rf := r.asInt()
+ // TODO(austin) This pulls over the whole string in a
+ // remote setting, instead of just the one character.
+ expr.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ if r < 0 || r >= int64(len(l)) {
+ t.Abort(IndexError{r, int64(len(l))})
+ }
+ return uint64(l[r])
+ }
+
+ case *MapType:
+ lf := l.asMap()
+ rf := r.asInterface()
+ expr.genValue(func(t *Thread) Value {
+ m := lf(t)
+ k := rf(t)
+ if m == nil {
+ t.Abort(NilPointerError{})
+ }
+ e := m.Elem(t, k)
+ if e == nil {
+ t.Abort(KeyError{k})
+ }
+ return e
+ })
+ // genValue makes things addressable, but map values
+ // aren't addressable.
+ expr.evalAddr = nil
+ expr.evalMapValue = func(t *Thread) (Map, interface{}) {
+ // TODO(austin) Key check? nil check?
+ return lf(t), rf(t)
+ }
+
+ default:
+ log.Panicf("unexpected left operand type %T", l.t.lit())
+ }
+
+ return expr
+}
+
+func (a *exprInfo) compileCallExpr(b *block, l *expr, as []*expr) *expr {
+ // TODO(austin) Variadic functions.
+
+ // Type check
+
+ // XXX(Spec) Calling a named function type is okay. I really
+ // think there needs to be a general discussion of named
+ // types. A named type creates a new, distinct type, but the
+ // type of that type is still whatever it's defined to. Thus,
+ // in "type Foo int", Foo is still an integer type and in
+ // "type Foo func()", Foo is a function type.
+ lt, ok := l.t.lit().(*FuncType)
+ if !ok {
+ a.diag("cannot call non-function type %v", l.t)
+ return nil
+ }
+
+ // The arguments must be single-valued expressions assignment
+ // compatible with the parameters of F.
+ //
+ // XXX(Spec) The spec is wrong. It can also be a single
+ // multi-valued expression.
+ nin := len(lt.In)
+ assign := a.compileAssign(a.pos, b, NewMultiType(lt.In), as, "function call", "argument")
+ if assign == nil {
+ return nil
+ }
+
+ var t Type
+ nout := len(lt.Out)
+ switch nout {
+ case 0:
+ t = EmptyType
+ case 1:
+ t = lt.Out[0]
+ default:
+ t = NewMultiType(lt.Out)
+ }
+ expr := a.newExpr(t, "function call")
+
+ // Gather argument and out types to initialize frame variables
+ vts := make([]Type, nin+nout)
+ copy(vts, lt.In)
+ copy(vts[nin:], lt.Out)
+
+ // Compile
+ lf := l.asFunc()
+ call := func(t *Thread) []Value {
+ fun := lf(t)
+ fr := fun.NewFrame()
+ for i, t := range vts {
+ fr.Vars[i] = t.Zero()
+ }
+ assign(multiV(fr.Vars[0:nin]), t)
+ oldf := t.f
+ t.f = fr
+ fun.Call(t)
+ t.f = oldf
+ return fr.Vars[nin : nin+nout]
+ }
+ expr.genFuncCall(call)
+
+ return expr
+}
+
+func (a *exprInfo) compileBuiltinCallExpr(b *block, ft *FuncType, as []*expr) *expr {
+ checkCount := func(min, max int) bool {
+ if len(as) < min {
+ a.diag("not enough arguments to %s", ft.builtin)
+ return false
+ } else if len(as) > max {
+ a.diag("too many arguments to %s", ft.builtin)
+ return false
+ }
+ return true
+ }
+
+ switch ft {
+ case capType:
+ if !checkCount(1, 1) {
+ return nil
+ }
+ arg := as[0].derefArray()
+ expr := a.newExpr(IntType, "function call")
+ switch t := arg.t.lit().(type) {
+ case *ArrayType:
+ // TODO(austin) It would be nice if this could
+ // be a constant int.
+ v := t.Len
+ expr.eval = func(t *Thread) int64 { return v }
+
+ case *SliceType:
+ vf := arg.asSlice()
+ expr.eval = func(t *Thread) int64 { return vf(t).Cap }
+
+ //case *ChanType:
+
+ default:
+ a.diag("illegal argument type for cap function\n\t%v", arg.t)
+ return nil
+ }
+ return expr
+
+ case copyType:
+ if !checkCount(2, 2) {
+ return nil
+ }
+ src := as[1]
+ dst := as[0]
+ if src.t != dst.t {
+ a.diag("arguments to built-in function 'copy' must have same type\nsrc: %s\ndst: %s\n", src.t, dst.t)
+ return nil
+ }
+ if _, ok := src.t.lit().(*SliceType); !ok {
+ a.diag("src argument to 'copy' must be a slice (got: %s)", src.t)
+ return nil
+ }
+ if _, ok := dst.t.lit().(*SliceType); !ok {
+ a.diag("dst argument to 'copy' must be a slice (got: %s)", dst.t)
+ return nil
+ }
+ expr := a.newExpr(IntType, "function call")
+ srcf := src.asSlice()
+ dstf := dst.asSlice()
+ expr.eval = func(t *Thread) int64 {
+ src, dst := srcf(t), dstf(t)
+ nelems := src.Len
+ if nelems > dst.Len {
+ nelems = dst.Len
+ }
+ dst.Base.Sub(0, nelems).Assign(t, src.Base.Sub(0, nelems))
+ return nelems
+ }
+ return expr
+
+ case lenType:
+ if !checkCount(1, 1) {
+ return nil
+ }
+ arg := as[0].derefArray()
+ expr := a.newExpr(IntType, "function call")
+ switch t := arg.t.lit().(type) {
+ case *stringType:
+ vf := arg.asString()
+ expr.eval = func(t *Thread) int64 { return int64(len(vf(t))) }
+
+ case *ArrayType:
+ // TODO(austin) It would be nice if this could
+ // be a constant int.
+ v := t.Len
+ expr.eval = func(t *Thread) int64 { return v }
+
+ case *SliceType:
+ vf := arg.asSlice()
+ expr.eval = func(t *Thread) int64 { return vf(t).Len }
+
+ case *MapType:
+ vf := arg.asMap()
+ expr.eval = func(t *Thread) int64 {
+ // XXX(Spec) What's the len of an
+ // uninitialized map?
+ m := vf(t)
+ if m == nil {
+ return 0
+ }
+ return m.Len(t)
+ }
+
+ //case *ChanType:
+
+ default:
+ a.diag("illegal argument type for len function\n\t%v", arg.t)
+ return nil
+ }
+ return expr
+
+ case makeType:
+ if !checkCount(1, 3) {
+ return nil
+ }
+ // XXX(Spec) What are the types of the
+ // arguments? Do they have to be ints? 6g
+ // accepts any integral type.
+ var lenexpr, capexpr *expr
+ var lenf, capf func(*Thread) int64
+ if len(as) > 1 {
+ lenexpr = as[1].convertToInt(-1, "length", "make function")
+ if lenexpr == nil {
+ return nil
+ }
+ lenf = lenexpr.asInt()
+ }
+ if len(as) > 2 {
+ capexpr = as[2].convertToInt(-1, "capacity", "make function")
+ if capexpr == nil {
+ return nil
+ }
+ capf = capexpr.asInt()
+ }
+
+ switch t := as[0].valType.lit().(type) {
+ case *SliceType:
+ // A new, initialized slice value for a given
+ // element type T is made using the built-in
+ // function make, which takes a slice type and
+ // parameters specifying the length and
+ // optionally the capacity.
+ if !checkCount(2, 3) {
+ return nil
+ }
+ et := t.Elem
+ expr := a.newExpr(t, "function call")
+ expr.eval = func(t *Thread) Slice {
+ l := lenf(t)
+ // XXX(Spec) What if len or cap is
+ // negative? The runtime panics.
+ if l < 0 {
+ t.Abort(NegativeLengthError{l})
+ }
+ c := l
+ if capf != nil {
+ c = capf(t)
+ if c < 0 {
+ t.Abort(NegativeCapacityError{c})
+ }
+ // XXX(Spec) What happens if
+ // len > cap? The runtime
+ // sets cap to len.
+ if l > c {
+ c = l
+ }
+ }
+ base := arrayV(make([]Value, c))
+ for i := int64(0); i < c; i++ {
+ base[i] = et.Zero()
+ }
+ return Slice{&base, l, c}
+ }
+ return expr
+
+ case *MapType:
+ // A new, empty map value is made using the
+ // built-in function make, which takes the map
+ // type and an optional capacity hint as
+ // arguments.
+ if !checkCount(1, 2) {
+ return nil
+ }
+ expr := a.newExpr(t, "function call")
+ expr.eval = func(t *Thread) Map {
+ if lenf == nil {
+ return make(evalMap)
+ }
+ l := lenf(t)
+ return make(evalMap, l)
+ }
+ return expr
+
+ //case *ChanType:
+
+ default:
+ a.diag("illegal argument type for make function\n\t%v", as[0].valType)
+ return nil
+ }
+
+ case closeType, closedType:
+ a.diag("built-in function %s not implemented", ft.builtin)
+ return nil
+
+ case newType:
+ if !checkCount(1, 1) {
+ return nil
+ }
+
+ t := as[0].valType
+ expr := a.newExpr(NewPtrType(t), "new")
+ expr.eval = func(*Thread) Value { return t.Zero() }
+ return expr
+
+ case panicType, printType, printlnType:
+ evals := make([]func(*Thread) interface{}, len(as))
+ for i, x := range as {
+ evals[i] = x.asInterface()
+ }
+ spaces := ft == printlnType
+ newline := ft != printType
+ printer := func(t *Thread) {
+ for i, eval := range evals {
+ if i > 0 && spaces {
+ print(" ")
+ }
+ v := eval(t)
+ type stringer interface {
+ String() string
+ }
+ switch v1 := v.(type) {
+ case bool:
+ print(v1)
+ case uint64:
+ print(v1)
+ case int64:
+ print(v1)
+ case float64:
+ print(v1)
+ case string:
+ print(v1)
+ case stringer:
+ print(v1.String())
+ default:
+ print("???")
+ }
+ }
+ if newline {
+ print("\n")
+ }
+ }
+ expr := a.newExpr(EmptyType, "print")
+ expr.exec = printer
+ if ft == panicType {
+ expr.exec = func(t *Thread) {
+ printer(t)
+ t.Abort(os.NewError("panic"))
+ }
+ }
+ return expr
+ }
+
+ log.Panicf("unexpected built-in function '%s'", ft.builtin)
+ panic("unreachable")
+}
+
+func (a *exprInfo) compileStarExpr(v *expr) *expr {
+ switch vt := v.t.lit().(type) {
+ case *PtrType:
+ expr := a.newExpr(vt.Elem, "indirect expression")
+ vf := v.asPtr()
+ expr.genValue(func(t *Thread) Value {
+ v := vf(t)
+ if v == nil {
+ t.Abort(NilPointerError{})
+ }
+ return v
+ })
+ return expr
+ }
+
+ a.diagOpType(token.MUL, v.t)
+ return nil
+}
+
+var unaryOpDescs = make(map[token.Token]string)
+
+func (a *exprInfo) compileUnaryExpr(op token.Token, v *expr) *expr {
+ // Type check
+ var t Type
+ switch op {
+ case token.ADD, token.SUB:
+ if !v.t.isInteger() && !v.t.isFloat() {
+ a.diagOpType(op, v.t)
+ return nil
+ }
+ t = v.t
+
+ case token.NOT:
+ if !v.t.isBoolean() {
+ a.diagOpType(op, v.t)
+ return nil
+ }
+ t = BoolType
+
+ case token.XOR:
+ if !v.t.isInteger() {
+ a.diagOpType(op, v.t)
+ return nil
+ }
+ t = v.t
+
+ case token.AND:
+ // The unary prefix address-of operator & generates
+ // the address of its operand, which must be a
+ // variable, pointer indirection, field selector, or
+ // array or slice indexing operation.
+ if v.evalAddr == nil {
+ a.diag("cannot take the address of %s", v.desc)
+ return nil
+ }
+
+ // TODO(austin) Implement "It is illegal to take the
+ // address of a function result variable" once I have
+ // function result variables.
+
+ t = NewPtrType(v.t)
+
+ case token.ARROW:
+ log.Panicf("Unary op %v not implemented", op)
+
+ default:
+ log.Panicf("unknown unary operator %v", op)
+ }
+
+ desc, ok := unaryOpDescs[op]
+ if !ok {
+ desc = "unary " + op.String() + " expression"
+ unaryOpDescs[op] = desc
+ }
+
+ // Compile
+ expr := a.newExpr(t, desc)
+ switch op {
+ case token.ADD:
+ // Just compile it out
+ expr = v
+ expr.desc = desc
+
+ case token.SUB:
+ expr.genUnaryOpNeg(v)
+
+ case token.NOT:
+ expr.genUnaryOpNot(v)
+
+ case token.XOR:
+ expr.genUnaryOpXor(v)
+
+ case token.AND:
+ vf := v.evalAddr
+ expr.eval = func(t *Thread) Value { return vf(t) }
+
+ default:
+ log.Panicf("Compilation of unary op %v not implemented", op)
+ }
+
+ return expr
+}
+
+var binOpDescs = make(map[token.Token]string)
+
+func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr {
+ // Save the original types of l.t and r.t for error messages.
+ origlt := l.t
+ origrt := r.t
+
+ // XXX(Spec) What is the exact definition of a "named type"?
+
+ // XXX(Spec) Arithmetic operators: "Integer types" apparently
+ // means all types compatible with basic integer types, though
+ // this is never explained. Likewise for float types, etc.
+ // This relates to the missing explanation of named types.
+
+ // XXX(Spec) Operators: "If both operands are ideal numbers,
+ // the conversion is to ideal floats if one of the operands is
+ // an ideal float (relevant for / and %)." How is that
+ // relevant only for / and %? If I add an ideal int and an
+ // ideal float, I get an ideal float.
+
+ if op != token.SHL && op != token.SHR {
+ // Except in shift expressions, if one operand has
+ // numeric type and the other operand is an ideal
+ // number, the ideal number is converted to match the
+ // type of the other operand.
+ if (l.t.isInteger() || l.t.isFloat()) && !l.t.isIdeal() && r.t.isIdeal() {
+ r = r.convertTo(l.t)
+ } else if (r.t.isInteger() || r.t.isFloat()) && !r.t.isIdeal() && l.t.isIdeal() {
+ l = l.convertTo(r.t)
+ }
+ if l == nil || r == nil {
+ return nil
+ }
+
+ // Except in shift expressions, if both operands are
+ // ideal numbers and one is an ideal float, the other
+ // is converted to ideal float.
+ if l.t.isIdeal() && r.t.isIdeal() {
+ if l.t.isInteger() && r.t.isFloat() {
+ l = l.convertTo(r.t)
+ } else if l.t.isFloat() && r.t.isInteger() {
+ r = r.convertTo(l.t)
+ }
+ if l == nil || r == nil {
+ return nil
+ }
+ }
+ }
+
+ // Useful type predicates
+ // TODO(austin) CL 33668 mandates identical types except for comparisons.
+ compat := func() bool { return l.t.compat(r.t, false) }
+ integers := func() bool { return l.t.isInteger() && r.t.isInteger() }
+ floats := func() bool { return l.t.isFloat() && r.t.isFloat() }
+ strings := func() bool {
+ // TODO(austin) Deal with named types
+ return l.t == StringType && r.t == StringType
+ }
+ booleans := func() bool { return l.t.isBoolean() && r.t.isBoolean() }
+
+ // Type check
+ var t Type
+ switch op {
+ case token.ADD:
+ if !compat() || (!integers() && !floats() && !strings()) {
+ a.diagOpTypes(op, origlt, origrt)
+ return nil
+ }
+ t = l.t
+
+ case token.SUB, token.MUL, token.QUO:
+ if !compat() || (!integers() && !floats()) {
+ a.diagOpTypes(op, origlt, origrt)
+ return nil
+ }
+ t = l.t
+
+ case token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
+ if !compat() || !integers() {
+ a.diagOpTypes(op, origlt, origrt)
+ return nil
+ }
+ t = l.t
+
+ case token.SHL, token.SHR:
+ // XXX(Spec) Is it okay for the right operand to be an
+ // ideal float with no fractional part? "The right
+ // operand in a shift operation must be always be of
+ // unsigned integer type or an ideal number that can
+ // be safely converted into an unsigned integer type
+ // (§Arithmetic operators)" suggests so and 6g agrees.
+
+ if !l.t.isInteger() || !(r.t.isInteger() || r.t.isIdeal()) {
+ a.diagOpTypes(op, origlt, origrt)
+ return nil
+ }
+
+ // The right operand in a shift operation must be
+ // always be of unsigned integer type or an ideal
+ // number that can be safely converted into an
+ // unsigned integer type.
+ if r.t.isIdeal() {
+ r2 := r.convertTo(UintType)
+ if r2 == nil {
+ return nil
+ }
+
+ // If the left operand is not ideal, convert
+ // the right to not ideal.
+ if !l.t.isIdeal() {
+ r = r2
+ }
+
+ // If both are ideal, but the right side isn't
+ // an ideal int, convert it to simplify things.
+ if l.t.isIdeal() && !r.t.isInteger() {
+ r = r.convertTo(IdealIntType)
+ if r == nil {
+ log.Panicf("conversion to uintType succeeded, but conversion to idealIntType failed")
+ }
+ }
+ } else if _, ok := r.t.lit().(*uintType); !ok {
+ a.diag("right operand of shift must be unsigned")
+ return nil
+ }
+
+ if l.t.isIdeal() && !r.t.isIdeal() {
+ // XXX(Spec) What is the meaning of "ideal >>
+ // non-ideal"? Russ says the ideal should be
+ // converted to an int. 6g propagates the
+ // type down from assignments as a hint.
+
+ l = l.convertTo(IntType)
+ if l == nil {
+ return nil
+ }
+ }
+
+ // At this point, we should have one of three cases:
+ // 1) uint SHIFT uint
+ // 2) int SHIFT uint
+ // 3) ideal int SHIFT ideal int
+
+ t = l.t
+
+ case token.LOR, token.LAND:
+ if !booleans() {
+ return nil
+ }
+ // XXX(Spec) There's no mention of *which* boolean
+ // type the logical operators return. From poking at
+ // 6g, it appears to be the named boolean type, NOT
+ // the type of the left operand, and NOT an unnamed
+ // boolean type.
+
+ t = BoolType
+
+ case token.ARROW:
+ // The operands in channel sends differ in type: one
+ // is always a channel and the other is a variable or
+ // value of the channel's element type.
+ log.Panic("Binary op <- not implemented")
+ t = BoolType
+
+ case token.LSS, token.GTR, token.LEQ, token.GEQ:
+ // XXX(Spec) It's really unclear what types which
+ // comparison operators apply to. I feel like the
+ // text is trying to paint a Venn diagram for me,
+ // which it's really pretty simple: <, <=, >, >= apply
+ // only to numeric types and strings. == and != apply
+ // to everything except arrays and structs, and there
+ // are some restrictions on when it applies to slices.
+
+ if !compat() || (!integers() && !floats() && !strings()) {
+ a.diagOpTypes(op, origlt, origrt)
+ return nil
+ }
+ t = BoolType
+
+ case token.EQL, token.NEQ:
+ // XXX(Spec) The rules for type checking comparison
+ // operators are spread across three places that all
+ // partially overlap with each other: the Comparison
+ // Compatibility section, the Operators section, and
+ // the Comparison Operators section. The Operators
+ // section should just say that operators require
+ // identical types (as it does currently) except that
+ // there a few special cases for comparison, which are
+ // described in section X. Currently it includes just
+ // one of the four special cases. The Comparison
+ // Compatibility section and the Comparison Operators
+ // section should either be merged, or at least the
+ // Comparison Compatibility section should be
+ // exclusively about type checking and the Comparison
+ // Operators section should be exclusively about
+ // semantics.
+
+ // XXX(Spec) Comparison operators: "All comparison
+ // operators apply to basic types except bools." This
+ // is very difficult to parse. It's explained much
+ // better in the Comparison Compatibility section.
+
+ // XXX(Spec) Comparison compatibility: "Function
+ // values are equal if they refer to the same
+ // function." is rather vague. It should probably be
+ // similar to the way the rule for map values is
+ // written: Function values are equal if they were
+ // created by the same execution of a function literal
+ // or refer to the same function declaration. This is
+ // *almost* but not quite waht 6g implements. If a
+ // function literals does not capture any variables,
+ // then multiple executions of it will result in the
+ // same closure. Russ says he'll change that.
+
+ // TODO(austin) Deal with remaining special cases
+
+ if !compat() {
+ a.diagOpTypes(op, origlt, origrt)
+ return nil
+ }
+ // Arrays and structs may not be compared to anything.
+ switch l.t.(type) {
+ case *ArrayType, *StructType:
+ a.diagOpTypes(op, origlt, origrt)
+ return nil
+ }
+ t = BoolType
+
+ default:
+ log.Panicf("unknown binary operator %v", op)
+ }
+
+ desc, ok := binOpDescs[op]
+ if !ok {
+ desc = op.String() + " expression"
+ binOpDescs[op] = desc
+ }
+
+ // Check for ideal divide by zero
+ switch op {
+ case token.QUO, token.REM:
+ if r.t.isIdeal() {
+ if (r.t.isInteger() && r.asIdealInt()().Sign() == 0) ||
+ (r.t.isFloat() && r.asIdealFloat()().Sign() == 0) {
+ a.diag("divide by zero")
+ return nil
+ }
+ }
+ }
+
+ // Compile
+ expr := a.newExpr(t, desc)
+ switch op {
+ case token.ADD:
+ expr.genBinOpAdd(l, r)
+
+ case token.SUB:
+ expr.genBinOpSub(l, r)
+
+ case token.MUL:
+ expr.genBinOpMul(l, r)
+
+ case token.QUO:
+ expr.genBinOpQuo(l, r)
+
+ case token.REM:
+ expr.genBinOpRem(l, r)
+
+ case token.AND:
+ expr.genBinOpAnd(l, r)
+
+ case token.OR:
+ expr.genBinOpOr(l, r)
+
+ case token.XOR:
+ expr.genBinOpXor(l, r)
+
+ case token.AND_NOT:
+ expr.genBinOpAndNot(l, r)
+
+ case token.SHL:
+ if l.t.isIdeal() {
+ lv := l.asIdealInt()()
+ rv := r.asIdealInt()()
+ const maxShift = 99999
+ if rv.Cmp(big.NewInt(maxShift)) > 0 {
+ a.diag("left shift by %v; exceeds implementation limit of %v", rv, maxShift)
+ expr.t = nil
+ return nil
+ }
+ val := new(big.Int).Lsh(lv, uint(rv.Int64()))
+ expr.eval = func() *big.Int { return val }
+ } else {
+ expr.genBinOpShl(l, r)
+ }
+
+ case token.SHR:
+ if l.t.isIdeal() {
+ lv := l.asIdealInt()()
+ rv := r.asIdealInt()()
+ val := new(big.Int).Rsh(lv, uint(rv.Int64()))
+ expr.eval = func() *big.Int { return val }
+ } else {
+ expr.genBinOpShr(l, r)
+ }
+
+ case token.LSS:
+ expr.genBinOpLss(l, r)
+
+ case token.GTR:
+ expr.genBinOpGtr(l, r)
+
+ case token.LEQ:
+ expr.genBinOpLeq(l, r)
+
+ case token.GEQ:
+ expr.genBinOpGeq(l, r)
+
+ case token.EQL:
+ expr.genBinOpEql(l, r)
+
+ case token.NEQ:
+ expr.genBinOpNeq(l, r)
+
+ case token.LAND:
+ expr.genBinOpLogAnd(l, r)
+
+ case token.LOR:
+ expr.genBinOpLogOr(l, r)
+
+ default:
+ log.Panicf("Compilation of binary op %v not implemented", op)
+ }
+
+ return expr
+}
+
+// TODO(austin) This is a hack to eliminate a circular dependency
+// between type.go and expr.go
+func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
+ lenExpr := a.compileExpr(b, true, expr)
+ if lenExpr == nil {
+ return 0, false
+ }
+
+ // XXX(Spec) Are ideal floats with no fractional part okay?
+ if lenExpr.t.isIdeal() {
+ lenExpr = lenExpr.convertTo(IntType)
+ if lenExpr == nil {
+ return 0, false
+ }
+ }
+
+ if !lenExpr.t.isInteger() {
+ a.diagAt(expr.Pos(), "array size must be an integer")
+ return 0, false
+ }
+
+ switch lenExpr.t.lit().(type) {
+ case *intType:
+ return lenExpr.asInt()(nil), true
+ case *uintType:
+ return int64(lenExpr.asUint()(nil)), true
+ }
+ log.Panicf("unexpected integer type %T", lenExpr.t)
+ return 0, false
+}
+
+func (a *compiler) compileExpr(b *block, constant bool, expr ast.Expr) *expr {
+ ec := &exprCompiler{a, b, constant}
+ nerr := a.numError()
+ e := ec.compile(expr, false)
+ if e == nil && nerr == a.numError() {
+ log.Panicf("expression compilation failed without reporting errors")
+ }
+ return e
+}
+
+// extractEffect separates out any effects that the expression may
+// have, returning a function that will perform those effects and a
+// new exprCompiler that is guaranteed to be side-effect free. These
+// are the moral equivalents of "temp := expr" and "temp" (or "temp :=
+// &expr" and "*temp" for addressable exprs). Because this creates a
+// temporary variable, the caller should create a temporary block for
+// the compilation of this expression and the evaluation of the
+// results.
+func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) {
+ // Create "&a" if a is addressable
+ rhs := a
+ if a.evalAddr != nil {
+ rhs = a.compileUnaryExpr(token.AND, rhs)
+ }
+
+ // Create temp
+ ac, ok := a.checkAssign(a.pos, []*expr{rhs}, errOp, "")
+ if !ok {
+ return nil, nil
+ }
+ if len(ac.rmt.Elems) != 1 {
+ a.diag("multi-valued expression not allowed in %s", errOp)
+ return nil, nil
+ }
+ tempType := ac.rmt.Elems[0]
+ if tempType.isIdeal() {
+ // It's too bad we have to duplicate this rule.
+ switch {
+ case tempType.isInteger():
+ tempType = IntType
+ case tempType.isFloat():
+ tempType = Float64Type
+ default:
+ log.Panicf("unexpected ideal type %v", tempType)
+ }
+ }
+ temp := b.DefineTemp(tempType)
+ tempIdx := temp.Index
+
+ // Create "temp := rhs"
+ assign := ac.compile(b, tempType)
+ if assign == nil {
+ log.Panicf("compileAssign type check failed")
+ }
+
+ effect := func(t *Thread) {
+ tempVal := tempType.Zero()
+ t.f.Vars[tempIdx] = tempVal
+ assign(tempVal, t)
+ }
+
+ // Generate "temp" or "*temp"
+ getTemp := a.compileVariable(0, temp)
+ if a.evalAddr == nil {
+ return effect, getTemp
+ }
+
+ deref := a.compileStarExpr(getTemp)
+ if deref == nil {
+ return nil, nil
+ }
+ return effect, deref
+}
diff --git a/libgo/go/exp/eval/expr1.go b/libgo/go/exp/eval/expr1.go
new file mode 100644
index 000000000..5d0e50000
--- /dev/null
+++ b/libgo/go/exp/eval/expr1.go
@@ -0,0 +1,1874 @@
+// This file is machine generated by gen.go.
+// 6g gen.go && 6l gen.6 && ./6.out >expr1.go
+
+package eval
+
+import (
+ "big"
+ "log"
+)
+
+/*
+ * "As" functions. These retrieve evaluator functions from an
+ * expr, panicking if the requested evaluator has the wrong type.
+ */
+func (a *expr) asBool() func(*Thread) bool {
+ return a.eval.(func(*Thread) bool)
+}
+func (a *expr) asUint() func(*Thread) uint64 {
+ return a.eval.(func(*Thread) uint64)
+}
+func (a *expr) asInt() func(*Thread) int64 {
+ return a.eval.(func(*Thread) int64)
+}
+func (a *expr) asIdealInt() func() *big.Int {
+ return a.eval.(func() *big.Int)
+}
+func (a *expr) asFloat() func(*Thread) float64 {
+ return a.eval.(func(*Thread) float64)
+}
+func (a *expr) asIdealFloat() func() *big.Rat {
+ return a.eval.(func() *big.Rat)
+}
+func (a *expr) asString() func(*Thread) string {
+ return a.eval.(func(*Thread) string)
+}
+func (a *expr) asArray() func(*Thread) ArrayValue {
+ return a.eval.(func(*Thread) ArrayValue)
+}
+func (a *expr) asStruct() func(*Thread) StructValue {
+ return a.eval.(func(*Thread) StructValue)
+}
+func (a *expr) asPtr() func(*Thread) Value {
+ return a.eval.(func(*Thread) Value)
+}
+func (a *expr) asFunc() func(*Thread) Func {
+ return a.eval.(func(*Thread) Func)
+}
+func (a *expr) asSlice() func(*Thread) Slice {
+ return a.eval.(func(*Thread) Slice)
+}
+func (a *expr) asMap() func(*Thread) Map {
+ return a.eval.(func(*Thread) Map)
+}
+func (a *expr) asMulti() func(*Thread) []Value {
+ return a.eval.(func(*Thread) []Value)
+}
+
+func (a *expr) asInterface() func(*Thread) interface{} {
+ switch sf := a.eval.(type) {
+ case func(t *Thread) bool:
+ return func(t *Thread) interface{} { return sf(t) }
+ case func(t *Thread) uint64:
+ return func(t *Thread) interface{} { return sf(t) }
+ case func(t *Thread) int64:
+ return func(t *Thread) interface{} { return sf(t) }
+ case func() *big.Int:
+ return func(*Thread) interface{} { return sf() }
+ case func(t *Thread) float64:
+ return func(t *Thread) interface{} { return sf(t) }
+ case func() *big.Rat:
+ return func(*Thread) interface{} { return sf() }
+ case func(t *Thread) string:
+ return func(t *Thread) interface{} { return sf(t) }
+ case func(t *Thread) ArrayValue:
+ return func(t *Thread) interface{} { return sf(t) }
+ case func(t *Thread) StructValue:
+ return func(t *Thread) interface{} { return sf(t) }
+ case func(t *Thread) Value:
+ return func(t *Thread) interface{} { return sf(t) }
+ case func(t *Thread) Func:
+ return func(t *Thread) interface{} { return sf(t) }
+ case func(t *Thread) Slice:
+ return func(t *Thread) interface{} { return sf(t) }
+ case func(t *Thread) Map:
+ return func(t *Thread) interface{} { return sf(t) }
+ default:
+ log.Panicf("unexpected expression node type %T at %v", a.eval, a.pos)
+ }
+ panic("fail")
+}
+
+/*
+ * Operator generators.
+ */
+
+func (a *expr) genConstant(v Value) {
+ switch a.t.lit().(type) {
+ case *boolType:
+ a.eval = func(t *Thread) bool { return v.(BoolValue).Get(t) }
+ case *uintType:
+ a.eval = func(t *Thread) uint64 { return v.(UintValue).Get(t) }
+ case *intType:
+ a.eval = func(t *Thread) int64 { return v.(IntValue).Get(t) }
+ case *idealIntType:
+ val := v.(IdealIntValue).Get()
+ a.eval = func() *big.Int { return val }
+ case *floatType:
+ a.eval = func(t *Thread) float64 { return v.(FloatValue).Get(t) }
+ case *idealFloatType:
+ val := v.(IdealFloatValue).Get()
+ a.eval = func() *big.Rat { return val }
+ case *stringType:
+ a.eval = func(t *Thread) string { return v.(StringValue).Get(t) }
+ case *ArrayType:
+ a.eval = func(t *Thread) ArrayValue { return v.(ArrayValue).Get(t) }
+ case *StructType:
+ a.eval = func(t *Thread) StructValue { return v.(StructValue).Get(t) }
+ case *PtrType:
+ a.eval = func(t *Thread) Value { return v.(PtrValue).Get(t) }
+ case *FuncType:
+ a.eval = func(t *Thread) Func { return v.(FuncValue).Get(t) }
+ case *SliceType:
+ a.eval = func(t *Thread) Slice { return v.(SliceValue).Get(t) }
+ case *MapType:
+ a.eval = func(t *Thread) Map { return v.(MapValue).Get(t) }
+ default:
+ log.Panicf("unexpected constant type %v at %v", a.t, a.pos)
+ }
+}
+
+func (a *expr) genIdentOp(level, index int) {
+ a.evalAddr = func(t *Thread) Value { return t.f.Get(level, index) }
+ switch a.t.lit().(type) {
+ case *boolType:
+ a.eval = func(t *Thread) bool { return t.f.Get(level, index).(BoolValue).Get(t) }
+ case *uintType:
+ a.eval = func(t *Thread) uint64 { return t.f.Get(level, index).(UintValue).Get(t) }
+ case *intType:
+ a.eval = func(t *Thread) int64 { return t.f.Get(level, index).(IntValue).Get(t) }
+ case *floatType:
+ a.eval = func(t *Thread) float64 { return t.f.Get(level, index).(FloatValue).Get(t) }
+ case *stringType:
+ a.eval = func(t *Thread) string { return t.f.Get(level, index).(StringValue).Get(t) }
+ case *ArrayType:
+ a.eval = func(t *Thread) ArrayValue { return t.f.Get(level, index).(ArrayValue).Get(t) }
+ case *StructType:
+ a.eval = func(t *Thread) StructValue { return t.f.Get(level, index).(StructValue).Get(t) }
+ case *PtrType:
+ a.eval = func(t *Thread) Value { return t.f.Get(level, index).(PtrValue).Get(t) }
+ case *FuncType:
+ a.eval = func(t *Thread) Func { return t.f.Get(level, index).(FuncValue).Get(t) }
+ case *SliceType:
+ a.eval = func(t *Thread) Slice { return t.f.Get(level, index).(SliceValue).Get(t) }
+ case *MapType:
+ a.eval = func(t *Thread) Map { return t.f.Get(level, index).(MapValue).Get(t) }
+ default:
+ log.Panicf("unexpected identifier type %v at %v", a.t, a.pos)
+ }
+}
+
+func (a *expr) genFuncCall(call func(t *Thread) []Value) {
+ a.exec = func(t *Thread) { call(t) }
+ switch a.t.lit().(type) {
+ case *boolType:
+ a.eval = func(t *Thread) bool { return call(t)[0].(BoolValue).Get(t) }
+ case *uintType:
+ a.eval = func(t *Thread) uint64 { return call(t)[0].(UintValue).Get(t) }
+ case *intType:
+ a.eval = func(t *Thread) int64 { return call(t)[0].(IntValue).Get(t) }
+ case *floatType:
+ a.eval = func(t *Thread) float64 { return call(t)[0].(FloatValue).Get(t) }
+ case *stringType:
+ a.eval = func(t *Thread) string { return call(t)[0].(StringValue).Get(t) }
+ case *ArrayType:
+ a.eval = func(t *Thread) ArrayValue { return call(t)[0].(ArrayValue).Get(t) }
+ case *StructType:
+ a.eval = func(t *Thread) StructValue { return call(t)[0].(StructValue).Get(t) }
+ case *PtrType:
+ a.eval = func(t *Thread) Value { return call(t)[0].(PtrValue).Get(t) }
+ case *FuncType:
+ a.eval = func(t *Thread) Func { return call(t)[0].(FuncValue).Get(t) }
+ case *SliceType:
+ a.eval = func(t *Thread) Slice { return call(t)[0].(SliceValue).Get(t) }
+ case *MapType:
+ a.eval = func(t *Thread) Map { return call(t)[0].(MapValue).Get(t) }
+ case *MultiType:
+ a.eval = func(t *Thread) []Value { return call(t) }
+ default:
+ log.Panicf("unexpected result type %v at %v", a.t, a.pos)
+ }
+}
+
+func (a *expr) genValue(vf func(*Thread) Value) {
+ a.evalAddr = vf
+ switch a.t.lit().(type) {
+ case *boolType:
+ a.eval = func(t *Thread) bool { return vf(t).(BoolValue).Get(t) }
+ case *uintType:
+ a.eval = func(t *Thread) uint64 { return vf(t).(UintValue).Get(t) }
+ case *intType:
+ a.eval = func(t *Thread) int64 { return vf(t).(IntValue).Get(t) }
+ case *floatType:
+ a.eval = func(t *Thread) float64 { return vf(t).(FloatValue).Get(t) }
+ case *stringType:
+ a.eval = func(t *Thread) string { return vf(t).(StringValue).Get(t) }
+ case *ArrayType:
+ a.eval = func(t *Thread) ArrayValue { return vf(t).(ArrayValue).Get(t) }
+ case *StructType:
+ a.eval = func(t *Thread) StructValue { return vf(t).(StructValue).Get(t) }
+ case *PtrType:
+ a.eval = func(t *Thread) Value { return vf(t).(PtrValue).Get(t) }
+ case *FuncType:
+ a.eval = func(t *Thread) Func { return vf(t).(FuncValue).Get(t) }
+ case *SliceType:
+ a.eval = func(t *Thread) Slice { return vf(t).(SliceValue).Get(t) }
+ case *MapType:
+ a.eval = func(t *Thread) Map { return vf(t).(MapValue).Get(t) }
+ default:
+ log.Panicf("unexpected result type %v at %v", a.t, a.pos)
+ }
+}
+
+func (a *expr) genUnaryOpNeg(v *expr) {
+ switch a.t.lit().(type) {
+ case *uintType:
+ vf := v.asUint()
+ a.eval = func(t *Thread) uint64 { v := vf(t); return -v }
+ case *intType:
+ vf := v.asInt()
+ a.eval = func(t *Thread) int64 { v := vf(t); return -v }
+ case *idealIntType:
+ val := v.asIdealInt()()
+ val.Neg(val)
+ a.eval = func() *big.Int { return val }
+ case *floatType:
+ vf := v.asFloat()
+ a.eval = func(t *Thread) float64 { v := vf(t); return -v }
+ case *idealFloatType:
+ val := v.asIdealFloat()()
+ val.Neg(val)
+ a.eval = func() *big.Rat { return val }
+ default:
+ log.Panicf("unexpected type %v at %v", a.t, a.pos)
+ }
+}
+
+func (a *expr) genUnaryOpNot(v *expr) {
+ switch a.t.lit().(type) {
+ case *boolType:
+ vf := v.asBool()
+ a.eval = func(t *Thread) bool { v := vf(t); return !v }
+ default:
+ log.Panicf("unexpected type %v at %v", a.t, a.pos)
+ }
+}
+
+func (a *expr) genUnaryOpXor(v *expr) {
+ switch a.t.lit().(type) {
+ case *uintType:
+ vf := v.asUint()
+ a.eval = func(t *Thread) uint64 { v := vf(t); return ^v }
+ case *intType:
+ vf := v.asInt()
+ a.eval = func(t *Thread) int64 { v := vf(t); return ^v }
+ case *idealIntType:
+ val := v.asIdealInt()()
+ val.Not(val)
+ a.eval = func() *big.Int { return val }
+ default:
+ log.Panicf("unexpected type %v at %v", a.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpLogAnd(l, r *expr) {
+ lf := l.asBool()
+ rf := r.asBool()
+ a.eval = func(t *Thread) bool { return lf(t) && rf(t) }
+}
+
+func (a *expr) genBinOpLogOr(l, r *expr) {
+ lf := l.asBool()
+ rf := r.asBool()
+ a.eval = func(t *Thread) bool { return lf(t) || rf(t) }
+}
+
+func (a *expr) genBinOpAdd(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l + r
+ return uint64(uint8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l + r
+ return uint64(uint16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l + r
+ return uint64(uint32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l + r
+ return uint64(uint64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l + r
+ return uint64(uint(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l + r
+ return int64(int8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l + r
+ return int64(int16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l + r
+ return int64(int32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l + r
+ return int64(int64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l + r
+ return int64(int(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Add(l, r)
+ a.eval = func() *big.Int { return val }
+ case *floatType:
+ lf := l.asFloat()
+ rf := r.asFloat()
+ switch t.Bits {
+ case 32:
+ a.eval = func(t *Thread) float64 {
+ l, r := lf(t), rf(t)
+ var ret float64
+ ret = l + r
+ return float64(float32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) float64 {
+ l, r := lf(t), rf(t)
+ var ret float64
+ ret = l + r
+ return float64(float64(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealFloatType:
+ l := l.asIdealFloat()()
+ r := r.asIdealFloat()()
+ val := l.Add(l, r)
+ a.eval = func() *big.Rat { return val }
+ case *stringType:
+ lf := l.asString()
+ rf := r.asString()
+ a.eval = func(t *Thread) string {
+ l, r := lf(t), rf(t)
+ return l + r
+ }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpSub(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l - r
+ return uint64(uint8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l - r
+ return uint64(uint16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l - r
+ return uint64(uint32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l - r
+ return uint64(uint64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l - r
+ return uint64(uint(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l - r
+ return int64(int8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l - r
+ return int64(int16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l - r
+ return int64(int32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l - r
+ return int64(int64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l - r
+ return int64(int(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Sub(l, r)
+ a.eval = func() *big.Int { return val }
+ case *floatType:
+ lf := l.asFloat()
+ rf := r.asFloat()
+ switch t.Bits {
+ case 32:
+ a.eval = func(t *Thread) float64 {
+ l, r := lf(t), rf(t)
+ var ret float64
+ ret = l - r
+ return float64(float32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) float64 {
+ l, r := lf(t), rf(t)
+ var ret float64
+ ret = l - r
+ return float64(float64(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealFloatType:
+ l := l.asIdealFloat()()
+ r := r.asIdealFloat()()
+ val := l.Sub(l, r)
+ a.eval = func() *big.Rat { return val }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpMul(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l * r
+ return uint64(uint8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l * r
+ return uint64(uint16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l * r
+ return uint64(uint32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l * r
+ return uint64(uint64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l * r
+ return uint64(uint(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l * r
+ return int64(int8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l * r
+ return int64(int16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l * r
+ return int64(int32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l * r
+ return int64(int64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l * r
+ return int64(int(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Mul(l, r)
+ a.eval = func() *big.Int { return val }
+ case *floatType:
+ lf := l.asFloat()
+ rf := r.asFloat()
+ switch t.Bits {
+ case 32:
+ a.eval = func(t *Thread) float64 {
+ l, r := lf(t), rf(t)
+ var ret float64
+ ret = l * r
+ return float64(float32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) float64 {
+ l, r := lf(t), rf(t)
+ var ret float64
+ ret = l * r
+ return float64(float64(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealFloatType:
+ l := l.asIdealFloat()()
+ r := r.asIdealFloat()()
+ val := l.Mul(l, r)
+ a.eval = func() *big.Rat { return val }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpQuo(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return uint64(uint8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return uint64(uint16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return uint64(uint32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return uint64(uint64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return uint64(uint(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return int64(int8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return int64(int16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return int64(int32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return int64(int64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return int64(int(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Quo(l, r)
+ a.eval = func() *big.Int { return val }
+ case *floatType:
+ lf := l.asFloat()
+ rf := r.asFloat()
+ switch t.Bits {
+ case 32:
+ a.eval = func(t *Thread) float64 {
+ l, r := lf(t), rf(t)
+ var ret float64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return float64(float32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) float64 {
+ l, r := lf(t), rf(t)
+ var ret float64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l / r
+ return float64(float64(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealFloatType:
+ l := l.asIdealFloat()()
+ r := r.asIdealFloat()()
+ val := l.Quo(l, r)
+ a.eval = func() *big.Rat { return val }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpRem(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l % r
+ return uint64(uint8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l % r
+ return uint64(uint16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l % r
+ return uint64(uint32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l % r
+ return uint64(uint64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l % r
+ return uint64(uint(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l % r
+ return int64(int8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l % r
+ return int64(int16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l % r
+ return int64(int32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l % r
+ return int64(int64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ if r == 0 {
+ t.Abort(DivByZeroError{})
+ }
+ ret = l % r
+ return int64(int(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Rem(l, r)
+ a.eval = func() *big.Int { return val }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpAnd(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l & r
+ return uint64(uint8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l & r
+ return uint64(uint16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l & r
+ return uint64(uint32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l & r
+ return uint64(uint64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l & r
+ return uint64(uint(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l & r
+ return int64(int8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l & r
+ return int64(int16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l & r
+ return int64(int32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l & r
+ return int64(int64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l & r
+ return int64(int(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.And(l, r)
+ a.eval = func() *big.Int { return val }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpOr(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l | r
+ return uint64(uint8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l | r
+ return uint64(uint16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l | r
+ return uint64(uint32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l | r
+ return uint64(uint64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l | r
+ return uint64(uint(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l | r
+ return int64(int8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l | r
+ return int64(int16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l | r
+ return int64(int32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l | r
+ return int64(int64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l | r
+ return int64(int(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Or(l, r)
+ a.eval = func() *big.Int { return val }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpXor(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l ^ r
+ return uint64(uint8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l ^ r
+ return uint64(uint16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l ^ r
+ return uint64(uint32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l ^ r
+ return uint64(uint64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l ^ r
+ return uint64(uint(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l ^ r
+ return int64(int8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l ^ r
+ return int64(int16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l ^ r
+ return int64(int32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l ^ r
+ return int64(int64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l ^ r
+ return int64(int(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Xor(l, r)
+ a.eval = func() *big.Int { return val }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpAndNot(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l &^ r
+ return uint64(uint8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l &^ r
+ return uint64(uint16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l &^ r
+ return uint64(uint32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l &^ r
+ return uint64(uint64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l &^ r
+ return uint64(uint(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l &^ r
+ return int64(int8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l &^ r
+ return int64(int16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l &^ r
+ return int64(int32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l &^ r
+ return int64(int64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l &^ r
+ return int64(int(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.AndNot(l, r)
+ a.eval = func() *big.Int { return val }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpShl(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l << r
+ return uint64(uint8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l << r
+ return uint64(uint16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l << r
+ return uint64(uint32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l << r
+ return uint64(uint64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l << r
+ return uint64(uint(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l << r
+ return int64(int8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l << r
+ return int64(int16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l << r
+ return int64(int32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l << r
+ return int64(int64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l << r
+ return int64(int(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpShr(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l >> r
+ return uint64(uint8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l >> r
+ return uint64(uint16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l >> r
+ return uint64(uint32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l >> r
+ return uint64(uint64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) uint64 {
+ l, r := lf(t), rf(t)
+ var ret uint64
+ ret = l >> r
+ return uint64(uint(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asUint()
+ switch t.Bits {
+ case 8:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l >> r
+ return int64(int8(ret))
+ }
+ case 16:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l >> r
+ return int64(int16(ret))
+ }
+ case 32:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l >> r
+ return int64(int32(ret))
+ }
+ case 64:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l >> r
+ return int64(int64(ret))
+ }
+ case 0:
+ a.eval = func(t *Thread) int64 {
+ l, r := lf(t), rf(t)
+ var ret int64
+ ret = l >> r
+ return int64(int(ret))
+ }
+ default:
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpLss(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l < r
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l < r
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Cmp(r) < 0
+ a.eval = func(t *Thread) bool { return val }
+ case *floatType:
+ lf := l.asFloat()
+ rf := r.asFloat()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l < r
+ }
+ case *idealFloatType:
+ l := l.asIdealFloat()()
+ r := r.asIdealFloat()()
+ val := l.Cmp(r) < 0
+ a.eval = func(t *Thread) bool { return val }
+ case *stringType:
+ lf := l.asString()
+ rf := r.asString()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l < r
+ }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpGtr(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l > r
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l > r
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Cmp(r) > 0
+ a.eval = func(t *Thread) bool { return val }
+ case *floatType:
+ lf := l.asFloat()
+ rf := r.asFloat()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l > r
+ }
+ case *idealFloatType:
+ l := l.asIdealFloat()()
+ r := r.asIdealFloat()()
+ val := l.Cmp(r) > 0
+ a.eval = func(t *Thread) bool { return val }
+ case *stringType:
+ lf := l.asString()
+ rf := r.asString()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l > r
+ }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpLeq(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l <= r
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l <= r
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Cmp(r) <= 0
+ a.eval = func(t *Thread) bool { return val }
+ case *floatType:
+ lf := l.asFloat()
+ rf := r.asFloat()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l <= r
+ }
+ case *idealFloatType:
+ l := l.asIdealFloat()()
+ r := r.asIdealFloat()()
+ val := l.Cmp(r) <= 0
+ a.eval = func(t *Thread) bool { return val }
+ case *stringType:
+ lf := l.asString()
+ rf := r.asString()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l <= r
+ }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpGeq(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l >= r
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l >= r
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Cmp(r) >= 0
+ a.eval = func(t *Thread) bool { return val }
+ case *floatType:
+ lf := l.asFloat()
+ rf := r.asFloat()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l >= r
+ }
+ case *idealFloatType:
+ l := l.asIdealFloat()()
+ r := r.asIdealFloat()()
+ val := l.Cmp(r) >= 0
+ a.eval = func(t *Thread) bool { return val }
+ case *stringType:
+ lf := l.asString()
+ rf := r.asString()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l >= r
+ }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpEql(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *boolType:
+ lf := l.asBool()
+ rf := r.asBool()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l == r
+ }
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l == r
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l == r
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Cmp(r) == 0
+ a.eval = func(t *Thread) bool { return val }
+ case *floatType:
+ lf := l.asFloat()
+ rf := r.asFloat()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l == r
+ }
+ case *idealFloatType:
+ l := l.asIdealFloat()()
+ r := r.asIdealFloat()()
+ val := l.Cmp(r) == 0
+ a.eval = func(t *Thread) bool { return val }
+ case *stringType:
+ lf := l.asString()
+ rf := r.asString()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l == r
+ }
+ case *PtrType:
+ lf := l.asPtr()
+ rf := r.asPtr()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l == r
+ }
+ case *FuncType:
+ lf := l.asFunc()
+ rf := r.asFunc()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l == r
+ }
+ case *MapType:
+ lf := l.asMap()
+ rf := r.asMap()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l == r
+ }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func (a *expr) genBinOpNeq(l, r *expr) {
+ switch t := l.t.lit().(type) {
+ case *boolType:
+ lf := l.asBool()
+ rf := r.asBool()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l != r
+ }
+ case *uintType:
+ lf := l.asUint()
+ rf := r.asUint()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l != r
+ }
+ case *intType:
+ lf := l.asInt()
+ rf := r.asInt()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l != r
+ }
+ case *idealIntType:
+ l := l.asIdealInt()()
+ r := r.asIdealInt()()
+ val := l.Cmp(r) != 0
+ a.eval = func(t *Thread) bool { return val }
+ case *floatType:
+ lf := l.asFloat()
+ rf := r.asFloat()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l != r
+ }
+ case *idealFloatType:
+ l := l.asIdealFloat()()
+ r := r.asIdealFloat()()
+ val := l.Cmp(r) != 0
+ a.eval = func(t *Thread) bool { return val }
+ case *stringType:
+ lf := l.asString()
+ rf := r.asString()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l != r
+ }
+ case *PtrType:
+ lf := l.asPtr()
+ rf := r.asPtr()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l != r
+ }
+ case *FuncType:
+ lf := l.asFunc()
+ rf := r.asFunc()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l != r
+ }
+ case *MapType:
+ lf := l.asMap()
+ rf := r.asMap()
+ a.eval = func(t *Thread) bool {
+ l, r := lf(t), rf(t)
+ return l != r
+ }
+ default:
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
+ }
+}
+
+func genAssign(lt Type, r *expr) func(lv Value, t *Thread) {
+ switch lt.lit().(type) {
+ case *boolType:
+ rf := r.asBool()
+ return func(lv Value, t *Thread) { lv.(BoolValue).Set(t, rf(t)) }
+ case *uintType:
+ rf := r.asUint()
+ return func(lv Value, t *Thread) { lv.(UintValue).Set(t, rf(t)) }
+ case *intType:
+ rf := r.asInt()
+ return func(lv Value, t *Thread) { lv.(IntValue).Set(t, rf(t)) }
+ case *floatType:
+ rf := r.asFloat()
+ return func(lv Value, t *Thread) { lv.(FloatValue).Set(t, rf(t)) }
+ case *stringType:
+ rf := r.asString()
+ return func(lv Value, t *Thread) { lv.(StringValue).Set(t, rf(t)) }
+ case *ArrayType:
+ rf := r.asArray()
+ return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) }
+ case *StructType:
+ rf := r.asStruct()
+ return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) }
+ case *PtrType:
+ rf := r.asPtr()
+ return func(lv Value, t *Thread) { lv.(PtrValue).Set(t, rf(t)) }
+ case *FuncType:
+ rf := r.asFunc()
+ return func(lv Value, t *Thread) { lv.(FuncValue).Set(t, rf(t)) }
+ case *SliceType:
+ rf := r.asSlice()
+ return func(lv Value, t *Thread) { lv.(SliceValue).Set(t, rf(t)) }
+ case *MapType:
+ rf := r.asMap()
+ return func(lv Value, t *Thread) { lv.(MapValue).Set(t, rf(t)) }
+ default:
+ log.Panicf("unexpected left operand type %v at %v", lt, r.pos)
+ }
+ panic("fail")
+}
diff --git a/libgo/go/exp/eval/expr_test.go b/libgo/go/exp/eval/expr_test.go
new file mode 100644
index 000000000..0dbce4315
--- /dev/null
+++ b/libgo/go/exp/eval/expr_test.go
@@ -0,0 +1,355 @@
+// 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 eval
+
+import (
+ "big"
+ "testing"
+)
+
+var undefined = "undefined"
+var typeAsExpr = "type .* used as expression"
+var badCharLit = "character literal"
+var unknownEscape = "unknown escape sequence"
+var opTypes = "illegal (operand|argument) type|cannot index into"
+var badAddrOf = "cannot take the address"
+var constantTruncated = "constant [^ ]* truncated"
+var constantUnderflows = "constant [^ ]* underflows"
+var constantOverflows = "constant [^ ]* overflows"
+var implLimit = "implementation limit"
+var mustBeUnsigned = "must be unsigned"
+var divByZero = "divide by zero"
+
+var hugeInteger = new(big.Int).Lsh(idealOne, 64)
+
+var exprTests = []test{
+ Val("i", 1),
+ CErr("zzz", undefined),
+ // TODO(austin) Test variable in constant context
+ //CErr("t", typeAsExpr),
+
+ Val("'a'", big.NewInt('a')),
+ Val("'\\uffff'", big.NewInt('\uffff')),
+ Val("'\\n'", big.NewInt('\n')),
+ CErr("''+x", badCharLit),
+ // Produces two parse errors
+ //CErr("'''", ""),
+ CErr("'\n'", badCharLit),
+ CErr("'\\z'", unknownEscape),
+ CErr("'ab'", badCharLit),
+
+ Val("1.0", big.NewRat(1, 1)),
+ Val("1.", big.NewRat(1, 1)),
+ Val(".1", big.NewRat(1, 10)),
+ Val("1e2", big.NewRat(100, 1)),
+
+ Val("\"abc\"", "abc"),
+ Val("\"\"", ""),
+ Val("\"\\n\\\"\"", "\n\""),
+ CErr("\"\\z\"", unknownEscape),
+ CErr("\"abc", "string not terminated"),
+
+ Val("(i)", 1),
+
+ Val("ai[0]", 1),
+ Val("(&ai)[0]", 1),
+ Val("ai[1]", 2),
+ Val("ai[i]", 2),
+ Val("ai[u]", 2),
+ CErr("ai[f]", opTypes),
+ CErr("ai[0][0]", opTypes),
+ CErr("ai[2]", "index 2 exceeds"),
+ CErr("ai[1+1]", "index 2 exceeds"),
+ CErr("ai[-1]", "negative index"),
+ RErr("ai[i+i]", "index 2 exceeds"),
+ RErr("ai[-i]", "negative index"),
+ CErr("i[0]", opTypes),
+ CErr("f[0]", opTypes),
+
+ Val("aai[0][0]", 1),
+ Val("aai[1][1]", 4),
+ CErr("aai[2][0]", "index 2 exceeds"),
+ CErr("aai[0][2]", "index 2 exceeds"),
+
+ Val("sli[0]", 1),
+ Val("sli[1]", 2),
+ CErr("sli[-1]", "negative index"),
+ RErr("sli[-i]", "negative index"),
+ RErr("sli[2]", "index 2 exceeds"),
+
+ Val("s[0]", uint8('a')),
+ Val("s[1]", uint8('b')),
+ CErr("s[-1]", "negative index"),
+ RErr("s[-i]", "negative index"),
+ RErr("s[3]", "index 3 exceeds"),
+
+ Val("ai[0:2]", vslice{varray{1, 2}, 2, 2}),
+ Val("ai[0:1]", vslice{varray{1, 2}, 1, 2}),
+ Val("ai[0:]", vslice{varray{1, 2}, 2, 2}),
+ Val("ai[i:]", vslice{varray{2}, 1, 1}),
+
+ Val("sli[0:2]", vslice{varray{1, 2, 3}, 2, 3}),
+ Val("sli[0:i]", vslice{varray{1, 2, 3}, 1, 3}),
+ Val("sli[1:]", vslice{varray{2, 3}, 1, 2}),
+
+ CErr("1(2)", "cannot call"),
+ CErr("fn(1,2)", "too many"),
+ CErr("fn()", "not enough"),
+ CErr("fn(true)", opTypes),
+ CErr("fn(true)", "function call"),
+ // Single argument functions don't say which argument.
+ //CErr("fn(true)", "argument 1"),
+ Val("fn(1)", 2),
+ Val("fn(1.0)", 2),
+ CErr("fn(1.5)", constantTruncated),
+ Val("fn(i)", 2),
+ CErr("fn(u)", opTypes),
+
+ CErr("void()+2", opTypes),
+ CErr("oneTwo()+2", opTypes),
+
+ Val("cap(ai)", 2),
+ Val("cap(&ai)", 2),
+ Val("cap(aai)", 2),
+ Val("cap(sli)", 3),
+ CErr("cap(0)", opTypes),
+ CErr("cap(i)", opTypes),
+ CErr("cap(s)", opTypes),
+
+ Val("len(s)", 3),
+ Val("len(ai)", 2),
+ Val("len(&ai)", 2),
+ Val("len(ai[0:])", 2),
+ Val("len(ai[1:])", 1),
+ Val("len(ai[2:])", 0),
+ Val("len(aai)", 2),
+ Val("len(sli)", 2),
+ Val("len(sli[0:])", 2),
+ Val("len(sli[1:])", 1),
+ Val("len(sli[2:])", 0),
+ // TODO(austin) Test len of map
+ CErr("len(0)", opTypes),
+ CErr("len(i)", opTypes),
+
+ CErr("*i", opTypes),
+ Val("*&i", 1),
+ Val("*&(i)", 1),
+ CErr("&1", badAddrOf),
+ CErr("&c", badAddrOf),
+ Val("*(&ai[0])", 1),
+
+ Val("+1", big.NewInt(+1)),
+ Val("+1.0", big.NewRat(1, 1)),
+ Val("01.5", big.NewRat(15, 10)),
+ CErr("+\"x\"", opTypes),
+
+ Val("-42", big.NewInt(-42)),
+ Val("-i", -1),
+ Val("-f", -1.0),
+ // 6g bug?
+ //Val("-(f-1)", -0.0),
+ CErr("-\"x\"", opTypes),
+
+ // TODO(austin) Test unary !
+
+ Val("^2", big.NewInt(^2)),
+ Val("^(-2)", big.NewInt(^(-2))),
+ CErr("^2.0", opTypes),
+ CErr("^2.5", opTypes),
+ Val("^i", ^1),
+ Val("^u", ^uint(1)),
+ CErr("^f", opTypes),
+
+ Val("1+i", 2),
+ Val("1+u", uint(2)),
+ Val("3.0+i", 4),
+ Val("1+1", big.NewInt(2)),
+ Val("f+f", 2.0),
+ Val("1+f", 2.0),
+ Val("1.0+1", big.NewRat(2, 1)),
+ Val("\"abc\" + \"def\"", "abcdef"),
+ CErr("i+u", opTypes),
+ CErr("-1+u", constantUnderflows),
+ // TODO(austin) Test named types
+
+ Val("2-1", big.NewInt(1)),
+ Val("2.0-1", big.NewRat(1, 1)),
+ Val("f-2", -1.0),
+ Val("-0.0", big.NewRat(0, 1)),
+ Val("2*2", big.NewInt(4)),
+ Val("2*i", 2),
+ Val("3/2", big.NewInt(1)),
+ Val("3/i", 3),
+ CErr("1/0", divByZero),
+ CErr("1.0/0", divByZero),
+ RErr("i/0", divByZero),
+ Val("3%2", big.NewInt(1)),
+ Val("i%2", 1),
+ CErr("3%0", divByZero),
+ CErr("3.0%0", opTypes),
+ RErr("i%0", divByZero),
+
+ // Examples from "Arithmetic operators"
+ Val("5/3", big.NewInt(1)),
+ Val("(i+4)/(i+2)", 1),
+ Val("5%3", big.NewInt(2)),
+ Val("(i+4)%(i+2)", 2),
+ Val("-5/3", big.NewInt(-1)),
+ Val("(i-6)/(i+2)", -1),
+ Val("-5%3", big.NewInt(-2)),
+ Val("(i-6)%(i+2)", -2),
+ Val("5/-3", big.NewInt(-1)),
+ Val("(i+4)/(i-4)", -1),
+ Val("5%-3", big.NewInt(2)),
+ Val("(i+4)%(i-4)", 2),
+ Val("-5/-3", big.NewInt(1)),
+ Val("(i-6)/(i-4)", 1),
+ Val("-5%-3", big.NewInt(-2)),
+ Val("(i-6)%(i-4)", -2),
+
+ // Examples from "Arithmetic operators"
+ Val("11/4", big.NewInt(2)),
+ Val("(i+10)/4", 2),
+ Val("11%4", big.NewInt(3)),
+ Val("(i+10)%4", 3),
+ Val("11>>2", big.NewInt(2)),
+ Val("(i+10)>>2", 2),
+ Val("11&3", big.NewInt(3)),
+ Val("(i+10)&3", 3),
+ Val("-11/4", big.NewInt(-2)),
+ Val("(i-12)/4", -2),
+ Val("-11%4", big.NewInt(-3)),
+ Val("(i-12)%4", -3),
+ Val("-11>>2", big.NewInt(-3)),
+ Val("(i-12)>>2", -3),
+ Val("-11&3", big.NewInt(1)),
+ Val("(i-12)&3", 1),
+
+ // TODO(austin) Test bit ops
+
+ // For shift, we try nearly every combination of positive
+ // ideal int, negative ideal int, big ideal int, ideal
+ // fractional float, ideal non-fractional float, int, uint,
+ // and float.
+ Val("2<<2", big.NewInt(2<<2)),
+ CErr("2<<(-1)", constantUnderflows),
+ CErr("2<<0x10000000000000000", constantOverflows),
+ CErr("2<<2.5", constantTruncated),
+ Val("2<<2.0", big.NewInt(2<<2.0)),
+ CErr("2<<i", mustBeUnsigned),
+ Val("2<<u", 2<<1),
+ CErr("2<<f", opTypes),
+
+ Val("-2<<2", big.NewInt(-2<<2)),
+ CErr("-2<<(-1)", constantUnderflows),
+ CErr("-2<<0x10000000000000000", constantOverflows),
+ CErr("-2<<2.5", constantTruncated),
+ Val("-2<<2.0", big.NewInt(-2<<2.0)),
+ CErr("-2<<i", mustBeUnsigned),
+ Val("-2<<u", -2<<1),
+ CErr("-2<<f", opTypes),
+
+ Val("0x10000000000000000<<2", new(big.Int).Lsh(hugeInteger, 2)),
+ CErr("0x10000000000000000<<(-1)", constantUnderflows),
+ CErr("0x10000000000000000<<0x10000000000000000", constantOverflows),
+ CErr("0x10000000000000000<<2.5", constantTruncated),
+ Val("0x10000000000000000<<2.0", new(big.Int).Lsh(hugeInteger, 2)),
+ CErr("0x10000000000000000<<i", mustBeUnsigned),
+ CErr("0x10000000000000000<<u", constantOverflows),
+ CErr("0x10000000000000000<<f", opTypes),
+
+ CErr("2.5<<2", opTypes),
+ CErr("2.0<<2", opTypes),
+
+ Val("i<<2", 1<<2),
+ CErr("i<<(-1)", constantUnderflows),
+ CErr("i<<0x10000000000000000", constantOverflows),
+ CErr("i<<2.5", constantTruncated),
+ Val("i<<2.0", 1<<2),
+ CErr("i<<i", mustBeUnsigned),
+ Val("i<<u", 1<<1),
+ CErr("i<<f", opTypes),
+ Val("i<<u", 1<<1),
+
+ Val("u<<2", uint(1<<2)),
+ CErr("u<<(-1)", constantUnderflows),
+ CErr("u<<0x10000000000000000", constantOverflows),
+ CErr("u<<2.5", constantTruncated),
+ Val("u<<2.0", uint(1<<2)),
+ CErr("u<<i", mustBeUnsigned),
+ Val("u<<u", uint(1<<1)),
+ CErr("u<<f", opTypes),
+ Val("u<<u", uint(1<<1)),
+
+ CErr("f<<2", opTypes),
+
+ // <, <=, >, >=
+ Val("1<2", 1 < 2),
+ Val("1<=2", 1 <= 2),
+ Val("2<=2", 2 <= 2),
+ Val("1>2", 1 > 2),
+ Val("1>=2", 1 >= 2),
+ Val("2>=2", 2 >= 2),
+
+ Val("i<2", 1 < 2),
+ Val("i<=2", 1 <= 2),
+ Val("i+1<=2", 2 <= 2),
+ Val("i>2", 1 > 2),
+ Val("i>=2", 1 >= 2),
+ Val("i+1>=2", 2 >= 2),
+
+ Val("u<2", 1 < 2),
+ Val("f<2", 1 < 2),
+
+ Val("s<\"b\"", true),
+ Val("s<\"a\"", false),
+ Val("s<=\"abc\"", true),
+ Val("s>\"aa\"", true),
+ Val("s>\"ac\"", false),
+ Val("s>=\"abc\"", true),
+
+ CErr("i<u", opTypes),
+ CErr("i<f", opTypes),
+ CErr("i<s", opTypes),
+ CErr("&i<&i", opTypes),
+ CErr("ai<ai", opTypes),
+
+ // ==, !=
+ Val("1==1", true),
+ Val("1!=1", false),
+ Val("1==2", false),
+ Val("1!=2", true),
+
+ Val("1.0==1", true),
+ Val("1.5==1", false),
+
+ Val("i==1", true),
+ Val("i!=1", false),
+ Val("i==2", false),
+ Val("i!=2", true),
+
+ Val("u==1", true),
+ Val("f==1", true),
+
+ Val("s==\"abc\"", true),
+ Val("s!=\"abc\"", false),
+ Val("s==\"abcd\"", false),
+ Val("s!=\"abcd\"", true),
+
+ Val("&i==&i", true),
+ Val("&i==&i2", false),
+
+ Val("fn==fn", true),
+ Val("fn==func(int)int{return 0}", false),
+
+ CErr("i==u", opTypes),
+ CErr("i==f", opTypes),
+ CErr("&i==&f", opTypes),
+ CErr("ai==ai", opTypes),
+ CErr("t==t", opTypes),
+ CErr("fn==oneTwo", opTypes),
+}
+
+func TestExpr(t *testing.T) { runTests(t, "exprTests", exprTests) }
diff --git a/libgo/go/exp/eval/func.go b/libgo/go/exp/eval/func.go
new file mode 100644
index 000000000..cb1b579e4
--- /dev/null
+++ b/libgo/go/exp/eval/func.go
@@ -0,0 +1,70 @@
+// 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 eval
+
+import "os"
+
+/*
+ * Virtual machine
+ */
+
+type Thread struct {
+ abort chan os.Error
+ pc uint
+ // The execution frame of this function. This remains the
+ // same throughout a function invocation.
+ f *Frame
+}
+
+type code []func(*Thread)
+
+func (i code) exec(t *Thread) {
+ opc := t.pc
+ t.pc = 0
+ l := uint(len(i))
+ for t.pc < l {
+ pc := t.pc
+ t.pc++
+ i[pc](t)
+ }
+ t.pc = opc
+}
+
+/*
+ * Code buffer
+ */
+
+type codeBuf struct {
+ instrs code
+}
+
+func newCodeBuf() *codeBuf { return &codeBuf{make(code, 0, 16)} }
+
+func (b *codeBuf) push(instr func(*Thread)) {
+ b.instrs = append(b.instrs, instr)
+}
+
+func (b *codeBuf) nextPC() uint { return uint(len(b.instrs)) }
+
+func (b *codeBuf) get() code {
+ // Freeze this buffer into an array of exactly the right size
+ a := make(code, len(b.instrs))
+ copy(a, b.instrs)
+ return code(a)
+}
+
+/*
+ * User-defined functions
+ */
+
+type evalFunc struct {
+ outer *Frame
+ frameSize int
+ code code
+}
+
+func (f *evalFunc) NewFrame() *Frame { return f.outer.child(f.frameSize) }
+
+func (f *evalFunc) Call(t *Thread) { f.code.exec(t) }
diff --git a/libgo/go/exp/eval/scope.go b/libgo/go/exp/eval/scope.go
new file mode 100644
index 000000000..66305de25
--- /dev/null
+++ b/libgo/go/exp/eval/scope.go
@@ -0,0 +1,207 @@
+// 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 eval
+
+import (
+ "go/token"
+ "log"
+)
+
+/*
+ * Blocks and scopes
+ */
+
+// A definition can be a *Variable, *Constant, or Type.
+type Def interface {
+ Pos() token.Pos
+}
+
+type Variable struct {
+ VarPos token.Pos
+ // Index of this variable in the Frame structure
+ Index int
+ // Static type of this variable
+ Type Type
+ // Value of this variable. This is only used by Scope.NewFrame;
+ // therefore, it is useful for global scopes but cannot be used
+ // in function scopes.
+ Init Value
+}
+
+func (v *Variable) Pos() token.Pos {
+ return v.VarPos
+}
+
+type Constant struct {
+ ConstPos token.Pos
+ Type Type
+ Value Value
+}
+
+func (c *Constant) Pos() token.Pos {
+ return c.ConstPos
+}
+
+// A block represents a definition block in which a name may not be
+// defined more than once.
+type block struct {
+ // The block enclosing this one, including blocks in other
+ // scopes.
+ outer *block
+ // The nested block currently being compiled, or nil.
+ inner *block
+ // The Scope containing this block.
+ scope *Scope
+ // The Variables, Constants, and Types defined in this block.
+ defs map[string]Def
+ // The index of the first variable defined in this block.
+ // This must be greater than the index of any variable defined
+ // in any parent of this block within the same Scope at the
+ // time this block is entered.
+ offset int
+ // The number of Variables defined in this block.
+ numVars int
+ // If global, do not allocate new vars and consts in
+ // the frame; assume that the refs will be compiled in
+ // using defs[name].Init.
+ global bool
+}
+
+// A Scope is the compile-time analogue of a Frame, which captures
+// some subtree of blocks.
+type Scope struct {
+ // The root block of this scope.
+ *block
+ // The maximum number of variables required at any point in
+ // this Scope. This determines the number of slots needed in
+ // Frame's created from this Scope at run-time.
+ maxVars int
+}
+
+func (b *block) enterChild() *block {
+ if b.inner != nil && b.inner.scope == b.scope {
+ log.Panic("Failed to exit child block before entering another child")
+ }
+ sub := &block{
+ outer: b,
+ scope: b.scope,
+ defs: make(map[string]Def),
+ offset: b.offset + b.numVars,
+ }
+ b.inner = sub
+ return sub
+}
+
+func (b *block) exit() {
+ if b.outer == nil {
+ log.Panic("Cannot exit top-level block")
+ }
+ if b.outer.scope == b.scope {
+ if b.outer.inner != b {
+ log.Panic("Already exited block")
+ }
+ if b.inner != nil && b.inner.scope == b.scope {
+ log.Panic("Exit of parent block without exit of child block")
+ }
+ }
+ b.outer.inner = nil
+}
+
+func (b *block) ChildScope() *Scope {
+ if b.inner != nil && b.inner.scope == b.scope {
+ log.Panic("Failed to exit child block before entering a child scope")
+ }
+ sub := b.enterChild()
+ sub.offset = 0
+ sub.scope = &Scope{sub, 0}
+ return sub.scope
+}
+
+func (b *block) DefineVar(name string, pos token.Pos, t Type) (*Variable, Def) {
+ if prev, ok := b.defs[name]; ok {
+ return nil, prev
+ }
+ v := b.defineSlot(t, false)
+ v.VarPos = pos
+ b.defs[name] = v
+ return v, nil
+}
+
+func (b *block) DefineTemp(t Type) *Variable { return b.defineSlot(t, true) }
+
+func (b *block) defineSlot(t Type, temp bool) *Variable {
+ if b.inner != nil && b.inner.scope == b.scope {
+ log.Panic("Failed to exit child block before defining variable")
+ }
+ index := -1
+ if !b.global || temp {
+ index = b.offset + b.numVars
+ b.numVars++
+ if index >= b.scope.maxVars {
+ b.scope.maxVars = index + 1
+ }
+ }
+ v := &Variable{token.NoPos, index, t, nil}
+ return v
+}
+
+func (b *block) DefineConst(name string, pos token.Pos, t Type, v Value) (*Constant, Def) {
+ if prev, ok := b.defs[name]; ok {
+ return nil, prev
+ }
+ c := &Constant{pos, t, v}
+ b.defs[name] = c
+ return c, nil
+}
+
+func (b *block) DefineType(name string, pos token.Pos, t Type) Type {
+ if _, ok := b.defs[name]; ok {
+ return nil
+ }
+ nt := &NamedType{pos, name, nil, true, make(map[string]Method)}
+ if t != nil {
+ nt.Complete(t)
+ }
+ b.defs[name] = nt
+ return nt
+}
+
+func (b *block) Lookup(name string) (bl *block, level int, def Def) {
+ for b != nil {
+ if d, ok := b.defs[name]; ok {
+ return b, level, d
+ }
+ if b.outer != nil && b.scope != b.outer.scope {
+ level++
+ }
+ b = b.outer
+ }
+ return nil, 0, nil
+}
+
+func (s *Scope) NewFrame(outer *Frame) *Frame { return outer.child(s.maxVars) }
+
+/*
+ * Frames
+ */
+
+type Frame struct {
+ Outer *Frame
+ Vars []Value
+}
+
+func (f *Frame) Get(level int, index int) Value {
+ for ; level > 0; level-- {
+ f = f.Outer
+ }
+ return f.Vars[index]
+}
+
+func (f *Frame) child(numVars int) *Frame {
+ // TODO(austin) This is probably rather expensive. All values
+ // require heap allocation and zeroing them when we execute a
+ // definition typically requires some computation.
+ return &Frame{f, make([]Value, numVars)}
+}
diff --git a/libgo/go/exp/eval/stmt.go b/libgo/go/exp/eval/stmt.go
new file mode 100644
index 000000000..77ff066d0
--- /dev/null
+++ b/libgo/go/exp/eval/stmt.go
@@ -0,0 +1,1302 @@
+// 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 eval
+
+import (
+ "big"
+ "log"
+ "go/ast"
+ "go/token"
+)
+
+const (
+ returnPC = ^uint(0)
+ badPC = ^uint(1)
+)
+
+/*
+ * Statement compiler
+ */
+
+type stmtCompiler struct {
+ *blockCompiler
+ pos token.Pos
+ // This statement's label, or nil if it is not labeled.
+ stmtLabel *label
+}
+
+func (a *stmtCompiler) diag(format string, args ...interface{}) {
+ a.diagAt(a.pos, format, args...)
+}
+
+/*
+ * Flow checker
+ */
+
+type flowEnt struct {
+ // Whether this flow entry is conditional. If true, flow can
+ // continue to the next PC.
+ cond bool
+ // True if this will terminate flow (e.g., a return statement).
+ // cond must be false and jumps must be nil if this is true.
+ term bool
+ // PC's that can be reached from this flow entry.
+ jumps []*uint
+ // Whether this flow entry has been visited by reachesEnd.
+ visited bool
+}
+
+type flowBlock struct {
+ // If this is a goto, the target label.
+ target string
+ // The inner-most block containing definitions.
+ block *block
+ // The numVars from each block leading to the root of the
+ // scope, starting at block.
+ numVars []int
+}
+
+type flowBuf struct {
+ cb *codeBuf
+ // ents is a map from PC's to flow entries. Any PC missing
+ // from this map is assumed to reach only PC+1.
+ ents map[uint]*flowEnt
+ // gotos is a map from goto positions to information on the
+ // block at the point of the goto.
+ gotos map[token.Pos]*flowBlock
+ // labels is a map from label name to information on the block
+ // at the point of the label. labels are tracked by name,
+ // since mutliple labels at the same PC can have different
+ // blocks.
+ labels map[string]*flowBlock
+}
+
+func newFlowBuf(cb *codeBuf) *flowBuf {
+ return &flowBuf{cb, make(map[uint]*flowEnt), make(map[token.Pos]*flowBlock), make(map[string]*flowBlock)}
+}
+
+// put creates a flow control point for the next PC in the code buffer.
+// This should be done before pushing the instruction into the code buffer.
+func (f *flowBuf) put(cond bool, term bool, jumps []*uint) {
+ pc := f.cb.nextPC()
+ if ent, ok := f.ents[pc]; ok {
+ log.Panicf("Flow entry already exists at PC %d: %+v", pc, ent)
+ }
+ f.ents[pc] = &flowEnt{cond, term, jumps, false}
+}
+
+// putTerm creates a flow control point at the next PC that
+// unconditionally terminates execution.
+func (f *flowBuf) putTerm() { f.put(false, true, nil) }
+
+// put1 creates a flow control point at the next PC that jumps to one
+// PC and, if cond is true, can also continue to the PC following the
+// next PC.
+func (f *flowBuf) put1(cond bool, jumpPC *uint) {
+ f.put(cond, false, []*uint{jumpPC})
+}
+
+func newFlowBlock(target string, b *block) *flowBlock {
+ // Find the inner-most block containing definitions
+ for b.numVars == 0 && b.outer != nil && b.outer.scope == b.scope {
+ b = b.outer
+ }
+
+ // Count parents leading to the root of the scope
+ n := 0
+ for bp := b; bp.scope == b.scope; bp = bp.outer {
+ n++
+ }
+
+ // Capture numVars from each block to the root of the scope
+ numVars := make([]int, n)
+ i := 0
+ for bp := b; i < n; bp = bp.outer {
+ numVars[i] = bp.numVars
+ i++
+ }
+
+ return &flowBlock{target, b, numVars}
+}
+
+// putGoto captures the block at a goto statement. This should be
+// called in addition to putting a flow control point.
+func (f *flowBuf) putGoto(pos token.Pos, target string, b *block) {
+ f.gotos[pos] = newFlowBlock(target, b)
+}
+
+// putLabel captures the block at a label.
+func (f *flowBuf) putLabel(name string, b *block) {
+ f.labels[name] = newFlowBlock("", b)
+}
+
+// reachesEnd returns true if the end of f's code buffer can be
+// reached from the given program counter. Error reporting is the
+// caller's responsibility.
+func (f *flowBuf) reachesEnd(pc uint) bool {
+ endPC := f.cb.nextPC()
+ if pc > endPC {
+ log.Panicf("Reached bad PC %d past end PC %d", pc, endPC)
+ }
+
+ for ; pc < endPC; pc++ {
+ ent, ok := f.ents[pc]
+ if !ok {
+ continue
+ }
+
+ if ent.visited {
+ return false
+ }
+ ent.visited = true
+
+ if ent.term {
+ return false
+ }
+
+ // If anything can reach the end, we can reach the end
+ // from pc.
+ for _, j := range ent.jumps {
+ if f.reachesEnd(*j) {
+ return true
+ }
+ }
+ // If the jump was conditional, we can reach the next
+ // PC, so try reaching the end from it.
+ if ent.cond {
+ continue
+ }
+ return false
+ }
+ return true
+}
+
+// gotosObeyScopes returns true if no goto statement causes any
+// variables to come into scope that were not in scope at the point of
+// the goto. Reports any errors using the given compiler.
+func (f *flowBuf) gotosObeyScopes(a *compiler) {
+ for pos, src := range f.gotos {
+ tgt := f.labels[src.target]
+
+ // The target block must be a parent of this block
+ numVars := src.numVars
+ b := src.block
+ for len(numVars) > 0 && b != tgt.block {
+ b = b.outer
+ numVars = numVars[1:]
+ }
+ if b != tgt.block {
+ // We jumped into a deeper block
+ a.diagAt(pos, "goto causes variables to come into scope")
+ return
+ }
+
+ // There must be no variables in the target block that
+ // did not exist at the jump
+ tgtNumVars := tgt.numVars
+ for i := range numVars {
+ if tgtNumVars[i] > numVars[i] {
+ a.diagAt(pos, "goto causes variables to come into scope")
+ return
+ }
+ }
+ }
+}
+
+/*
+ * Statement generation helpers
+ */
+
+func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable {
+ v, prev := a.block.DefineVar(ident.Name, ident.Pos(), t)
+ if prev != nil {
+ if prev.Pos().IsValid() {
+ a.diagAt(ident.Pos(), "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Name, a.fset.Position(prev.Pos()))
+ } else {
+ a.diagAt(ident.Pos(), "variable %s redeclared in this block", ident.Name)
+ }
+ return nil
+ }
+
+ // Initialize the variable
+ index := v.Index
+ if v.Index >= 0 {
+ a.push(func(v *Thread) { v.f.Vars[index] = t.Zero() })
+ }
+ return v
+}
+
+// TODO(austin) Move doAssign to here
+
+/*
+ * Statement compiler
+ */
+
+func (a *stmtCompiler) compile(s ast.Stmt) {
+ if a.block.inner != nil {
+ log.Panic("Child scope still entered")
+ }
+
+ notimpl := false
+ switch s := s.(type) {
+ case *ast.BadStmt:
+ // Error already reported by parser.
+ a.silentErrors++
+
+ case *ast.DeclStmt:
+ a.compileDeclStmt(s)
+
+ case *ast.EmptyStmt:
+ // Do nothing.
+
+ case *ast.LabeledStmt:
+ a.compileLabeledStmt(s)
+
+ case *ast.ExprStmt:
+ a.compileExprStmt(s)
+
+ case *ast.IncDecStmt:
+ a.compileIncDecStmt(s)
+
+ case *ast.AssignStmt:
+ a.compileAssignStmt(s)
+
+ case *ast.GoStmt:
+ notimpl = true
+
+ case *ast.DeferStmt:
+ notimpl = true
+
+ case *ast.ReturnStmt:
+ a.compileReturnStmt(s)
+
+ case *ast.BranchStmt:
+ a.compileBranchStmt(s)
+
+ case *ast.BlockStmt:
+ a.compileBlockStmt(s)
+
+ case *ast.IfStmt:
+ a.compileIfStmt(s)
+
+ case *ast.CaseClause:
+ a.diag("case clause outside switch")
+
+ case *ast.SwitchStmt:
+ a.compileSwitchStmt(s)
+
+ case *ast.TypeCaseClause:
+ notimpl = true
+
+ case *ast.TypeSwitchStmt:
+ notimpl = true
+
+ case *ast.CommClause:
+ notimpl = true
+
+ case *ast.SelectStmt:
+ notimpl = true
+
+ case *ast.ForStmt:
+ a.compileForStmt(s)
+
+ case *ast.RangeStmt:
+ notimpl = true
+
+ default:
+ log.Panicf("unexpected ast node type %T", s)
+ }
+
+ if notimpl {
+ a.diag("%T statment node not implemented", s)
+ }
+
+ if a.block.inner != nil {
+ log.Panic("Forgot to exit child scope")
+ }
+}
+
+func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) {
+ switch decl := s.Decl.(type) {
+ case *ast.BadDecl:
+ // Do nothing. Already reported by parser.
+ a.silentErrors++
+
+ case *ast.FuncDecl:
+ if !a.block.global {
+ log.Panic("FuncDecl at statement level")
+ }
+
+ case *ast.GenDecl:
+ if decl.Tok == token.IMPORT && !a.block.global {
+ log.Panic("import at statement level")
+ }
+
+ default:
+ log.Panicf("Unexpected Decl type %T", s.Decl)
+ }
+ a.compileDecl(s.Decl)
+}
+
+func (a *stmtCompiler) compileVarDecl(decl *ast.GenDecl) {
+ for _, spec := range decl.Specs {
+ spec := spec.(*ast.ValueSpec)
+ if spec.Values == nil {
+ // Declaration without assignment
+ if spec.Type == nil {
+ // Parser should have caught
+ log.Panic("Type and Values nil")
+ }
+ t := a.compileType(a.block, spec.Type)
+ // Define placeholders even if type compile failed
+ for _, n := range spec.Names {
+ a.defineVar(n, t)
+ }
+ } else {
+ // Declaration with assignment
+ lhs := make([]ast.Expr, len(spec.Names))
+ for i, n := range spec.Names {
+ lhs[i] = n
+ }
+ a.doAssign(lhs, spec.Values, decl.Tok, spec.Type)
+ }
+ }
+}
+
+func (a *stmtCompiler) compileDecl(decl ast.Decl) {
+ switch d := decl.(type) {
+ case *ast.BadDecl:
+ // Do nothing. Already reported by parser.
+ a.silentErrors++
+
+ case *ast.FuncDecl:
+ decl := a.compileFuncType(a.block, d.Type)
+ if decl == nil {
+ return
+ }
+ // Declare and initialize v before compiling func
+ // so that body can refer to itself.
+ c, prev := a.block.DefineConst(d.Name.Name, a.pos, decl.Type, decl.Type.Zero())
+ if prev != nil {
+ pos := prev.Pos()
+ if pos.IsValid() {
+ a.diagAt(d.Name.Pos(), "identifier %s redeclared in this block\n\tprevious declaration at %s", d.Name.Name, a.fset.Position(pos))
+ } else {
+ a.diagAt(d.Name.Pos(), "identifier %s redeclared in this block", d.Name.Name)
+ }
+ }
+ fn := a.compileFunc(a.block, decl, d.Body)
+ if c == nil || fn == nil {
+ return
+ }
+ var zeroThread Thread
+ c.Value.(FuncValue).Set(nil, fn(&zeroThread))
+
+ case *ast.GenDecl:
+ switch d.Tok {
+ case token.IMPORT:
+ log.Panicf("%v not implemented", d.Tok)
+ case token.CONST:
+ log.Panicf("%v not implemented", d.Tok)
+ case token.TYPE:
+ a.compileTypeDecl(a.block, d)
+ case token.VAR:
+ a.compileVarDecl(d)
+ }
+
+ default:
+ log.Panicf("Unexpected Decl type %T", decl)
+ }
+}
+
+func (a *stmtCompiler) compileLabeledStmt(s *ast.LabeledStmt) {
+ // Define label
+ l, ok := a.labels[s.Label.Name]
+ if ok {
+ if l.resolved.IsValid() {
+ a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Name, a.fset.Position(l.resolved))
+ }
+ } else {
+ pc := badPC
+ l = &label{name: s.Label.Name, gotoPC: &pc}
+ a.labels[l.name] = l
+ }
+ l.desc = "regular label"
+ l.resolved = s.Pos()
+
+ // Set goto PC
+ *l.gotoPC = a.nextPC()
+
+ // Define flow entry so we can check for jumps over declarations.
+ a.flow.putLabel(l.name, a.block)
+
+ // Compile the statement. Reuse our stmtCompiler for simplicity.
+ sc := &stmtCompiler{a.blockCompiler, s.Stmt.Pos(), l}
+ sc.compile(s.Stmt)
+}
+
+func (a *stmtCompiler) compileExprStmt(s *ast.ExprStmt) {
+ bc := a.enterChild()
+ defer bc.exit()
+
+ e := a.compileExpr(bc.block, false, s.X)
+ if e == nil {
+ return
+ }
+
+ if e.exec == nil {
+ a.diag("%s cannot be used as expression statement", e.desc)
+ return
+ }
+
+ a.push(e.exec)
+}
+
+func (a *stmtCompiler) compileIncDecStmt(s *ast.IncDecStmt) {
+ // Create temporary block for extractEffect
+ bc := a.enterChild()
+ defer bc.exit()
+
+ l := a.compileExpr(bc.block, false, s.X)
+ if l == nil {
+ return
+ }
+
+ if l.evalAddr == nil {
+ l.diag("cannot assign to %s", l.desc)
+ return
+ }
+ if !(l.t.isInteger() || l.t.isFloat()) {
+ l.diagOpType(s.Tok, l.t)
+ return
+ }
+
+ var op token.Token
+ var desc string
+ switch s.Tok {
+ case token.INC:
+ op = token.ADD
+ desc = "increment statement"
+ case token.DEC:
+ op = token.SUB
+ desc = "decrement statement"
+ default:
+ log.Panicf("Unexpected IncDec token %v", s.Tok)
+ }
+
+ effect, l := l.extractEffect(bc.block, desc)
+
+ one := l.newExpr(IdealIntType, "constant")
+ one.pos = s.Pos()
+ one.eval = func() *big.Int { return big.NewInt(1) }
+
+ binop := l.compileBinaryExpr(op, l, one)
+ if binop == nil {
+ return
+ }
+
+ assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "", "")
+ if assign == nil {
+ log.Panicf("compileAssign type check failed")
+ }
+
+ lf := l.evalAddr
+ a.push(func(v *Thread) {
+ effect(v)
+ assign(lf(v), v)
+ })
+}
+
+func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, declTypeExpr ast.Expr) {
+ nerr := a.numError()
+
+ // Compile right side first so we have the types when
+ // compiling the left side and so we don't see definitions
+ // made on the left side.
+ rs := make([]*expr, len(rhs))
+ for i, re := range rhs {
+ rs[i] = a.compileExpr(a.block, false, re)
+ }
+
+ errOp := "assignment"
+ if tok == token.DEFINE || tok == token.VAR {
+ errOp = "declaration"
+ }
+ ac, ok := a.checkAssign(a.pos, rs, errOp, "value")
+ ac.allowMapForms(len(lhs))
+
+ // If this is a definition and the LHS is too big, we won't be
+ // able to produce the usual error message because we can't
+ // begin to infer the types of the LHS.
+ if (tok == token.DEFINE || tok == token.VAR) && len(lhs) > len(ac.rmt.Elems) {
+ a.diag("not enough values for definition")
+ }
+
+ // Compile left type if there is one
+ var declType Type
+ if declTypeExpr != nil {
+ declType = a.compileType(a.block, declTypeExpr)
+ }
+
+ // Compile left side
+ ls := make([]*expr, len(lhs))
+ nDefs := 0
+ for i, le := range lhs {
+ // If this is a definition, get the identifier and its type
+ var ident *ast.Ident
+ var lt Type
+ switch tok {
+ case token.DEFINE:
+ // Check that it's an identifier
+ ident, ok = le.(*ast.Ident)
+ if !ok {
+ a.diagAt(le.Pos(), "left side of := must be a name")
+ // Suppress new defitions errors
+ nDefs++
+ continue
+ }
+
+ // Is this simply an assignment?
+ if _, ok := a.block.defs[ident.Name]; ok {
+ ident = nil
+ break
+ }
+ nDefs++
+
+ case token.VAR:
+ ident = le.(*ast.Ident)
+ }
+
+ // If it's a definition, get or infer its type.
+ if ident != nil {
+ // Compute the identifier's type from the RHS
+ // type. We use the computed MultiType so we
+ // don't have to worry about unpacking.
+ switch {
+ case declTypeExpr != nil:
+ // We have a declaration type, use it.
+ // If declType is nil, we gave an
+ // error when we compiled it.
+ lt = declType
+
+ case i >= len(ac.rmt.Elems):
+ // Define a placeholder. We already
+ // gave the "not enough" error above.
+ lt = nil
+
+ case ac.rmt.Elems[i] == nil:
+ // We gave the error when we compiled
+ // the RHS.
+ lt = nil
+
+ case ac.rmt.Elems[i].isIdeal():
+ // If the type is absent and the
+ // corresponding expression is a
+ // constant expression of ideal
+ // integer or ideal float type, the
+ // type of the declared variable is
+ // int or float respectively.
+ switch {
+ case ac.rmt.Elems[i].isInteger():
+ lt = IntType
+ case ac.rmt.Elems[i].isFloat():
+ lt = Float64Type
+ default:
+ log.Panicf("unexpected ideal type %v", rs[i].t)
+ }
+
+ default:
+ lt = ac.rmt.Elems[i]
+ }
+ }
+
+ // If it's a definition, define the identifier
+ if ident != nil {
+ if a.defineVar(ident, lt) == nil {
+ continue
+ }
+ }
+
+ // Compile LHS
+ ls[i] = a.compileExpr(a.block, false, le)
+ if ls[i] == nil {
+ continue
+ }
+
+ if ls[i].evalMapValue != nil {
+ // Map indexes are not generally addressable,
+ // but they are assignable.
+ //
+ // TODO(austin) Now that the expression
+ // compiler uses semantic values, this might
+ // be easier to implement as a function call.
+ sub := ls[i]
+ ls[i] = ls[i].newExpr(sub.t, sub.desc)
+ ls[i].evalMapValue = sub.evalMapValue
+ mvf := sub.evalMapValue
+ et := sub.t
+ ls[i].evalAddr = func(t *Thread) Value {
+ m, k := mvf(t)
+ e := m.Elem(t, k)
+ if e == nil {
+ e = et.Zero()
+ m.SetElem(t, k, e)
+ }
+ return e
+ }
+ } else if ls[i].evalAddr == nil {
+ ls[i].diag("cannot assign to %s", ls[i].desc)
+ continue
+ }
+ }
+
+ // A short variable declaration may redeclare variables
+ // provided they were originally declared in the same block
+ // with the same type, and at least one of the variables is
+ // new.
+ if tok == token.DEFINE && nDefs == 0 {
+ a.diag("at least one new variable must be declared")
+ return
+ }
+
+ // If there have been errors, our arrays are full of nil's so
+ // get out of here now.
+ if nerr != a.numError() {
+ return
+ }
+
+ // Check for 'a[x] = r, ok'
+ if len(ls) == 1 && len(rs) == 2 && ls[0].evalMapValue != nil {
+ a.diag("a[x] = r, ok form not implemented")
+ return
+ }
+
+ // Create assigner
+ var lt Type
+ n := len(lhs)
+ if n == 1 {
+ lt = ls[0].t
+ } else {
+ lts := make([]Type, len(ls))
+ for i, l := range ls {
+ if l != nil {
+ lts[i] = l.t
+ }
+ }
+ lt = NewMultiType(lts)
+ }
+ bc := a.enterChild()
+ defer bc.exit()
+ assign := ac.compile(bc.block, lt)
+ if assign == nil {
+ return
+ }
+
+ // Compile
+ if n == 1 {
+ // Don't need temporaries and can avoid []Value.
+ lf := ls[0].evalAddr
+ a.push(func(t *Thread) { assign(lf(t), t) })
+ } else if tok == token.VAR || (tok == token.DEFINE && nDefs == n) {
+ // Don't need temporaries
+ lfs := make([]func(*Thread) Value, n)
+ for i, l := range ls {
+ lfs[i] = l.evalAddr
+ }
+ a.push(func(t *Thread) {
+ dest := make([]Value, n)
+ for i, lf := range lfs {
+ dest[i] = lf(t)
+ }
+ assign(multiV(dest), t)
+ })
+ } else {
+ // Need temporaries
+ lmt := lt.(*MultiType)
+ lfs := make([]func(*Thread) Value, n)
+ for i, l := range ls {
+ lfs[i] = l.evalAddr
+ }
+ a.push(func(t *Thread) {
+ temp := lmt.Zero().(multiV)
+ assign(temp, t)
+ // Copy to destination
+ for i := 0; i < n; i++ {
+ // TODO(austin) Need to evaluate LHS
+ // before RHS
+ lfs[i](t).Assign(t, temp[i])
+ }
+ })
+ }
+}
+
+var assignOpToOp = map[token.Token]token.Token{
+ token.ADD_ASSIGN: token.ADD,
+ token.SUB_ASSIGN: token.SUB,
+ token.MUL_ASSIGN: token.MUL,
+ token.QUO_ASSIGN: token.QUO,
+ token.REM_ASSIGN: token.REM,
+
+ token.AND_ASSIGN: token.AND,
+ token.OR_ASSIGN: token.OR,
+ token.XOR_ASSIGN: token.XOR,
+ token.SHL_ASSIGN: token.SHL,
+ token.SHR_ASSIGN: token.SHR,
+ token.AND_NOT_ASSIGN: token.AND_NOT,
+}
+
+func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
+ if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
+ a.diag("tuple assignment cannot be combined with an arithmetic operation")
+ return
+ }
+
+ // Create temporary block for extractEffect
+ bc := a.enterChild()
+ defer bc.exit()
+
+ l := a.compileExpr(bc.block, false, s.Lhs[0])
+ r := a.compileExpr(bc.block, false, s.Rhs[0])
+ if l == nil || r == nil {
+ return
+ }
+
+ if l.evalAddr == nil {
+ l.diag("cannot assign to %s", l.desc)
+ return
+ }
+
+ effect, l := l.extractEffect(bc.block, "operator-assignment")
+
+ binop := r.compileBinaryExpr(assignOpToOp[s.Tok], l, r)
+ if binop == nil {
+ return
+ }
+
+ assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "assignment", "value")
+ if assign == nil {
+ log.Panicf("compileAssign type check failed")
+ }
+
+ lf := l.evalAddr
+ a.push(func(t *Thread) {
+ effect(t)
+ assign(lf(t), t)
+ })
+}
+
+func (a *stmtCompiler) compileAssignStmt(s *ast.AssignStmt) {
+ switch s.Tok {
+ case token.ASSIGN, token.DEFINE:
+ a.doAssign(s.Lhs, s.Rhs, s.Tok, nil)
+
+ default:
+ a.doAssignOp(s)
+ }
+}
+
+func (a *stmtCompiler) compileReturnStmt(s *ast.ReturnStmt) {
+ if a.fnType == nil {
+ a.diag("cannot return at the top level")
+ return
+ }
+
+ if len(s.Results) == 0 && (len(a.fnType.Out) == 0 || a.outVarsNamed) {
+ // Simple case. Simply exit from the function.
+ a.flow.putTerm()
+ a.push(func(v *Thread) { v.pc = returnPC })
+ return
+ }
+
+ bc := a.enterChild()
+ defer bc.exit()
+
+ // Compile expressions
+ bad := false
+ rs := make([]*expr, len(s.Results))
+ for i, re := range s.Results {
+ rs[i] = a.compileExpr(bc.block, false, re)
+ if rs[i] == nil {
+ bad = true
+ }
+ }
+ if bad {
+ return
+ }
+
+ // Create assigner
+
+ // However, if the expression list in the "return" statement
+ // is a single call to a multi-valued function, the values
+ // returned from the called function will be returned from
+ // this one.
+ assign := a.compileAssign(s.Pos(), bc.block, NewMultiType(a.fnType.Out), rs, "return", "value")
+
+ // XXX(Spec) "The result types of the current function and the
+ // called function must match." Match is fuzzy. It should
+ // say that they must be assignment compatible.
+
+ // Compile
+ start := len(a.fnType.In)
+ nout := len(a.fnType.Out)
+ a.flow.putTerm()
+ a.push(func(t *Thread) {
+ assign(multiV(t.f.Vars[start:start+nout]), t)
+ t.pc = returnPC
+ })
+}
+
+func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool, errOp, errCtx string) *label {
+ bc := a.blockCompiler
+ for ; bc != nil; bc = bc.parent {
+ if bc.label == nil {
+ continue
+ }
+ l := bc.label
+ if name == nil && pred(l) {
+ return l
+ }
+ if name != nil && l.name == name.Name {
+ if !pred(l) {
+ a.diag("cannot %s to %s %s", errOp, l.desc, l.name)
+ return nil
+ }
+ return l
+ }
+ }
+ if name == nil {
+ a.diag("%s outside %s", errOp, errCtx)
+ } else {
+ a.diag("%s label %s not defined", errOp, name.Name)
+ }
+ return nil
+}
+
+func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) {
+ var pc *uint
+
+ switch s.Tok {
+ case token.BREAK:
+ l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.breakPC != nil }, "break", "for loop, switch, or select")
+ if l == nil {
+ return
+ }
+ pc = l.breakPC
+
+ case token.CONTINUE:
+ l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.continuePC != nil }, "continue", "for loop")
+ if l == nil {
+ return
+ }
+ pc = l.continuePC
+
+ case token.GOTO:
+ l, ok := a.labels[s.Label.Name]
+ if !ok {
+ pc := badPC
+ l = &label{name: s.Label.Name, desc: "unresolved label", gotoPC: &pc, used: s.Pos()}
+ a.labels[l.name] = l
+ }
+
+ pc = l.gotoPC
+ a.flow.putGoto(s.Pos(), l.name, a.block)
+
+ case token.FALLTHROUGH:
+ a.diag("fallthrough outside switch")
+ return
+
+ default:
+ log.Panic("Unexpected branch token %v", s.Tok)
+ }
+
+ a.flow.put1(false, pc)
+ a.push(func(v *Thread) { v.pc = *pc })
+}
+
+func (a *stmtCompiler) compileBlockStmt(s *ast.BlockStmt) {
+ bc := a.enterChild()
+ bc.compileStmts(s)
+ bc.exit()
+}
+
+func (a *stmtCompiler) compileIfStmt(s *ast.IfStmt) {
+ // The scope of any variables declared by [the init] statement
+ // extends to the end of the "if" statement and the variables
+ // are initialized once before the statement is entered.
+ //
+ // XXX(Spec) What this really wants to say is that there's an
+ // implicit scope wrapping every if, for, and switch
+ // statement. This is subtly different from what it actually
+ // says when there's a non-block else clause, because that
+ // else claus has to execute in a scope that is *not* the
+ // surrounding scope.
+ bc := a.enterChild()
+ defer bc.exit()
+
+ // Compile init statement, if any
+ if s.Init != nil {
+ bc.compileStmt(s.Init)
+ }
+
+ elsePC := badPC
+ endPC := badPC
+
+ // Compile condition, if any. If there is no condition, we
+ // fall through to the body.
+ if s.Cond != nil {
+ e := bc.compileExpr(bc.block, false, s.Cond)
+ switch {
+ case e == nil:
+ // Error reported by compileExpr
+ case !e.t.isBoolean():
+ e.diag("'if' condition must be boolean\n\t%v", e.t)
+ default:
+ eval := e.asBool()
+ a.flow.put1(true, &elsePC)
+ a.push(func(t *Thread) {
+ if !eval(t) {
+ t.pc = elsePC
+ }
+ })
+ }
+ }
+
+ // Compile body
+ body := bc.enterChild()
+ body.compileStmts(s.Body)
+ body.exit()
+
+ // Compile else
+ if s.Else != nil {
+ // Skip over else if we executed the body
+ a.flow.put1(false, &endPC)
+ a.push(func(v *Thread) { v.pc = endPC })
+ elsePC = a.nextPC()
+ bc.compileStmt(s.Else)
+ } else {
+ elsePC = a.nextPC()
+ }
+ endPC = a.nextPC()
+}
+
+func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
+ // Create implicit scope around switch
+ bc := a.enterChild()
+ defer bc.exit()
+
+ // Compile init statement, if any
+ if s.Init != nil {
+ bc.compileStmt(s.Init)
+ }
+
+ // Compile condition, if any, and extract its effects
+ var cond *expr
+ condbc := bc.enterChild()
+ if s.Tag != nil {
+ e := condbc.compileExpr(condbc.block, false, s.Tag)
+ if e != nil {
+ var effect func(*Thread)
+ effect, cond = e.extractEffect(condbc.block, "switch")
+ a.push(effect)
+ }
+ }
+
+ // Count cases
+ ncases := 0
+ hasDefault := false
+ for _, c := range s.Body.List {
+ clause, ok := c.(*ast.CaseClause)
+ if !ok {
+ a.diagAt(clause.Pos(), "switch statement must contain case clauses")
+ continue
+ }
+ if clause.Values == nil {
+ if hasDefault {
+ a.diagAt(clause.Pos(), "switch statement contains more than one default case")
+ }
+ hasDefault = true
+ } else {
+ ncases += len(clause.Values)
+ }
+ }
+
+ // Compile case expressions
+ cases := make([]func(*Thread) bool, ncases)
+ i := 0
+ for _, c := range s.Body.List {
+ clause, ok := c.(*ast.CaseClause)
+ if !ok {
+ continue
+ }
+ for _, v := range clause.Values {
+ e := condbc.compileExpr(condbc.block, false, v)
+ switch {
+ case e == nil:
+ // Error reported by compileExpr
+ case cond == nil && !e.t.isBoolean():
+ a.diagAt(v.Pos(), "'case' condition must be boolean")
+ case cond == nil:
+ cases[i] = e.asBool()
+ case cond != nil:
+ // Create comparison
+ // TOOD(austin) This produces bad error messages
+ compare := e.compileBinaryExpr(token.EQL, cond, e)
+ if compare != nil {
+ cases[i] = compare.asBool()
+ }
+ }
+ i++
+ }
+ }
+
+ // Emit condition
+ casePCs := make([]*uint, ncases+1)
+ endPC := badPC
+
+ a.flow.put(false, false, casePCs)
+ a.push(func(t *Thread) {
+ for i, c := range cases {
+ if c(t) {
+ t.pc = *casePCs[i]
+ return
+ }
+ }
+ t.pc = *casePCs[ncases]
+ })
+ condbc.exit()
+
+ // Compile cases
+ i = 0
+ for _, c := range s.Body.List {
+ clause, ok := c.(*ast.CaseClause)
+ if !ok {
+ continue
+ }
+
+ // Save jump PC's
+ pc := a.nextPC()
+ if clause.Values != nil {
+ for _ = range clause.Values {
+ casePCs[i] = &pc
+ i++
+ }
+ } else {
+ // Default clause
+ casePCs[ncases] = &pc
+ }
+
+ // Compile body
+ fall := false
+ for j, s := range clause.Body {
+ if br, ok := s.(*ast.BranchStmt); ok && br.Tok == token.FALLTHROUGH {
+ // println("Found fallthrough");
+ // It may be used only as the final
+ // non-empty statement in a case or
+ // default clause in an expression
+ // "switch" statement.
+ for _, s2 := range clause.Body[j+1:] {
+ // XXX(Spec) 6g also considers
+ // empty blocks to be empty
+ // statements.
+ if _, ok := s2.(*ast.EmptyStmt); !ok {
+ a.diagAt(s.Pos(), "fallthrough statement must be final statement in case")
+ break
+ }
+ }
+ fall = true
+ } else {
+ bc.compileStmt(s)
+ }
+ }
+ // Jump out of switch, unless there was a fallthrough
+ if !fall {
+ a.flow.put1(false, &endPC)
+ a.push(func(v *Thread) { v.pc = endPC })
+ }
+ }
+
+ // Get end PC
+ endPC = a.nextPC()
+ if !hasDefault {
+ casePCs[ncases] = &endPC
+ }
+}
+
+func (a *stmtCompiler) compileForStmt(s *ast.ForStmt) {
+ // Wrap the entire for in a block.
+ bc := a.enterChild()
+ defer bc.exit()
+
+ // Compile init statement, if any
+ if s.Init != nil {
+ bc.compileStmt(s.Init)
+ }
+
+ bodyPC := badPC
+ postPC := badPC
+ checkPC := badPC
+ endPC := badPC
+
+ // Jump to condition check. We generate slightly less code by
+ // placing the condition check after the body.
+ a.flow.put1(false, &checkPC)
+ a.push(func(v *Thread) { v.pc = checkPC })
+
+ // Compile body
+ bodyPC = a.nextPC()
+ body := bc.enterChild()
+ if a.stmtLabel != nil {
+ body.label = a.stmtLabel
+ } else {
+ body.label = &label{resolved: s.Pos()}
+ }
+ body.label.desc = "for loop"
+ body.label.breakPC = &endPC
+ body.label.continuePC = &postPC
+ body.compileStmts(s.Body)
+ body.exit()
+
+ // Compile post, if any
+ postPC = a.nextPC()
+ if s.Post != nil {
+ // TODO(austin) Does the parser disallow short
+ // declarations in s.Post?
+ bc.compileStmt(s.Post)
+ }
+
+ // Compile condition check, if any
+ checkPC = a.nextPC()
+ if s.Cond == nil {
+ // If the condition is absent, it is equivalent to true.
+ a.flow.put1(false, &bodyPC)
+ a.push(func(v *Thread) { v.pc = bodyPC })
+ } else {
+ e := bc.compileExpr(bc.block, false, s.Cond)
+ switch {
+ case e == nil:
+ // Error reported by compileExpr
+ case !e.t.isBoolean():
+ a.diag("'for' condition must be boolean\n\t%v", e.t)
+ default:
+ eval := e.asBool()
+ a.flow.put1(true, &bodyPC)
+ a.push(func(t *Thread) {
+ if eval(t) {
+ t.pc = bodyPC
+ }
+ })
+ }
+ }
+
+ endPC = a.nextPC()
+}
+
+/*
+ * Block compiler
+ */
+
+func (a *blockCompiler) compileStmt(s ast.Stmt) {
+ sc := &stmtCompiler{a, s.Pos(), nil}
+ sc.compile(s)
+}
+
+func (a *blockCompiler) compileStmts(block *ast.BlockStmt) {
+ for _, sub := range block.List {
+ a.compileStmt(sub)
+ }
+}
+
+func (a *blockCompiler) enterChild() *blockCompiler {
+ block := a.block.enterChild()
+ return &blockCompiler{
+ funcCompiler: a.funcCompiler,
+ block: block,
+ parent: a,
+ }
+}
+
+func (a *blockCompiler) exit() { a.block.exit() }
+
+/*
+ * Function compiler
+ */
+
+func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) func(*Thread) Func {
+ // Create body scope
+ //
+ // The scope of a parameter or result is the body of the
+ // corresponding function.
+ bodyScope := b.ChildScope()
+ defer bodyScope.exit()
+ for i, t := range decl.Type.In {
+ if decl.InNames[i] != nil {
+ bodyScope.DefineVar(decl.InNames[i].Name, decl.InNames[i].Pos(), t)
+ } else {
+ bodyScope.DefineTemp(t)
+ }
+ }
+ for i, t := range decl.Type.Out {
+ if decl.OutNames[i] != nil {
+ bodyScope.DefineVar(decl.OutNames[i].Name, decl.OutNames[i].Pos(), t)
+ } else {
+ bodyScope.DefineTemp(t)
+ }
+ }
+
+ // Create block context
+ cb := newCodeBuf()
+ fc := &funcCompiler{
+ compiler: a,
+ fnType: decl.Type,
+ outVarsNamed: len(decl.OutNames) > 0 && decl.OutNames[0] != nil,
+ codeBuf: cb,
+ flow: newFlowBuf(cb),
+ labels: make(map[string]*label),
+ }
+ bc := &blockCompiler{
+ funcCompiler: fc,
+ block: bodyScope.block,
+ }
+
+ // Compile body
+ nerr := a.numError()
+ bc.compileStmts(body)
+ fc.checkLabels()
+ if nerr != a.numError() {
+ return nil
+ }
+
+ // Check that the body returned if necessary. We only check
+ // this if there were no errors compiling the body.
+ if len(decl.Type.Out) > 0 && fc.flow.reachesEnd(0) {
+ // XXX(Spec) Not specified.
+ a.diagAt(body.Rbrace, "function ends without a return statement")
+ return nil
+ }
+
+ code := fc.get()
+ maxVars := bodyScope.maxVars
+ return func(t *Thread) Func { return &evalFunc{t.f, maxVars, code} }
+}
+
+// Checks that labels were resolved and that all jumps obey scoping
+// rules. Reports an error and set fc.err if any check fails.
+func (a *funcCompiler) checkLabels() {
+ nerr := a.numError()
+ for _, l := range a.labels {
+ if !l.resolved.IsValid() {
+ a.diagAt(l.used, "label %s not defined", l.name)
+ }
+ }
+ if nerr != a.numError() {
+ // Don't check scopes if we have unresolved labels
+ return
+ }
+
+ // Executing the "goto" statement must not cause any variables
+ // to come into scope that were not already in scope at the
+ // point of the goto.
+ a.flow.gotosObeyScopes(a.compiler)
+}
diff --git a/libgo/go/exp/eval/stmt_test.go b/libgo/go/exp/eval/stmt_test.go
new file mode 100644
index 000000000..a14a288d9
--- /dev/null
+++ b/libgo/go/exp/eval/stmt_test.go
@@ -0,0 +1,343 @@
+// 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 eval
+
+import "testing"
+
+var atLeastOneDecl = "at least one new variable must be declared"
+
+var stmtTests = []test{
+ // Short declarations
+ Val1("x := i", "x", 1),
+ Val1("x := f", "x", 1.0),
+ // Type defaulting
+ Val1("a := 42", "a", 42),
+ Val1("a := 1.0", "a", 1.0),
+ // Parallel assignment
+ Val2("a, b := 1, 2", "a", 1, "b", 2),
+ Val2("a, i := 1, 2", "a", 1, "i", 2),
+ CErr("a, i := 1, f", opTypes),
+ CErr("a, b := 1, 2, 3", "too many"),
+ CErr("a := 1, 2", "too many"),
+ CErr("a, b := 1", "not enough"),
+ // Mixed declarations
+ CErr("i := 1", atLeastOneDecl),
+ CErr("i, u := 1, 2", atLeastOneDecl),
+ Val2("i, x := 2, f", "i", 2, "x", 1.0),
+ // Various errors
+ CErr("1 := 2", "left side of := must be a name"),
+ CErr("c, a := 1, 1", "cannot assign"),
+ // Unpacking
+ Val2("x, y := oneTwo()", "x", 1, "y", 2),
+ CErr("x := oneTwo()", "too many"),
+ CErr("x, y, z := oneTwo()", "not enough"),
+ CErr("x, y := oneTwo(), 2", "multi-valued"),
+ CErr("x := oneTwo()+2", opTypes),
+ // TOOD(austin) This error message is weird
+ CErr("x := void()", "not enough"),
+ // Placeholders
+ CErr("x := 1+\"x\"; i=x+1", opTypes),
+
+ // Assignment
+ Val1("i = 2", "i", 2),
+ Val1("(i) = 2", "i", 2),
+ CErr("1 = 2", "cannot assign"),
+ CErr("1-1 = 2", "- expression"),
+ Val1("i = 2.0", "i", 2),
+ CErr("i = 2.2", constantTruncated),
+ CErr("u = -2", constantUnderflows),
+ CErr("i = f", opTypes),
+ CErr("i, u = 0, f", opTypes),
+ CErr("i, u = 0, f", "value 2"),
+ Val2("i, i2 = i2, i", "i", 2, "i2", 1),
+ CErr("c = 1", "cannot assign"),
+
+ Val1("x := &i; *x = 2", "i", 2),
+
+ Val1("ai[0] = 42", "ai", varray{42, 2}),
+ Val1("aai[1] = ai; ai[0] = 42", "aai", varray{varray{1, 2}, varray{1, 2}}),
+ Val1("aai = aai2", "aai", varray{varray{5, 6}, varray{7, 8}}),
+
+ // Assignment conversions
+ Run("var sl []int; sl = &ai"),
+ CErr("type ST []int; type AT *[2]int; var x AT = &ai; var y ST = x", opTypes),
+ Run("type ST []int; var y ST = &ai"),
+ Run("type AT *[2]int; var x AT = &ai; var y []int = x"),
+
+ // Op-assignment
+ Val1("i += 2", "i", 3),
+ Val("i", 1),
+ Val1("f += 2", "f", 3.0),
+ CErr("2 += 2", "cannot assign"),
+ CErr("i, j += 2", "cannot be combined"),
+ CErr("i += 2, 3", "cannot be combined"),
+ Val2("s2 := s; s += \"def\"", "s2", "abc", "s", "abcdef"),
+ CErr("s += 1", opTypes),
+ // Single evaluation
+ Val2("ai[func()int{i+=1;return 0}()] *= 3; i2 = ai[0]", "i", 2, "i2", 3),
+
+ // Type declarations
+ // Identifiers
+ Run("type T int"),
+ CErr("type T x", "undefined"),
+ CErr("type T c", "constant"),
+ CErr("type T i", "variable"),
+ CErr("type T T", "recursive"),
+ CErr("type T x; type U T; var v U; v = 1", "undefined"),
+ // Pointer types
+ Run("type T *int"),
+ Run("type T *T"),
+ // Array types
+ Run("type T [5]int"),
+ Run("type T [c+42/2]int"),
+ Run("type T [2.0]int"),
+ CErr("type T [i]int", "constant expression"),
+ CErr("type T [2.5]int", constantTruncated),
+ CErr("type T [-1]int", "negative"),
+ CErr("type T [2]T", "recursive"),
+ // Struct types
+ Run("type T struct { a int; b int }"),
+ Run("type T struct { a int; int }"),
+ Run("type T struct { x *T }"),
+ Run("type T int; type U struct { T }"),
+ CErr("type T *int; type U struct { T }", "embedded.*pointer"),
+ CErr("type T *struct { T }", "embedded.*pointer"),
+ CErr("type T struct { a int; a int }", " a .*redeclared.*:1:17"),
+ CErr("type T struct { int; int }", "int .*redeclared.*:1:17"),
+ CErr("type T struct { int int; int }", "int .*redeclared.*:1:17"),
+ Run("type T struct { x *struct { T } }"),
+ CErr("type T struct { x struct { T } }", "recursive"),
+ CErr("type T struct { x }; type U struct { T }", "undefined"),
+ // Function types
+ Run("type T func()"),
+ Run("type T func(a, b int) int"),
+ Run("type T func(a, b int) (x int, y int)"),
+ Run("type T func(a, a int) (a int, a int)"),
+ Run("type T func(a, b int) (x, y int)"),
+ Run("type T func(int, int) (int, int)"),
+ CErr("type T func(x); type U T", "undefined"),
+ CErr("type T func(a T)", "recursive"),
+ // Interface types
+ Run("type T interface {x(a, b int) int}"),
+ Run("type T interface {x(a, b int) int}; type U interface {T; y(c int)}"),
+ CErr("type T interface {x(a int); x()}", "method x redeclared"),
+ CErr("type T interface {x()}; type U interface {T; x()}", "method x redeclared"),
+ CErr("type T int; type U interface {T}", "embedded type"),
+ // Parens
+ Run("type T (int)"),
+
+ // Variable declarations
+ Val2("var x int", "i", 1, "x", 0),
+ Val1("var x = 1", "x", 1),
+ Val1("var x = 1.0", "x", 1.0),
+ Val1("var x int = 1.0", "x", 1),
+ // Placeholders
+ CErr("var x foo; x = 1", "undefined"),
+ CErr("var x foo = 1; x = 1", "undefined"),
+ // Redeclaration
+ CErr("var i, x int", " i .*redeclared"),
+ CErr("var x int; var x int", " x .*redeclared.*:1:5"),
+
+ // Expression statements
+ CErr("x := func(){ 1-1 }", "expression statement"),
+ CErr("x := func(){ 1-1 }", "- expression"),
+ Val1("fn(2)", "i", 1),
+
+ // IncDec statements
+ Val1("i++", "i", 2),
+ Val1("i--", "i", 0),
+ Val1("u++", "u", uint(2)),
+ Val1("u--", "u", uint(0)),
+ Val1("f++", "f", 2.0),
+ Val1("f--", "f", 0.0),
+ // Single evaluation
+ Val2("ai[func()int{i+=1;return 0}()]++; i2 = ai[0]", "i", 2, "i2", 2),
+ // Operand types
+ CErr("s++", opTypes),
+ CErr("s++", "'\\+\\+'"),
+ CErr("2++", "cannot assign"),
+ CErr("c++", "cannot assign"),
+
+ // Function scoping
+ Val1("fn1 := func() { i=2 }; fn1()", "i", 2),
+ Val1("fn1 := func() { i:=2 }; fn1()", "i", 1),
+ Val2("fn1 := func() int { i=2; i:=3; i=4; return i }; x := fn1()", "i", 2, "x", 4),
+
+ // Basic returns
+ CErr("fn1 := func() int {}", "return"),
+ Run("fn1 := func() {}"),
+ CErr("fn1 := func() (r int) {}", "return"),
+ Val1("fn1 := func() (r int) {return}; i = fn1()", "i", 0),
+ Val1("fn1 := func() (r int) {r = 2; return}; i = fn1()", "i", 2),
+ Val1("fn1 := func() (r int) {return 2}; i = fn1()", "i", 2),
+ Val1("fn1 := func(int) int {return 2}; i = fn1(1)", "i", 2),
+
+ // Multi-valued returns
+ Val2("fn1 := func() (bool, int) {return true, 2}; x, y := fn1()", "x", true, "y", 2),
+ CErr("fn1 := func() int {return}", "not enough values"),
+ CErr("fn1 := func() int {return 1,2}", "too many values"),
+ CErr("fn1 := func() {return 1}", "too many values"),
+ CErr("fn1 := func() (int,int,int) {return 1,2}", "not enough values"),
+ Val2("fn1 := func() (int, int) {return oneTwo()}; x, y := fn1()", "x", 1, "y", 2),
+ CErr("fn1 := func() int {return oneTwo()}", "too many values"),
+ CErr("fn1 := func() (int,int,int) {return oneTwo()}", "not enough values"),
+ Val1("fn1 := func(x,y int) int {return x+y}; x := fn1(oneTwo())", "x", 3),
+
+ // Return control flow
+ Val2("fn1 := func(x *int) bool { *x = 2; return true; *x = 3; }; x := fn1(&i)", "i", 2, "x", true),
+
+ // Break/continue/goto/fallthrough
+ CErr("break", "outside"),
+ CErr("break foo", "break.*foo.*not defined"),
+ CErr("continue", "outside"),
+ CErr("continue foo", "continue.*foo.*not defined"),
+ CErr("fallthrough", "outside"),
+ CErr("goto foo", "foo.*not defined"),
+ CErr(" foo: foo:;", "foo.*redeclared.*:1:2"),
+ Val1("i+=2; goto L; i+=4; L: i+=8", "i", 1+2+8),
+ // Return checking
+ CErr("fn1 := func() int { goto L; return 1; L: }", "return"),
+ Run("fn1 := func() int { L: goto L; i = 2 }"),
+ Run("fn1 := func() int { return 1; L: goto L }"),
+ // Scope checking
+ Run("fn1 := func() { { L: x:=1 }; goto L }"),
+ CErr("fn1 := func() { { x:=1; L: }; goto L }", "into scope"),
+ CErr("fn1 := func() { goto L; x:=1; L: }", "into scope"),
+ Run("fn1 := func() { goto L; { L: x:=1 } }"),
+ CErr("fn1 := func() { goto L; { x:=1; L: } }", "into scope"),
+
+ // Blocks
+ CErr("fn1 := func() int {{}}", "return"),
+ Val1("fn1 := func() bool { { return true } }; b := fn1()", "b", true),
+
+ // If
+ Val2("if true { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
+ Val2("if false { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
+ Val2("if i == i2 { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
+ // Omit optional parts
+ Val2("if { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
+ Val2("if true { i = 2 }; i2 = 4", "i", 2, "i2", 4),
+ Val2("if false { i = 2 }; i2 = 4", "i", 1, "i2", 4),
+ // Init
+ Val2("if x := true; x { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4),
+ Val2("if x := false; x { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4),
+ // Statement else
+ Val2("if true { i = 2 } else i = 3; i2 = 4", "i", 2, "i2", 4),
+ Val2("if false { i = 2 } else i = 3; i2 = 4", "i", 3, "i2", 4),
+ // Scoping
+ Val2("if true { i := 2 } else { i := 3 }; i2 = i", "i", 1, "i2", 1),
+ Val2("if false { i := 2 } else { i := 3 }; i2 = i", "i", 1, "i2", 1),
+ Val2("if false { i := 2 } else i := 3; i2 = i", "i", 1, "i2", 1),
+ CErr("if true { x := 2 }; x = 4", undefined),
+ Val2("if i := 2; true { i2 = i; i := 3 }", "i", 1, "i2", 2),
+ Val2("if i := 2; false {} else { i2 = i; i := 3 }", "i", 1, "i2", 2),
+ // Return checking
+ Run("fn1 := func() int { if true { return 1 } else { return 2 } }"),
+ Run("fn1 := func() int { if true { return 1 } else return 2 }"),
+ CErr("fn1 := func() int { if true { return 1 } else { } }", "return"),
+ CErr("fn1 := func() int { if true { } else { return 1 } }", "return"),
+ CErr("fn1 := func() int { if true { } else return 1 }", "return"),
+ CErr("fn1 := func() int { if true { } else { } }", "return"),
+ CErr("fn1 := func() int { if true { return 1 } }", "return"),
+ CErr("fn1 := func() int { if true { } }", "return"),
+ Run("fn1 := func() int { if true { }; return 1 }"),
+ CErr("fn1 := func() int { if { } }", "return"),
+ CErr("fn1 := func() int { if { } else { return 2 } }", "return"),
+ Run("fn1 := func() int { if { return 1 } }"),
+ Run("fn1 := func() int { if { return 1 } else { } }"),
+ Run("fn1 := func() int { if { return 1 } else { } }"),
+
+ // Switch
+ Val1("switch { case false: i += 2; case true: i += 4; default: i += 8 }", "i", 1+4),
+ Val1("switch { default: i += 2; case false: i += 4; case true: i += 8 }", "i", 1+8),
+ CErr("switch { default: i += 2; default: i += 4 }", "more than one"),
+ Val1("switch false { case false: i += 2; case true: i += 4; default: i += 8 }", "i", 1+2),
+ CErr("switch s { case 1: }", opTypes),
+ CErr("switch ai { case ai: i += 2 }", opTypes),
+ Val1("switch 1.0 { case 1: i += 2; case 2: i += 4 }", "i", 1+2),
+ Val1("switch 1.5 { case 1: i += 2; case 2: i += 4 }", "i", 1),
+ CErr("switch oneTwo() {}", "multi-valued expression"),
+ Val1("switch 2 { case 1: i += 2; fallthrough; case 2: i += 4; fallthrough; case 3: i += 8; fallthrough }", "i", 1+4+8),
+ Val1("switch 5 { case 1: i += 2; fallthrough; default: i += 4; fallthrough; case 2: i += 8; fallthrough; case 3: i += 16; fallthrough }", "i", 1+4+8+16),
+ CErr("switch { case true: fallthrough; i += 2 }", "final statement"),
+ Val1("switch { case true: i += 2; fallthrough; ; ; case false: i += 4 }", "i", 1+2+4),
+ Val1("switch 2 { case 0, 1: i += 2; case 2, 3: i += 4 }", "i", 1+4),
+ Val2("switch func()int{i2++;return 5}() { case 1, 2: i += 2; case 4, 5: i += 4 }", "i", 1+4, "i2", 3),
+ Run("switch i { case i: }"),
+ // TODO(austin) Why doesn't this fail?
+ //CErr("case 1:", "XXX"),
+
+ // For
+ Val2("for x := 1; x < 5; x++ { i+=x }; i2 = 4", "i", 11, "i2", 4),
+ Val2("for x := 1; x < 5; x++ { i+=x; break; i++ }; i2 = 4", "i", 2, "i2", 4),
+ Val2("for x := 1; x < 5; x++ { i+=x; continue; i++ }; i2 = 4", "i", 11, "i2", 4),
+ Val2("for i = 2; false; i = 3 { i = 4 }; i2 = 4", "i", 2, "i2", 4),
+ Val2("for i < 5 { i++ }; i2 = 4", "i", 5, "i2", 4),
+ Val2("for i < 0 { i++ }; i2 = 4", "i", 1, "i2", 4),
+ // Scoping
+ Val2("for i := 2; true; { i2 = i; i := 3; break }", "i", 1, "i2", 2),
+ // Labeled break/continue
+ Val1("L1: for { L2: for { i+=2; break L1; i+=4 }; i+=8 }", "i", 1+2),
+ Val1("L1: for { L2: for { i+=2; break L2; i+=4 }; i+=8; break; i+=16 }", "i", 1+2+8),
+ CErr("L1: { for { break L1 } }", "break.*not defined"),
+ CErr("L1: for {}; for { break L1 }", "break.*not defined"),
+ CErr("L1:; for { break L1 }", "break.*not defined"),
+ Val2("L1: for i = 0; i < 2; i++ { L2: for { i2++; continue L1; i2++ } }", "i", 2, "i2", 4),
+ CErr("L1: { for { continue L1 } }", "continue.*not defined"),
+ CErr("L1:; for { continue L1 }", "continue.*not defined"),
+ // Return checking
+ Run("fn1 := func() int{ for {} }"),
+ CErr("fn1 := func() int{ for true {} }", "return"),
+ CErr("fn1 := func() int{ for true {return 1} }", "return"),
+ CErr("fn1 := func() int{ for {break} }", "return"),
+ Run("fn1 := func() int{ for { for {break} } }"),
+ CErr("fn1 := func() int{ L1: for { for {break L1} } }", "return"),
+ Run("fn1 := func() int{ for true {}; return 1 }"),
+
+ // Selectors
+ Val1("var x struct { a int; b int }; x.a = 42; i = x.a", "i", 42),
+ Val1("type T struct { x int }; var y struct { T }; y.x = 42; i = y.x", "i", 42),
+ Val2("type T struct { x int }; var y struct { T; x int }; y.x = 42; i = y.x; i2 = y.T.x", "i", 42, "i2", 0),
+ Run("type T struct { x int }; var y struct { *T }; a := func(){i=y.x}"),
+ CErr("type T struct { x int }; var x T; x.y = 42", "no field"),
+ CErr("type T struct { x int }; type U struct { x int }; var y struct { T; U }; y.x = 42", "ambiguous.*\tT\\.x\n\tU\\.x"),
+ CErr("type T struct { *T }; var x T; x.foo", "no field"),
+
+ Val1("fib := func(int) int{return 0;}; fib = func(v int) int { if v < 2 { return 1 }; return fib(v-1)+fib(v-2) }; i = fib(20)", "i", 10946),
+
+ // Make slice
+ Val2("x := make([]int, 2); x[0] = 42; i, i2 = x[0], x[1]", "i", 42, "i2", 0),
+ Val2("x := make([]int, 2); x[1] = 42; i, i2 = x[0], x[1]", "i", 0, "i2", 42),
+ RErr("x := make([]int, 2); x[-i] = 42", "negative index"),
+ RErr("x := make([]int, 2); x[2] = 42", "index 2 exceeds"),
+ Val2("x := make([]int, 2, 3); i, i2 = len(x), cap(x)", "i", 2, "i2", 3),
+ Val2("x := make([]int, 3, 2); i, i2 = len(x), cap(x)", "i", 3, "i2", 3),
+ RErr("x := make([]int, -i)", "negative length"),
+ RErr("x := make([]int, 2, -i)", "negative capacity"),
+ RErr("x := make([]int, 2, 3); x[2] = 42", "index 2 exceeds"),
+ CErr("x := make([]int, 2, 3, 4)", "too many"),
+ CErr("x := make([]int)", "not enough"),
+
+ // TODO(austin) Test make map
+
+ // Maps
+ Val1("x := make(map[int] int); x[1] = 42; i = x[1]", "i", 42),
+ Val2("x := make(map[int] int); x[1] = 42; i, y := x[1]", "i", 42, "y", true),
+ Val2("x := make(map[int] int); x[1] = 42; i, y := x[2]", "i", 0, "y", false),
+ // Not implemented
+ //Val1("x := make(map[int] int); x[1] = 42, true; i = x[1]", "i", 42),
+ //Val2("x := make(map[int] int); x[1] = 42; x[1] = 42, false; i, y := x[1]", "i", 0, "y", false),
+ Run("var x int; a := make(map[int] int); a[0], x = 1, 2"),
+ CErr("x := make(map[int] int); (func(a,b int){})(x[0])", "not enough"),
+ CErr("x := make(map[int] int); x[1] = oneTwo()", "too many"),
+ RErr("x := make(map[int] int); i = x[1]", "key '1' not found"),
+
+ // Functions
+ Val2("func fib(n int) int { if n <= 2 { return n }; return fib(n-1) + fib(n-2) }", "fib(4)", 5, "fib(10)", 89),
+ Run("func f1(){}"),
+ Run2("func f1(){}", "f1()"),
+}
+
+func TestStmt(t *testing.T) { runTests(t, "stmtTests", stmtTests) }
diff --git a/libgo/go/exp/eval/type.go b/libgo/go/exp/eval/type.go
new file mode 100644
index 000000000..3f272ce4b
--- /dev/null
+++ b/libgo/go/exp/eval/type.go
@@ -0,0 +1,1252 @@
+// 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 eval
+
+import (
+ "big"
+ "go/ast"
+ "go/token"
+ "log"
+ "reflect"
+ "sort"
+ "unsafe" // For Sizeof
+)
+
+
+// XXX(Spec) The type compatibility section is very confusing because
+// it makes it seem like there are three distinct types of
+// compatibility: plain compatibility, assignment compatibility, and
+// comparison compatibility. As I understand it, there's really only
+// assignment compatibility and comparison and conversion have some
+// restrictions and have special meaning in some cases where the types
+// are not otherwise assignment compatible. The comparison
+// compatibility section is almost all about the semantics of
+// comparison, not the type checking of it, so it would make much more
+// sense in the comparison operators section. The compatibility and
+// assignment compatibility sections should be rolled into one.
+
+type Type interface {
+ // compat returns whether this type is compatible with another
+ // type. If conv is false, this is normal compatibility,
+ // where two named types are compatible only if they are the
+ // same named type. If conv if true, this is conversion
+ // compatibility, where two named types are conversion
+ // compatible if their definitions are conversion compatible.
+ //
+ // TODO(austin) Deal with recursive types
+ compat(o Type, conv bool) bool
+ // lit returns this type's literal. If this is a named type,
+ // this is the unnamed underlying type. Otherwise, this is an
+ // identity operation.
+ lit() Type
+ // isBoolean returns true if this is a boolean type.
+ isBoolean() bool
+ // isInteger returns true if this is an integer type.
+ isInteger() bool
+ // isFloat returns true if this is a floating type.
+ isFloat() bool
+ // isIdeal returns true if this is an ideal int or float.
+ isIdeal() bool
+ // Zero returns a new zero value of this type.
+ Zero() Value
+ // String returns the string representation of this type.
+ String() string
+ // The position where this type was defined, if any.
+ Pos() token.Pos
+}
+
+type BoundedType interface {
+ Type
+ // minVal returns the smallest value of this type.
+ minVal() *big.Rat
+ // maxVal returns the largest value of this type.
+ maxVal() *big.Rat
+}
+
+var universePos = token.NoPos
+
+/*
+ * Type array maps. These are used to memoize composite types.
+ */
+
+type typeArrayMapEntry struct {
+ key []Type
+ v interface{}
+ next *typeArrayMapEntry
+}
+
+type typeArrayMap map[uintptr]*typeArrayMapEntry
+
+func hashTypeArray(key []Type) uintptr {
+ hash := uintptr(0)
+ for _, t := range key {
+ hash = hash * 33
+ if t == nil {
+ continue
+ }
+ addr := reflect.NewValue(t).(*reflect.PtrValue).Get()
+ hash ^= addr
+ }
+ return hash
+}
+
+func newTypeArrayMap() typeArrayMap { return make(map[uintptr]*typeArrayMapEntry) }
+
+func (m typeArrayMap) Get(key []Type) interface{} {
+ ent, ok := m[hashTypeArray(key)]
+ if !ok {
+ return nil
+ }
+
+nextEnt:
+ for ; ent != nil; ent = ent.next {
+ if len(key) != len(ent.key) {
+ continue
+ }
+ for i := 0; i < len(key); i++ {
+ if key[i] != ent.key[i] {
+ continue nextEnt
+ }
+ }
+ // Found it
+ return ent.v
+ }
+
+ return nil
+}
+
+func (m typeArrayMap) Put(key []Type, v interface{}) interface{} {
+ hash := hashTypeArray(key)
+ ent := m[hash]
+
+ new := &typeArrayMapEntry{key, v, ent}
+ m[hash] = new
+ return v
+}
+
+/*
+ * Common type
+ */
+
+type commonType struct{}
+
+func (commonType) isBoolean() bool { return false }
+
+func (commonType) isInteger() bool { return false }
+
+func (commonType) isFloat() bool { return false }
+
+func (commonType) isIdeal() bool { return false }
+
+func (commonType) Pos() token.Pos { return token.NoPos }
+
+/*
+ * Bool
+ */
+
+type boolType struct {
+ commonType
+}
+
+var BoolType = universe.DefineType("bool", universePos, &boolType{})
+
+func (t *boolType) compat(o Type, conv bool) bool {
+ _, ok := o.lit().(*boolType)
+ return ok
+}
+
+func (t *boolType) lit() Type { return t }
+
+func (t *boolType) isBoolean() bool { return true }
+
+func (boolType) String() string {
+ // Use angle brackets as a convention for printing the
+ // underlying, unnamed type. This should only show up in
+ // debug output.
+ return "<bool>"
+}
+
+func (t *boolType) Zero() Value {
+ res := boolV(false)
+ return &res
+}
+
+/*
+ * Uint
+ */
+
+type uintType struct {
+ commonType
+
+ // 0 for architecture-dependent types
+ Bits uint
+ // true for uintptr, false for all others
+ Ptr bool
+ name string
+}
+
+var (
+ Uint8Type = universe.DefineType("uint8", universePos, &uintType{commonType{}, 8, false, "uint8"})
+ Uint16Type = universe.DefineType("uint16", universePos, &uintType{commonType{}, 16, false, "uint16"})
+ Uint32Type = universe.DefineType("uint32", universePos, &uintType{commonType{}, 32, false, "uint32"})
+ Uint64Type = universe.DefineType("uint64", universePos, &uintType{commonType{}, 64, false, "uint64"})
+
+ UintType = universe.DefineType("uint", universePos, &uintType{commonType{}, 0, false, "uint"})
+ UintptrType = universe.DefineType("uintptr", universePos, &uintType{commonType{}, 0, true, "uintptr"})
+)
+
+func (t *uintType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*uintType)
+ return ok && t == t2
+}
+
+func (t *uintType) lit() Type { return t }
+
+func (t *uintType) isInteger() bool { return true }
+
+func (t *uintType) String() string { return "<" + t.name + ">" }
+
+func (t *uintType) Zero() Value {
+ switch t.Bits {
+ case 0:
+ if t.Ptr {
+ res := uintptrV(0)
+ return &res
+ } else {
+ res := uintV(0)
+ return &res
+ }
+ case 8:
+ res := uint8V(0)
+ return &res
+ case 16:
+ res := uint16V(0)
+ return &res
+ case 32:
+ res := uint32V(0)
+ return &res
+ case 64:
+ res := uint64V(0)
+ return &res
+ }
+ panic("unexpected uint bit count")
+}
+
+func (t *uintType) minVal() *big.Rat { return big.NewRat(0, 1) }
+
+func (t *uintType) maxVal() *big.Rat {
+ bits := t.Bits
+ if bits == 0 {
+ if t.Ptr {
+ bits = uint(8 * unsafe.Sizeof(uintptr(0)))
+ } else {
+ bits = uint(8 * unsafe.Sizeof(uint(0)))
+ }
+ }
+ numer := big.NewInt(1)
+ numer.Lsh(numer, bits)
+ numer.Sub(numer, idealOne)
+ return new(big.Rat).SetInt(numer)
+}
+
+/*
+ * Int
+ */
+
+type intType struct {
+ commonType
+
+ // XXX(Spec) Numeric types: "There is also a set of
+ // architecture-independent basic numeric types whose size
+ // depends on the architecture." Should that be
+ // architecture-dependent?
+
+ // 0 for architecture-dependent types
+ Bits uint
+ name string
+}
+
+var (
+ Int8Type = universe.DefineType("int8", universePos, &intType{commonType{}, 8, "int8"})
+ Int16Type = universe.DefineType("int16", universePos, &intType{commonType{}, 16, "int16"})
+ Int32Type = universe.DefineType("int32", universePos, &intType{commonType{}, 32, "int32"})
+ Int64Type = universe.DefineType("int64", universePos, &intType{commonType{}, 64, "int64"})
+
+ IntType = universe.DefineType("int", universePos, &intType{commonType{}, 0, "int"})
+)
+
+func (t *intType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*intType)
+ return ok && t == t2
+}
+
+func (t *intType) lit() Type { return t }
+
+func (t *intType) isInteger() bool { return true }
+
+func (t *intType) String() string { return "<" + t.name + ">" }
+
+func (t *intType) Zero() Value {
+ switch t.Bits {
+ case 8:
+ res := int8V(0)
+ return &res
+ case 16:
+ res := int16V(0)
+ return &res
+ case 32:
+ res := int32V(0)
+ return &res
+ case 64:
+ res := int64V(0)
+ return &res
+
+ case 0:
+ res := intV(0)
+ return &res
+ }
+ panic("unexpected int bit count")
+}
+
+func (t *intType) minVal() *big.Rat {
+ bits := t.Bits
+ if bits == 0 {
+ bits = uint(8 * unsafe.Sizeof(int(0)))
+ }
+ numer := big.NewInt(-1)
+ numer.Lsh(numer, bits-1)
+ return new(big.Rat).SetInt(numer)
+}
+
+func (t *intType) maxVal() *big.Rat {
+ bits := t.Bits
+ if bits == 0 {
+ bits = uint(8 * unsafe.Sizeof(int(0)))
+ }
+ numer := big.NewInt(1)
+ numer.Lsh(numer, bits-1)
+ numer.Sub(numer, idealOne)
+ return new(big.Rat).SetInt(numer)
+}
+
+/*
+ * Ideal int
+ */
+
+type idealIntType struct {
+ commonType
+}
+
+var IdealIntType Type = &idealIntType{}
+
+func (t *idealIntType) compat(o Type, conv bool) bool {
+ _, ok := o.lit().(*idealIntType)
+ return ok
+}
+
+func (t *idealIntType) lit() Type { return t }
+
+func (t *idealIntType) isInteger() bool { return true }
+
+func (t *idealIntType) isIdeal() bool { return true }
+
+func (t *idealIntType) String() string { return "ideal integer" }
+
+func (t *idealIntType) Zero() Value { return &idealIntV{idealZero} }
+
+/*
+ * Float
+ */
+
+type floatType struct {
+ commonType
+
+ // 0 for architecture-dependent type
+ Bits uint
+
+ name string
+}
+
+var (
+ Float32Type = universe.DefineType("float32", universePos, &floatType{commonType{}, 32, "float32"})
+ Float64Type = universe.DefineType("float64", universePos, &floatType{commonType{}, 64, "float64"})
+)
+
+func (t *floatType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*floatType)
+ return ok && t == t2
+}
+
+func (t *floatType) lit() Type { return t }
+
+func (t *floatType) isFloat() bool { return true }
+
+func (t *floatType) String() string { return "<" + t.name + ">" }
+
+func (t *floatType) Zero() Value {
+ switch t.Bits {
+ case 32:
+ res := float32V(0)
+ return &res
+ case 64:
+ res := float64V(0)
+ return &res
+ }
+ panic("unexpected float bit count")
+}
+
+var maxFloat32Val *big.Rat
+var maxFloat64Val *big.Rat
+var minFloat32Val *big.Rat
+var minFloat64Val *big.Rat
+
+func (t *floatType) minVal() *big.Rat {
+ bits := t.Bits
+ switch bits {
+ case 32:
+ return minFloat32Val
+ case 64:
+ return minFloat64Val
+ }
+ log.Panicf("unexpected floating point bit count: %d", bits)
+ panic("unreachable")
+}
+
+func (t *floatType) maxVal() *big.Rat {
+ bits := t.Bits
+ switch bits {
+ case 32:
+ return maxFloat32Val
+ case 64:
+ return maxFloat64Val
+ }
+ log.Panicf("unexpected floating point bit count: %d", bits)
+ panic("unreachable")
+}
+
+/*
+ * Ideal float
+ */
+
+type idealFloatType struct {
+ commonType
+}
+
+var IdealFloatType Type = &idealFloatType{}
+
+func (t *idealFloatType) compat(o Type, conv bool) bool {
+ _, ok := o.lit().(*idealFloatType)
+ return ok
+}
+
+func (t *idealFloatType) lit() Type { return t }
+
+func (t *idealFloatType) isFloat() bool { return true }
+
+func (t *idealFloatType) isIdeal() bool { return true }
+
+func (t *idealFloatType) String() string { return "ideal float" }
+
+func (t *idealFloatType) Zero() Value { return &idealFloatV{big.NewRat(0, 1)} }
+
+/*
+ * String
+ */
+
+type stringType struct {
+ commonType
+}
+
+var StringType = universe.DefineType("string", universePos, &stringType{})
+
+func (t *stringType) compat(o Type, conv bool) bool {
+ _, ok := o.lit().(*stringType)
+ return ok
+}
+
+func (t *stringType) lit() Type { return t }
+
+func (t *stringType) String() string { return "<string>" }
+
+func (t *stringType) Zero() Value {
+ res := stringV("")
+ return &res
+}
+
+/*
+ * Array
+ */
+
+type ArrayType struct {
+ commonType
+ Len int64
+ Elem Type
+}
+
+var arrayTypes = make(map[int64]map[Type]*ArrayType)
+
+// Two array types are identical if they have identical element types
+// and the same array length.
+
+func NewArrayType(len int64, elem Type) *ArrayType {
+ ts, ok := arrayTypes[len]
+ if !ok {
+ ts = make(map[Type]*ArrayType)
+ arrayTypes[len] = ts
+ }
+ t, ok := ts[elem]
+ if !ok {
+ t = &ArrayType{commonType{}, len, elem}
+ ts[elem] = t
+ }
+ return t
+}
+
+func (t *ArrayType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*ArrayType)
+ if !ok {
+ return false
+ }
+ return t.Len == t2.Len && t.Elem.compat(t2.Elem, conv)
+}
+
+func (t *ArrayType) lit() Type { return t }
+
+func (t *ArrayType) String() string { return "[]" + t.Elem.String() }
+
+func (t *ArrayType) Zero() Value {
+ res := arrayV(make([]Value, t.Len))
+ // TODO(austin) It's unfortunate that each element is
+ // separately heap allocated. We could add ZeroArray to
+ // everything, though that doesn't help with multidimensional
+ // arrays. Or we could do something unsafe. We'll have this
+ // same problem with structs.
+ for i := int64(0); i < t.Len; i++ {
+ res[i] = t.Elem.Zero()
+ }
+ return &res
+}
+
+/*
+ * Struct
+ */
+
+type StructField struct {
+ Name string
+ Type Type
+ Anonymous bool
+}
+
+type StructType struct {
+ commonType
+ Elems []StructField
+}
+
+var structTypes = newTypeArrayMap()
+
+// Two struct types are identical if they have the same sequence of
+// fields, and if corresponding fields have the same names and
+// identical types. Two anonymous fields are considered to have the
+// same name.
+
+func NewStructType(fields []StructField) *StructType {
+ // Start by looking up just the types
+ fts := make([]Type, len(fields))
+ for i, f := range fields {
+ fts[i] = f.Type
+ }
+ tMapI := structTypes.Get(fts)
+ if tMapI == nil {
+ tMapI = structTypes.Put(fts, make(map[string]*StructType))
+ }
+ tMap := tMapI.(map[string]*StructType)
+
+ // Construct key for field names
+ key := ""
+ for _, f := range fields {
+ // XXX(Spec) It's not clear if struct { T } and struct
+ // { T T } are either identical or compatible. The
+ // "Struct Types" section says that the name of that
+ // field is "T", which suggests that they are
+ // identical, but it really means that it's the name
+ // for the purpose of selector expressions and nothing
+ // else. We decided that they should be neither
+ // identical or compatible.
+ if f.Anonymous {
+ key += "!"
+ }
+ key += f.Name + " "
+ }
+
+ // XXX(Spec) Do the tags also have to be identical for the
+ // types to be identical? I certainly hope so, because
+ // otherwise, this is the only case where two distinct type
+ // objects can represent identical types.
+
+ t, ok := tMap[key]
+ if !ok {
+ // Create new struct type
+ t = &StructType{commonType{}, fields}
+ tMap[key] = t
+ }
+ return t
+}
+
+func (t *StructType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*StructType)
+ if !ok {
+ return false
+ }
+ if len(t.Elems) != len(t2.Elems) {
+ return false
+ }
+ for i, e := range t.Elems {
+ e2 := t2.Elems[i]
+ // XXX(Spec) An anonymous and a non-anonymous field
+ // are neither identical nor compatible.
+ if e.Anonymous != e2.Anonymous ||
+ (!e.Anonymous && e.Name != e2.Name) ||
+ !e.Type.compat(e2.Type, conv) {
+ return false
+ }
+ }
+ return true
+}
+
+func (t *StructType) lit() Type { return t }
+
+func (t *StructType) String() string {
+ s := "struct {"
+ for i, f := range t.Elems {
+ if i > 0 {
+ s += "; "
+ }
+ if !f.Anonymous {
+ s += f.Name + " "
+ }
+ s += f.Type.String()
+ }
+ return s + "}"
+}
+
+func (t *StructType) Zero() Value {
+ res := structV(make([]Value, len(t.Elems)))
+ for i, f := range t.Elems {
+ res[i] = f.Type.Zero()
+ }
+ return &res
+}
+
+/*
+ * Pointer
+ */
+
+type PtrType struct {
+ commonType
+ Elem Type
+}
+
+var ptrTypes = make(map[Type]*PtrType)
+
+// Two pointer types are identical if they have identical base types.
+
+func NewPtrType(elem Type) *PtrType {
+ t, ok := ptrTypes[elem]
+ if !ok {
+ t = &PtrType{commonType{}, elem}
+ ptrTypes[elem] = t
+ }
+ return t
+}
+
+func (t *PtrType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*PtrType)
+ if !ok {
+ return false
+ }
+ return t.Elem.compat(t2.Elem, conv)
+}
+
+func (t *PtrType) lit() Type { return t }
+
+func (t *PtrType) String() string { return "*" + t.Elem.String() }
+
+func (t *PtrType) Zero() Value { return &ptrV{nil} }
+
+/*
+ * Function
+ */
+
+type FuncType struct {
+ commonType
+ // TODO(austin) Separate receiver Type for methods?
+ In []Type
+ Variadic bool
+ Out []Type
+ builtin string
+}
+
+var funcTypes = newTypeArrayMap()
+var variadicFuncTypes = newTypeArrayMap()
+
+// Create singleton function types for magic built-in functions
+var (
+ capType = &FuncType{builtin: "cap"}
+ closeType = &FuncType{builtin: "close"}
+ closedType = &FuncType{builtin: "closed"}
+ lenType = &FuncType{builtin: "len"}
+ makeType = &FuncType{builtin: "make"}
+ newType = &FuncType{builtin: "new"}
+ panicType = &FuncType{builtin: "panic"}
+ printType = &FuncType{builtin: "print"}
+ printlnType = &FuncType{builtin: "println"}
+ copyType = &FuncType{builtin: "copy"}
+)
+
+// Two function types are identical if they have the same number of
+// parameters and result values and if corresponding parameter and
+// result types are identical. All "..." parameters have identical
+// type. Parameter and result names are not required to match.
+
+func NewFuncType(in []Type, variadic bool, out []Type) *FuncType {
+ inMap := funcTypes
+ if variadic {
+ inMap = variadicFuncTypes
+ }
+
+ outMapI := inMap.Get(in)
+ if outMapI == nil {
+ outMapI = inMap.Put(in, newTypeArrayMap())
+ }
+ outMap := outMapI.(typeArrayMap)
+
+ tI := outMap.Get(out)
+ if tI != nil {
+ return tI.(*FuncType)
+ }
+
+ t := &FuncType{commonType{}, in, variadic, out, ""}
+ outMap.Put(out, t)
+ return t
+}
+
+func (t *FuncType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*FuncType)
+ if !ok {
+ return false
+ }
+ if len(t.In) != len(t2.In) || t.Variadic != t2.Variadic || len(t.Out) != len(t2.Out) {
+ return false
+ }
+ for i := range t.In {
+ if !t.In[i].compat(t2.In[i], conv) {
+ return false
+ }
+ }
+ for i := range t.Out {
+ if !t.Out[i].compat(t2.Out[i], conv) {
+ return false
+ }
+ }
+ return true
+}
+
+func (t *FuncType) lit() Type { return t }
+
+func typeListString(ts []Type, ns []*ast.Ident) string {
+ s := ""
+ for i, t := range ts {
+ if i > 0 {
+ s += ", "
+ }
+ if ns != nil && ns[i] != nil {
+ s += ns[i].Name + " "
+ }
+ if t == nil {
+ // Some places use nil types to represent errors
+ s += "<none>"
+ } else {
+ s += t.String()
+ }
+ }
+ return s
+}
+
+func (t *FuncType) String() string {
+ if t.builtin != "" {
+ return "built-in function " + t.builtin
+ }
+ args := typeListString(t.In, nil)
+ if t.Variadic {
+ if len(args) > 0 {
+ args += ", "
+ }
+ args += "..."
+ }
+ s := "func(" + args + ")"
+ if len(t.Out) > 0 {
+ s += " (" + typeListString(t.Out, nil) + ")"
+ }
+ return s
+}
+
+func (t *FuncType) Zero() Value { return &funcV{nil} }
+
+type FuncDecl struct {
+ Type *FuncType
+ Name *ast.Ident // nil for function literals
+ // InNames will be one longer than Type.In if this function is
+ // variadic.
+ InNames []*ast.Ident
+ OutNames []*ast.Ident
+}
+
+func (t *FuncDecl) String() string {
+ s := "func"
+ if t.Name != nil {
+ s += " " + t.Name.Name
+ }
+ s += funcTypeString(t.Type, t.InNames, t.OutNames)
+ return s
+}
+
+func funcTypeString(ft *FuncType, ins []*ast.Ident, outs []*ast.Ident) string {
+ s := "("
+ s += typeListString(ft.In, ins)
+ if ft.Variadic {
+ if len(ft.In) > 0 {
+ s += ", "
+ }
+ s += "..."
+ }
+ s += ")"
+ if len(ft.Out) > 0 {
+ s += " (" + typeListString(ft.Out, outs) + ")"
+ }
+ return s
+}
+
+/*
+ * Interface
+ */
+
+// TODO(austin) Interface values, types, and type compilation are
+// implemented, but none of the type checking or semantics of
+// interfaces are.
+
+type InterfaceType struct {
+ commonType
+ // TODO(austin) This should be a map from names to
+ // *FuncType's. We only need the sorted list for generating
+ // the type map key. It's detrimental for everything else.
+ methods []IMethod
+}
+
+type IMethod struct {
+ Name string
+ Type *FuncType
+}
+
+var interfaceTypes = newTypeArrayMap()
+
+func NewInterfaceType(methods []IMethod, embeds []*InterfaceType) *InterfaceType {
+ // Count methods of embedded interfaces
+ nMethods := len(methods)
+ for _, e := range embeds {
+ nMethods += len(e.methods)
+ }
+
+ // Combine methods
+ allMethods := make([]IMethod, nMethods)
+ copy(allMethods, methods)
+ n := len(methods)
+ for _, e := range embeds {
+ for _, m := range e.methods {
+ allMethods[n] = m
+ n++
+ }
+ }
+
+ // Sort methods
+ sort.Sort(iMethodSorter(allMethods))
+
+ mts := make([]Type, len(allMethods))
+ for i, m := range methods {
+ mts[i] = m.Type
+ }
+ tMapI := interfaceTypes.Get(mts)
+ if tMapI == nil {
+ tMapI = interfaceTypes.Put(mts, make(map[string]*InterfaceType))
+ }
+ tMap := tMapI.(map[string]*InterfaceType)
+
+ key := ""
+ for _, m := range allMethods {
+ key += m.Name + " "
+ }
+
+ t, ok := tMap[key]
+ if !ok {
+ t = &InterfaceType{commonType{}, allMethods}
+ tMap[key] = t
+ }
+ return t
+}
+
+type iMethodSorter []IMethod
+
+func (s iMethodSorter) Less(a, b int) bool { return s[a].Name < s[b].Name }
+
+func (s iMethodSorter) Swap(a, b int) { s[a], s[b] = s[b], s[a] }
+
+func (s iMethodSorter) Len() int { return len(s) }
+
+func (t *InterfaceType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*InterfaceType)
+ if !ok {
+ return false
+ }
+ if len(t.methods) != len(t2.methods) {
+ return false
+ }
+ for i, e := range t.methods {
+ e2 := t2.methods[i]
+ if e.Name != e2.Name || !e.Type.compat(e2.Type, conv) {
+ return false
+ }
+ }
+ return true
+}
+
+func (t *InterfaceType) lit() Type { return t }
+
+func (t *InterfaceType) String() string {
+ // TODO(austin) Instead of showing embedded interfaces, this
+ // shows their methods.
+ s := "interface {"
+ for i, m := range t.methods {
+ if i > 0 {
+ s += "; "
+ }
+ s += m.Name + funcTypeString(m.Type, nil, nil)
+ }
+ return s + "}"
+}
+
+// implementedBy tests if o implements t, returning nil, true if it does.
+// Otherwise, it returns a method of t that o is missing and false.
+func (t *InterfaceType) implementedBy(o Type) (*IMethod, bool) {
+ if len(t.methods) == 0 {
+ return nil, true
+ }
+
+ // The methods of a named interface types are those of the
+ // underlying type.
+ if it, ok := o.lit().(*InterfaceType); ok {
+ o = it
+ }
+
+ // XXX(Spec) Interface types: "A type implements any interface
+ // comprising any subset of its methods" It's unclear if
+ // methods must have identical or compatible types. 6g
+ // requires identical types.
+
+ switch o := o.(type) {
+ case *NamedType:
+ for _, tm := range t.methods {
+ sm, ok := o.methods[tm.Name]
+ if !ok || sm.decl.Type != tm.Type {
+ return &tm, false
+ }
+ }
+ return nil, true
+
+ case *InterfaceType:
+ var ti, oi int
+ for ti < len(t.methods) && oi < len(o.methods) {
+ tm, om := &t.methods[ti], &o.methods[oi]
+ switch {
+ case tm.Name == om.Name:
+ if tm.Type != om.Type {
+ return tm, false
+ }
+ ti++
+ oi++
+ case tm.Name > om.Name:
+ oi++
+ default:
+ return tm, false
+ }
+ }
+ if ti < len(t.methods) {
+ return &t.methods[ti], false
+ }
+ return nil, true
+ }
+
+ return &t.methods[0], false
+}
+
+func (t *InterfaceType) Zero() Value { return &interfaceV{} }
+
+/*
+ * Slice
+ */
+
+type SliceType struct {
+ commonType
+ Elem Type
+}
+
+var sliceTypes = make(map[Type]*SliceType)
+
+// Two slice types are identical if they have identical element types.
+
+func NewSliceType(elem Type) *SliceType {
+ t, ok := sliceTypes[elem]
+ if !ok {
+ t = &SliceType{commonType{}, elem}
+ sliceTypes[elem] = t
+ }
+ return t
+}
+
+func (t *SliceType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*SliceType)
+ if !ok {
+ return false
+ }
+ return t.Elem.compat(t2.Elem, conv)
+}
+
+func (t *SliceType) lit() Type { return t }
+
+func (t *SliceType) String() string { return "[]" + t.Elem.String() }
+
+func (t *SliceType) Zero() Value {
+ // The value of an uninitialized slice is nil. The length and
+ // capacity of a nil slice are 0.
+ return &sliceV{Slice{nil, 0, 0}}
+}
+
+/*
+ * Map type
+ */
+
+type MapType struct {
+ commonType
+ Key Type
+ Elem Type
+}
+
+var mapTypes = make(map[Type]map[Type]*MapType)
+
+func NewMapType(key Type, elem Type) *MapType {
+ ts, ok := mapTypes[key]
+ if !ok {
+ ts = make(map[Type]*MapType)
+ mapTypes[key] = ts
+ }
+ t, ok := ts[elem]
+ if !ok {
+ t = &MapType{commonType{}, key, elem}
+ ts[elem] = t
+ }
+ return t
+}
+
+func (t *MapType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*MapType)
+ if !ok {
+ return false
+ }
+ return t.Elem.compat(t2.Elem, conv) && t.Key.compat(t2.Key, conv)
+}
+
+func (t *MapType) lit() Type { return t }
+
+func (t *MapType) String() string { return "map[" + t.Key.String() + "] " + t.Elem.String() }
+
+func (t *MapType) Zero() Value {
+ // The value of an uninitialized map is nil.
+ return &mapV{nil}
+}
+
+/*
+type ChanType struct {
+ // TODO(austin)
+}
+*/
+
+/*
+ * Named types
+ */
+
+type Method struct {
+ decl *FuncDecl
+ fn Func
+}
+
+type NamedType struct {
+ NamePos token.Pos
+ Name string
+ // Underlying type. If incomplete is true, this will be nil.
+ // If incomplete is false and this is still nil, then this is
+ // a placeholder type representing an error.
+ Def Type
+ // True while this type is being defined.
+ incomplete bool
+ methods map[string]Method
+}
+
+// TODO(austin) This is temporarily needed by the debugger's remote
+// type parser. This should only be possible with block.DefineType.
+func NewNamedType(name string) *NamedType {
+ return &NamedType{token.NoPos, name, nil, true, make(map[string]Method)}
+}
+
+func (t *NamedType) Pos() token.Pos {
+ return t.NamePos
+}
+
+func (t *NamedType) Complete(def Type) {
+ if !t.incomplete {
+ log.Panicf("cannot complete already completed NamedType %+v", *t)
+ }
+ // We strip the name from def because multiple levels of
+ // naming are useless.
+ if ndef, ok := def.(*NamedType); ok {
+ def = ndef.Def
+ }
+ t.Def = def
+ t.incomplete = false
+}
+
+func (t *NamedType) compat(o Type, conv bool) bool {
+ t2, ok := o.(*NamedType)
+ if ok {
+ if conv {
+ // Two named types are conversion compatible
+ // if their literals are conversion
+ // compatible.
+ return t.Def.compat(t2.Def, conv)
+ } else {
+ // Two named types are compatible if their
+ // type names originate in the same type
+ // declaration.
+ return t == t2
+ }
+ }
+ // A named and an unnamed type are compatible if the
+ // respective type literals are compatible.
+ return o.compat(t.Def, conv)
+}
+
+func (t *NamedType) lit() Type { return t.Def.lit() }
+
+func (t *NamedType) isBoolean() bool { return t.Def.isBoolean() }
+
+func (t *NamedType) isInteger() bool { return t.Def.isInteger() }
+
+func (t *NamedType) isFloat() bool { return t.Def.isFloat() }
+
+func (t *NamedType) isIdeal() bool { return false }
+
+func (t *NamedType) String() string { return t.Name }
+
+func (t *NamedType) Zero() Value { return t.Def.Zero() }
+
+/*
+ * Multi-valued type
+ */
+
+// MultiType is a special type used for multi-valued expressions, akin
+// to a tuple type. It's not generally accessible within the
+// language.
+type MultiType struct {
+ commonType
+ Elems []Type
+}
+
+var multiTypes = newTypeArrayMap()
+
+func NewMultiType(elems []Type) *MultiType {
+ if t := multiTypes.Get(elems); t != nil {
+ return t.(*MultiType)
+ }
+
+ t := &MultiType{commonType{}, elems}
+ multiTypes.Put(elems, t)
+ return t
+}
+
+func (t *MultiType) compat(o Type, conv bool) bool {
+ t2, ok := o.lit().(*MultiType)
+ if !ok {
+ return false
+ }
+ if len(t.Elems) != len(t2.Elems) {
+ return false
+ }
+ for i := range t.Elems {
+ if !t.Elems[i].compat(t2.Elems[i], conv) {
+ return false
+ }
+ }
+ return true
+}
+
+var EmptyType Type = NewMultiType([]Type{})
+
+func (t *MultiType) lit() Type { return t }
+
+func (t *MultiType) String() string {
+ if len(t.Elems) == 0 {
+ return "<none>"
+ }
+ return typeListString(t.Elems, nil)
+}
+
+func (t *MultiType) Zero() Value {
+ res := make([]Value, len(t.Elems))
+ for i, t := range t.Elems {
+ res[i] = t.Zero()
+ }
+ return multiV(res)
+}
+
+/*
+ * Initialize the universe
+ */
+
+func init() {
+ numer := big.NewInt(0xffffff)
+ numer.Lsh(numer, 127-23)
+ maxFloat32Val = new(big.Rat).SetInt(numer)
+ numer.SetInt64(0x1fffffffffffff)
+ numer.Lsh(numer, 1023-52)
+ maxFloat64Val = new(big.Rat).SetInt(numer)
+ minFloat32Val = new(big.Rat).Neg(maxFloat32Val)
+ minFloat64Val = new(big.Rat).Neg(maxFloat64Val)
+
+ // To avoid portability issues all numeric types are distinct
+ // except byte, which is an alias for uint8.
+
+ // Make byte an alias for the named type uint8. Type aliases
+ // are otherwise impossible in Go, so just hack it here.
+ universe.defs["byte"] = universe.defs["uint8"]
+
+ // Built-in functions
+ universe.DefineConst("cap", universePos, capType, nil)
+ universe.DefineConst("close", universePos, closeType, nil)
+ universe.DefineConst("closed", universePos, closedType, nil)
+ universe.DefineConst("copy", universePos, copyType, nil)
+ universe.DefineConst("len", universePos, lenType, nil)
+ universe.DefineConst("make", universePos, makeType, nil)
+ universe.DefineConst("new", universePos, newType, nil)
+ universe.DefineConst("panic", universePos, panicType, nil)
+ universe.DefineConst("print", universePos, printType, nil)
+ universe.DefineConst("println", universePos, printlnType, nil)
+}
diff --git a/libgo/go/exp/eval/typec.go b/libgo/go/exp/eval/typec.go
new file mode 100644
index 000000000..de90cf664
--- /dev/null
+++ b/libgo/go/exp/eval/typec.go
@@ -0,0 +1,409 @@
+// 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 eval
+
+import (
+ "go/ast"
+ "go/token"
+ "log"
+)
+
+
+/*
+ * Type compiler
+ */
+
+type typeCompiler struct {
+ *compiler
+ block *block
+ // Check to be performed after a type declaration is compiled.
+ //
+ // TODO(austin) This will probably have to change after we
+ // eliminate forward declarations.
+ lateCheck func() bool
+}
+
+func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
+ _, _, def := a.block.Lookup(x.Name)
+ if def == nil {
+ a.diagAt(x.Pos(), "%s: undefined", x.Name)
+ return nil
+ }
+ switch def := def.(type) {
+ case *Constant:
+ a.diagAt(x.Pos(), "constant %v used as type", x.Name)
+ return nil
+ case *Variable:
+ a.diagAt(x.Pos(), "variable %v used as type", x.Name)
+ return nil
+ case *NamedType:
+ if !allowRec && def.incomplete {
+ a.diagAt(x.Pos(), "illegal recursive type")
+ return nil
+ }
+ if !def.incomplete && def.Def == nil {
+ // Placeholder type from an earlier error
+ return nil
+ }
+ return def
+ case Type:
+ return def
+ }
+ log.Panicf("name %s has unknown type %T", x.Name, def)
+ return nil
+}
+
+func (a *typeCompiler) compileArrayType(x *ast.ArrayType, allowRec bool) Type {
+ // Compile element type
+ elem := a.compileType(x.Elt, allowRec)
+
+ // Compile length expression
+ if x.Len == nil {
+ if elem == nil {
+ return nil
+ }
+ return NewSliceType(elem)
+ }
+
+ if _, ok := x.Len.(*ast.Ellipsis); ok {
+ a.diagAt(x.Len.Pos(), "... array initailizers not implemented")
+ return nil
+ }
+ l, ok := a.compileArrayLen(a.block, x.Len)
+ if !ok {
+ return nil
+ }
+ if l < 0 {
+ a.diagAt(x.Len.Pos(), "array length must be non-negative")
+ return nil
+ }
+ if elem == nil {
+ return nil
+ }
+
+ return NewArrayType(l, elem)
+}
+
+func (a *typeCompiler) compileFields(fields *ast.FieldList, allowRec bool) ([]Type, []*ast.Ident, []token.Pos, bool) {
+ n := fields.NumFields()
+ ts := make([]Type, n)
+ ns := make([]*ast.Ident, n)
+ ps := make([]token.Pos, n)
+ bad := false
+
+ if fields != nil {
+ i := 0
+ for _, f := range fields.List {
+ t := a.compileType(f.Type, allowRec)
+ if t == nil {
+ bad = true
+ }
+ if f.Names == nil {
+ ns[i] = nil
+ ts[i] = t
+ ps[i] = f.Type.Pos()
+ i++
+ continue
+ }
+ for _, n := range f.Names {
+ ns[i] = n
+ ts[i] = t
+ ps[i] = n.Pos()
+ i++
+ }
+ }
+ }
+
+ return ts, ns, ps, bad
+}
+
+func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type {
+ ts, names, poss, bad := a.compileFields(x.Fields, allowRec)
+
+ // XXX(Spec) The spec claims that field identifiers must be
+ // unique, but 6g only checks this when they are accessed. I
+ // think the spec is better in this regard: if I write two
+ // fields with the same name in the same struct type, clearly
+ // that's a mistake. This definition does *not* descend into
+ // anonymous fields, so it doesn't matter if those change.
+ // There's separate language in the spec about checking
+ // uniqueness of field names inherited from anonymous fields
+ // at use time.
+ fields := make([]StructField, len(ts))
+ nameSet := make(map[string]token.Pos, len(ts))
+ for i := range fields {
+ // Compute field name and check anonymous fields
+ var name string
+ if names[i] != nil {
+ name = names[i].Name
+ } else {
+ if ts[i] == nil {
+ continue
+ }
+
+ var nt *NamedType
+ // [For anonymous fields,] the unqualified
+ // type name acts as the field identifier.
+ switch t := ts[i].(type) {
+ case *NamedType:
+ name = t.Name
+ nt = t
+ case *PtrType:
+ switch t := t.Elem.(type) {
+ case *NamedType:
+ name = t.Name
+ nt = t
+ }
+ }
+ // [An anonymous field] must be specified as a
+ // type name T or as a pointer to a type name
+ // *T, and T itself, may not be a pointer or
+ // interface type.
+ if nt == nil {
+ a.diagAt(poss[i], "embedded type must T or *T, where T is a named type")
+ bad = true
+ continue
+ }
+ // The check for embedded pointer types must
+ // be deferred because of things like
+ // type T *struct { T }
+ lateCheck := a.lateCheck
+ a.lateCheck = func() bool {
+ if _, ok := nt.lit().(*PtrType); ok {
+ a.diagAt(poss[i], "embedded type %v is a pointer type", nt)
+ return false
+ }
+ return lateCheck()
+ }
+ }
+
+ // Check name uniqueness
+ if prev, ok := nameSet[name]; ok {
+ a.diagAt(poss[i], "field %s redeclared\n\tprevious declaration at %s", name, a.fset.Position(prev))
+ bad = true
+ continue
+ }
+ nameSet[name] = poss[i]
+
+ // Create field
+ fields[i].Name = name
+ fields[i].Type = ts[i]
+ fields[i].Anonymous = (names[i] == nil)
+ }
+
+ if bad {
+ return nil
+ }
+
+ return NewStructType(fields)
+}
+
+func (a *typeCompiler) compilePtrType(x *ast.StarExpr) Type {
+ elem := a.compileType(x.X, true)
+ if elem == nil {
+ return nil
+ }
+ return NewPtrType(elem)
+}
+
+func (a *typeCompiler) compileFuncType(x *ast.FuncType, allowRec bool) *FuncDecl {
+ // TODO(austin) Variadic function types
+
+ // The types of parameters and results must be complete.
+ //
+ // TODO(austin) It's not clear they actually have to be complete.
+ in, inNames, _, inBad := a.compileFields(x.Params, allowRec)
+ out, outNames, _, outBad := a.compileFields(x.Results, allowRec)
+
+ if inBad || outBad {
+ return nil
+ }
+ return &FuncDecl{NewFuncType(in, false, out), nil, inNames, outNames}
+}
+
+func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool) *InterfaceType {
+ ts, names, poss, bad := a.compileFields(x.Methods, allowRec)
+
+ methods := make([]IMethod, len(ts))
+ nameSet := make(map[string]token.Pos, len(ts))
+ embeds := make([]*InterfaceType, len(ts))
+
+ var nm, ne int
+ for i := range ts {
+ if ts[i] == nil {
+ continue
+ }
+
+ if names[i] != nil {
+ name := names[i].Name
+ methods[nm].Name = name
+ methods[nm].Type = ts[i].(*FuncType)
+ nm++
+ if prev, ok := nameSet[name]; ok {
+ a.diagAt(poss[i], "method %s redeclared\n\tprevious declaration at %s", name, a.fset.Position(prev))
+ bad = true
+ continue
+ }
+ nameSet[name] = poss[i]
+ } else {
+ // Embedded interface
+ it, ok := ts[i].lit().(*InterfaceType)
+ if !ok {
+ a.diagAt(poss[i], "embedded type must be an interface")
+ bad = true
+ continue
+ }
+ embeds[ne] = it
+ ne++
+ for _, m := range it.methods {
+ if prev, ok := nameSet[m.Name]; ok {
+ a.diagAt(poss[i], "method %s redeclared\n\tprevious declaration at %s", m.Name, a.fset.Position(prev))
+ bad = true
+ continue
+ }
+ nameSet[m.Name] = poss[i]
+ }
+ }
+ }
+
+ if bad {
+ return nil
+ }
+
+ methods = methods[0:nm]
+ embeds = embeds[0:ne]
+
+ return NewInterfaceType(methods, embeds)
+}
+
+func (a *typeCompiler) compileMapType(x *ast.MapType) Type {
+ key := a.compileType(x.Key, true)
+ val := a.compileType(x.Value, true)
+ if key == nil || val == nil {
+ return nil
+ }
+ // XXX(Spec) The Map types section explicitly lists all types
+ // that can be map keys except for function types.
+ switch key.lit().(type) {
+ case *StructType:
+ a.diagAt(x.Pos(), "map key cannot be a struct type")
+ return nil
+ case *ArrayType:
+ a.diagAt(x.Pos(), "map key cannot be an array type")
+ return nil
+ case *SliceType:
+ a.diagAt(x.Pos(), "map key cannot be a slice type")
+ return nil
+ }
+ return NewMapType(key, val)
+}
+
+func (a *typeCompiler) compileType(x ast.Expr, allowRec bool) Type {
+ switch x := x.(type) {
+ case *ast.BadExpr:
+ // Error already reported by parser
+ a.silentErrors++
+ return nil
+
+ case *ast.Ident:
+ return a.compileIdent(x, allowRec)
+
+ case *ast.ArrayType:
+ return a.compileArrayType(x, allowRec)
+
+ case *ast.StructType:
+ return a.compileStructType(x, allowRec)
+
+ case *ast.StarExpr:
+ return a.compilePtrType(x)
+
+ case *ast.FuncType:
+ fd := a.compileFuncType(x, allowRec)
+ if fd == nil {
+ return nil
+ }
+ return fd.Type
+
+ case *ast.InterfaceType:
+ return a.compileInterfaceType(x, allowRec)
+
+ case *ast.MapType:
+ return a.compileMapType(x)
+
+ case *ast.ChanType:
+ goto notimpl
+
+ case *ast.ParenExpr:
+ return a.compileType(x.X, allowRec)
+
+ case *ast.Ellipsis:
+ a.diagAt(x.Pos(), "illegal use of ellipsis")
+ return nil
+ }
+ a.diagAt(x.Pos(), "expression used as type")
+ return nil
+
+notimpl:
+ a.diagAt(x.Pos(), "compileType: %T not implemented", x)
+ return nil
+}
+
+/*
+ * Type compiler interface
+ */
+
+func noLateCheck() bool { return true }
+
+func (a *compiler) compileType(b *block, typ ast.Expr) Type {
+ tc := &typeCompiler{a, b, noLateCheck}
+ t := tc.compileType(typ, false)
+ if !tc.lateCheck() {
+ t = nil
+ }
+ return t
+}
+
+func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool {
+ ok := true
+ for _, spec := range decl.Specs {
+ spec := spec.(*ast.TypeSpec)
+ // Create incomplete type for this type
+ nt := b.DefineType(spec.Name.Name, spec.Name.Pos(), nil)
+ if nt != nil {
+ nt.(*NamedType).incomplete = true
+ }
+ // Compile type
+ tc := &typeCompiler{a, b, noLateCheck}
+ t := tc.compileType(spec.Type, false)
+ if t == nil {
+ // Create a placeholder type
+ ok = false
+ }
+ // Fill incomplete type
+ if nt != nil {
+ nt.(*NamedType).Complete(t)
+ }
+ // Perform late type checking with complete type
+ if !tc.lateCheck() {
+ ok = false
+ if nt != nil {
+ // Make the type a placeholder
+ nt.(*NamedType).Def = nil
+ }
+ }
+ }
+ return ok
+}
+
+func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl {
+ tc := &typeCompiler{a, b, noLateCheck}
+ res := tc.compileFuncType(typ, false)
+ if res != nil {
+ if !tc.lateCheck() {
+ res = nil
+ }
+ }
+ return res
+}
diff --git a/libgo/go/exp/eval/value.go b/libgo/go/exp/eval/value.go
new file mode 100644
index 000000000..daa691897
--- /dev/null
+++ b/libgo/go/exp/eval/value.go
@@ -0,0 +1,586 @@
+// 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 eval
+
+import (
+ "big"
+ "fmt"
+)
+
+type Value interface {
+ String() string
+ // Assign copies another value into this one. It should
+ // assume that the other value satisfies the same specific
+ // value interface (BoolValue, etc.), but must not assume
+ // anything about its specific type.
+ Assign(t *Thread, o Value)
+}
+
+type BoolValue interface {
+ Value
+ Get(*Thread) bool
+ Set(*Thread, bool)
+}
+
+type UintValue interface {
+ Value
+ Get(*Thread) uint64
+ Set(*Thread, uint64)
+}
+
+type IntValue interface {
+ Value
+ Get(*Thread) int64
+ Set(*Thread, int64)
+}
+
+// TODO(austin) IdealIntValue and IdealFloatValue should not exist
+// because ideals are not l-values.
+type IdealIntValue interface {
+ Value
+ Get() *big.Int
+}
+
+type FloatValue interface {
+ Value
+ Get(*Thread) float64
+ Set(*Thread, float64)
+}
+
+type IdealFloatValue interface {
+ Value
+ Get() *big.Rat
+}
+
+type StringValue interface {
+ Value
+ Get(*Thread) string
+ Set(*Thread, string)
+}
+
+type ArrayValue interface {
+ Value
+ // TODO(austin) Get() is here for uniformity, but is
+ // completely useless. If a lot of other types have similarly
+ // useless Get methods, just special-case these uses.
+ Get(*Thread) ArrayValue
+ Elem(*Thread, int64) Value
+ // Sub returns an ArrayValue backed by the same array that
+ // starts from element i and has length len.
+ Sub(i int64, len int64) ArrayValue
+}
+
+type StructValue interface {
+ Value
+ // TODO(austin) This is another useless Get()
+ Get(*Thread) StructValue
+ Field(*Thread, int) Value
+}
+
+type PtrValue interface {
+ Value
+ Get(*Thread) Value
+ Set(*Thread, Value)
+}
+
+type Func interface {
+ NewFrame() *Frame
+ Call(*Thread)
+}
+
+type FuncValue interface {
+ Value
+ Get(*Thread) Func
+ Set(*Thread, Func)
+}
+
+type Interface struct {
+ Type Type
+ Value Value
+}
+
+type InterfaceValue interface {
+ Value
+ Get(*Thread) Interface
+ Set(*Thread, Interface)
+}
+
+type Slice struct {
+ Base ArrayValue
+ Len, Cap int64
+}
+
+type SliceValue interface {
+ Value
+ Get(*Thread) Slice
+ Set(*Thread, Slice)
+}
+
+type Map interface {
+ Len(*Thread) int64
+ // Retrieve an element from the map, returning nil if it does
+ // not exist.
+ Elem(t *Thread, key interface{}) Value
+ // Set an entry in the map. If val is nil, delete the entry.
+ SetElem(t *Thread, key interface{}, val Value)
+ // TODO(austin) Perhaps there should be an iterator interface instead.
+ Iter(func(key interface{}, val Value) bool)
+}
+
+type MapValue interface {
+ Value
+ Get(*Thread) Map
+ Set(*Thread, Map)
+}
+
+/*
+ * Bool
+ */
+
+type boolV bool
+
+func (v *boolV) String() string { return fmt.Sprint(*v) }
+
+func (v *boolV) Assign(t *Thread, o Value) { *v = boolV(o.(BoolValue).Get(t)) }
+
+func (v *boolV) Get(*Thread) bool { return bool(*v) }
+
+func (v *boolV) Set(t *Thread, x bool) { *v = boolV(x) }
+
+/*
+ * Uint
+ */
+
+type uint8V uint8
+
+func (v *uint8V) String() string { return fmt.Sprint(*v) }
+
+func (v *uint8V) Assign(t *Thread, o Value) { *v = uint8V(o.(UintValue).Get(t)) }
+
+func (v *uint8V) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uint8V) Set(t *Thread, x uint64) { *v = uint8V(x) }
+
+type uint16V uint16
+
+func (v *uint16V) String() string { return fmt.Sprint(*v) }
+
+func (v *uint16V) Assign(t *Thread, o Value) { *v = uint16V(o.(UintValue).Get(t)) }
+
+func (v *uint16V) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uint16V) Set(t *Thread, x uint64) { *v = uint16V(x) }
+
+type uint32V uint32
+
+func (v *uint32V) String() string { return fmt.Sprint(*v) }
+
+func (v *uint32V) Assign(t *Thread, o Value) { *v = uint32V(o.(UintValue).Get(t)) }
+
+func (v *uint32V) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uint32V) Set(t *Thread, x uint64) { *v = uint32V(x) }
+
+type uint64V uint64
+
+func (v *uint64V) String() string { return fmt.Sprint(*v) }
+
+func (v *uint64V) Assign(t *Thread, o Value) { *v = uint64V(o.(UintValue).Get(t)) }
+
+func (v *uint64V) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uint64V) Set(t *Thread, x uint64) { *v = uint64V(x) }
+
+type uintV uint
+
+func (v *uintV) String() string { return fmt.Sprint(*v) }
+
+func (v *uintV) Assign(t *Thread, o Value) { *v = uintV(o.(UintValue).Get(t)) }
+
+func (v *uintV) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uintV) Set(t *Thread, x uint64) { *v = uintV(x) }
+
+type uintptrV uintptr
+
+func (v *uintptrV) String() string { return fmt.Sprint(*v) }
+
+func (v *uintptrV) Assign(t *Thread, o Value) { *v = uintptrV(o.(UintValue).Get(t)) }
+
+func (v *uintptrV) Get(*Thread) uint64 { return uint64(*v) }
+
+func (v *uintptrV) Set(t *Thread, x uint64) { *v = uintptrV(x) }
+
+/*
+ * Int
+ */
+
+type int8V int8
+
+func (v *int8V) String() string { return fmt.Sprint(*v) }
+
+func (v *int8V) Assign(t *Thread, o Value) { *v = int8V(o.(IntValue).Get(t)) }
+
+func (v *int8V) Get(*Thread) int64 { return int64(*v) }
+
+func (v *int8V) Set(t *Thread, x int64) { *v = int8V(x) }
+
+type int16V int16
+
+func (v *int16V) String() string { return fmt.Sprint(*v) }
+
+func (v *int16V) Assign(t *Thread, o Value) { *v = int16V(o.(IntValue).Get(t)) }
+
+func (v *int16V) Get(*Thread) int64 { return int64(*v) }
+
+func (v *int16V) Set(t *Thread, x int64) { *v = int16V(x) }
+
+type int32V int32
+
+func (v *int32V) String() string { return fmt.Sprint(*v) }
+
+func (v *int32V) Assign(t *Thread, o Value) { *v = int32V(o.(IntValue).Get(t)) }
+
+func (v *int32V) Get(*Thread) int64 { return int64(*v) }
+
+func (v *int32V) Set(t *Thread, x int64) { *v = int32V(x) }
+
+type int64V int64
+
+func (v *int64V) String() string { return fmt.Sprint(*v) }
+
+func (v *int64V) Assign(t *Thread, o Value) { *v = int64V(o.(IntValue).Get(t)) }
+
+func (v *int64V) Get(*Thread) int64 { return int64(*v) }
+
+func (v *int64V) Set(t *Thread, x int64) { *v = int64V(x) }
+
+type intV int
+
+func (v *intV) String() string { return fmt.Sprint(*v) }
+
+func (v *intV) Assign(t *Thread, o Value) { *v = intV(o.(IntValue).Get(t)) }
+
+func (v *intV) Get(*Thread) int64 { return int64(*v) }
+
+func (v *intV) Set(t *Thread, x int64) { *v = intV(x) }
+
+/*
+ * Ideal int
+ */
+
+type idealIntV struct {
+ V *big.Int
+}
+
+func (v *idealIntV) String() string { return v.V.String() }
+
+func (v *idealIntV) Assign(t *Thread, o Value) {
+ v.V = o.(IdealIntValue).Get()
+}
+
+func (v *idealIntV) Get() *big.Int { return v.V }
+
+/*
+ * Float
+ */
+
+type float32V float32
+
+func (v *float32V) String() string { return fmt.Sprint(*v) }
+
+func (v *float32V) Assign(t *Thread, o Value) { *v = float32V(o.(FloatValue).Get(t)) }
+
+func (v *float32V) Get(*Thread) float64 { return float64(*v) }
+
+func (v *float32V) Set(t *Thread, x float64) { *v = float32V(x) }
+
+type float64V float64
+
+func (v *float64V) String() string { return fmt.Sprint(*v) }
+
+func (v *float64V) Assign(t *Thread, o Value) { *v = float64V(o.(FloatValue).Get(t)) }
+
+func (v *float64V) Get(*Thread) float64 { return float64(*v) }
+
+func (v *float64V) Set(t *Thread, x float64) { *v = float64V(x) }
+
+/*
+ * Ideal float
+ */
+
+type idealFloatV struct {
+ V *big.Rat
+}
+
+func (v *idealFloatV) String() string { return v.V.FloatString(6) }
+
+func (v *idealFloatV) Assign(t *Thread, o Value) {
+ v.V = o.(IdealFloatValue).Get()
+}
+
+func (v *idealFloatV) Get() *big.Rat { return v.V }
+
+/*
+ * String
+ */
+
+type stringV string
+
+func (v *stringV) String() string { return fmt.Sprint(*v) }
+
+func (v *stringV) Assign(t *Thread, o Value) { *v = stringV(o.(StringValue).Get(t)) }
+
+func (v *stringV) Get(*Thread) string { return string(*v) }
+
+func (v *stringV) Set(t *Thread, x string) { *v = stringV(x) }
+
+/*
+ * Array
+ */
+
+type arrayV []Value
+
+func (v *arrayV) String() string {
+ res := "{"
+ for i, e := range *v {
+ if i > 0 {
+ res += ", "
+ }
+ res += e.String()
+ }
+ return res + "}"
+}
+
+func (v *arrayV) Assign(t *Thread, o Value) {
+ oa := o.(ArrayValue)
+ l := int64(len(*v))
+ for i := int64(0); i < l; i++ {
+ (*v)[i].Assign(t, oa.Elem(t, i))
+ }
+}
+
+func (v *arrayV) Get(*Thread) ArrayValue { return v }
+
+func (v *arrayV) Elem(t *Thread, i int64) Value {
+ return (*v)[i]
+}
+
+func (v *arrayV) Sub(i int64, len int64) ArrayValue {
+ res := (*v)[i : i+len]
+ return &res
+}
+
+/*
+ * Struct
+ */
+
+type structV []Value
+
+// TODO(austin) Should these methods (and arrayV's) be on structV
+// instead of *structV?
+func (v *structV) String() string {
+ res := "{"
+ for i, v := range *v {
+ if i > 0 {
+ res += ", "
+ }
+ res += v.String()
+ }
+ return res + "}"
+}
+
+func (v *structV) Assign(t *Thread, o Value) {
+ oa := o.(StructValue)
+ l := len(*v)
+ for i := 0; i < l; i++ {
+ (*v)[i].Assign(t, oa.Field(t, i))
+ }
+}
+
+func (v *structV) Get(*Thread) StructValue { return v }
+
+func (v *structV) Field(t *Thread, i int) Value {
+ return (*v)[i]
+}
+
+/*
+ * Pointer
+ */
+
+type ptrV struct {
+ // nil if the pointer is nil
+ target Value
+}
+
+func (v *ptrV) String() string {
+ if v.target == nil {
+ return "<nil>"
+ }
+ return "&" + v.target.String()
+}
+
+func (v *ptrV) Assign(t *Thread, o Value) { v.target = o.(PtrValue).Get(t) }
+
+func (v *ptrV) Get(*Thread) Value { return v.target }
+
+func (v *ptrV) Set(t *Thread, x Value) { v.target = x }
+
+/*
+ * Functions
+ */
+
+type funcV struct {
+ target Func
+}
+
+func (v *funcV) String() string {
+ // TODO(austin) Rob wants to see the definition
+ return "func {...}"
+}
+
+func (v *funcV) Assign(t *Thread, o Value) { v.target = o.(FuncValue).Get(t) }
+
+func (v *funcV) Get(*Thread) Func { return v.target }
+
+func (v *funcV) Set(t *Thread, x Func) { v.target = x }
+
+/*
+ * Interfaces
+ */
+
+type interfaceV struct {
+ Interface
+}
+
+func (v *interfaceV) String() string {
+ if v.Type == nil || v.Value == nil {
+ return "<nil>"
+ }
+ return v.Value.String()
+}
+
+func (v *interfaceV) Assign(t *Thread, o Value) {
+ v.Interface = o.(InterfaceValue).Get(t)
+}
+
+func (v *interfaceV) Get(*Thread) Interface { return v.Interface }
+
+func (v *interfaceV) Set(t *Thread, x Interface) {
+ v.Interface = x
+}
+
+/*
+ * Slices
+ */
+
+type sliceV struct {
+ Slice
+}
+
+func (v *sliceV) String() string {
+ if v.Base == nil {
+ return "<nil>"
+ }
+ return v.Base.Sub(0, v.Len).String()
+}
+
+func (v *sliceV) Assign(t *Thread, o Value) { v.Slice = o.(SliceValue).Get(t) }
+
+func (v *sliceV) Get(*Thread) Slice { return v.Slice }
+
+func (v *sliceV) Set(t *Thread, x Slice) { v.Slice = x }
+
+/*
+ * Maps
+ */
+
+type mapV struct {
+ target Map
+}
+
+func (v *mapV) String() string {
+ if v.target == nil {
+ return "<nil>"
+ }
+ res := "map["
+ i := 0
+ v.target.Iter(func(key interface{}, val Value) bool {
+ if i > 0 {
+ res += ", "
+ }
+ i++
+ res += fmt.Sprint(key) + ":" + val.String()
+ return true
+ })
+ return res + "]"
+}
+
+func (v *mapV) Assign(t *Thread, o Value) { v.target = o.(MapValue).Get(t) }
+
+func (v *mapV) Get(*Thread) Map { return v.target }
+
+func (v *mapV) Set(t *Thread, x Map) { v.target = x }
+
+type evalMap map[interface{}]Value
+
+func (m evalMap) Len(t *Thread) int64 { return int64(len(m)) }
+
+func (m evalMap) Elem(t *Thread, key interface{}) Value {
+ return m[key]
+}
+
+func (m evalMap) SetElem(t *Thread, key interface{}, val Value) {
+ if val == nil {
+ m[key] = nil, false
+ } else {
+ m[key] = val
+ }
+}
+
+func (m evalMap) Iter(cb func(key interface{}, val Value) bool) {
+ for k, v := range m {
+ if !cb(k, v) {
+ break
+ }
+ }
+}
+
+/*
+ * Multi-values
+ */
+
+type multiV []Value
+
+func (v multiV) String() string {
+ res := "("
+ for i, v := range v {
+ if i > 0 {
+ res += ", "
+ }
+ res += v.String()
+ }
+ return res + ")"
+}
+
+func (v multiV) Assign(t *Thread, o Value) {
+ omv := o.(multiV)
+ for i := range v {
+ v[i].Assign(t, omv[i])
+ }
+}
+
+/*
+ * Universal constants
+ */
+
+func init() {
+ s := universe
+
+ true := boolV(true)
+ s.DefineConst("true", universePos, BoolType, &true)
+ false := boolV(false)
+ s.DefineConst("false", universePos, BoolType, &false)
+}
diff --git a/libgo/go/exp/eval/world.go b/libgo/go/exp/eval/world.go
new file mode 100644
index 000000000..02d18bd79
--- /dev/null
+++ b/libgo/go/exp/eval/world.go
@@ -0,0 +1,188 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package is the beginning of an interpreter for Go.
+// It can run simple Go programs but does not implement
+// interface values or packages.
+package eval
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "os"
+)
+
+type World struct {
+ scope *Scope
+ frame *Frame
+}
+
+func NewWorld() *World {
+ w := new(World)
+ w.scope = universe.ChildScope()
+ w.scope.global = true // this block's vars allocate directly
+ return w
+}
+
+type Code interface {
+ // The type of the value Run returns, or nil if Run returns nil.
+ Type() Type
+
+ // Run runs the code; if the code is a single expression
+ // with a value, it returns the value; otherwise it returns nil.
+ Run() (Value, os.Error)
+}
+
+type stmtCode struct {
+ w *World
+ code code
+}
+
+func (w *World) CompileStmtList(fset *token.FileSet, stmts []ast.Stmt) (Code, os.Error) {
+ if len(stmts) == 1 {
+ if s, ok := stmts[0].(*ast.ExprStmt); ok {
+ return w.CompileExpr(fset, s.X)
+ }
+ }
+ errors := new(scanner.ErrorVector)
+ cc := &compiler{fset, errors, 0, 0}
+ cb := newCodeBuf()
+ fc := &funcCompiler{
+ compiler: cc,
+ fnType: nil,
+ outVarsNamed: false,
+ codeBuf: cb,
+ flow: newFlowBuf(cb),
+ labels: make(map[string]*label),
+ }
+ bc := &blockCompiler{
+ funcCompiler: fc,
+ block: w.scope.block,
+ }
+ nerr := cc.numError()
+ for _, stmt := range stmts {
+ bc.compileStmt(stmt)
+ }
+ fc.checkLabels()
+ if nerr != cc.numError() {
+ return nil, errors.GetError(scanner.Sorted)
+ }
+ return &stmtCode{w, fc.get()}, nil
+}
+
+func (w *World) CompileDeclList(fset *token.FileSet, decls []ast.Decl) (Code, os.Error) {
+ stmts := make([]ast.Stmt, len(decls))
+ for i, d := range decls {
+ stmts[i] = &ast.DeclStmt{d}
+ }
+ return w.CompileStmtList(fset, stmts)
+}
+
+func (s *stmtCode) Type() Type { return nil }
+
+func (s *stmtCode) Run() (Value, os.Error) {
+ t := new(Thread)
+ t.f = s.w.scope.NewFrame(nil)
+ return nil, t.Try(func(t *Thread) { s.code.exec(t) })
+}
+
+type exprCode struct {
+ w *World
+ e *expr
+ eval func(Value, *Thread)
+}
+
+func (w *World) CompileExpr(fset *token.FileSet, e ast.Expr) (Code, os.Error) {
+ errors := new(scanner.ErrorVector)
+ cc := &compiler{fset, errors, 0, 0}
+
+ ec := cc.compileExpr(w.scope.block, false, e)
+ if ec == nil {
+ return nil, errors.GetError(scanner.Sorted)
+ }
+ var eval func(Value, *Thread)
+ switch t := ec.t.(type) {
+ case *idealIntType:
+ // nothing
+ case *idealFloatType:
+ // nothing
+ default:
+ if tm, ok := t.(*MultiType); ok && len(tm.Elems) == 0 {
+ return &stmtCode{w, code{ec.exec}}, nil
+ }
+ eval = genAssign(ec.t, ec)
+ }
+ return &exprCode{w, ec, eval}, nil
+}
+
+func (e *exprCode) Type() Type { return e.e.t }
+
+func (e *exprCode) Run() (Value, os.Error) {
+ t := new(Thread)
+ t.f = e.w.scope.NewFrame(nil)
+ switch e.e.t.(type) {
+ case *idealIntType:
+ return &idealIntV{e.e.asIdealInt()()}, nil
+ case *idealFloatType:
+ return &idealFloatV{e.e.asIdealFloat()()}, nil
+ }
+ v := e.e.t.Zero()
+ eval := e.eval
+ err := t.Try(func(t *Thread) { eval(v, t) })
+ return v, err
+}
+
+func (w *World) Compile(fset *token.FileSet, text string) (Code, os.Error) {
+ stmts, err := parser.ParseStmtList(fset, "input", text)
+ if err == nil {
+ return w.CompileStmtList(fset, stmts)
+ }
+
+ // Otherwise try as DeclList.
+ decls, err1 := parser.ParseDeclList(fset, "input", text)
+ if err1 == nil {
+ return w.CompileDeclList(fset, decls)
+ }
+
+ // Have to pick an error.
+ // Parsing as statement list admits more forms,
+ // its error is more likely to be useful.
+ return nil, err
+}
+
+type RedefinitionError struct {
+ Name string
+ Prev Def
+}
+
+func (e *RedefinitionError) String() string {
+ res := "identifier " + e.Name + " redeclared"
+ pos := e.Prev.Pos()
+ if pos.IsValid() {
+ // TODO: fix this - currently this code is not reached by the tests
+ // need to get a file set (fset) from somewhere
+ //res += "; previous declaration at " + fset.Position(pos).String()
+ panic(0)
+ }
+ return res
+}
+
+func (w *World) DefineConst(name string, t Type, val Value) os.Error {
+ _, prev := w.scope.DefineConst(name, token.NoPos, t, val)
+ if prev != nil {
+ return &RedefinitionError{name, prev}
+ }
+ return nil
+}
+
+func (w *World) DefineVar(name string, t Type, val Value) os.Error {
+ v, prev := w.scope.DefineVar(name, token.NoPos, t)
+ if prev != nil {
+ return &RedefinitionError{name, prev}
+ }
+ v.Init = val
+ return nil
+}
diff --git a/libgo/go/exp/ogle/abort.go b/libgo/go/exp/ogle/abort.go
new file mode 100644
index 000000000..311a7b38e
--- /dev/null
+++ b/libgo/go/exp/ogle/abort.go
@@ -0,0 +1,35 @@
+// 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 ogle
+
+import (
+ "os"
+ "runtime"
+)
+
+// An aborter aborts the thread's current computation, usually
+// passing the error to a waiting thread.
+type aborter interface {
+ Abort(err os.Error)
+}
+
+type ogleAborter chan os.Error
+
+func (a ogleAborter) Abort(err os.Error) {
+ a <- err
+ runtime.Goexit()
+}
+
+// try executes a computation; if the computation Aborts, try returns
+// the error passed to abort.
+func try(f func(a aborter)) os.Error {
+ a := make(ogleAborter)
+ go func() {
+ f(a)
+ a <- nil
+ }()
+ err := <-a
+ return err
+}
diff --git a/libgo/go/exp/ogle/arch.go b/libgo/go/exp/ogle/arch.go
new file mode 100644
index 000000000..52b1c9757
--- /dev/null
+++ b/libgo/go/exp/ogle/arch.go
@@ -0,0 +1,125 @@
+// 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 ogle
+
+import (
+ "debug/proc"
+ "math"
+)
+
+type Arch interface {
+ // ToWord converts an array of up to 8 bytes in memory order
+ // to a word.
+ ToWord(data []byte) proc.Word
+ // FromWord converts a word to an array of up to 8 bytes in
+ // memory order.
+ FromWord(v proc.Word, out []byte)
+ // ToFloat32 converts a word to a float. The order of this
+ // word will be the order returned by ToWord on the memory
+ // representation of a float, and thus may require reversing.
+ ToFloat32(bits uint32) float32
+ // FromFloat32 converts a float to a word. This should return
+ // a word that can be passed to FromWord to get the memory
+ // representation of a float on this architecture.
+ FromFloat32(f float32) uint32
+ // ToFloat64 is to float64 as ToFloat32 is to float32.
+ ToFloat64(bits uint64) float64
+ // FromFloat64 is to float64 as FromFloat32 is to float32.
+ FromFloat64(f float64) uint64
+
+ // IntSize returns the number of bytes in an 'int'.
+ IntSize() int
+ // PtrSize returns the number of bytes in a 'uintptr'.
+ PtrSize() int
+ // FloatSize returns the number of bytes in a 'float'.
+ FloatSize() int
+ // Align rounds offset up to the appropriate offset for a
+ // basic type with the given width.
+ Align(offset, width int) int
+
+ // G returns the current G pointer.
+ G(regs proc.Regs) proc.Word
+
+ // ClosureSize returns the number of bytes expected by
+ // ParseClosure.
+ ClosureSize() int
+ // ParseClosure takes ClosureSize bytes read from a return PC
+ // in a remote process, determines if the code is a closure,
+ // and returns the frame size of the closure if it is.
+ ParseClosure(data []byte) (frame int, ok bool)
+}
+
+type ArchLSB struct{}
+
+func (ArchLSB) ToWord(data []byte) proc.Word {
+ var v proc.Word
+ for i, b := range data {
+ v |= proc.Word(b) << (uint(i) * 8)
+ }
+ return v
+}
+
+func (ArchLSB) FromWord(v proc.Word, out []byte) {
+ for i := range out {
+ out[i] = byte(v)
+ v >>= 8
+ }
+}
+
+func (ArchLSB) ToFloat32(bits uint32) float32 {
+ // TODO(austin) Do these definitions depend on my current
+ // architecture?
+ return math.Float32frombits(bits)
+}
+
+func (ArchLSB) FromFloat32(f float32) uint32 { return math.Float32bits(f) }
+
+func (ArchLSB) ToFloat64(bits uint64) float64 { return math.Float64frombits(bits) }
+
+func (ArchLSB) FromFloat64(f float64) uint64 { return math.Float64bits(f) }
+
+type ArchAlignedMultiple struct{}
+
+func (ArchAlignedMultiple) Align(offset, width int) int {
+ return ((offset - 1) | (width - 1)) + 1
+}
+
+type amd64 struct {
+ ArchLSB
+ ArchAlignedMultiple
+ gReg int
+}
+
+func (a *amd64) IntSize() int { return 4 }
+
+func (a *amd64) PtrSize() int { return 8 }
+
+func (a *amd64) FloatSize() int { return 4 }
+
+func (a *amd64) G(regs proc.Regs) proc.Word {
+ // See src/pkg/runtime/mkasmh
+ if a.gReg == -1 {
+ ns := regs.Names()
+ for i, n := range ns {
+ if n == "r15" {
+ a.gReg = i
+ break
+ }
+ }
+ }
+
+ return regs.Get(a.gReg)
+}
+
+func (a *amd64) ClosureSize() int { return 8 }
+
+func (a *amd64) ParseClosure(data []byte) (int, bool) {
+ if data[0] == 0x48 && data[1] == 0x81 && data[2] == 0xc4 && data[7] == 0xc3 {
+ return int(a.ToWord(data[3:7]) + 8), true
+ }
+ return 0, false
+}
+
+var Amd64 = &amd64{gReg: -1}
diff --git a/libgo/go/exp/ogle/cmd.go b/libgo/go/exp/ogle/cmd.go
new file mode 100644
index 000000000..4f67032d0
--- /dev/null
+++ b/libgo/go/exp/ogle/cmd.go
@@ -0,0 +1,373 @@
+// 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.
+
+// Ogle is the beginning of a debugger for Go.
+package ogle
+
+import (
+ "bufio"
+ "debug/elf"
+ "debug/proc"
+ "exp/eval"
+ "fmt"
+ "go/scanner"
+ "go/token"
+ "os"
+ "strconv"
+ "strings"
+)
+
+var fset = token.NewFileSet()
+var world *eval.World
+var curProc *Process
+
+func Main() {
+ world = eval.NewWorld()
+ defineFuncs()
+ r := bufio.NewReader(os.Stdin)
+ for {
+ print("; ")
+ line, err := r.ReadSlice('\n')
+ if err != nil {
+ break
+ }
+
+ // Try line as a command
+ cmd, rest := getCmd(line)
+ if cmd != nil {
+ err := cmd.handler(rest)
+ if err != nil {
+ scanner.PrintError(os.Stderr, err)
+ }
+ continue
+ }
+
+ // Try line as code
+ code, err := world.Compile(fset, string(line))
+ if err != nil {
+ scanner.PrintError(os.Stderr, err)
+ continue
+ }
+ v, err := code.Run()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, err.String())
+ continue
+ }
+ if v != nil {
+ println(v.String())
+ }
+ }
+}
+
+// newScanner creates a new scanner that scans that given input bytes.
+func newScanner(input []byte) (*scanner.Scanner, *scanner.ErrorVector) {
+ sc := new(scanner.Scanner)
+ ev := new(scanner.ErrorVector)
+ file := fset.AddFile("input", fset.Base(), len(input))
+ sc.Init(file, input, ev, 0)
+ return sc, ev
+}
+
+/*
+ * Commands
+ */
+
+// A UsageError occurs when a command is called with illegal arguments.
+type UsageError string
+
+func (e UsageError) String() string { return string(e) }
+
+// A cmd represents a single command with a handler.
+type cmd struct {
+ cmd string
+ handler func([]byte) os.Error
+}
+
+var cmds = []cmd{
+ {"load", cmdLoad},
+ {"bt", cmdBt},
+}
+
+// getCmd attempts to parse an input line as a registered command. If
+// successful, it returns the command and the bytes remaining after
+// the command, which should be passed to the command.
+func getCmd(line []byte) (*cmd, []byte) {
+ sc, _ := newScanner(line)
+ pos, tok, lit := sc.Scan()
+ if sc.ErrorCount != 0 || tok != token.IDENT {
+ return nil, nil
+ }
+
+ slit := string(lit)
+ for i := range cmds {
+ if cmds[i].cmd == slit {
+ return &cmds[i], line[fset.Position(pos).Offset+len(lit):]
+ }
+ }
+ return nil, nil
+}
+
+// cmdLoad starts or attaches to a process. Its form is similar to
+// import:
+//
+// load [sym] "path" [;]
+//
+// sym specifies the name to give to the process. If not given, the
+// name is derived from the path of the process. If ".", then the
+// packages from the remote process are defined into the current
+// namespace. If given, this symbol is defined as a package
+// containing the process' packages.
+//
+// path gives the path of the process to start or attach to. If it is
+// "pid:<num>", then attach to the given PID. Otherwise, treat it as
+// a file path and space-separated arguments and start a new process.
+//
+// load always sets the current process to the loaded process.
+func cmdLoad(args []byte) os.Error {
+ ident, path, err := parseLoad(args)
+ if err != nil {
+ return err
+ }
+ if curProc != nil {
+ return UsageError("multiple processes not implemented")
+ }
+ if ident != "." {
+ return UsageError("process identifiers not implemented")
+ }
+
+ // Parse argument and start or attach to process
+ var fname string
+ var tproc proc.Process
+ if len(path) >= 4 && path[0:4] == "pid:" {
+ pid, err := strconv.Atoi(path[4:])
+ if err != nil {
+ return err
+ }
+ fname, err = os.Readlink(fmt.Sprintf("/proc/%d/exe", pid))
+ if err != nil {
+ return err
+ }
+ tproc, err = proc.Attach(pid)
+ if err != nil {
+ return err
+ }
+ println("Attached to", pid)
+ } else {
+ parts := strings.Split(path, " ", -1)
+ if len(parts) == 0 {
+ fname = ""
+ } else {
+ fname = parts[0]
+ }
+ tproc, err = proc.ForkExec(fname, parts, os.Environ(), "", []*os.File{os.Stdin, os.Stdout, os.Stderr})
+ if err != nil {
+ return err
+ }
+ println("Started", path)
+ // TODO(austin) If we fail after this point, kill tproc
+ // before detaching.
+ }
+
+ // Get symbols
+ f, err := os.Open(fname, os.O_RDONLY, 0)
+ if err != nil {
+ tproc.Detach()
+ return err
+ }
+ defer f.Close()
+ elf, err := elf.NewFile(f)
+ if err != nil {
+ tproc.Detach()
+ return err
+ }
+ curProc, err = NewProcessElf(tproc, elf)
+ if err != nil {
+ tproc.Detach()
+ return err
+ }
+
+ // Prepare new process
+ curProc.OnGoroutineCreate().AddHandler(EventPrint)
+ curProc.OnGoroutineExit().AddHandler(EventPrint)
+
+ err = curProc.populateWorld(world)
+ if err != nil {
+ tproc.Detach()
+ return err
+ }
+
+ return nil
+}
+
+func parseLoad(args []byte) (ident string, path string, err os.Error) {
+ err = UsageError("Usage: load [sym] \"path\"")
+ sc, ev := newScanner(args)
+
+ var toks [4]token.Token
+ var lits [4][]byte
+ for i := range toks {
+ _, toks[i], lits[i] = sc.Scan()
+ }
+ if sc.ErrorCount != 0 {
+ err = ev.GetError(scanner.NoMultiples)
+ return
+ }
+
+ i := 0
+ switch toks[i] {
+ case token.PERIOD, token.IDENT:
+ ident = string(lits[i])
+ i++
+ }
+
+ if toks[i] != token.STRING {
+ return
+ }
+ path, uerr := strconv.Unquote(string(lits[i]))
+ if uerr != nil {
+ err = uerr
+ return
+ }
+ i++
+
+ if toks[i] == token.SEMICOLON {
+ i++
+ }
+ if toks[i] != token.EOF {
+ return
+ }
+
+ return ident, path, nil
+}
+
+// cmdBt prints a backtrace for the current goroutine. It takes no
+// arguments.
+func cmdBt(args []byte) os.Error {
+ err := parseNoArgs(args, "Usage: bt")
+ if err != nil {
+ return err
+ }
+
+ if curProc == nil || curProc.curGoroutine == nil {
+ return NoCurrentGoroutine{}
+ }
+
+ f := curProc.curGoroutine.frame
+ if f == nil {
+ fmt.Println("No frames on stack")
+ return nil
+ }
+
+ for f.Inner() != nil {
+ f = f.Inner()
+ }
+
+ for i := 0; i < 100; i++ {
+ if f == curProc.curGoroutine.frame {
+ fmt.Printf("=> ")
+ } else {
+ fmt.Printf(" ")
+ }
+ fmt.Printf("%8x %v\n", f.pc, f)
+ f, err = f.Outer()
+ if err != nil {
+ return err
+ }
+ if f == nil {
+ return nil
+ }
+ }
+
+ fmt.Println("...")
+ return nil
+}
+
+func parseNoArgs(args []byte, usage string) os.Error {
+ sc, ev := newScanner(args)
+ _, tok, _ := sc.Scan()
+ if sc.ErrorCount != 0 {
+ return ev.GetError(scanner.NoMultiples)
+ }
+ if tok != token.EOF {
+ return UsageError(usage)
+ }
+ return nil
+}
+
+/*
+ * Functions
+ */
+
+// defineFuncs populates world with the built-in functions.
+func defineFuncs() {
+ t, v := eval.FuncFromNativeTyped(fnOut, fnOutSig)
+ world.DefineConst("Out", t, v)
+ t, v = eval.FuncFromNativeTyped(fnContWait, fnContWaitSig)
+ world.DefineConst("ContWait", t, v)
+ t, v = eval.FuncFromNativeTyped(fnBpSet, fnBpSetSig)
+ world.DefineConst("BpSet", t, v)
+}
+
+// printCurFrame prints the current stack frame, as it would appear in
+// a backtrace.
+func printCurFrame() {
+ if curProc == nil || curProc.curGoroutine == nil {
+ return
+ }
+ f := curProc.curGoroutine.frame
+ if f == nil {
+ return
+ }
+ fmt.Printf("=> %8x %v\n", f.pc, f)
+}
+
+// fnOut moves the current frame to the caller of the current frame.
+func fnOutSig() {}
+func fnOut(t *eval.Thread, args []eval.Value, res []eval.Value) {
+ if curProc == nil {
+ t.Abort(NoCurrentGoroutine{})
+ }
+ err := curProc.Out()
+ if err != nil {
+ t.Abort(err)
+ }
+ // TODO(austin) Only in the command form
+ printCurFrame()
+}
+
+// fnContWait continues the current process and waits for a stopping event.
+func fnContWaitSig() {}
+func fnContWait(t *eval.Thread, args []eval.Value, res []eval.Value) {
+ if curProc == nil {
+ t.Abort(NoCurrentGoroutine{})
+ }
+ err := curProc.ContWait()
+ if err != nil {
+ t.Abort(err)
+ }
+ // TODO(austin) Only in the command form
+ ev := curProc.Event()
+ if ev != nil {
+ fmt.Printf("%v\n", ev)
+ }
+ printCurFrame()
+}
+
+// fnBpSet sets a breakpoint at the entry to the named function.
+func fnBpSetSig(string) {}
+func fnBpSet(t *eval.Thread, args []eval.Value, res []eval.Value) {
+ // TODO(austin) This probably shouldn't take a symbol name.
+ // Perhaps it should take an interface that provides PC's.
+ // Functions and instructions can implement that interface and
+ // we can have something to translate file:line pairs.
+ if curProc == nil {
+ t.Abort(NoCurrentGoroutine{})
+ }
+ name := args[0].(eval.StringValue).Get(t)
+ fn := curProc.syms.LookupFunc(name)
+ if fn == nil {
+ t.Abort(UsageError("no such function " + name))
+ }
+ curProc.OnBreakpoint(proc.Word(fn.Entry)).AddHandler(EventStop)
+}
diff --git a/libgo/go/exp/ogle/event.go b/libgo/go/exp/ogle/event.go
new file mode 100644
index 000000000..d7092ded3
--- /dev/null
+++ b/libgo/go/exp/ogle/event.go
@@ -0,0 +1,280 @@
+// 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 ogle
+
+import (
+ "debug/proc"
+ "fmt"
+ "os"
+)
+
+/*
+ * Hooks and events
+ */
+
+// An EventHandler is a function that takes an event and returns a
+// response to that event and possibly an error. If an event handler
+// returns an error, the process stops and no other handlers for that
+// event are executed.
+type EventHandler func(e Event) (EventAction, os.Error)
+
+// An EventAction is an event handler's response to an event. If all
+// of an event's handlers execute without returning errors, their
+// results are combined as follows: If any handler returned
+// EAContinue, then the process resumes (without returning from
+// WaitStop); otherwise, if any handler returned EAStop, the process
+// remains stopped; otherwise, if all handlers returned EADefault, the
+// process resumes. A handler may return EARemoveSelf bit-wise or'd
+// with any other action to indicate that the handler should be
+// removed from the hook.
+type EventAction int
+
+const (
+ EARemoveSelf EventAction = 0x100
+ EADefault EventAction = iota
+ EAStop
+ EAContinue
+)
+
+// A EventHook allows event handlers to be added and removed.
+type EventHook interface {
+ AddHandler(EventHandler)
+ RemoveHandler(EventHandler)
+ NumHandler() int
+ handle(e Event) (EventAction, os.Error)
+ String() string
+}
+
+// EventHook is almost, but not quite, suitable for user-defined
+// events. If we want user-defined events, make EventHook a struct,
+// special-case adding and removing handlers in breakpoint hooks, and
+// provide a public interface for posting events to hooks.
+
+type Event interface {
+ Process() *Process
+ Goroutine() *Goroutine
+ String() string
+}
+
+type commonHook struct {
+ // Head of handler chain
+ head *handler
+ // Number of non-internal handlers
+ len int
+}
+
+type handler struct {
+ eh EventHandler
+ // True if this handler must be run before user-defined
+ // handlers in order to ensure correctness.
+ internal bool
+ // True if this handler has been removed from the chain.
+ removed bool
+ next *handler
+}
+
+func (h *commonHook) AddHandler(eh EventHandler) {
+ h.addHandler(eh, false)
+}
+
+func (h *commonHook) addHandler(eh EventHandler, internal bool) {
+ // Ensure uniqueness of handlers
+ h.RemoveHandler(eh)
+
+ if !internal {
+ h.len++
+ }
+ // Add internal handlers to the beginning
+ if internal || h.head == nil {
+ h.head = &handler{eh, internal, false, h.head}
+ return
+ }
+ // Add handler after internal handlers
+ // TODO(austin) This should probably go on the end instead
+ prev := h.head
+ for prev.next != nil && prev.internal {
+ prev = prev.next
+ }
+ prev.next = &handler{eh, internal, false, prev.next}
+}
+
+func (h *commonHook) RemoveHandler(eh EventHandler) {
+ plink := &h.head
+ for l := *plink; l != nil; plink, l = &l.next, l.next {
+ if l.eh == eh {
+ if !l.internal {
+ h.len--
+ }
+ l.removed = true
+ *plink = l.next
+ break
+ }
+ }
+}
+
+func (h *commonHook) NumHandler() int { return h.len }
+
+func (h *commonHook) handle(e Event) (EventAction, os.Error) {
+ action := EADefault
+ plink := &h.head
+ for l := *plink; l != nil; plink, l = &l.next, l.next {
+ if l.removed {
+ continue
+ }
+ a, err := l.eh(e)
+ if a&EARemoveSelf == EARemoveSelf {
+ if !l.internal {
+ h.len--
+ }
+ l.removed = true
+ *plink = l.next
+ a &^= EARemoveSelf
+ }
+ if err != nil {
+ return EAStop, err
+ }
+ if a > action {
+ action = a
+ }
+ }
+ return action, nil
+}
+
+type commonEvent struct {
+ // The process of this event
+ p *Process
+ // The goroutine of this event.
+ t *Goroutine
+}
+
+func (e *commonEvent) Process() *Process { return e.p }
+
+func (e *commonEvent) Goroutine() *Goroutine { return e.t }
+
+/*
+ * Standard event handlers
+ */
+
+// EventPrint is a standard event handler that prints events as they
+// occur. It will not cause the process to stop.
+func EventPrint(ev Event) (EventAction, os.Error) {
+ // TODO(austin) Include process name here?
+ fmt.Fprintf(os.Stderr, "*** %v\n", ev.String())
+ return EADefault, nil
+}
+
+// EventStop is a standard event handler that causes the process to stop.
+func EventStop(ev Event) (EventAction, os.Error) {
+ return EAStop, nil
+}
+
+/*
+ * Breakpoints
+ */
+
+type breakpointHook struct {
+ commonHook
+ p *Process
+ pc proc.Word
+}
+
+// A Breakpoint event occurs when a process reaches a particular
+// program counter. When this event is handled, the current goroutine
+// will be the goroutine that reached the program counter.
+type Breakpoint struct {
+ commonEvent
+ osThread proc.Thread
+ pc proc.Word
+}
+
+func (h *breakpointHook) AddHandler(eh EventHandler) {
+ h.addHandler(eh, false)
+}
+
+func (h *breakpointHook) addHandler(eh EventHandler, internal bool) {
+ // We register breakpoint events lazily to avoid holding
+ // references to breakpoints without handlers. Be sure to use
+ // the "canonical" breakpoint if there is one.
+ if cur, ok := h.p.breakpointHooks[h.pc]; ok {
+ h = cur
+ }
+ oldhead := h.head
+ h.commonHook.addHandler(eh, internal)
+ if oldhead == nil && h.head != nil {
+ h.p.proc.AddBreakpoint(h.pc)
+ h.p.breakpointHooks[h.pc] = h
+ }
+}
+
+func (h *breakpointHook) RemoveHandler(eh EventHandler) {
+ oldhead := h.head
+ h.commonHook.RemoveHandler(eh)
+ if oldhead != nil && h.head == nil {
+ h.p.proc.RemoveBreakpoint(h.pc)
+ h.p.breakpointHooks[h.pc] = nil, false
+ }
+}
+
+func (h *breakpointHook) String() string {
+ // TODO(austin) Include process name?
+ // TODO(austin) Use line:pc or at least sym+%#x
+ return fmt.Sprintf("breakpoint at %#x", h.pc)
+}
+
+func (b *Breakpoint) PC() proc.Word { return b.pc }
+
+func (b *Breakpoint) String() string {
+ // TODO(austin) Include process name and goroutine
+ // TODO(austin) Use line:pc or at least sym+%#x
+ return fmt.Sprintf("breakpoint at %#x", b.pc)
+}
+
+/*
+ * Goroutine create/exit
+ */
+
+type goroutineCreateHook struct {
+ commonHook
+}
+
+func (h *goroutineCreateHook) String() string { return "goroutine create" }
+
+// A GoroutineCreate event occurs when a process creates a new
+// goroutine. When this event is handled, the current goroutine will
+// be the newly created goroutine.
+type GoroutineCreate struct {
+ commonEvent
+ parent *Goroutine
+}
+
+// Parent returns the goroutine that created this goroutine. May be
+// nil if this event is the creation of the first goroutine.
+func (e *GoroutineCreate) Parent() *Goroutine { return e.parent }
+
+func (e *GoroutineCreate) String() string {
+ // TODO(austin) Include process name
+ if e.parent == nil {
+ return fmt.Sprintf("%v created", e.t)
+ }
+ return fmt.Sprintf("%v created by %v", e.t, e.parent)
+}
+
+type goroutineExitHook struct {
+ commonHook
+}
+
+func (h *goroutineExitHook) String() string { return "goroutine exit" }
+
+// A GoroutineExit event occurs when a Go goroutine exits.
+type GoroutineExit struct {
+ commonEvent
+}
+
+func (e *GoroutineExit) String() string {
+ // TODO(austin) Include process name
+ //return fmt.Sprintf("%v exited", e.t);
+ // For debugging purposes
+ return fmt.Sprintf("goroutine %#x exited", e.t.g.addr().base)
+}
diff --git a/libgo/go/exp/ogle/frame.go b/libgo/go/exp/ogle/frame.go
new file mode 100644
index 000000000..1538362ba
--- /dev/null
+++ b/libgo/go/exp/ogle/frame.go
@@ -0,0 +1,212 @@
+// 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 ogle
+
+import (
+ "debug/gosym"
+ "debug/proc"
+ "fmt"
+ "os"
+)
+
+// A Frame represents a single frame on a remote call stack.
+type Frame struct {
+ // pc is the PC of the next instruction that will execute in
+ // this frame. For lower frames, this is the instruction
+ // following the CALL instruction.
+ pc, sp, fp proc.Word
+ // The runtime.Stktop of the active stack segment
+ stk remoteStruct
+ // The function this stack frame is in
+ fn *gosym.Func
+ // The path and line of the CALL or current instruction. Note
+ // that this differs slightly from the meaning of Frame.pc.
+ path string
+ line int
+ // The inner and outer frames of this frame. outer is filled
+ // in lazily.
+ inner, outer *Frame
+}
+
+// newFrame returns the top-most Frame of the given g's thread.
+func newFrame(g remoteStruct) (*Frame, os.Error) {
+ var f *Frame
+ err := try(func(a aborter) { f = aNewFrame(a, g) })
+ return f, err
+}
+
+func aNewFrame(a aborter, g remoteStruct) *Frame {
+ p := g.r.p
+ var pc, sp proc.Word
+
+ // Is this G alive?
+ switch g.field(p.f.G.Status).(remoteInt).aGet(a) {
+ case p.runtime.Gidle, p.runtime.Gmoribund, p.runtime.Gdead:
+ return nil
+ }
+
+ // Find the OS thread for this G
+
+ // TODO(austin) Ideally, we could look at the G's state and
+ // figure out if it's on an OS thread or not. However, this
+ // is difficult because the state isn't updated atomically
+ // with scheduling changes.
+ for _, t := range p.proc.Threads() {
+ regs, err := t.Regs()
+ if err != nil {
+ // TODO(austin) What to do?
+ continue
+ }
+ thisg := p.G(regs)
+ if thisg == g.addr().base {
+ // Found this G's OS thread
+ pc = regs.PC()
+ sp = regs.SP()
+
+ // If this thread crashed, try to recover it
+ if pc == 0 {
+ pc = p.peekUintptr(a, pc)
+ sp += 8
+ }
+
+ break
+ }
+ }
+
+ if pc == 0 && sp == 0 {
+ // G is not mapped to an OS thread. Use the
+ // scheduler's stored PC and SP.
+ sched := g.field(p.f.G.Sched).(remoteStruct)
+ pc = proc.Word(sched.field(p.f.Gobuf.Pc).(remoteUint).aGet(a))
+ sp = proc.Word(sched.field(p.f.Gobuf.Sp).(remoteUint).aGet(a))
+ }
+
+ // Get Stktop
+ stk := g.field(p.f.G.Stackbase).(remotePtr).aGet(a).(remoteStruct)
+
+ return prepareFrame(a, pc, sp, stk, nil)
+}
+
+// prepareFrame creates a Frame from the PC and SP within that frame,
+// as well as the active stack segment. This function takes care of
+// traversing stack breaks and unwinding closures.
+func prepareFrame(a aborter, pc, sp proc.Word, stk remoteStruct, inner *Frame) *Frame {
+ // Based on src/pkg/runtime/amd64/traceback.c:traceback
+ p := stk.r.p
+ top := inner == nil
+
+ // Get function
+ var path string
+ var line int
+ var fn *gosym.Func
+
+ for i := 0; i < 100; i++ {
+ // Traverse segmented stack breaks
+ if p.sys.lessstack != nil && pc == proc.Word(p.sys.lessstack.Value) {
+ // Get stk->gobuf.pc
+ pc = proc.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Pc).(remoteUint).aGet(a))
+ // Get stk->gobuf.sp
+ sp = proc.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Sp).(remoteUint).aGet(a))
+ // Get stk->stackbase
+ stk = stk.field(p.f.Stktop.Stackbase).(remotePtr).aGet(a).(remoteStruct)
+ continue
+ }
+
+ // Get the PC of the call instruction
+ callpc := pc
+ if !top && (p.sys.goexit == nil || pc != proc.Word(p.sys.goexit.Value)) {
+ callpc--
+ }
+
+ // Look up function
+ path, line, fn = p.syms.PCToLine(uint64(callpc))
+ if fn != nil {
+ break
+ }
+
+ // Closure?
+ var buf = make([]byte, p.ClosureSize())
+ if _, err := p.Peek(pc, buf); err != nil {
+ break
+ }
+ spdelta, ok := p.ParseClosure(buf)
+ if ok {
+ sp += proc.Word(spdelta)
+ pc = p.peekUintptr(a, sp-proc.Word(p.PtrSize()))
+ }
+ }
+ if fn == nil {
+ return nil
+ }
+
+ // Compute frame pointer
+ var fp proc.Word
+ if fn.FrameSize < p.PtrSize() {
+ fp = sp + proc.Word(p.PtrSize())
+ } else {
+ fp = sp + proc.Word(fn.FrameSize)
+ }
+ // TODO(austin) To really figure out if we're in the prologue,
+ // we need to disassemble the function and look for the call
+ // to morestack. For now, just special case the entry point.
+ //
+ // TODO(austin) What if we're in the call to morestack in the
+ // prologue? Then top == false.
+ if top && pc == proc.Word(fn.Entry) {
+ // We're in the function prologue, before SP
+ // has been adjusted for the frame.
+ fp -= proc.Word(fn.FrameSize - p.PtrSize())
+ }
+
+ return &Frame{pc, sp, fp, stk, fn, path, line, inner, nil}
+}
+
+// Outer returns the Frame that called this Frame, or nil if this is
+// the outermost frame.
+func (f *Frame) Outer() (*Frame, os.Error) {
+ var fr *Frame
+ err := try(func(a aborter) { fr = f.aOuter(a) })
+ return fr, err
+}
+
+func (f *Frame) aOuter(a aborter) *Frame {
+ // Is there a cached outer frame
+ if f.outer != nil {
+ return f.outer
+ }
+
+ p := f.stk.r.p
+
+ sp := f.fp
+ if f.fn == p.sys.newproc && f.fn == p.sys.deferproc {
+ // TODO(rsc) The compiler inserts two push/pop's
+ // around calls to go and defer. Russ says this
+ // should get fixed in the compiler, but we account
+ // for it for now.
+ sp += proc.Word(2 * p.PtrSize())
+ }
+
+ pc := p.peekUintptr(a, f.fp-proc.Word(p.PtrSize()))
+ if pc < 0x1000 {
+ return nil
+ }
+
+ // TODO(austin) Register this frame for shoot-down.
+
+ f.outer = prepareFrame(a, pc, sp, f.stk, f)
+ return f.outer
+}
+
+// Inner returns the Frame called by this Frame, or nil if this is the
+// innermost frame.
+func (f *Frame) Inner() *Frame { return f.inner }
+
+func (f *Frame) String() string {
+ res := f.fn.Name
+ if f.pc > proc.Word(f.fn.Value) {
+ res += fmt.Sprintf("+%#x", f.pc-proc.Word(f.fn.Entry))
+ }
+ return res + fmt.Sprintf(" %s:%d", f.path, f.line)
+}
diff --git a/libgo/go/exp/ogle/goroutine.go b/libgo/go/exp/ogle/goroutine.go
new file mode 100644
index 000000000..5104ec6d4
--- /dev/null
+++ b/libgo/go/exp/ogle/goroutine.go
@@ -0,0 +1,117 @@
+// 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 ogle
+
+import (
+ "debug/proc"
+ "exp/eval"
+ "fmt"
+ "os"
+)
+
+// A Goroutine represents a goroutine in a remote process.
+type Goroutine struct {
+ g remoteStruct
+ frame *Frame
+ dead bool
+}
+
+func (t *Goroutine) String() string {
+ if t.dead {
+ return "<dead thread>"
+ }
+ // TODO(austin) Give threads friendly ID's, possibly including
+ // the name of the entry function.
+ return fmt.Sprintf("thread %#x", t.g.addr().base)
+}
+
+// isG0 returns true if this thread if the internal idle thread
+func (t *Goroutine) isG0() bool { return t.g.addr().base == t.g.r.p.sys.g0.addr().base }
+
+func (t *Goroutine) resetFrame() (err os.Error) {
+ // TODO(austin) Reuse any live part of the current frame stack
+ // so existing references to Frame's keep working.
+ t.frame, err = newFrame(t.g)
+ return
+}
+
+// Out selects the caller frame of the current frame.
+func (t *Goroutine) Out() os.Error {
+ f, err := t.frame.Outer()
+ if f != nil {
+ t.frame = f
+ }
+ return err
+}
+
+// In selects the frame called by the current frame.
+func (t *Goroutine) In() os.Error {
+ f := t.frame.Inner()
+ if f != nil {
+ t.frame = f
+ }
+ return nil
+}
+
+func readylockedBP(ev Event) (EventAction, os.Error) {
+ b := ev.(*Breakpoint)
+ p := b.Process()
+
+ // The new g is the only argument to this function, so the
+ // stack will have the return address, then the G*.
+ regs, err := b.osThread.Regs()
+ if err != nil {
+ return EAStop, err
+ }
+ sp := regs.SP()
+ addr := sp + proc.Word(p.PtrSize())
+ arg := remotePtr{remote{addr, p}, p.runtime.G}
+ var gp eval.Value
+ err = try(func(a aborter) { gp = arg.aGet(a) })
+ if err != nil {
+ return EAStop, err
+ }
+ if gp == nil {
+ return EAStop, UnknownGoroutine{b.osThread, 0}
+ }
+ gs := gp.(remoteStruct)
+ g := &Goroutine{gs, nil, false}
+ p.goroutines[gs.addr().base] = g
+
+ // Enqueue goroutine creation event
+ parent := b.Goroutine()
+ if parent.isG0() {
+ parent = nil
+ }
+ p.postEvent(&GoroutineCreate{commonEvent{p, g}, parent})
+
+ // If we don't have any thread selected, select this one
+ if p.curGoroutine == nil {
+ p.curGoroutine = g
+ }
+
+ return EADefault, nil
+}
+
+func goexitBP(ev Event) (EventAction, os.Error) {
+ b := ev.(*Breakpoint)
+ p := b.Process()
+
+ g := b.Goroutine()
+ g.dead = true
+
+ addr := g.g.addr().base
+ p.goroutines[addr] = nil, false
+
+ // Enqueue thread exit event
+ p.postEvent(&GoroutineExit{commonEvent{p, g}})
+
+ // If we just exited our selected goroutine, selected another
+ if p.curGoroutine == g {
+ p.selectSomeGoroutine()
+ }
+
+ return EADefault, nil
+}
diff --git a/libgo/go/exp/ogle/main.go b/libgo/go/exp/ogle/main.go
new file mode 100644
index 000000000..1999eccca
--- /dev/null
+++ b/libgo/go/exp/ogle/main.go
@@ -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.
+
+package main
+
+import "exp/ogle"
+
+func main() { ogle.Main() }
diff --git a/libgo/go/exp/ogle/process.go b/libgo/go/exp/ogle/process.go
new file mode 100644
index 000000000..58e830aa6
--- /dev/null
+++ b/libgo/go/exp/ogle/process.go
@@ -0,0 +1,521 @@
+// 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 ogle
+
+import (
+ "debug/elf"
+ "debug/gosym"
+ "debug/proc"
+ "exp/eval"
+ "fmt"
+ "log"
+ "os"
+ "reflect"
+)
+
+// A FormatError indicates a failure to process information in or
+// about a remote process, such as unexpected or missing information
+// in the object file or runtime structures.
+type FormatError string
+
+func (e FormatError) String() string { return string(e) }
+
+// An UnknownArchitecture occurs when trying to load an object file
+// that indicates an architecture not supported by the debugger.
+type UnknownArchitecture elf.Machine
+
+func (e UnknownArchitecture) String() string {
+ return "unknown architecture: " + elf.Machine(e).String()
+}
+
+// A ProcessNotStopped error occurs when attempting to read or write
+// memory or registers of a process that is not stopped.
+type ProcessNotStopped struct{}
+
+func (e ProcessNotStopped) String() string { return "process not stopped" }
+
+// An UnknownGoroutine error is an internal error representing an
+// unrecognized G structure pointer.
+type UnknownGoroutine struct {
+ OSThread proc.Thread
+ Goroutine proc.Word
+}
+
+func (e UnknownGoroutine) String() string {
+ return fmt.Sprintf("internal error: unknown goroutine (G %#x)", e.Goroutine)
+}
+
+// A NoCurrentGoroutine error occurs when no goroutine is currently
+// selected in a process (or when there are no goroutines in a
+// process).
+type NoCurrentGoroutine struct{}
+
+func (e NoCurrentGoroutine) String() string { return "no current goroutine" }
+
+// A Process represents a remote attached process.
+type Process struct {
+ Arch
+ proc proc.Process
+
+ // The symbol table of this process
+ syms *gosym.Table
+
+ // A possibly-stopped OS thread, or nil
+ threadCache proc.Thread
+
+ // Types parsed from the remote process
+ types map[proc.Word]*remoteType
+
+ // Types and values from the remote runtime package
+ runtime runtimeValues
+
+ // Runtime field indexes
+ f runtimeIndexes
+
+ // Globals from the sys package (or from no package)
+ sys struct {
+ lessstack, goexit, newproc, deferproc, newprocreadylocked *gosym.Func
+ allg remotePtr
+ g0 remoteStruct
+ }
+
+ // Event queue
+ posted []Event
+ pending []Event
+ event Event
+
+ // Event hooks
+ breakpointHooks map[proc.Word]*breakpointHook
+ goroutineCreateHook *goroutineCreateHook
+ goroutineExitHook *goroutineExitHook
+
+ // Current goroutine, or nil if there are no goroutines
+ curGoroutine *Goroutine
+
+ // Goroutines by the address of their G structure
+ goroutines map[proc.Word]*Goroutine
+}
+
+/*
+ * Process creation
+ */
+
+// NewProcess constructs a new remote process around a traced
+// process, an architecture, and a symbol table.
+func NewProcess(tproc proc.Process, arch Arch, syms *gosym.Table) (*Process, os.Error) {
+ p := &Process{
+ Arch: arch,
+ proc: tproc,
+ syms: syms,
+ types: make(map[proc.Word]*remoteType),
+ breakpointHooks: make(map[proc.Word]*breakpointHook),
+ goroutineCreateHook: new(goroutineCreateHook),
+ goroutineExitHook: new(goroutineExitHook),
+ goroutines: make(map[proc.Word]*Goroutine),
+ }
+
+ // Fill in remote runtime
+ p.bootstrap()
+
+ switch {
+ case p.sys.allg.addr().base == 0:
+ return nil, FormatError("failed to find runtime symbol 'allg'")
+ case p.sys.g0.addr().base == 0:
+ return nil, FormatError("failed to find runtime symbol 'g0'")
+ case p.sys.newprocreadylocked == nil:
+ return nil, FormatError("failed to find runtime symbol 'newprocreadylocked'")
+ case p.sys.goexit == nil:
+ return nil, FormatError("failed to find runtime symbol 'sys.goexit'")
+ }
+
+ // Get current goroutines
+ p.goroutines[p.sys.g0.addr().base] = &Goroutine{p.sys.g0, nil, false}
+ err := try(func(a aborter) {
+ g := p.sys.allg.aGet(a)
+ for g != nil {
+ gs := g.(remoteStruct)
+ fmt.Printf("*** Found goroutine at %#x\n", gs.addr().base)
+ p.goroutines[gs.addr().base] = &Goroutine{gs, nil, false}
+ g = gs.field(p.f.G.Alllink).(remotePtr).aGet(a)
+ }
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ // Create internal breakpoints to catch new and exited goroutines
+ p.OnBreakpoint(proc.Word(p.sys.newprocreadylocked.Entry)).(*breakpointHook).addHandler(readylockedBP, true)
+ p.OnBreakpoint(proc.Word(p.sys.goexit.Entry)).(*breakpointHook).addHandler(goexitBP, true)
+
+ // Select current frames
+ for _, g := range p.goroutines {
+ g.resetFrame()
+ }
+
+ p.selectSomeGoroutine()
+
+ return p, nil
+}
+
+func elfGoSyms(f *elf.File) (*gosym.Table, os.Error) {
+ text := f.Section(".text")
+ symtab := f.Section(".gosymtab")
+ pclntab := f.Section(".gopclntab")
+ if text == nil || symtab == nil || pclntab == nil {
+ return nil, nil
+ }
+
+ symdat, err := symtab.Data()
+ if err != nil {
+ return nil, err
+ }
+ pclndat, err := pclntab.Data()
+ if err != nil {
+ return nil, err
+ }
+
+ pcln := gosym.NewLineTable(pclndat, text.Addr)
+ tab, err := gosym.NewTable(symdat, pcln)
+ if err != nil {
+ return nil, err
+ }
+
+ return tab, nil
+}
+
+// NewProcessElf constructs a new remote process around a traced
+// process and the process' ELF object.
+func NewProcessElf(tproc proc.Process, f *elf.File) (*Process, os.Error) {
+ syms, err := elfGoSyms(f)
+ if err != nil {
+ return nil, err
+ }
+ if syms == nil {
+ return nil, FormatError("Failed to find symbol table")
+ }
+ var arch Arch
+ switch f.Machine {
+ case elf.EM_X86_64:
+ arch = Amd64
+ default:
+ return nil, UnknownArchitecture(f.Machine)
+ }
+ return NewProcess(tproc, arch, syms)
+}
+
+// bootstrap constructs the runtime structure of a remote process.
+func (p *Process) bootstrap() {
+ // Manually construct runtime types
+ p.runtime.String = newManualType(eval.TypeOfNative(rt1String{}), p.Arch)
+ p.runtime.Slice = newManualType(eval.TypeOfNative(rt1Slice{}), p.Arch)
+ p.runtime.Eface = newManualType(eval.TypeOfNative(rt1Eface{}), p.Arch)
+
+ p.runtime.Type = newManualType(eval.TypeOfNative(rt1Type{}), p.Arch)
+ p.runtime.CommonType = newManualType(eval.TypeOfNative(rt1CommonType{}), p.Arch)
+ p.runtime.UncommonType = newManualType(eval.TypeOfNative(rt1UncommonType{}), p.Arch)
+ p.runtime.StructField = newManualType(eval.TypeOfNative(rt1StructField{}), p.Arch)
+ p.runtime.StructType = newManualType(eval.TypeOfNative(rt1StructType{}), p.Arch)
+ p.runtime.PtrType = newManualType(eval.TypeOfNative(rt1PtrType{}), p.Arch)
+ p.runtime.ArrayType = newManualType(eval.TypeOfNative(rt1ArrayType{}), p.Arch)
+ p.runtime.SliceType = newManualType(eval.TypeOfNative(rt1SliceType{}), p.Arch)
+
+ p.runtime.Stktop = newManualType(eval.TypeOfNative(rt1Stktop{}), p.Arch)
+ p.runtime.Gobuf = newManualType(eval.TypeOfNative(rt1Gobuf{}), p.Arch)
+ p.runtime.G = newManualType(eval.TypeOfNative(rt1G{}), p.Arch)
+
+ // Get addresses of type.*runtime.XType for discrimination.
+ rtv := reflect.Indirect(reflect.NewValue(&p.runtime)).(*reflect.StructValue)
+ rtvt := rtv.Type().(*reflect.StructType)
+ for i := 0; i < rtv.NumField(); i++ {
+ n := rtvt.Field(i).Name
+ if n[0] != 'P' || n[1] < 'A' || n[1] > 'Z' {
+ continue
+ }
+ sym := p.syms.LookupSym("type.*runtime." + n[1:])
+ if sym == nil {
+ continue
+ }
+ rtv.Field(i).(*reflect.UintValue).Set(sym.Value)
+ }
+
+ // Get runtime field indexes
+ fillRuntimeIndexes(&p.runtime, &p.f)
+
+ // Fill G status
+ p.runtime.runtimeGStatus = rt1GStatus
+
+ // Get globals
+ p.sys.lessstack = p.syms.LookupFunc("sys.lessstack")
+ p.sys.goexit = p.syms.LookupFunc("goexit")
+ p.sys.newproc = p.syms.LookupFunc("sys.newproc")
+ p.sys.deferproc = p.syms.LookupFunc("sys.deferproc")
+ p.sys.newprocreadylocked = p.syms.LookupFunc("newprocreadylocked")
+ if allg := p.syms.LookupSym("allg"); allg != nil {
+ p.sys.allg = remotePtr{remote{proc.Word(allg.Value), p}, p.runtime.G}
+ }
+ if g0 := p.syms.LookupSym("g0"); g0 != nil {
+ p.sys.g0 = p.runtime.G.mk(remote{proc.Word(g0.Value), p}).(remoteStruct)
+ }
+}
+
+func (p *Process) selectSomeGoroutine() {
+ // Once we have friendly goroutine ID's, there might be a more
+ // reasonable behavior for this.
+ p.curGoroutine = nil
+ for _, g := range p.goroutines {
+ if !g.isG0() && g.frame != nil {
+ p.curGoroutine = g
+ return
+ }
+ }
+}
+
+/*
+ * Process memory
+ */
+
+func (p *Process) someStoppedOSThread() proc.Thread {
+ if p.threadCache != nil {
+ if _, err := p.threadCache.Stopped(); err == nil {
+ return p.threadCache
+ }
+ }
+
+ for _, t := range p.proc.Threads() {
+ if _, err := t.Stopped(); err == nil {
+ p.threadCache = t
+ return t
+ }
+ }
+ return nil
+}
+
+func (p *Process) Peek(addr proc.Word, out []byte) (int, os.Error) {
+ thr := p.someStoppedOSThread()
+ if thr == nil {
+ return 0, ProcessNotStopped{}
+ }
+ return thr.Peek(addr, out)
+}
+
+func (p *Process) Poke(addr proc.Word, b []byte) (int, os.Error) {
+ thr := p.someStoppedOSThread()
+ if thr == nil {
+ return 0, ProcessNotStopped{}
+ }
+ return thr.Poke(addr, b)
+}
+
+func (p *Process) peekUintptr(a aborter, addr proc.Word) proc.Word {
+ return proc.Word(mkUintptr(remote{addr, p}).(remoteUint).aGet(a))
+}
+
+/*
+ * Events
+ */
+
+// OnBreakpoint returns the hook that is run when the program reaches
+// the given program counter.
+func (p *Process) OnBreakpoint(pc proc.Word) EventHook {
+ if bp, ok := p.breakpointHooks[pc]; ok {
+ return bp
+ }
+ // The breakpoint will register itself when a handler is added
+ return &breakpointHook{commonHook{nil, 0}, p, pc}
+}
+
+// OnGoroutineCreate returns the hook that is run when a goroutine is created.
+func (p *Process) OnGoroutineCreate() EventHook {
+ return p.goroutineCreateHook
+}
+
+// OnGoroutineExit returns the hook that is run when a goroutine exits.
+func (p *Process) OnGoroutineExit() EventHook { return p.goroutineExitHook }
+
+// osThreadToGoroutine looks up the goroutine running on an OS thread.
+func (p *Process) osThreadToGoroutine(t proc.Thread) (*Goroutine, os.Error) {
+ regs, err := t.Regs()
+ if err != nil {
+ return nil, err
+ }
+ g := p.G(regs)
+ gt, ok := p.goroutines[g]
+ if !ok {
+ return nil, UnknownGoroutine{t, g}
+ }
+ return gt, nil
+}
+
+// causesToEvents translates the stop causes of the underlying process
+// into an event queue.
+func (p *Process) causesToEvents() ([]Event, os.Error) {
+ // Count causes we're interested in
+ nev := 0
+ for _, t := range p.proc.Threads() {
+ if c, err := t.Stopped(); err == nil {
+ switch c := c.(type) {
+ case proc.Breakpoint:
+ nev++
+ case proc.Signal:
+ // TODO(austin)
+ //nev++;
+ }
+ }
+ }
+
+ // Translate causes to events
+ events := make([]Event, nev)
+ i := 0
+ for _, t := range p.proc.Threads() {
+ if c, err := t.Stopped(); err == nil {
+ switch c := c.(type) {
+ case proc.Breakpoint:
+ gt, err := p.osThreadToGoroutine(t)
+ if err != nil {
+ return nil, err
+ }
+ events[i] = &Breakpoint{commonEvent{p, gt}, t, proc.Word(c)}
+ i++
+ case proc.Signal:
+ // TODO(austin)
+ }
+ }
+ }
+
+ return events, nil
+}
+
+// postEvent appends an event to the posted queue. These events will
+// be processed before any currently pending events.
+func (p *Process) postEvent(ev Event) {
+ p.posted = append(p.posted, ev)
+}
+
+// processEvents processes events in the event queue until no events
+// remain, a handler returns EAStop, or a handler returns an error.
+// It returns either EAStop or EAContinue and possibly an error.
+func (p *Process) processEvents() (EventAction, os.Error) {
+ var ev Event
+ for len(p.posted) > 0 {
+ ev, p.posted = p.posted[0], p.posted[1:]
+ action, err := p.processEvent(ev)
+ if action == EAStop {
+ return action, err
+ }
+ }
+
+ for len(p.pending) > 0 {
+ ev, p.pending = p.pending[0], p.pending[1:]
+ action, err := p.processEvent(ev)
+ if action == EAStop {
+ return action, err
+ }
+ }
+
+ return EAContinue, nil
+}
+
+// processEvent processes a single event, without manipulating the
+// event queues. It returns either EAStop or EAContinue and possibly
+// an error.
+func (p *Process) processEvent(ev Event) (EventAction, os.Error) {
+ p.event = ev
+
+ var action EventAction
+ var err os.Error
+ switch ev := p.event.(type) {
+ case *Breakpoint:
+ hook, ok := p.breakpointHooks[ev.pc]
+ if !ok {
+ break
+ }
+ p.curGoroutine = ev.Goroutine()
+ action, err = hook.handle(ev)
+
+ case *GoroutineCreate:
+ p.curGoroutine = ev.Goroutine()
+ action, err = p.goroutineCreateHook.handle(ev)
+
+ case *GoroutineExit:
+ action, err = p.goroutineExitHook.handle(ev)
+
+ default:
+ log.Panicf("Unknown event type %T in queue", p.event)
+ }
+
+ if err != nil {
+ return EAStop, err
+ } else if action == EAStop {
+ return EAStop, nil
+ }
+ return EAContinue, nil
+}
+
+// Event returns the last event that caused the process to stop. This
+// may return nil if the process has never been stopped by an event.
+//
+// TODO(austin) Return nil if the user calls p.Stop()?
+func (p *Process) Event() Event { return p.event }
+
+/*
+ * Process control
+ */
+
+// TODO(austin) Cont, WaitStop, and Stop. Need to figure out how
+// event handling works with these. Originally I did it only in
+// WaitStop, but if you Cont and there are pending events, then you
+// have to not actually continue and wait until a WaitStop to process
+// them, even if the event handlers will tell you to continue. We
+// could handle them in both Cont and WaitStop to avoid this problem,
+// but it's still weird if an event happens after the Cont and before
+// the WaitStop that the handlers say to continue from. Or we could
+// handle them on a separate thread. Then obviously you get weird
+// asynchronous things, like prints while the user it typing a command,
+// but that's not necessarily a bad thing.
+
+// ContWait resumes process execution and waits for an event to occur
+// that stops the process.
+func (p *Process) ContWait() os.Error {
+ for {
+ a, err := p.processEvents()
+ if err != nil {
+ return err
+ } else if a == EAStop {
+ break
+ }
+ err = p.proc.Continue()
+ if err != nil {
+ return err
+ }
+ err = p.proc.WaitStop()
+ if err != nil {
+ return err
+ }
+ for _, g := range p.goroutines {
+ g.resetFrame()
+ }
+ p.pending, err = p.causesToEvents()
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Out selects the caller frame of the current frame.
+func (p *Process) Out() os.Error {
+ if p.curGoroutine == nil {
+ return NoCurrentGoroutine{}
+ }
+ return p.curGoroutine.Out()
+}
+
+// In selects the frame called by the current frame.
+func (p *Process) In() os.Error {
+ if p.curGoroutine == nil {
+ return NoCurrentGoroutine{}
+ }
+ return p.curGoroutine.In()
+}
diff --git a/libgo/go/exp/ogle/rruntime.go b/libgo/go/exp/ogle/rruntime.go
new file mode 100644
index 000000000..33f1935b8
--- /dev/null
+++ b/libgo/go/exp/ogle/rruntime.go
@@ -0,0 +1,271 @@
+// 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 ogle
+
+import (
+ "debug/proc"
+ "exp/eval"
+ "reflect"
+)
+
+// This file contains remote runtime definitions. Using reflection,
+// we convert all of these to interpreter types and layout their
+// remote representations using the architecture rules.
+//
+// We could get most of these definitions from our own runtime
+// package; however, some of them differ in convenient ways, some of
+// them are not defined or exported by the runtime, and having our own
+// definitions makes it easy to support multiple remote runtime
+// versions. This may turn out to be overkill.
+//
+// All of these structures are prefixed with rt1 to indicate the
+// runtime version and to mark them as types used only as templates
+// for remote types.
+
+/*
+ * Runtime data headers
+ *
+ * See $GOROOT/src/pkg/runtime/runtime.h
+ */
+
+type rt1String struct {
+ str uintptr
+ len int
+}
+
+type rt1Slice struct {
+ array uintptr
+ len int
+ cap int
+}
+
+type rt1Eface struct {
+ typ uintptr
+ ptr uintptr
+}
+
+/*
+ * Runtime type structures
+ *
+ * See $GOROOT/src/pkg/runtime/type.h and $GOROOT/src/pkg/runtime/type.go
+ */
+
+type rt1UncommonType struct {
+ name *string
+ pkgPath *string
+ //methods []method;
+}
+
+type rt1CommonType struct {
+ size uintptr
+ hash uint32
+ alg, align, fieldAlign uint8
+ string *string
+ uncommonType *rt1UncommonType
+}
+
+type rt1Type struct {
+ // While Type is technically an Eface, treating the
+ // discriminator as an opaque pointer and taking advantage of
+ // the commonType prologue on all Type's makes type parsing
+ // much simpler.
+ typ uintptr
+ ptr *rt1CommonType
+}
+
+type rt1StructField struct {
+ name *string
+ pkgPath *string
+ typ *rt1Type
+ tag *string
+ offset uintptr
+}
+
+type rt1StructType struct {
+ rt1CommonType
+ fields []rt1StructField
+}
+
+type rt1PtrType struct {
+ rt1CommonType
+ elem *rt1Type
+}
+
+type rt1SliceType struct {
+ rt1CommonType
+ elem *rt1Type
+}
+
+type rt1ArrayType struct {
+ rt1CommonType
+ elem *rt1Type
+ len uintptr
+}
+
+/*
+ * Runtime scheduler structures
+ *
+ * See $GOROOT/src/pkg/runtime/runtime.h
+ */
+
+// Fields beginning with _ are only for padding
+
+type rt1Stktop struct {
+ stackguard uintptr
+ stackbase *rt1Stktop
+ gobuf rt1Gobuf
+ _args uint32
+ _fp uintptr
+}
+
+type rt1Gobuf struct {
+ sp uintptr
+ pc uintptr
+ g *rt1G
+ r0 uintptr
+}
+
+type rt1G struct {
+ _stackguard uintptr
+ stackbase *rt1Stktop
+ _defer uintptr
+ sched rt1Gobuf
+ _stack0 uintptr
+ _entry uintptr
+ alllink *rt1G
+ _param uintptr
+ status int16
+ // Incomplete
+}
+
+var rt1GStatus = runtimeGStatus{
+ Gidle: 0,
+ Grunnable: 1,
+ Grunning: 2,
+ Gsyscall: 3,
+ Gwaiting: 4,
+ Gmoribund: 5,
+ Gdead: 6,
+}
+
+// runtimeIndexes stores the indexes of fields in the runtime
+// structures. It is filled in using reflection, so the name of the
+// fields must match the names of the remoteType's in runtimeValues
+// exactly and the names of the index fields must be the capitalized
+// version of the names of the fields in the runtime structures above.
+type runtimeIndexes struct {
+ String struct {
+ Str, Len int
+ }
+ Slice struct {
+ Array, Len, Cap int
+ }
+ Eface struct {
+ Typ, Ptr int
+ }
+
+ UncommonType struct {
+ Name, PkgPath int
+ }
+ CommonType struct {
+ Size, Hash, Alg, Align, FieldAlign, String, UncommonType int
+ }
+ Type struct {
+ Typ, Ptr int
+ }
+ StructField struct {
+ Name, PkgPath, Typ, Tag, Offset int
+ }
+ StructType struct {
+ Fields int
+ }
+ PtrType struct {
+ Elem int
+ }
+ SliceType struct {
+ Elem int
+ }
+ ArrayType struct {
+ Elem, Len int
+ }
+
+ Stktop struct {
+ Stackguard, Stackbase, Gobuf int
+ }
+ Gobuf struct {
+ Sp, Pc, G int
+ }
+ G struct {
+ Stackbase, Sched, Status, Alllink int
+ }
+}
+
+// Values of G status codes
+type runtimeGStatus struct {
+ Gidle, Grunnable, Grunning, Gsyscall, Gwaiting, Gmoribund, Gdead int64
+}
+
+// runtimeValues stores the types and values that correspond to those
+// in the remote runtime package.
+type runtimeValues struct {
+ // Runtime data headers
+ String, Slice, Eface *remoteType
+ // Runtime type structures
+ Type, CommonType, UncommonType, StructField, StructType, PtrType,
+ ArrayType, SliceType *remoteType
+ // Runtime scheduler structures
+ Stktop, Gobuf, G *remoteType
+ // Addresses of *runtime.XType types. These are the
+ // discriminators on the runtime.Type interface. We use local
+ // reflection to fill these in from the remote symbol table,
+ // so the names must match the runtime names.
+ PBoolType,
+ PUint8Type, PUint16Type, PUint32Type, PUint64Type, PUintType, PUintptrType,
+ PInt8Type, PInt16Type, PInt32Type, PInt64Type, PIntType,
+ PFloat32Type, PFloat64Type, PFloatType,
+ PArrayType, PStringType, PStructType, PPtrType, PFuncType,
+ PInterfaceType, PSliceType, PMapType, PChanType,
+ PDotDotDotType, PUnsafePointerType proc.Word
+ // G status values
+ runtimeGStatus
+}
+
+// fillRuntimeIndexes fills a runtimeIndexes structure will the field
+// indexes gathered from the remoteTypes recorded in a runtimeValues
+// structure.
+func fillRuntimeIndexes(runtime *runtimeValues, out *runtimeIndexes) {
+ outv := reflect.Indirect(reflect.NewValue(out)).(*reflect.StructValue)
+ outt := outv.Type().(*reflect.StructType)
+ runtimev := reflect.Indirect(reflect.NewValue(runtime)).(*reflect.StructValue)
+
+ // out contains fields corresponding to each runtime type
+ for i := 0; i < outt.NumField(); i++ {
+ // Find the interpreter type for this runtime type
+ name := outt.Field(i).Name
+ et := runtimev.FieldByName(name).Interface().(*remoteType).Type.(*eval.StructType)
+
+ // Get the field indexes of the interpreter struct type
+ indexes := make(map[string]int, len(et.Elems))
+ for j, f := range et.Elems {
+ if f.Anonymous {
+ continue
+ }
+ name := f.Name
+ if name[0] >= 'a' && name[0] <= 'z' {
+ name = string(name[0]+'A'-'a') + name[1:]
+ }
+ indexes[name] = j
+ }
+
+ // Fill this field of out
+ outStructv := outv.Field(i).(*reflect.StructValue)
+ outStructt := outStructv.Type().(*reflect.StructType)
+ for j := 0; j < outStructt.NumField(); j++ {
+ f := outStructv.Field(j).(*reflect.IntValue)
+ name := outStructt.Field(j).Name
+ f.Set(int64(indexes[name]))
+ }
+ }
+}
diff --git a/libgo/go/exp/ogle/rtype.go b/libgo/go/exp/ogle/rtype.go
new file mode 100644
index 000000000..b3c35575a
--- /dev/null
+++ b/libgo/go/exp/ogle/rtype.go
@@ -0,0 +1,288 @@
+// 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 ogle
+
+import (
+ "debug/proc"
+ "exp/eval"
+ "fmt"
+ "log"
+)
+
+const debugParseRemoteType = false
+
+// A remoteType is the local representation of a type in a remote process.
+type remoteType struct {
+ eval.Type
+ // The size of values of this type in bytes.
+ size int
+ // The field alignment of this type. Only used for
+ // manually-constructed types.
+ fieldAlign int
+ // The maker function to turn a remote address of a value of
+ // this type into an interpreter Value.
+ mk maker
+}
+
+var manualTypes = make(map[Arch]map[eval.Type]*remoteType)
+
+// newManualType constructs a remote type from an interpreter Type
+// using the size and alignment properties of the given architecture.
+// Most types are parsed directly out of the remote process, but to do
+// so we need to layout the structures that describe those types ourselves.
+func newManualType(t eval.Type, arch Arch) *remoteType {
+ if nt, ok := t.(*eval.NamedType); ok {
+ t = nt.Def
+ }
+
+ // Get the type map for this architecture
+ typeMap := manualTypes[arch]
+ if typeMap == nil {
+ typeMap = make(map[eval.Type]*remoteType)
+ manualTypes[arch] = typeMap
+
+ // Construct basic types for this architecture
+ basicType := func(t eval.Type, mk maker, size int, fieldAlign int) {
+ t = t.(*eval.NamedType).Def
+ if fieldAlign == 0 {
+ fieldAlign = size
+ }
+ typeMap[t] = &remoteType{t, size, fieldAlign, mk}
+ }
+ basicType(eval.Uint8Type, mkUint8, 1, 0)
+ basicType(eval.Uint32Type, mkUint32, 4, 0)
+ basicType(eval.UintptrType, mkUintptr, arch.PtrSize(), 0)
+ basicType(eval.Int16Type, mkInt16, 2, 0)
+ basicType(eval.Int32Type, mkInt32, 4, 0)
+ basicType(eval.IntType, mkInt, arch.IntSize(), 0)
+ basicType(eval.StringType, mkString, arch.PtrSize()+arch.IntSize(), arch.PtrSize())
+ }
+
+ if rt, ok := typeMap[t]; ok {
+ return rt
+ }
+
+ var rt *remoteType
+ switch t := t.(type) {
+ case *eval.PtrType:
+ var elem *remoteType
+ mk := func(r remote) eval.Value { return remotePtr{r, elem} }
+ rt = &remoteType{t, arch.PtrSize(), arch.PtrSize(), mk}
+ // Construct the element type after registering the
+ // type to break cycles.
+ typeMap[eval.Type(t)] = rt
+ elem = newManualType(t.Elem, arch)
+
+ case *eval.ArrayType:
+ elem := newManualType(t.Elem, arch)
+ mk := func(r remote) eval.Value { return remoteArray{r, t.Len, elem} }
+ rt = &remoteType{t, elem.size * int(t.Len), elem.fieldAlign, mk}
+
+ case *eval.SliceType:
+ elem := newManualType(t.Elem, arch)
+ mk := func(r remote) eval.Value { return remoteSlice{r, elem} }
+ rt = &remoteType{t, arch.PtrSize() + 2*arch.IntSize(), arch.PtrSize(), mk}
+
+ case *eval.StructType:
+ layout := make([]remoteStructField, len(t.Elems))
+ offset := 0
+ fieldAlign := 0
+ for i, f := range t.Elems {
+ elem := newManualType(f.Type, arch)
+ if fieldAlign == 0 {
+ fieldAlign = elem.fieldAlign
+ }
+ offset = arch.Align(offset, elem.fieldAlign)
+ layout[i].offset = offset
+ layout[i].fieldType = elem
+ offset += elem.size
+ }
+ mk := func(r remote) eval.Value { return remoteStruct{r, layout} }
+ rt = &remoteType{t, offset, fieldAlign, mk}
+
+ default:
+ log.Panicf("cannot manually construct type %T", t)
+ }
+
+ typeMap[t] = rt
+ return rt
+}
+
+var prtIndent = ""
+
+// parseRemoteType parses a Type structure in a remote process to
+// construct the corresponding interpreter type and remote type.
+func parseRemoteType(a aborter, rs remoteStruct) *remoteType {
+ addr := rs.addr().base
+ p := rs.addr().p
+
+ // We deal with circular types by discovering cycles at
+ // NamedTypes. If a type cycles back to something other than
+ // a named type, we're guaranteed that there will be a named
+ // type somewhere in that cycle. Thus, we continue down,
+ // re-parsing types until we reach the named type in the
+ // cycle. In order to still create one remoteType per remote
+ // type, we insert an empty remoteType in the type map the
+ // first time we encounter the type and re-use that structure
+ // the second time we encounter it.
+
+ rt, ok := p.types[addr]
+ if ok && rt.Type != nil {
+ return rt
+ } else if !ok {
+ rt = &remoteType{}
+ p.types[addr] = rt
+ }
+
+ if debugParseRemoteType {
+ sym := p.syms.SymByAddr(uint64(addr))
+ name := "<unknown>"
+ if sym != nil {
+ name = sym.Name
+ }
+ log.Printf("%sParsing type at %#x (%s)", prtIndent, addr, name)
+ prtIndent += " "
+ defer func() { prtIndent = prtIndent[0 : len(prtIndent)-1] }()
+ }
+
+ // Get Type header
+ itype := proc.Word(rs.field(p.f.Type.Typ).(remoteUint).aGet(a))
+ typ := rs.field(p.f.Type.Ptr).(remotePtr).aGet(a).(remoteStruct)
+
+ // Is this a named type?
+ var nt *eval.NamedType
+ uncommon := typ.field(p.f.CommonType.UncommonType).(remotePtr).aGet(a)
+ if uncommon != nil {
+ name := uncommon.(remoteStruct).field(p.f.UncommonType.Name).(remotePtr).aGet(a)
+ if name != nil {
+ // TODO(austin) Declare type in appropriate remote package
+ nt = eval.NewNamedType(name.(remoteString).aGet(a))
+ rt.Type = nt
+ }
+ }
+
+ // Create type
+ var t eval.Type
+ var mk maker
+ switch itype {
+ case p.runtime.PBoolType:
+ t = eval.BoolType
+ mk = mkBool
+ case p.runtime.PUint8Type:
+ t = eval.Uint8Type
+ mk = mkUint8
+ case p.runtime.PUint16Type:
+ t = eval.Uint16Type
+ mk = mkUint16
+ case p.runtime.PUint32Type:
+ t = eval.Uint32Type
+ mk = mkUint32
+ case p.runtime.PUint64Type:
+ t = eval.Uint64Type
+ mk = mkUint64
+ case p.runtime.PUintType:
+ t = eval.UintType
+ mk = mkUint
+ case p.runtime.PUintptrType:
+ t = eval.UintptrType
+ mk = mkUintptr
+ case p.runtime.PInt8Type:
+ t = eval.Int8Type
+ mk = mkInt8
+ case p.runtime.PInt16Type:
+ t = eval.Int16Type
+ mk = mkInt16
+ case p.runtime.PInt32Type:
+ t = eval.Int32Type
+ mk = mkInt32
+ case p.runtime.PInt64Type:
+ t = eval.Int64Type
+ mk = mkInt64
+ case p.runtime.PIntType:
+ t = eval.IntType
+ mk = mkInt
+ case p.runtime.PFloat32Type:
+ t = eval.Float32Type
+ mk = mkFloat32
+ case p.runtime.PFloat64Type:
+ t = eval.Float64Type
+ mk = mkFloat64
+ case p.runtime.PStringType:
+ t = eval.StringType
+ mk = mkString
+
+ case p.runtime.PArrayType:
+ // Cast to an ArrayType
+ typ := p.runtime.ArrayType.mk(typ.addr()).(remoteStruct)
+ len := int64(typ.field(p.f.ArrayType.Len).(remoteUint).aGet(a))
+ elem := parseRemoteType(a, typ.field(p.f.ArrayType.Elem).(remotePtr).aGet(a).(remoteStruct))
+ t = eval.NewArrayType(len, elem.Type)
+ mk = func(r remote) eval.Value { return remoteArray{r, len, elem} }
+
+ case p.runtime.PStructType:
+ // Cast to a StructType
+ typ := p.runtime.StructType.mk(typ.addr()).(remoteStruct)
+ fs := typ.field(p.f.StructType.Fields).(remoteSlice).aGet(a)
+
+ fields := make([]eval.StructField, fs.Len)
+ layout := make([]remoteStructField, fs.Len)
+ for i := range fields {
+ f := fs.Base.(remoteArray).elem(int64(i)).(remoteStruct)
+ elemrs := f.field(p.f.StructField.Typ).(remotePtr).aGet(a).(remoteStruct)
+ elem := parseRemoteType(a, elemrs)
+ fields[i].Type = elem.Type
+ name := f.field(p.f.StructField.Name).(remotePtr).aGet(a)
+ if name == nil {
+ fields[i].Anonymous = true
+ } else {
+ fields[i].Name = name.(remoteString).aGet(a)
+ }
+ layout[i].offset = int(f.field(p.f.StructField.Offset).(remoteUint).aGet(a))
+ layout[i].fieldType = elem
+ }
+
+ t = eval.NewStructType(fields)
+ mk = func(r remote) eval.Value { return remoteStruct{r, layout} }
+
+ case p.runtime.PPtrType:
+ // Cast to a PtrType
+ typ := p.runtime.PtrType.mk(typ.addr()).(remoteStruct)
+ elem := parseRemoteType(a, typ.field(p.f.PtrType.Elem).(remotePtr).aGet(a).(remoteStruct))
+ t = eval.NewPtrType(elem.Type)
+ mk = func(r remote) eval.Value { return remotePtr{r, elem} }
+
+ case p.runtime.PSliceType:
+ // Cast to a SliceType
+ typ := p.runtime.SliceType.mk(typ.addr()).(remoteStruct)
+ elem := parseRemoteType(a, typ.field(p.f.SliceType.Elem).(remotePtr).aGet(a).(remoteStruct))
+ t = eval.NewSliceType(elem.Type)
+ mk = func(r remote) eval.Value { return remoteSlice{r, elem} }
+
+ case p.runtime.PMapType, p.runtime.PChanType, p.runtime.PFuncType, p.runtime.PInterfaceType, p.runtime.PUnsafePointerType, p.runtime.PDotDotDotType:
+ // TODO(austin)
+ t = eval.UintptrType
+ mk = mkUintptr
+
+ default:
+ sym := p.syms.SymByAddr(uint64(itype))
+ name := "<unknown symbol>"
+ if sym != nil {
+ name = sym.Name
+ }
+ err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name)
+ a.Abort(FormatError(err))
+ }
+
+ // Fill in the remote type
+ if nt != nil {
+ nt.Complete(t)
+ } else {
+ rt.Type = t
+ }
+ rt.size = int(typ.field(p.f.CommonType.Size).(remoteUint).aGet(a))
+ rt.mk = mk
+
+ return rt
+}
diff --git a/libgo/go/exp/ogle/rvalue.go b/libgo/go/exp/ogle/rvalue.go
new file mode 100644
index 000000000..3d630f936
--- /dev/null
+++ b/libgo/go/exp/ogle/rvalue.go
@@ -0,0 +1,515 @@
+// 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 ogle
+
+import (
+ "debug/proc"
+ "exp/eval"
+ "fmt"
+)
+
+// A RemoteMismatchError occurs when an operation that requires two
+// identical remote processes is given different process. For
+// example, this occurs when trying to set a pointer in one process to
+// point to something in another process.
+type RemoteMismatchError string
+
+func (e RemoteMismatchError) String() string { return string(e) }
+
+// A ReadOnlyError occurs when attempting to set or assign to a
+// read-only value.
+type ReadOnlyError string
+
+func (e ReadOnlyError) String() string { return string(e) }
+
+// A maker is a function that converts a remote address into an
+// interpreter Value.
+type maker func(remote) eval.Value
+
+type remoteValue interface {
+ addr() remote
+}
+
+// remote represents an address in a remote process.
+type remote struct {
+ base proc.Word
+ p *Process
+}
+
+func (v remote) Get(a aborter, size int) uint64 {
+ // TODO(austin) This variable might temporarily be in a
+ // register. We could trace the assembly back from the
+ // current PC, looking for the beginning of the function or a
+ // call (both of which guarantee that the variable is in
+ // memory), or an instruction that loads the variable into a
+ // register.
+ //
+ // TODO(austin) If this is a local variable, it might not be
+ // live at this PC. In fact, because the compiler reuses
+ // slots, there might even be a different local variable at
+ // this location right now. A simple solution to both
+ // problems is to include the range of PC's over which a local
+ // variable is live in the symbol table.
+ //
+ // TODO(austin) We need to prevent the remote garbage
+ // collector from collecting objects out from under us.
+ var arr [8]byte
+ buf := arr[0:size]
+ _, err := v.p.Peek(v.base, buf)
+ if err != nil {
+ a.Abort(err)
+ }
+ return uint64(v.p.ToWord(buf))
+}
+
+func (v remote) Set(a aborter, size int, x uint64) {
+ var arr [8]byte
+ buf := arr[0:size]
+ v.p.FromWord(proc.Word(x), buf)
+ _, err := v.p.Poke(v.base, buf)
+ if err != nil {
+ a.Abort(err)
+ }
+}
+
+func (v remote) plus(x proc.Word) remote { return remote{v.base + x, v.p} }
+
+func tryRVString(f func(a aborter) string) string {
+ var s string
+ err := try(func(a aborter) { s = f(a) })
+ if err != nil {
+ return fmt.Sprintf("<error: %v>", err)
+ }
+ return s
+}
+
+/*
+ * Bool
+ */
+
+type remoteBool struct {
+ r remote
+}
+
+func (v remoteBool) String() string {
+ return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
+}
+
+func (v remoteBool) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.BoolValue).Get(t))
+}
+
+func (v remoteBool) Get(t *eval.Thread) bool { return v.aGet(t) }
+
+func (v remoteBool) aGet(a aborter) bool { return v.r.Get(a, 1) != 0 }
+
+func (v remoteBool) Set(t *eval.Thread, x bool) {
+ v.aSet(t, x)
+}
+
+func (v remoteBool) aSet(a aborter, x bool) {
+ if x {
+ v.r.Set(a, 1, 1)
+ } else {
+ v.r.Set(a, 1, 0)
+ }
+}
+
+func (v remoteBool) addr() remote { return v.r }
+
+func mkBool(r remote) eval.Value { return remoteBool{r} }
+
+/*
+ * Uint
+ */
+
+type remoteUint struct {
+ r remote
+ size int
+}
+
+func (v remoteUint) String() string {
+ return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
+}
+
+func (v remoteUint) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.UintValue).Get(t))
+}
+
+func (v remoteUint) Get(t *eval.Thread) uint64 {
+ return v.aGet(t)
+}
+
+func (v remoteUint) aGet(a aborter) uint64 { return v.r.Get(a, v.size) }
+
+func (v remoteUint) Set(t *eval.Thread, x uint64) {
+ v.aSet(t, x)
+}
+
+func (v remoteUint) aSet(a aborter, x uint64) { v.r.Set(a, v.size, x) }
+
+func (v remoteUint) addr() remote { return v.r }
+
+func mkUint8(r remote) eval.Value { return remoteUint{r, 1} }
+
+func mkUint16(r remote) eval.Value { return remoteUint{r, 2} }
+
+func mkUint32(r remote) eval.Value { return remoteUint{r, 4} }
+
+func mkUint64(r remote) eval.Value { return remoteUint{r, 8} }
+
+func mkUint(r remote) eval.Value { return remoteUint{r, r.p.IntSize()} }
+
+func mkUintptr(r remote) eval.Value { return remoteUint{r, r.p.PtrSize()} }
+
+/*
+ * Int
+ */
+
+type remoteInt struct {
+ r remote
+ size int
+}
+
+func (v remoteInt) String() string {
+ return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
+}
+
+func (v remoteInt) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.IntValue).Get(t))
+}
+
+func (v remoteInt) Get(t *eval.Thread) int64 { return v.aGet(t) }
+
+func (v remoteInt) aGet(a aborter) int64 { return int64(v.r.Get(a, v.size)) }
+
+func (v remoteInt) Set(t *eval.Thread, x int64) {
+ v.aSet(t, x)
+}
+
+func (v remoteInt) aSet(a aborter, x int64) { v.r.Set(a, v.size, uint64(x)) }
+
+func (v remoteInt) addr() remote { return v.r }
+
+func mkInt8(r remote) eval.Value { return remoteInt{r, 1} }
+
+func mkInt16(r remote) eval.Value { return remoteInt{r, 2} }
+
+func mkInt32(r remote) eval.Value { return remoteInt{r, 4} }
+
+func mkInt64(r remote) eval.Value { return remoteInt{r, 8} }
+
+func mkInt(r remote) eval.Value { return remoteInt{r, r.p.IntSize()} }
+
+/*
+ * Float
+ */
+
+type remoteFloat struct {
+ r remote
+ size int
+}
+
+func (v remoteFloat) String() string {
+ return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) })
+}
+
+func (v remoteFloat) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.FloatValue).Get(t))
+}
+
+func (v remoteFloat) Get(t *eval.Thread) float64 {
+ return v.aGet(t)
+}
+
+func (v remoteFloat) aGet(a aborter) float64 {
+ bits := v.r.Get(a, v.size)
+ switch v.size {
+ case 4:
+ return float64(v.r.p.ToFloat32(uint32(bits)))
+ case 8:
+ return v.r.p.ToFloat64(bits)
+ }
+ panic("Unexpected float size")
+}
+
+func (v remoteFloat) Set(t *eval.Thread, x float64) {
+ v.aSet(t, x)
+}
+
+func (v remoteFloat) aSet(a aborter, x float64) {
+ var bits uint64
+ switch v.size {
+ case 4:
+ bits = uint64(v.r.p.FromFloat32(float32(x)))
+ case 8:
+ bits = v.r.p.FromFloat64(x)
+ default:
+ panic("Unexpected float size")
+ }
+ v.r.Set(a, v.size, bits)
+}
+
+func (v remoteFloat) addr() remote { return v.r }
+
+func mkFloat32(r remote) eval.Value { return remoteFloat{r, 4} }
+
+func mkFloat64(r remote) eval.Value { return remoteFloat{r, 8} }
+
+func mkFloat(r remote) eval.Value { return remoteFloat{r, r.p.FloatSize()} }
+
+/*
+ * String
+ */
+
+type remoteString struct {
+ r remote
+}
+
+func (v remoteString) String() string {
+ return tryRVString(func(a aborter) string { return v.aGet(a) })
+}
+
+func (v remoteString) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.StringValue).Get(t))
+}
+
+func (v remoteString) Get(t *eval.Thread) string {
+ return v.aGet(t)
+}
+
+func (v remoteString) aGet(a aborter) string {
+ rs := v.r.p.runtime.String.mk(v.r).(remoteStruct)
+ str := proc.Word(rs.field(v.r.p.f.String.Str).(remoteUint).aGet(a))
+ len := rs.field(v.r.p.f.String.Len).(remoteInt).aGet(a)
+
+ bytes := make([]uint8, len)
+ _, err := v.r.p.Peek(str, bytes)
+ if err != nil {
+ a.Abort(err)
+ }
+ return string(bytes)
+}
+
+func (v remoteString) Set(t *eval.Thread, x string) {
+ v.aSet(t, x)
+}
+
+func (v remoteString) aSet(a aborter, x string) {
+ // TODO(austin) This isn't generally possible without the
+ // ability to allocate remote memory.
+ a.Abort(ReadOnlyError("remote strings cannot be assigned to"))
+}
+
+func mkString(r remote) eval.Value { return remoteString{r} }
+
+/*
+ * Array
+ */
+
+type remoteArray struct {
+ r remote
+ len int64
+ elemType *remoteType
+}
+
+func (v remoteArray) String() string {
+ res := "{"
+ for i := int64(0); i < v.len; i++ {
+ if i > 0 {
+ res += ", "
+ }
+ res += v.elem(i).String()
+ }
+ return res + "}"
+}
+
+func (v remoteArray) Assign(t *eval.Thread, o eval.Value) {
+ // TODO(austin) Could do a bigger memcpy if o is a
+ // remoteArray in the same Process.
+ oa := o.(eval.ArrayValue)
+ for i := int64(0); i < v.len; i++ {
+ v.Elem(t, i).Assign(t, oa.Elem(t, i))
+ }
+}
+
+func (v remoteArray) Get(t *eval.Thread) eval.ArrayValue {
+ return v
+}
+
+func (v remoteArray) Elem(t *eval.Thread, i int64) eval.Value {
+ return v.elem(i)
+}
+
+func (v remoteArray) elem(i int64) eval.Value {
+ return v.elemType.mk(v.r.plus(proc.Word(int64(v.elemType.size) * i)))
+}
+
+func (v remoteArray) Sub(i int64, len int64) eval.ArrayValue {
+ return remoteArray{v.r.plus(proc.Word(int64(v.elemType.size) * i)), len, v.elemType}
+}
+
+/*
+ * Struct
+ */
+
+type remoteStruct struct {
+ r remote
+ layout []remoteStructField
+}
+
+type remoteStructField struct {
+ offset int
+ fieldType *remoteType
+}
+
+func (v remoteStruct) String() string {
+ res := "{"
+ for i := range v.layout {
+ if i > 0 {
+ res += ", "
+ }
+ res += v.field(i).String()
+ }
+ return res + "}"
+}
+
+func (v remoteStruct) Assign(t *eval.Thread, o eval.Value) {
+ // TODO(austin) Could do a bigger memcpy.
+ oa := o.(eval.StructValue)
+ l := len(v.layout)
+ for i := 0; i < l; i++ {
+ v.Field(t, i).Assign(t, oa.Field(t, i))
+ }
+}
+
+func (v remoteStruct) Get(t *eval.Thread) eval.StructValue {
+ return v
+}
+
+func (v remoteStruct) Field(t *eval.Thread, i int) eval.Value {
+ return v.field(i)
+}
+
+func (v remoteStruct) field(i int) eval.Value {
+ f := &v.layout[i]
+ return f.fieldType.mk(v.r.plus(proc.Word(f.offset)))
+}
+
+func (v remoteStruct) addr() remote { return v.r }
+
+/*
+ * Pointer
+ */
+
+// TODO(austin) Comparing two remote pointers for equality in the
+// interpreter will crash it because the Value's returned from
+// remotePtr.Get() will be structs.
+
+type remotePtr struct {
+ r remote
+ elemType *remoteType
+}
+
+func (v remotePtr) String() string {
+ return tryRVString(func(a aborter) string {
+ e := v.aGet(a)
+ if e == nil {
+ return "<nil>"
+ }
+ return "&" + e.String()
+ })
+}
+
+func (v remotePtr) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.PtrValue).Get(t))
+}
+
+func (v remotePtr) Get(t *eval.Thread) eval.Value {
+ return v.aGet(t)
+}
+
+func (v remotePtr) aGet(a aborter) eval.Value {
+ addr := proc.Word(v.r.Get(a, v.r.p.PtrSize()))
+ if addr == 0 {
+ return nil
+ }
+ return v.elemType.mk(remote{addr, v.r.p})
+}
+
+func (v remotePtr) Set(t *eval.Thread, x eval.Value) {
+ v.aSet(t, x)
+}
+
+func (v remotePtr) aSet(a aborter, x eval.Value) {
+ if x == nil {
+ v.r.Set(a, v.r.p.PtrSize(), 0)
+ return
+ }
+ xr, ok := x.(remoteValue)
+ if !ok || v.r.p != xr.addr().p {
+ a.Abort(RemoteMismatchError("remote pointer must point within the same process"))
+ }
+ v.r.Set(a, v.r.p.PtrSize(), uint64(xr.addr().base))
+}
+
+func (v remotePtr) addr() remote { return v.r }
+
+/*
+ * Slice
+ */
+
+type remoteSlice struct {
+ r remote
+ elemType *remoteType
+}
+
+func (v remoteSlice) String() string {
+ return tryRVString(func(a aborter) string {
+ b := v.aGet(a).Base
+ if b == nil {
+ return "<nil>"
+ }
+ return b.String()
+ })
+}
+
+func (v remoteSlice) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.SliceValue).Get(t))
+}
+
+func (v remoteSlice) Get(t *eval.Thread) eval.Slice {
+ return v.aGet(t)
+}
+
+func (v remoteSlice) aGet(a aborter) eval.Slice {
+ rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct)
+ base := proc.Word(rs.field(v.r.p.f.Slice.Array).(remoteUint).aGet(a))
+ nel := rs.field(v.r.p.f.Slice.Len).(remoteInt).aGet(a)
+ cap := rs.field(v.r.p.f.Slice.Cap).(remoteInt).aGet(a)
+ if base == 0 {
+ return eval.Slice{nil, nel, cap}
+ }
+ return eval.Slice{remoteArray{remote{base, v.r.p}, nel, v.elemType}, nel, cap}
+}
+
+func (v remoteSlice) Set(t *eval.Thread, x eval.Slice) {
+ v.aSet(t, x)
+}
+
+func (v remoteSlice) aSet(a aborter, x eval.Slice) {
+ rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct)
+ if x.Base == nil {
+ rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, 0)
+ } else {
+ ar, ok := x.Base.(remoteArray)
+ if !ok || v.r.p != ar.r.p {
+ a.Abort(RemoteMismatchError("remote slice must point within the same process"))
+ }
+ rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, uint64(ar.r.base))
+ }
+ rs.field(v.r.p.f.Slice.Len).(remoteInt).aSet(a, x.Len)
+ rs.field(v.r.p.f.Slice.Cap).(remoteInt).aSet(a, x.Cap)
+}
diff --git a/libgo/go/exp/ogle/vars.go b/libgo/go/exp/ogle/vars.go
new file mode 100644
index 000000000..8a3a14791
--- /dev/null
+++ b/libgo/go/exp/ogle/vars.go
@@ -0,0 +1,272 @@
+// 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 ogle
+
+import (
+ "debug/gosym"
+ "debug/proc"
+ "exp/eval"
+ "log"
+ "os"
+)
+
+/*
+ * Remote frame pointers
+ */
+
+// A NotOnStack error occurs when attempting to access a variable in a
+// remote frame where that remote frame is not on the current stack.
+type NotOnStack struct {
+ Fn *gosym.Func
+ Goroutine *Goroutine
+}
+
+func (e NotOnStack) String() string {
+ return "function " + e.Fn.Name + " not on " + e.Goroutine.String() + "'s stack"
+}
+
+// A remoteFramePtr is an implementation of eval.PtrValue that
+// represents a pointer to a function frame in a remote process. When
+// accessed, this locates the function on the current goroutine's
+// stack and returns a structure containing the local variables of
+// that function.
+type remoteFramePtr struct {
+ p *Process
+ fn *gosym.Func
+ rt *remoteType
+}
+
+func (v remoteFramePtr) String() string {
+ // TODO(austin): This could be a really awesome string method
+ return "<remote frame>"
+}
+
+func (v remoteFramePtr) Assign(t *eval.Thread, o eval.Value) {
+ v.Set(t, o.(eval.PtrValue).Get(t))
+}
+
+func (v remoteFramePtr) Get(t *eval.Thread) eval.Value {
+ g := v.p.curGoroutine
+ if g == nil || g.frame == nil {
+ t.Abort(NoCurrentGoroutine{})
+ }
+
+ for f := g.frame; f != nil; f = f.aOuter(t) {
+ if f.fn != v.fn {
+ continue
+ }
+
+ // TODO(austin): Register for shootdown with f
+ return v.rt.mk(remote{f.fp, v.p})
+ }
+
+ t.Abort(NotOnStack{v.fn, g})
+ panic("fail")
+}
+
+func (v remoteFramePtr) Set(t *eval.Thread, x eval.Value) {
+ // Theoretically this could be a static error. If remote
+ // packages were packages, remote frames could just be defined
+ // as constants.
+ t.Abort(ReadOnlyError("remote frames cannot be assigned to"))
+}
+
+/*
+ * Remote packages
+ */
+
+// TODO(austin): Remote packages are implemented as structs right now,
+// which has some weird consequences. You can attempt to assign to a
+// remote package. It also produces terrible error messages.
+// Ideally, these would actually be packages, but somehow first-class
+// so they could be assigned to other names.
+
+// A remotePackage is an implementation of eval.StructValue that
+// represents a package in a remote process. It's essentially a
+// regular struct, except it cannot be assigned to.
+type remotePackage struct {
+ defs []eval.Value
+}
+
+func (v remotePackage) String() string { return "<remote package>" }
+
+func (v remotePackage) Assign(t *eval.Thread, o eval.Value) {
+ t.Abort(ReadOnlyError("remote packages cannot be assigned to"))
+}
+
+func (v remotePackage) Get(t *eval.Thread) eval.StructValue {
+ return v
+}
+
+func (v remotePackage) Field(t *eval.Thread, i int) eval.Value {
+ return v.defs[i]
+}
+
+/*
+ * Remote variables
+ */
+
+// populateWorld defines constants in the given world for each package
+// in this process. These packages are structs that, in turn, contain
+// fields for each global and function in that package.
+func (p *Process) populateWorld(w *eval.World) os.Error {
+ type def struct {
+ t eval.Type
+ v eval.Value
+ }
+ packages := make(map[string]map[string]def)
+
+ for _, s := range p.syms.Syms {
+ if s.ReceiverName() != "" {
+ // TODO(austin)
+ continue
+ }
+
+ // Package
+ pkgName := s.PackageName()
+ switch pkgName {
+ case "", "type", "extratype", "string", "go":
+ // "go" is really "go.string"
+ continue
+ }
+ pkg, ok := packages[pkgName]
+ if !ok {
+ pkg = make(map[string]def)
+ packages[pkgName] = pkg
+ }
+
+ // Symbol name
+ name := s.BaseName()
+ if _, ok := pkg[name]; ok {
+ log.Printf("Multiple definitions of symbol %s", s.Name)
+ continue
+ }
+
+ // Symbol type
+ rt, err := p.typeOfSym(&s)
+ if err != nil {
+ return err
+ }
+
+ // Definition
+ switch s.Type {
+ case 'D', 'd', 'B', 'b':
+ // Global variable
+ if rt == nil {
+ continue
+ }
+ pkg[name] = def{rt.Type, rt.mk(remote{proc.Word(s.Value), p})}
+
+ case 'T', 't', 'L', 'l':
+ // Function
+ s := s.Func
+ // TODO(austin): Ideally, this would *also* be
+ // callable. How does that interact with type
+ // conversion syntax?
+ rt, err := p.makeFrameType(s)
+ if err != nil {
+ return err
+ }
+ pkg[name] = def{eval.NewPtrType(rt.Type), remoteFramePtr{p, s, rt}}
+ }
+ }
+
+ // TODO(austin): Define remote types
+
+ // Define packages
+ for pkgName, defs := range packages {
+ fields := make([]eval.StructField, len(defs))
+ vals := make([]eval.Value, len(defs))
+ i := 0
+ for name, def := range defs {
+ fields[i].Name = name
+ fields[i].Type = def.t
+ vals[i] = def.v
+ i++
+ }
+ pkgType := eval.NewStructType(fields)
+ pkgVal := remotePackage{vals}
+
+ err := w.DefineConst(pkgName, pkgType, pkgVal)
+ if err != nil {
+ log.Printf("while defining package %s: %v", pkgName, err)
+ }
+ }
+
+ return nil
+}
+
+// typeOfSym returns the type associated with a symbol. If the symbol
+// has no type, returns nil.
+func (p *Process) typeOfSym(s *gosym.Sym) (*remoteType, os.Error) {
+ if s.GoType == 0 {
+ return nil, nil
+ }
+ addr := proc.Word(s.GoType)
+ var rt *remoteType
+ err := try(func(a aborter) { rt = parseRemoteType(a, p.runtime.Type.mk(remote{addr, p}).(remoteStruct)) })
+ if err != nil {
+ return nil, err
+ }
+ return rt, nil
+}
+
+// makeFrameType constructs a struct type for the frame of a function.
+// The offsets in this struct type are such that the struct can be
+// instantiated at this function's frame pointer.
+func (p *Process) makeFrameType(s *gosym.Func) (*remoteType, os.Error) {
+ n := len(s.Params) + len(s.Locals)
+ fields := make([]eval.StructField, n)
+ layout := make([]remoteStructField, n)
+ i := 0
+
+ // TODO(austin): There can be multiple locals/parameters with
+ // the same name. We probably need liveness information to do
+ // anything about this. Once we have that, perhaps we give
+ // such fields interface{} type? Or perhaps we disambiguate
+ // the names with numbers. Disambiguation is annoying for
+ // things like "i", where there's an obvious right answer.
+
+ for _, param := range s.Params {
+ rt, err := p.typeOfSym(param)
+ if err != nil {
+ return nil, err
+ }
+ if rt == nil {
+ //fmt.Printf(" (no type)\n");
+ continue
+ }
+ // TODO(austin): Why do local variables carry their
+ // package name?
+ fields[i].Name = param.BaseName()
+ fields[i].Type = rt.Type
+ // Parameters have positive offsets from FP
+ layout[i].offset = int(param.Value)
+ layout[i].fieldType = rt
+ i++
+ }
+
+ for _, local := range s.Locals {
+ rt, err := p.typeOfSym(local)
+ if err != nil {
+ return nil, err
+ }
+ if rt == nil {
+ continue
+ }
+ fields[i].Name = local.BaseName()
+ fields[i].Type = rt.Type
+ // Locals have negative offsets from FP - PtrSize
+ layout[i].offset = -int(local.Value) - p.PtrSize()
+ layout[i].fieldType = rt
+ i++
+ }
+
+ fields = fields[0:i]
+ layout = layout[0:i]
+ t := eval.NewStructType(fields)
+ mk := func(r remote) eval.Value { return remoteStruct{r, layout} }
+ return &remoteType{t, 0, 0, mk}, nil
+}
diff --git a/libgo/go/expvar/expvar.go b/libgo/go/expvar/expvar.go
new file mode 100644
index 000000000..b1f0f6c1b
--- /dev/null
+++ b/libgo/go/expvar/expvar.go
@@ -0,0 +1,299 @@
+// 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.
+
+// The expvar package provides a standardized interface to public variables,
+// such as operation counters in servers. It exposes these variables via
+// HTTP at /debug/vars in JSON format.
+//
+// Operations to set or modify these public variables are atomic.
+//
+// In addition to adding the HTTP handler, this package registers the
+// following variables:
+//
+// cmdline os.Args
+// memstats runtime.Memstats
+//
+// The package is sometimes only imported for the side effect of
+// registering its HTTP handler and the above variables. To use it
+// this way, simply link this package into your program:
+// import _ "expvar"
+//
+package expvar
+
+import (
+ "bytes"
+ "fmt"
+ "http"
+ "json"
+ "log"
+ "os"
+ "runtime"
+ "strconv"
+ "sync"
+)
+
+// Var is an abstract type for all exported variables.
+type Var interface {
+ String() string
+}
+
+// Int is a 64-bit integer variable that satisfies the Var interface.
+type Int struct {
+ i int64
+ mu sync.Mutex
+}
+
+func (v *Int) String() string { return strconv.Itoa64(v.i) }
+
+func (v *Int) Add(delta int64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.i += delta
+}
+
+func (v *Int) Set(value int64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.i = value
+}
+
+// Float is a 64-bit float variable that satisfies the Var interface.
+type Float struct {
+ f float64
+ mu sync.Mutex
+}
+
+func (v *Float) String() string { return strconv.Ftoa64(v.f, 'g', -1) }
+
+// Add adds delta to v.
+func (v *Float) Add(delta float64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.f += delta
+}
+
+// Set sets v to value.
+func (v *Float) Set(value float64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.f = value
+}
+
+// Map is a string-to-Var map variable that satisfies the Var interface.
+type Map struct {
+ m map[string]Var
+ mu sync.Mutex
+}
+
+// KeyValue represents a single entry in a Map.
+type KeyValue struct {
+ Key string
+ Value Var
+}
+
+func (v *Map) String() string {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ b := new(bytes.Buffer)
+ fmt.Fprintf(b, "{")
+ first := true
+ for key, val := range v.m {
+ if !first {
+ fmt.Fprintf(b, ", ")
+ }
+ fmt.Fprintf(b, "\"%s\": %v", key, val.String())
+ first = false
+ }
+ fmt.Fprintf(b, "}")
+ return b.String()
+}
+
+func (v *Map) Init() *Map {
+ v.m = make(map[string]Var)
+ return v
+}
+
+func (v *Map) Get(key string) Var {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ return v.m[key]
+}
+
+func (v *Map) Set(key string, av Var) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.m[key] = av
+}
+
+func (v *Map) Add(key string, delta int64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ av, ok := v.m[key]
+ if !ok {
+ av = new(Int)
+ v.m[key] = av
+ }
+
+ // Add to Int; ignore otherwise.
+ if iv, ok := av.(*Int); ok {
+ iv.Add(delta)
+ }
+}
+
+// AddFloat adds delta to the *Float value stored under the given map key.
+func (v *Map) AddFloat(key string, delta float64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ av, ok := v.m[key]
+ if !ok {
+ av = new(Float)
+ v.m[key] = av
+ }
+
+ // Add to Float; ignore otherwise.
+ if iv, ok := av.(*Float); ok {
+ iv.Add(delta)
+ }
+}
+
+// TODO(rsc): Make sure map access in separate thread is safe.
+func (v *Map) iterate(c chan<- KeyValue) {
+ for k, v := range v.m {
+ c <- KeyValue{k, v}
+ }
+ close(c)
+}
+
+func (v *Map) Iter() <-chan KeyValue {
+ c := make(chan KeyValue)
+ go v.iterate(c)
+ return c
+}
+
+// String is a string variable, and satisfies the Var interface.
+type String struct {
+ s string
+}
+
+func (v *String) String() string { return strconv.Quote(v.s) }
+
+func (v *String) Set(value string) { v.s = value }
+
+// IntFunc wraps a func() int64 to create a value that satisfies the Var interface.
+// The function will be called each time the Var is evaluated.
+type IntFunc func() int64
+
+func (v IntFunc) String() string { return strconv.Itoa64(v()) }
+
+// FloatFunc wraps a func() float64 to create a value that satisfies the Var interface.
+// The function will be called each time the Var is evaluated.
+type FloatFunc func() float64
+
+func (v FloatFunc) String() string { return strconv.Ftoa64(v(), 'g', -1) }
+
+// StringFunc wraps a func() string to create value that satisfies the Var interface.
+// The function will be called each time the Var is evaluated.
+type StringFunc func() string
+
+func (f StringFunc) String() string { return strconv.Quote(f()) }
+
+
+// All published variables.
+var vars map[string]Var = make(map[string]Var)
+var mutex sync.Mutex
+
+// Publish declares an named exported variable. This should be called from a
+// package's init function when it creates its Vars. If the name is already
+// registered then this will log.Panic.
+func Publish(name string, v Var) {
+ mutex.Lock()
+ defer mutex.Unlock()
+ if _, existing := vars[name]; existing {
+ log.Panicln("Reuse of exported var name:", name)
+ }
+ vars[name] = v
+}
+
+// Get retrieves a named exported variable.
+func Get(name string) Var {
+ return vars[name]
+}
+
+// RemoveAll removes all exported variables.
+// This is for tests; don't call this on a real server.
+func RemoveAll() {
+ mutex.Lock()
+ defer mutex.Unlock()
+ vars = make(map[string]Var)
+}
+
+// Convenience functions for creating new exported variables.
+
+func NewInt(name string) *Int {
+ v := new(Int)
+ Publish(name, v)
+ return v
+}
+
+func NewFloat(name string) *Float {
+ v := new(Float)
+ Publish(name, v)
+ return v
+}
+
+func NewMap(name string) *Map {
+ v := new(Map).Init()
+ Publish(name, v)
+ return v
+}
+
+func NewString(name string) *String {
+ v := new(String)
+ Publish(name, v)
+ return v
+}
+
+// TODO(rsc): Make sure map access in separate thread is safe.
+func iterate(c chan<- KeyValue) {
+ for k, v := range vars {
+ c <- KeyValue{k, v}
+ }
+ close(c)
+}
+
+func Iter() <-chan KeyValue {
+ c := make(chan KeyValue)
+ go iterate(c)
+ return c
+}
+
+func expvarHandler(w http.ResponseWriter, r *http.Request) {
+ w.SetHeader("content-type", "application/json; charset=utf-8")
+ fmt.Fprintf(w, "{\n")
+ first := true
+ for name, value := range vars {
+ if !first {
+ fmt.Fprintf(w, ",\n")
+ }
+ first = false
+ fmt.Fprintf(w, "%q: %s", name, value)
+ }
+ fmt.Fprintf(w, "\n}\n")
+}
+
+func memstats() string {
+ b, _ := json.MarshalIndent(&runtime.MemStats, "", "\t")
+ return string(b)
+}
+
+func cmdline() string {
+ b, _ := json.Marshal(os.Args)
+ return string(b)
+}
+
+func init() {
+ http.Handle("/debug/vars", http.HandlerFunc(expvarHandler))
+ Publish("cmdline", StringFunc(cmdline))
+ Publish("memstats", StringFunc(memstats))
+}
diff --git a/libgo/go/expvar/expvar_test.go b/libgo/go/expvar/expvar_test.go
new file mode 100644
index 000000000..a8b1a96a9
--- /dev/null
+++ b/libgo/go/expvar/expvar_test.go
@@ -0,0 +1,154 @@
+// 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 expvar
+
+import (
+ "json"
+ "testing"
+)
+
+func TestInt(t *testing.T) {
+ reqs := NewInt("requests")
+ if reqs.i != 0 {
+ t.Errorf("reqs.i = %v, want 0", reqs.i)
+ }
+ if reqs != Get("requests").(*Int) {
+ t.Errorf("Get() failed.")
+ }
+
+ reqs.Add(1)
+ reqs.Add(3)
+ if reqs.i != 4 {
+ t.Errorf("reqs.i = %v, want 4", reqs.i)
+ }
+
+ if s := reqs.String(); s != "4" {
+ t.Errorf("reqs.String() = %q, want \"4\"", s)
+ }
+
+ reqs.Set(-2)
+ if reqs.i != -2 {
+ t.Errorf("reqs.i = %v, want -2", reqs.i)
+ }
+}
+
+func TestFloat(t *testing.T) {
+ reqs := NewFloat("requests-float")
+ if reqs.f != 0.0 {
+ t.Errorf("reqs.f = %v, want 0", reqs.f)
+ }
+ if reqs != Get("requests-float").(*Float) {
+ t.Errorf("Get() failed.")
+ }
+
+ reqs.Add(1.5)
+ reqs.Add(1.25)
+ if reqs.f != 2.75 {
+ t.Errorf("reqs.f = %v, want 2.75", reqs.f)
+ }
+
+ if s := reqs.String(); s != "2.75" {
+ t.Errorf("reqs.String() = %q, want \"4.64\"", s)
+ }
+
+ reqs.Add(-2)
+ if reqs.f != 0.75 {
+ t.Errorf("reqs.f = %v, want 0.75", reqs.f)
+ }
+}
+
+func TestString(t *testing.T) {
+ name := NewString("my-name")
+ if name.s != "" {
+ t.Errorf("name.s = %q, want \"\"", name.s)
+ }
+
+ name.Set("Mike")
+ if name.s != "Mike" {
+ t.Errorf("name.s = %q, want \"Mike\"", name.s)
+ }
+
+ if s := name.String(); s != "\"Mike\"" {
+ t.Errorf("reqs.String() = %q, want \"\"Mike\"\"", s)
+ }
+}
+
+func TestMapCounter(t *testing.T) {
+ colours := NewMap("bike-shed-colours")
+
+ colours.Add("red", 1)
+ colours.Add("red", 2)
+ colours.Add("blue", 4)
+ colours.AddFloat("green", 4.125)
+ if x := colours.m["red"].(*Int).i; x != 3 {
+ t.Errorf("colours.m[\"red\"] = %v, want 3", x)
+ }
+ if x := colours.m["blue"].(*Int).i; x != 4 {
+ t.Errorf("colours.m[\"blue\"] = %v, want 4", x)
+ }
+ if x := colours.m["green"].(*Float).f; x != 4.125 {
+ t.Errorf("colours.m[\"green\"] = %v, want 3.14", x)
+ }
+
+ // colours.String() should be '{"red":3, "blue":4}',
+ // though the order of red and blue could vary.
+ s := colours.String()
+ var j interface{}
+ err := json.Unmarshal([]byte(s), &j)
+ if err != nil {
+ t.Errorf("colours.String() isn't valid JSON: %v", err)
+ }
+ m, ok := j.(map[string]interface{})
+ if !ok {
+ t.Error("colours.String() didn't produce a map.")
+ }
+ red := m["red"]
+ x, ok := red.(float64)
+ if !ok {
+ t.Error("red.Kind() is not a number.")
+ }
+ if x != 3 {
+ t.Errorf("red = %v, want 3", x)
+ }
+}
+
+func TestIntFunc(t *testing.T) {
+ x := int64(4)
+ ix := IntFunc(func() int64 { return x })
+ if s := ix.String(); s != "4" {
+ t.Errorf("ix.String() = %v, want 4", s)
+ }
+
+ x++
+ if s := ix.String(); s != "5" {
+ t.Errorf("ix.String() = %v, want 5", s)
+ }
+}
+
+func TestFloatFunc(t *testing.T) {
+ x := 8.5
+ ix := FloatFunc(func() float64 { return x })
+ if s := ix.String(); s != "8.5" {
+ t.Errorf("ix.String() = %v, want 3.14", s)
+ }
+
+ x -= 1.25
+ if s := ix.String(); s != "7.25" {
+ t.Errorf("ix.String() = %v, want 4.34", s)
+ }
+}
+
+func TestStringFunc(t *testing.T) {
+ x := "hello"
+ sx := StringFunc(func() string { return x })
+ if s, exp := sx.String(), `"hello"`; s != exp {
+ t.Errorf(`sx.String() = %q, want %q`, s, exp)
+ }
+
+ x = "goodbye"
+ if s, exp := sx.String(), `"goodbye"`; s != exp {
+ t.Errorf(`sx.String() = %q, want %q`, s, exp)
+ }
+}
diff --git a/libgo/go/flag/export_test.go b/libgo/go/flag/export_test.go
new file mode 100644
index 000000000..b5e3243b3
--- /dev/null
+++ b/libgo/go/flag/export_test.go
@@ -0,0 +1,32 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flag
+
+import "os"
+
+// Additional routines compiled into the package only during testing.
+
+// ResetForTesting clears all flag state and sets the usage function as directed.
+// After calling ResetForTesting, parse errors in flag handling will panic rather
+// than exit the program.
+func ResetForTesting(usage func()) {
+ flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]}
+ Usage = usage
+ panicOnError = true
+}
+
+// ParseForTesting parses the flag state using the provided arguments. It
+// should be called after 1) ResetForTesting and 2) setting up the new flags.
+// The return value reports whether the parse was error-free.
+func ParseForTesting(args []string) (result bool) {
+ defer func() {
+ if recover() != nil {
+ result = false
+ }
+ }()
+ os.Args = args
+ Parse()
+ return true
+}
diff --git a/libgo/go/flag/flag.go b/libgo/go/flag/flag.go
new file mode 100644
index 000000000..143a10611
--- /dev/null
+++ b/libgo/go/flag/flag.go
@@ -0,0 +1,480 @@
+// 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.
+
+/*
+ The flag package implements command-line flag parsing.
+
+ Usage:
+
+ Define flags using flag.String(), Bool(), Int(), etc. Example:
+ import "flag"
+ var ip *int = flag.Int("flagname", 1234, "help message for flagname")
+ If you like, you can bind the flag to a variable using the Var() functions.
+ var flagvar int
+ func init() {
+ flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
+ }
+ Or you can create custom flags that satisfy the Value interface (with
+ pointer receivers) and couple them to flag parsing by
+ flag.Var(&flagVal, "name", "help message for flagname")
+ For such flags, the default value is just the initial value of the variable.
+
+ After all flags are defined, call
+ flag.Parse()
+ to parse the command line into the defined flags.
+
+ Flags may then be used directly. If you're using the flags themselves,
+ they are all pointers; if you bind to variables, they're values.
+ fmt.Println("ip has value ", *ip);
+ fmt.Println("flagvar has value ", flagvar);
+
+ After parsing, the arguments after the flag are available as the
+ slice flag.Args() or individually as flag.Arg(i).
+ The arguments are indexed from 0 up to flag.NArg().
+
+ Command line flag syntax:
+ -flag
+ -flag=x
+ -flag x // non-boolean flags only
+ One or two minus signs may be used; they are equivalent.
+ The last form is not permitted for boolean flags because the
+ meaning of the command
+ cmd -x *
+ will change if there is a file called 0, false, etc. You must
+ use the -flag=false form to turn off a boolean flag.
+
+ Flag parsing stops just before the first non-flag argument
+ ("-" is a non-flag argument) or after the terminator "--".
+
+ Integer flags accept 1234, 0664, 0x1234 and may be negative.
+ Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
+
+ It is safe to call flag.Parse multiple times, possibly after changing
+ os.Args. This makes it possible to implement command lines with
+ subcommands that enable additional flags, as in:
+
+ flag.Bool(...) // global options
+ flag.Parse() // parse leading command
+ subcmd := flag.Args(0)
+ switch subcmd {
+ // add per-subcommand options
+ }
+ os.Args = flag.Args()
+ flag.Parse()
+*/
+package flag
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+)
+
+// -- Bool Value
+type boolValue bool
+
+func newBoolValue(val bool, p *bool) *boolValue {
+ *p = val
+ return (*boolValue)(p)
+}
+
+func (b *boolValue) Set(s string) bool {
+ v, err := strconv.Atob(s)
+ *b = boolValue(v)
+ return err == nil
+}
+
+func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
+
+// -- Int Value
+type intValue int
+
+func newIntValue(val int, p *int) *intValue {
+ *p = val
+ return (*intValue)(p)
+}
+
+func (i *intValue) Set(s string) bool {
+ v, err := strconv.Atoi(s)
+ *i = intValue(v)
+ return err == nil
+}
+
+func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- Int64 Value
+type int64Value int64
+
+func newInt64Value(val int64, p *int64) *int64Value {
+ *p = val
+ return (*int64Value)(p)
+}
+
+func (i *int64Value) Set(s string) bool {
+ v, err := strconv.Atoi64(s)
+ *i = int64Value(v)
+ return err == nil
+}
+
+func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- Uint Value
+type uintValue uint
+
+func newUintValue(val uint, p *uint) *uintValue {
+ *p = val
+ return (*uintValue)(p)
+}
+
+func (i *uintValue) Set(s string) bool {
+ v, err := strconv.Atoui(s)
+ *i = uintValue(v)
+ return err == nil
+}
+
+func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- uint64 Value
+type uint64Value uint64
+
+func newUint64Value(val uint64, p *uint64) *uint64Value {
+ *p = val
+ return (*uint64Value)(p)
+}
+
+func (i *uint64Value) Set(s string) bool {
+ v, err := strconv.Atoui64(s)
+ *i = uint64Value(v)
+ return err == nil
+}
+
+func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
+
+// -- string Value
+type stringValue string
+
+func newStringValue(val string, p *string) *stringValue {
+ *p = val
+ return (*stringValue)(p)
+}
+
+func (s *stringValue) Set(val string) bool {
+ *s = stringValue(val)
+ return true
+}
+
+func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
+
+// -- Float64 Value
+type float64Value float64
+
+func newFloat64Value(val float64, p *float64) *float64Value {
+ *p = val
+ return (*float64Value)(p)
+}
+
+func (f *float64Value) Set(s string) bool {
+ v, err := strconv.Atof64(s)
+ *f = float64Value(v)
+ return err == nil
+}
+
+func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
+
+// Value is the interface to the dynamic value stored in a flag.
+// (The default value is represented as a string.)
+type Value interface {
+ String() string
+ Set(string) bool
+}
+
+// A Flag represents the state of a flag.
+type Flag struct {
+ Name string // name as it appears on command line
+ Usage string // help message
+ Value Value // value as set
+ DefValue string // default value (as text); for usage message
+}
+
+type allFlags struct {
+ actual map[string]*Flag
+ formal map[string]*Flag
+ args []string // arguments after flags
+}
+
+var flags *allFlags
+
+// VisitAll visits the flags, calling fn for each. It visits all flags, even those not set.
+func VisitAll(fn func(*Flag)) {
+ for _, f := range flags.formal {
+ fn(f)
+ }
+}
+
+// Visit visits the flags, calling fn for each. It visits only those flags that have been set.
+func Visit(fn func(*Flag)) {
+ for _, f := range flags.actual {
+ fn(f)
+ }
+}
+
+// Lookup returns the Flag structure of the named flag, returning nil if none exists.
+func Lookup(name string) *Flag {
+ return flags.formal[name]
+}
+
+// Set sets the value of the named flag. It returns true if the set succeeded; false if
+// there is no such flag defined.
+func Set(name, value string) bool {
+ f, ok := flags.formal[name]
+ if !ok {
+ return false
+ }
+ ok = f.Value.Set(value)
+ if !ok {
+ return false
+ }
+ flags.actual[name] = f
+ return true
+}
+
+// PrintDefaults prints to standard error the default values of all defined flags.
+func PrintDefaults() {
+ VisitAll(func(f *Flag) {
+ format := " -%s=%s: %s\n"
+ if _, ok := f.Value.(*stringValue); ok {
+ // put quotes on the value
+ format = " -%s=%q: %s\n"
+ }
+ fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage)
+ })
+}
+
+// Usage prints to standard error a default usage message documenting all defined flags.
+// The function is a variable that may be changed to point to a custom function.
+var Usage = func() {
+ fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+ PrintDefaults()
+}
+
+var panicOnError = false
+
+func fail() {
+ Usage()
+ if panicOnError {
+ panic("flag parse error")
+ }
+ os.Exit(2)
+}
+
+func NFlag() int { return len(flags.actual) }
+
+// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument
+// after flags have been processed.
+func Arg(i int) string {
+ if i < 0 || i >= len(flags.args) {
+ return ""
+ }
+ return flags.args[i]
+}
+
+// NArg is the number of arguments remaining after flags have been processed.
+func NArg() int { return len(flags.args) }
+
+// Args returns the non-flag command-line arguments.
+func Args() []string { return flags.args }
+
+// BoolVar defines a bool flag with specified name, default value, and usage string.
+// The argument p points to a bool variable in which to store the value of the flag.
+func BoolVar(p *bool, name string, value bool, usage string) {
+ Var(newBoolValue(value, p), name, usage)
+}
+
+// Bool defines a bool flag with specified name, default value, and usage string.
+// The return value is the address of a bool variable that stores the value of the flag.
+func Bool(name string, value bool, usage string) *bool {
+ p := new(bool)
+ BoolVar(p, name, value, usage)
+ return p
+}
+
+// IntVar defines an int flag with specified name, default value, and usage string.
+// The argument p points to an int variable in which to store the value of the flag.
+func IntVar(p *int, name string, value int, usage string) {
+ Var(newIntValue(value, p), name, usage)
+}
+
+// Int defines an int flag with specified name, default value, and usage string.
+// The return value is the address of an int variable that stores the value of the flag.
+func Int(name string, value int, usage string) *int {
+ p := new(int)
+ IntVar(p, name, value, usage)
+ return p
+}
+
+// Int64Var defines an int64 flag with specified name, default value, and usage string.
+// The argument p points to an int64 variable in which to store the value of the flag.
+func Int64Var(p *int64, name string, value int64, usage string) {
+ Var(newInt64Value(value, p), name, usage)
+}
+
+// Int64 defines an int64 flag with specified name, default value, and usage string.
+// The return value is the address of an int64 variable that stores the value of the flag.
+func Int64(name string, value int64, usage string) *int64 {
+ p := new(int64)
+ Int64Var(p, name, value, usage)
+ return p
+}
+
+// UintVar defines a uint flag with specified name, default value, and usage string.
+// The argument p points to a uint variable in which to store the value of the flag.
+func UintVar(p *uint, name string, value uint, usage string) {
+ Var(newUintValue(value, p), name, usage)
+}
+
+// Uint defines a uint flag with specified name, default value, and usage string.
+// The return value is the address of a uint variable that stores the value of the flag.
+func Uint(name string, value uint, usage string) *uint {
+ p := new(uint)
+ UintVar(p, name, value, usage)
+ return p
+}
+
+// Uint64Var defines a uint64 flag with specified name, default value, and usage string.
+// The argument p points to a uint64 variable in which to store the value of the flag.
+func Uint64Var(p *uint64, name string, value uint64, usage string) {
+ Var(newUint64Value(value, p), name, usage)
+}
+
+// Uint64 defines a uint64 flag with specified name, default value, and usage string.
+// The return value is the address of a uint64 variable that stores the value of the flag.
+func Uint64(name string, value uint64, usage string) *uint64 {
+ p := new(uint64)
+ Uint64Var(p, name, value, usage)
+ return p
+}
+
+// StringVar defines a string flag with specified name, default value, and usage string.
+// The argument p points to a string variable in which to store the value of the flag.
+func StringVar(p *string, name, value string, usage string) {
+ Var(newStringValue(value, p), name, usage)
+}
+
+// String defines a string flag with specified name, default value, and usage string.
+// The return value is the address of a string variable that stores the value of the flag.
+func String(name, value string, usage string) *string {
+ p := new(string)
+ StringVar(p, name, value, usage)
+ return p
+}
+
+// Float64Var defines a float64 flag with specified name, default value, and usage string.
+// The argument p points to a float64 variable in which to store the value of the flag.
+func Float64Var(p *float64, name string, value float64, usage string) {
+ Var(newFloat64Value(value, p), name, usage)
+}
+
+// Float64 defines a float64 flag with specified name, default value, and usage string.
+// The return value is the address of a float64 variable that stores the value of the flag.
+func Float64(name string, value float64, usage string) *float64 {
+ p := new(float64)
+ Float64Var(p, name, value, usage)
+ return p
+}
+
+// Var defines a user-typed flag with specified name, default value, and usage string.
+// The argument p points to a Value variable in which to store the value of the flag.
+func Var(value Value, name string, usage string) {
+ // Remember the default value as a string; it won't change.
+ f := &Flag{name, usage, value, value.String()}
+ _, alreadythere := flags.formal[name]
+ if alreadythere {
+ fmt.Fprintln(os.Stderr, "flag redefined:", name)
+ panic("flag redefinition") // Happens only if flags are declared with identical names
+ }
+ flags.formal[name] = f
+}
+
+
+func (f *allFlags) parseOne() (ok bool) {
+ if len(f.args) == 0 {
+ return false
+ }
+ s := f.args[0]
+ if len(s) == 0 || s[0] != '-' || len(s) == 1 {
+ return false
+ }
+ num_minuses := 1
+ if s[1] == '-' {
+ num_minuses++
+ if len(s) == 2 { // "--" terminates the flags
+ f.args = f.args[1:]
+ return false
+ }
+ }
+ name := s[num_minuses:]
+ if len(name) == 0 || name[0] == '-' || name[0] == '=' {
+ fmt.Fprintln(os.Stderr, "bad flag syntax:", s)
+ fail()
+ }
+
+ // it's a flag. does it have an argument?
+ f.args = f.args[1:]
+ has_value := false
+ value := ""
+ for i := 1; i < len(name); i++ { // equals cannot be first
+ if name[i] == '=' {
+ value = name[i+1:]
+ has_value = true
+ name = name[0:i]
+ break
+ }
+ }
+ m := flags.formal
+ flag, alreadythere := m[name] // BUG
+ if !alreadythere {
+ fmt.Fprintf(os.Stderr, "flag provided but not defined: -%s\n", name)
+ fail()
+ }
+ if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
+ if has_value {
+ if !fv.Set(value) {
+ fmt.Fprintf(os.Stderr, "invalid boolean value %q for flag: -%s\n", value, name)
+ fail()
+ }
+ } else {
+ fv.Set("true")
+ }
+ } else {
+ // It must have a value, which might be the next argument.
+ if !has_value && len(f.args) > 0 {
+ // value is the next arg
+ has_value = true
+ value, f.args = f.args[0], f.args[1:]
+ }
+ if !has_value {
+ fmt.Fprintf(os.Stderr, "flag needs an argument: -%s\n", name)
+ fail()
+ }
+ ok = flag.Value.Set(value)
+ if !ok {
+ fmt.Fprintf(os.Stderr, "invalid value %q for flag: -%s\n", value, name)
+ fail()
+ }
+ }
+ flags.actual[name] = flag
+ return true
+}
+
+// Parse parses the command-line flags. Must be called after all flags are defined
+// and before any are accessed by the program.
+func Parse() {
+ flags.args = os.Args[1:]
+ for flags.parseOne() {
+ }
+}
+
+func init() {
+ flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]}
+}
diff --git a/libgo/go/flag/flag_test.go b/libgo/go/flag/flag_test.go
new file mode 100644
index 000000000..b91a8b567
--- /dev/null
+++ b/libgo/go/flag/flag_test.go
@@ -0,0 +1,194 @@
+// 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 flag_test
+
+import (
+ . "flag"
+ "fmt"
+ "os"
+ "testing"
+)
+
+var (
+ test_bool = Bool("test_bool", false, "bool value")
+ test_int = Int("test_int", 0, "int value")
+ test_int64 = Int64("test_int64", 0, "int64 value")
+ test_uint = Uint("test_uint", 0, "uint value")
+ test_uint64 = Uint64("test_uint64", 0, "uint64 value")
+ test_string = String("test_string", "0", "string value")
+ test_float64 = Float64("test_float64", 0, "float64 value")
+)
+
+func boolString(s string) string {
+ if s == "0" {
+ return "false"
+ }
+ return "true"
+}
+
+func TestEverything(t *testing.T) {
+ m := make(map[string]*Flag)
+ desired := "0"
+ visitor := func(f *Flag) {
+ if len(f.Name) > 5 && f.Name[0:5] == "test_" {
+ m[f.Name] = f
+ ok := false
+ switch {
+ case f.Value.String() == desired:
+ ok = true
+ case f.Name == "test_bool" && f.Value.String() == boolString(desired):
+ ok = true
+ }
+ if !ok {
+ t.Error("Visit: bad value", f.Value.String(), "for", f.Name)
+ }
+ }
+ }
+ VisitAll(visitor)
+ if len(m) != 7 {
+ t.Error("VisitAll misses some flags")
+ for k, v := range m {
+ t.Log(k, *v)
+ }
+ }
+ m = make(map[string]*Flag)
+ Visit(visitor)
+ if len(m) != 0 {
+ t.Errorf("Visit sees unset flags")
+ for k, v := range m {
+ t.Log(k, *v)
+ }
+ }
+ // Now set all flags
+ Set("test_bool", "true")
+ Set("test_int", "1")
+ Set("test_int64", "1")
+ Set("test_uint", "1")
+ Set("test_uint64", "1")
+ Set("test_string", "1")
+ Set("test_float64", "1")
+ desired = "1"
+ Visit(visitor)
+ if len(m) != 7 {
+ t.Error("Visit fails after set")
+ for k, v := range m {
+ t.Log(k, *v)
+ }
+ }
+}
+
+func TestUsage(t *testing.T) {
+ called := false
+ ResetForTesting(func() { called = true })
+ if ParseForTesting([]string{"a.out", "-x"}) {
+ t.Error("parse did not fail for unknown flag")
+ }
+ if !called {
+ t.Error("did not call Usage for unknown flag")
+ }
+}
+
+func TestParse(t *testing.T) {
+ ResetForTesting(func() { t.Error("bad parse") })
+ boolFlag := Bool("bool", false, "bool value")
+ bool2Flag := Bool("bool2", false, "bool2 value")
+ intFlag := Int("int", 0, "int value")
+ int64Flag := Int64("int64", 0, "int64 value")
+ uintFlag := Uint("uint", 0, "uint value")
+ uint64Flag := Uint64("uint64", 0, "uint64 value")
+ stringFlag := String("string", "0", "string value")
+ float64Flag := Float64("float64", 0, "float64 value")
+ extra := "one-extra-argument"
+ args := []string{
+ "a.out",
+ "-bool",
+ "-bool2=true",
+ "--int", "22",
+ "--int64", "23",
+ "-uint", "24",
+ "--uint64", "25",
+ "-string", "hello",
+ "-float64", "2718e28",
+ extra,
+ }
+ if !ParseForTesting(args) {
+ t.Fatal("parse failed")
+ }
+ if *boolFlag != true {
+ t.Error("bool flag should be true, is ", *boolFlag)
+ }
+ if *bool2Flag != true {
+ t.Error("bool2 flag should be true, is ", *bool2Flag)
+ }
+ if *intFlag != 22 {
+ t.Error("int flag should be 22, is ", *intFlag)
+ }
+ if *int64Flag != 23 {
+ t.Error("int64 flag should be 23, is ", *int64Flag)
+ }
+ if *uintFlag != 24 {
+ t.Error("uint flag should be 24, is ", *uintFlag)
+ }
+ if *uint64Flag != 25 {
+ t.Error("uint64 flag should be 25, is ", *uint64Flag)
+ }
+ if *stringFlag != "hello" {
+ t.Error("string flag should be `hello`, is ", *stringFlag)
+ }
+ if *float64Flag != 2718e28 {
+ t.Error("float64 flag should be 2718e28, is ", *float64Flag)
+ }
+ if len(Args()) != 1 {
+ t.Error("expected one argument, got", len(Args()))
+ } else if Args()[0] != extra {
+ t.Errorf("expected argument %q got %q", extra, Args()[0])
+ }
+}
+
+// Declare a user-defined flag.
+type flagVar []string
+
+func (f *flagVar) String() string {
+ return fmt.Sprint([]string(*f))
+}
+
+func (f *flagVar) Set(value string) bool {
+ *f = append(*f, value)
+ return true
+}
+
+func TestUserDefined(t *testing.T) {
+ ResetForTesting(func() { t.Fatal("bad parse") })
+ var v flagVar
+ Var(&v, "v", "usage")
+ if !ParseForTesting([]string{"a.out", "-v", "1", "-v", "2", "-v=3"}) {
+ t.Error("parse failed")
+ }
+ if len(v) != 3 {
+ t.Fatal("expected 3 args; got ", len(v))
+ }
+ expect := "[1 2 3]"
+ if v.String() != expect {
+ t.Errorf("expected value %q got %q", expect, v.String())
+ }
+}
+
+func TestChangingArgs(t *testing.T) {
+ ResetForTesting(func() { t.Fatal("bad parse") })
+ oldArgs := os.Args
+ defer func() { os.Args = oldArgs }()
+ os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"}
+ before := Bool("before", false, "")
+ Parse()
+ cmd := Arg(0)
+ os.Args = Args()
+ after := Bool("after", false, "")
+ Parse()
+ args := Args()
+
+ if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" {
+ t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
+ }
+}
diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go
new file mode 100644
index 000000000..191bf68b1
--- /dev/null
+++ b/libgo/go/fmt/doc.go
@@ -0,0 +1,164 @@
+// 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 fmt implements formatted I/O with functions analogous
+ to C's printf and scanf. The format 'verbs' are derived from C's but
+ are simpler.
+
+ Printing:
+
+ The verbs:
+
+ General:
+ %v the value in a default format.
+ when printing structs, the plus flag (%+v) adds field names
+ %#v a Go-syntax representation of the value
+ %T a Go-syntax representation of the type of the value
+
+ Boolean:
+ %t the word true or false
+ Integer:
+ %b base 2
+ %c the character represented by the corresponding Unicode code point
+ %d base 10
+ %o base 8
+ %x base 16, with lower-case letters for a-f
+ %X base 16, with upper-case letters for A-F
+ %U unicode format: U+1234; same as "U+%x" with 4 digits default
+ Floating-point and complex constituents:
+ %e scientific notation, e.g. -1234.456e+78
+ %E scientific notation, e.g. -1234.456E+78
+ %f decimal point but no exponent, e.g. 123.456
+ %g whichever of %e or %f produces more compact output
+ %G whichever of %E or %f produces more compact output
+ String and slice of bytes:
+ %s the uninterpreted bytes of the string or slice
+ %q a double-quoted string safely escaped with Go syntax
+ %x base 16, lower-case, two characters per byte
+ %X base 16, upper-case, two characters per byte
+ Pointer:
+ %p base 16 notation, with leading 0x
+
+ There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
+ Similarly, there is no need to specify the size of the operand (int8, int64).
+
+ For numeric values, the width and precision flags control
+ formatting; width sets the width of the field, precision the
+ number of places after the decimal, if appropriate. The
+ format %6.2f prints 123.45. The width of a field is the number
+ of Unicode code points in the string. This differs from C's printf where
+ the field width is the number of bytes. Either or both of the
+ flags may be replaced with the character '*', causing their values
+ to be obtained from the next operand, which must be of type int.
+
+ Other flags:
+ + always print a sign for numeric values
+ - 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)
+ ' ' (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
+
+ For each Printf-like function, there is also a Print function
+ that takes no format and is equivalent to saying %v for every
+ operand. Another variant Println inserts blanks between
+ operands and appends a newline.
+
+ Regardless of the verb, if an operand is an interface value,
+ the internal concrete value is used, not the interface itself.
+ Thus:
+ var i interface{} = 23
+ fmt.Printf("%v\n", i)
+ will print 23.
+
+ If an operand implements interface Formatter, that interface
+ can be used for fine control of formatting.
+
+ If an operand implements method String() string that method
+ will be used to convert the object to a string, which will then
+ be formatted as required by the verb (if any). To avoid
+ recursion in cases such as
+ type X int
+ func (x X) String() string { return Sprintf("%d", x) }
+ cast the value before recurring:
+ func (x X) String() string { return Sprintf("%d", int(x)) }
+
+ Format errors:
+
+ If an invalid argument is given for a verb, such as providing
+ a string to %d, the generated string will contain a
+ description of the problem, as in these examples:
+
+ Wrong type or unknown verb: %!verb(type=value)
+ Printf("%d", hi): %!d(string=hi)
+ Too many arguments: %!(EXTRA type=value)
+ Printf("hi", "guys"): hi%!(EXTRA string=guys)
+ Too few arguments: %!verb(MISSING)
+ Printf("hi%d"): hi %!d(MISSING)
+ Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
+ Printf("%*s", 4.5, "hi"): %!(BADWIDTH)hi
+ Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
+
+ All errors begin with the string "%!" followed sometimes
+ by a single character (the verb) and end with a parenthesized
+ description.
+
+ Scanning:
+
+ An analogous set of functions scans formatted text to yield
+ values. Scan, Scanf and Scanln read from os.Stdin; Fscan,
+ Fscanf and Fscanln read from a specified os.Reader; Sscan,
+ Sscanf and Sscanln read from an argument string. Sscanln,
+ Fscanln and Sscanln stop scanning at a newline and require that
+ the items be followed by one; Sscanf, Fscanf and Sscanf require
+ newlines in the input to match newlines in the format; the other
+ routines treat newlines as spaces.
+
+ Scanf, Fscanf, and Sscanf parse the arguments according to a
+ format string, analogous to that of Printf. For example, %x
+ will scan an integer as a hexadecimal number, and %v will scan
+ the default representation format for the value.
+
+ The formats behave analogously to those of Printf with the
+ following exceptions:
+
+ %p is not implemented
+ %T is not implemented
+ %e %E %f %F %g %g are all equivalent and scan any floating point or complex value
+ %s and %v on strings scan a space-delimited token
+
+ Width is interpreted in the input text (%5s means at most
+ five runes of input will be read to scan a string) but there
+ is no syntax for scanning with a precision (no %5.2f, just
+ %5f).
+
+ When scanning with a format, all non-empty runs of space
+ characters (except newline) are equivalent to a single
+ space in both the format and the input. With that proviso,
+ text in the format string must match the input text; scanning
+ stops if it does not, with the return value of the function
+ indicating the number of arguments scanned.
+
+ In all the scanning functions, if an operand implements method
+ Scan (that is, it implements the Scanner interface) that
+ method will be used to scan the text for that operand. Also,
+ if the number of arguments scanned is less than the number of
+ arguments provided, an error is returned.
+
+ All arguments to be scanned must be either pointers to basic
+ types or implementations of the Scanner interface.
+
+ Note: Fscan etc. can read one character (rune) past the
+ input they return, which means that a loop calling a scan
+ routine may skip some of the input. This is usually a
+ problem only when there is no space between input values.
+ However, if the reader provided to Fscan implements UnreadRune,
+ that method will be used to save the character and successive
+ calls will not lose data. To attach an UnreadRune method
+ to a reader without that capability, use bufio.NewReader.
+*/
+package fmt
diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go
new file mode 100644
index 000000000..3f085b722
--- /dev/null
+++ b/libgo/go/fmt/fmt_test.go
@@ -0,0 +1,650 @@
+// 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 fmt_test
+
+import (
+ . "fmt"
+ "io"
+ "math"
+ "runtime" // for the malloc count test only
+ "strings"
+ "testing"
+)
+
+type (
+ renamedBool bool
+ renamedInt int
+ renamedInt8 int8
+ renamedInt16 int16
+ renamedInt32 int32
+ renamedInt64 int64
+ renamedUint uint
+ renamedUint8 uint8
+ renamedUint16 uint16
+ renamedUint32 uint32
+ renamedUint64 uint64
+ renamedUintptr uintptr
+ renamedString string
+ renamedBytes []byte
+ renamedFloat32 float32
+ renamedFloat64 float64
+ renamedComplex64 complex64
+ renamedComplex128 complex128
+)
+
+func TestFmtInterface(t *testing.T) {
+ var i1 interface{}
+ i1 = "abc"
+ s := Sprintf("%s", i1)
+ if s != "abc" {
+ t.Errorf(`Sprintf("%%s", empty("abc")) = %q want %q`, s, "abc")
+ }
+}
+
+
+const b32 uint32 = 1<<32 - 1
+const b64 uint64 = 1<<64 - 1
+
+var array = []int{1, 2, 3, 4, 5}
+var iarray = []interface{}{1, "hello", 2.5, nil}
+
+type A struct {
+ i int
+ j uint
+ s string
+ x []int
+}
+
+type I int
+
+func (i I) String() string { return Sprintf("<%d>", int(i)) }
+
+type B struct {
+ i I
+ j int
+}
+
+type C struct {
+ i int
+ B
+}
+
+type F int
+
+func (f F) Format(s State, c int) {
+ Fprintf(s, "<%c=F(%d)>", c, int(f))
+}
+
+type G int
+
+func (g G) GoString() string {
+ return Sprintf("GoString(%d)", int(g))
+}
+
+type S struct {
+ f F // a struct field that Formats
+ g G // a struct field that GoStrings
+}
+
+// A type with a String method with pointer receiver for testing %p
+type P int
+
+var pValue P
+
+func (p *P) String() string {
+ return "String(p)"
+}
+
+var b byte
+
+var fmttests = []struct {
+ fmt string
+ val interface{}
+ out string
+}{
+ {"%d", 12345, "12345"},
+ {"%v", 12345, "12345"},
+ {"%t", true, "true"},
+
+ // basic string
+ {"%s", "abc", "abc"},
+ {"%x", "abc", "616263"},
+ {"%x", "xyz", "78797a"},
+ {"%X", "xyz", "78797A"},
+ {"%q", "abc", `"abc"`},
+
+ // basic bytes
+ {"%s", []byte("abc"), "abc"},
+ {"%x", []byte("abc"), "616263"},
+ {"% x", []byte("abc\xff"), "61 62 63 ff"},
+ {"% X", []byte("abc\xff"), "61 62 63 FF"},
+ {"%x", []byte("xyz"), "78797a"},
+ {"%X", []byte("xyz"), "78797A"},
+ {"%q", []byte("abc"), `"abc"`},
+
+ // escaped strings
+ {"%#q", `abc`, "`abc`"},
+ {"%#q", `"`, "`\"`"},
+ {"1 %#q", `\n`, "1 `\\n`"},
+ {"2 %#q", "\n", `2 "\n"`},
+ {"%q", `"`, `"\""`},
+ {"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
+ {"%q", "abc\xffdef", `"abc\xffdef"`},
+ {"%q", "\u263a", `"\u263a"`},
+ {"%q", "\U0010ffff", `"\U0010ffff"`},
+
+ // width
+ {"%5s", "abc", " abc"},
+ {"%2s", "\u263a", " \u263a"},
+ {"%-5s", "abc", "abc "},
+ {"%05s", "abc", "00abc"},
+
+ // integers
+ {"%d", 12345, "12345"},
+ {"%d", -12345, "-12345"},
+ {"%10d", 12345, " 12345"},
+ {"%10d", -12345, " -12345"},
+ {"%+10d", 12345, " +12345"},
+ {"%010d", 12345, "0000012345"},
+ {"%010d", -12345, "-000012345"},
+ {"%-10d", 12345, "12345 "},
+ {"%010.3d", 1, " 001"},
+ {"%010.3d", -1, " -001"},
+ {"%+d", 12345, "+12345"},
+ {"%+d", -12345, "-12345"},
+ {"%+d", 0, "+0"},
+ {"% d", 0, " 0"},
+ {"% d", 12345, " 12345"},
+
+ // unicode format
+ {"%U", 0x1, "U+0001"},
+ {"%.8U", 0x2, "U+00000002"},
+ {"%U", 0x1234, "U+1234"},
+ {"%U", 0x12345, "U+12345"},
+ {"%10.6U", 0xABC, " U+000ABC"},
+ {"%-10.6U", 0xABC, "U+000ABC "},
+
+ // floats
+ {"%+.3e", 0.0, "+0.000e+00"},
+ {"%+.3e", 1.0, "+1.000e+00"},
+ {"%+.3f", -1.0, "-1.000"},
+ {"% .3E", -1.0, "-1.000E+00"},
+ {"% .3e", 1.0, " 1.000e+00"},
+ {"%+.3g", 0.0, "+0"},
+ {"%+.3g", 1.0, "+1"},
+ {"%+.3g", -1.0, "-1"},
+ {"% .3g", -1.0, "-1"},
+ {"% .3g", 1.0, " 1"},
+
+ // complex values
+ {"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
+ {"%+.3f", 0i, "(+0.000+0.000i)"},
+ {"%+.3g", 0i, "(+0+0i)"},
+ {"%+.3e", 1 + 2i, "(+1.000e+00+2.000e+00i)"},
+ {"%+.3f", 1 + 2i, "(+1.000+2.000i)"},
+ {"%+.3g", 1 + 2i, "(+1+2i)"},
+ {"%.3e", 0i, "(0.000e+00+0.000e+00i)"},
+ {"%.3f", 0i, "(0.000+0.000i)"},
+ {"%.3g", 0i, "(0+0i)"},
+ {"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"},
+ {"%.3f", 1 + 2i, "(1.000+2.000i)"},
+ {"%.3g", 1 + 2i, "(1+2i)"},
+ {"%.3e", -1 - 2i, "(-1.000e+00-2.000e+00i)"},
+ {"%.3f", -1 - 2i, "(-1.000-2.000i)"},
+ {"%.3g", -1 - 2i, "(-1-2i)"},
+ {"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
+ {"%+.3g", complex64(1 + 2i), "(+1+2i)"},
+ {"%+.3g", complex128(1 + 2i), "(+1+2i)"},
+
+ // erroneous formats
+ {"", 2, "%!(EXTRA int=2)"},
+ {"%d", "hello", "%!d(string=hello)"},
+
+ // old test/fmt_test.go
+ {"%d", 1234, "1234"},
+ {"%d", -1234, "-1234"},
+ {"%d", uint(1234), "1234"},
+ {"%d", uint32(b32), "4294967295"},
+ {"%d", uint64(b64), "18446744073709551615"},
+ {"%o", 01234, "1234"},
+ {"%#o", 01234, "01234"},
+ {"%o", uint32(b32), "37777777777"},
+ {"%o", uint64(b64), "1777777777777777777777"},
+ {"%x", 0x1234abcd, "1234abcd"},
+ {"%#x", 0x1234abcd, "0x1234abcd"},
+ {"%x", b32 - 0x1234567, "fedcba98"},
+ {"%X", 0x1234abcd, "1234ABCD"},
+ {"%X", b32 - 0x1234567, "FEDCBA98"},
+ {"%#X", 0, "0X0"},
+ {"%x", b64, "ffffffffffffffff"},
+ {"%b", 7, "111"},
+ {"%b", b64, "1111111111111111111111111111111111111111111111111111111111111111"},
+ {"%b", -6, "-110"},
+ {"%e", 1.0, "1.000000e+00"},
+ {"%e", 1234.5678e3, "1.234568e+06"},
+ {"%e", 1234.5678e-8, "1.234568e-05"},
+ {"%e", -7.0, "-7.000000e+00"},
+ {"%e", -1e-9, "-1.000000e-09"},
+ {"%f", 1234.5678e3, "1234567.800000"},
+ {"%f", 1234.5678e-8, "0.000012"},
+ {"%f", -7.0, "-7.000000"},
+ {"%f", -1e-9, "-0.000000"},
+ {"%g", 1234.5678e3, "1.2345678e+06"},
+ {"%g", float32(1234.5678e3), "1.2345678e+06"},
+ {"%g", 1234.5678e-8, "1.2345678e-05"},
+ {"%g", -7.0, "-7"},
+ {"%g", -1e-9, "-1e-09"},
+ {"%g", float32(-1e-9), "-1e-09"},
+ {"%E", 1.0, "1.000000E+00"},
+ {"%E", 1234.5678e3, "1.234568E+06"},
+ {"%E", 1234.5678e-8, "1.234568E-05"},
+ {"%E", -7.0, "-7.000000E+00"},
+ {"%E", -1e-9, "-1.000000E-09"},
+ {"%G", 1234.5678e3, "1.2345678E+06"},
+ {"%G", float32(1234.5678e3), "1.2345678E+06"},
+ {"%G", 1234.5678e-8, "1.2345678E-05"},
+ {"%G", -7.0, "-7"},
+ {"%G", -1e-9, "-1E-09"},
+ {"%G", float32(-1e-9), "-1E-09"},
+ {"%c", 'x', "x"},
+ {"%c", 0xe4, "ä"},
+ {"%c", 0x672c, "本"},
+ {"%c", '日', "日"},
+ {"%20.8d", 1234, " 00001234"},
+ {"%20.8d", -1234, " -00001234"},
+ {"%20d", 1234, " 1234"},
+ {"%-20.8d", 1234, "00001234 "},
+ {"%-20.8d", -1234, "-00001234 "},
+ {"%-#20.8x", 0x1234abc, "0x01234abc "},
+ {"%-#20.8X", 0x1234abc, "0X01234ABC "},
+ {"%-#20.8o", 01234, "00001234 "},
+ {"%.20b", 7, "00000000000000000111"},
+ {"%20.5s", "qwertyuiop", " qwert"},
+ {"%.5s", "qwertyuiop", "qwert"},
+ {"%-20.5s", "qwertyuiop", "qwert "},
+ {"%20c", 'x', " x"},
+ {"%-20c", 'x', "x "},
+ {"%20.6e", 1.2345e3, " 1.234500e+03"},
+ {"%20.6e", 1.2345e-3, " 1.234500e-03"},
+ {"%20e", 1.2345e3, " 1.234500e+03"},
+ {"%20e", 1.2345e-3, " 1.234500e-03"},
+ {"%20.8e", 1.2345e3, " 1.23450000e+03"},
+ {"%20f", 1.23456789e3, " 1234.567890"},
+ {"%20f", 1.23456789e-3, " 0.001235"},
+ {"%20f", 12345678901.23456789, " 12345678901.234568"},
+ {"%-20f", 1.23456789e3, "1234.567890 "},
+ {"%20.8f", 1.23456789e3, " 1234.56789000"},
+ {"%20.8f", 1.23456789e-3, " 0.00123457"},
+ {"%g", 1.23456789e3, "1234.56789"},
+ {"%g", 1.23456789e-3, "0.00123456789"},
+ {"%g", 1.23456789e20, "1.23456789e+20"},
+ {"%20e", math.Inf(1), " +Inf"},
+ {"%-20f", math.Inf(-1), "-Inf "},
+ {"%20g", math.NaN(), " NaN"},
+
+ // arrays
+ {"%v", array, "[1 2 3 4 5]"},
+ {"%v", iarray, "[1 hello 2.5 <nil>]"},
+ {"%v", &array, "&[1 2 3 4 5]"},
+ {"%v", &iarray, "&[1 hello 2.5 <nil>]"},
+
+ // complexes with %v
+ {"%v", 1 + 2i, "(1+2i)"},
+ {"%v", complex64(1 + 2i), "(1+2i)"},
+ {"%v", complex128(1 + 2i), "(1+2i)"},
+
+ // structs
+ {"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`},
+ {"%+v", A{1, 2, "a", []int{1, 2}}, `{i:1 j:2 s:a x:[1 2]}`},
+
+ // +v on structs with Stringable items
+ {"%+v", B{1, 2}, `{i:<1> j:2}`},
+ {"%+v", C{1, B{2, 3}}, `{i:1 B:{i:<2> j:3}}`},
+
+ // q on Stringable items
+ {"%s", I(23), `<23>`},
+ {"%q", I(23), `"<23>"`},
+ {"%x", I(23), `3c32333e`},
+ {"%d", I(23), `%!d(string=<23>)`},
+
+ // go syntax
+ {"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
+ {"%#v", &b, "(*uint8)(PTR)"},
+ {"%#v", TestFmtInterface, "(func(*testing.T))(PTR)"},
+ {"%#v", make(chan int), "(chan int)(PTR)"},
+ {"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
+ {"%#v", 1000000000, "1000000000"},
+ {"%#v", map[string]int{"a": 1, "b": 2}, `map[string] int{"a":1, "b":2}`},
+ {"%#v", map[string]B{"a": {1, 2}, "b": {3, 4}}, `map[string] fmt_test.B{"a":fmt_test.B{i:1, j:2}, "b":fmt_test.B{i:3, j:4}}`},
+ {"%#v", []string{"a", "b"}, `[]string{"a", "b"}`},
+
+ // slices with other formats
+ {"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
+ {"%x", []int{1, 2, 15}, `[1 2 f]`},
+ {"%d", []int{1, 2, 15}, `[1 2 15]`},
+ {"%d", []byte{1, 2, 15}, `[1 2 15]`},
+ {"%q", []string{"a", "b"}, `["a" "b"]`},
+
+ // renamings
+ {"%v", renamedBool(true), "true"},
+ {"%d", renamedBool(true), "%!d(fmt_test.renamedBool=true)"},
+ {"%o", renamedInt(8), "10"},
+ {"%d", renamedInt8(-9), "-9"},
+ {"%v", renamedInt16(10), "10"},
+ {"%v", renamedInt32(-11), "-11"},
+ {"%X", renamedInt64(255), "FF"},
+ {"%v", renamedUint(13), "13"},
+ {"%o", renamedUint8(14), "16"},
+ {"%X", renamedUint16(15), "F"},
+ {"%d", renamedUint32(16), "16"},
+ {"%X", renamedUint64(17), "11"},
+ {"%o", renamedUintptr(18), "22"},
+ {"%x", renamedString("thing"), "7468696e67"},
+ {"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`},
+ {"%q", renamedBytes([]byte("hello")), `"hello"`},
+ {"%v", renamedFloat32(22), "22"},
+ {"%v", renamedFloat64(33), "33"},
+ {"%v", renamedComplex64(3 + 4i), "(3+4i)"},
+ {"%v", renamedComplex128(4 - 3i), "(4-3i)"},
+
+ // Formatter
+ {"%x", F(1), "<x=F(1)>"},
+ {"%x", G(2), "2"},
+ {"%+v", S{F(4), G(5)}, "{f:<v=F(4)> g:5}"},
+
+ // GoStringer
+ {"%#v", G(6), "GoString(6)"},
+ {"%#v", S{F(7), G(8)}, "fmt_test.S{f:<v=F(7)>, g:GoString(8)}"},
+
+ // %T
+ {"%T", (4 - 3i), "complex128"},
+ {"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
+ {"%T", intVal, "int"},
+ {"%6T", &intVal, " *int"},
+
+ // %p
+ {"p0=%p", new(int), "p0=PTR"},
+ {"p1=%s", &pValue, "p1=String(p)"}, // String method...
+ {"p2=%p", &pValue, "p2=PTR"}, // ... not called with %p
+
+ // %p on non-pointers
+ {"%p", make(chan int), "PTR"},
+ {"%p", make(map[int]int), "PTR"},
+ {"%p", make([]int, 1), "PTR"},
+ {"%p", 27, "%!p(int=27)"}, // not a pointer at all
+
+ // erroneous things
+ {"%s %", "hello", "hello %!(NOVERB)"},
+ {"%s %.2", "hello", "hello %!(NOVERB)"},
+ {"%d", "hello", "%!d(string=hello)"},
+ {"no args", "hello", "no args%!(EXTRA string=hello)"},
+ {"%s", nil, "%!s(<nil>)"},
+ {"%T", nil, "<nil>"},
+ {"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
+}
+
+func TestSprintf(t *testing.T) {
+ for _, tt := range fmttests {
+ s := Sprintf(tt.fmt, tt.val)
+ if i := strings.Index(s, "0x"); i >= 0 && strings.Contains(tt.out, "PTR") {
+ j := i + 2
+ for ; j < len(s); j++ {
+ c := s[j]
+ if (c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F') {
+ break
+ }
+ }
+ s = s[0:i] + "PTR" + s[j:]
+ }
+ if s != tt.out {
+ if _, ok := tt.val.(string); ok {
+ // Don't requote the already-quoted strings.
+ // It's too confusing to read the errors.
+ t.Errorf("Sprintf(%q, %q) = <%s> want <%s>", tt.fmt, tt.val, s, tt.out)
+ } else {
+ t.Errorf("Sprintf(%q, %v) = %q want %q", tt.fmt, tt.val, s, tt.out)
+ }
+ }
+ }
+}
+
+func BenchmarkSprintfEmpty(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("")
+ }
+}
+
+func BenchmarkSprintfString(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("%s", "hello")
+ }
+}
+
+func BenchmarkSprintfInt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("%d", 5)
+ }
+}
+
+func BenchmarkSprintfIntInt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("%d %d", 5, 6)
+ }
+}
+
+func BenchmarkSprintfPrefixedInt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
+ }
+}
+
+func TestCountMallocs(t *testing.T) {
+ mallocs := 0 - runtime.MemStats.Mallocs
+ for i := 0; i < 100; i++ {
+ Sprintf("")
+ }
+ mallocs += runtime.MemStats.Mallocs
+ Printf("mallocs per Sprintf(\"\"): %d\n", mallocs/100)
+ mallocs = 0 - runtime.MemStats.Mallocs
+ for i := 0; i < 100; i++ {
+ Sprintf("xxx")
+ }
+ mallocs += runtime.MemStats.Mallocs
+ Printf("mallocs per Sprintf(\"xxx\"): %d\n", mallocs/100)
+ mallocs = 0 - runtime.MemStats.Mallocs
+ for i := 0; i < 100; i++ {
+ Sprintf("%x", i)
+ }
+ mallocs += runtime.MemStats.Mallocs
+ Printf("mallocs per Sprintf(\"%%x\"): %d\n", mallocs/100)
+ mallocs = 0 - runtime.MemStats.Mallocs
+ for i := 0; i < 100; i++ {
+ Sprintf("%x %x", i, i)
+ }
+ mallocs += runtime.MemStats.Mallocs
+ Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/100)
+}
+
+type flagPrinter struct{}
+
+func (*flagPrinter) Format(f State, c int) {
+ s := "%"
+ for i := 0; i < 128; i++ {
+ if f.Flag(i) {
+ s += string(i)
+ }
+ }
+ if w, ok := f.Width(); ok {
+ s += Sprintf("%d", w)
+ }
+ if p, ok := f.Precision(); ok {
+ s += Sprintf(".%d", p)
+ }
+ s += string(c)
+ io.WriteString(f, "["+s+"]")
+}
+
+var flagtests = []struct {
+ in string
+ out string
+}{
+ {"%a", "[%a]"},
+ {"%-a", "[%-a]"},
+ {"%+a", "[%+a]"},
+ {"%#a", "[%#a]"},
+ {"% a", "[% a]"},
+ {"%0a", "[%0a]"},
+ {"%1.2a", "[%1.2a]"},
+ {"%-1.2a", "[%-1.2a]"},
+ {"%+1.2a", "[%+1.2a]"},
+ {"%-+1.2a", "[%+-1.2a]"},
+ {"%-+1.2abc", "[%+-1.2a]bc"},
+ {"%-1.2abc", "[%-1.2a]bc"},
+}
+
+func TestFlagParser(t *testing.T) {
+ var flagprinter flagPrinter
+ for _, tt := range flagtests {
+ s := Sprintf(tt.in, &flagprinter)
+ if s != tt.out {
+ t.Errorf("Sprintf(%q, &flagprinter) => %q, want %q", tt.in, s, tt.out)
+ }
+ }
+}
+
+func TestStructPrinter(t *testing.T) {
+ var s struct {
+ a string
+ b string
+ c int
+ }
+ s.a = "abc"
+ s.b = "def"
+ s.c = 123
+ var tests = []struct {
+ fmt string
+ out string
+ }{
+ {"%v", "{abc def 123}"},
+ {"%+v", "{a:abc b:def c:123}"},
+ }
+ for _, tt := range tests {
+ out := Sprintf(tt.fmt, s)
+ if out != tt.out {
+ t.Errorf("Sprintf(%q, &s) = %q, want %q", tt.fmt, out, tt.out)
+ }
+ }
+}
+
+// Check map printing using substrings so we don't depend on the print order.
+func presentInMap(s string, a []string, t *testing.T) {
+ for i := 0; i < len(a); i++ {
+ loc := strings.Index(s, a[i])
+ if loc < 0 {
+ t.Errorf("map print: expected to find %q in %q", a[i], s)
+ }
+ // make sure the match ends here
+ loc += len(a[i])
+ if loc >= len(s) || (s[loc] != ' ' && s[loc] != ']') {
+ t.Errorf("map print: %q not properly terminated in %q", a[i], s)
+ }
+ }
+}
+
+func TestMapPrinter(t *testing.T) {
+ m0 := make(map[int]string)
+ s := Sprint(m0)
+ if s != "map[]" {
+ t.Errorf("empty map printed as %q not %q", s, "map[]")
+ }
+ m1 := map[int]string{1: "one", 2: "two", 3: "three"}
+ a := []string{"1:one", "2:two", "3:three"}
+ presentInMap(Sprintf("%v", m1), a, t)
+ presentInMap(Sprint(m1), a, t)
+}
+
+func TestEmptyMap(t *testing.T) {
+ const emptyMapStr = "map[]"
+ var m map[string]int
+ s := Sprint(m)
+ if s != emptyMapStr {
+ t.Errorf("nil map printed as %q not %q", s, emptyMapStr)
+ }
+ m = make(map[string]int)
+ s = Sprint(m)
+ if s != emptyMapStr {
+ t.Errorf("empty map printed as %q not %q", s, emptyMapStr)
+ }
+}
+
+// Check that Sprint (and hence Print, Fprint) puts spaces in the right places,
+// that is, between arg pairs in which neither is a string.
+func TestBlank(t *testing.T) {
+ got := Sprint("<", 1, ">:", 1, 2, 3, "!")
+ expect := "<1>:1 2 3!"
+ if got != expect {
+ t.Errorf("got %q expected %q", got, expect)
+ }
+}
+
+// Check that Sprintln (and hence Println, Fprintln) puts spaces in the right places,
+// that is, between all arg pairs.
+func TestBlankln(t *testing.T) {
+ got := Sprintln("<", 1, ">:", 1, 2, 3, "!")
+ expect := "< 1 >: 1 2 3 !\n"
+ if got != expect {
+ t.Errorf("got %q expected %q", got, expect)
+ }
+}
+
+
+// Check Formatter with Sprint, Sprintln, Sprintf
+func TestFormatterPrintln(t *testing.T) {
+ f := F(1)
+ expect := "<v=F(1)>\n"
+ s := Sprint(f, "\n")
+ if s != expect {
+ t.Errorf("Sprint wrong with Formatter: expected %q got %q", expect, s)
+ }
+ s = Sprintln(f)
+ if s != expect {
+ t.Errorf("Sprintln wrong with Formatter: expected %q got %q", expect, s)
+ }
+ s = Sprintf("%v\n", f)
+ if s != expect {
+ t.Errorf("Sprintf wrong with Formatter: expected %q got %q", expect, s)
+ }
+}
+
+func args(a ...interface{}) []interface{} { return a }
+
+var startests = []struct {
+ fmt string
+ in []interface{}
+ out string
+}{
+ {"%*d", args(4, 42), " 42"},
+ {"%.*d", args(4, 42), "0042"},
+ {"%*.*d", args(8, 4, 42), " 0042"},
+ {"%0*d", args(4, 42), "0042"},
+ {"%-*d", args(4, 42), "42 "},
+
+ // erroneous
+ {"%*d", args(nil, 42), "%!(BADWIDTH)42"},
+ {"%.*d", args(nil, 42), "%!(BADPREC)42"},
+ {"%*d", args(5, "foo"), "%!d(string= foo)"},
+ {"%*% %d", args(20, 5), "% 5"},
+ {"%*", args(4), "%!(NOVERB)"},
+ {"%*d", args(int32(4), 42), "%!(BADWIDTH)42"},
+}
+
+func TestWidthAndPrecision(t *testing.T) {
+ for _, tt := range startests {
+ 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/libgo/go/fmt/format.go b/libgo/go/fmt/format.go
new file mode 100644
index 000000000..86057bf69
--- /dev/null
+++ b/libgo/go/fmt/format.go
@@ -0,0 +1,398 @@
+// 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 fmt
+
+import (
+ "bytes"
+ "strconv"
+ "utf8"
+)
+
+const (
+ nByte = 64
+
+ ldigits = "0123456789abcdef"
+ udigits = "0123456789ABCDEF"
+)
+
+const (
+ signed = true
+ unsigned = false
+)
+
+var padZeroBytes = make([]byte, nByte)
+var padSpaceBytes = make([]byte, nByte)
+
+var newline = []byte{'\n'}
+
+func init() {
+ for i := 0; i < nByte; i++ {
+ padZeroBytes[i] = '0'
+ padSpaceBytes[i] = ' '
+ }
+}
+
+// A fmt is the raw formatter used by Printf etc.
+// It prints into a bytes.Buffer that must be set up externally.
+type fmt struct {
+ intbuf [nByte]byte
+ buf *bytes.Buffer
+ // width, precision
+ wid int
+ prec int
+ // flags
+ widPresent bool
+ precPresent bool
+ minus bool
+ plus bool
+ sharp bool
+ space bool
+ unicode bool
+ zero bool
+}
+
+func (f *fmt) clearflags() {
+ f.wid = 0
+ f.widPresent = false
+ f.prec = 0
+ f.precPresent = false
+ f.minus = false
+ f.plus = false
+ f.sharp = false
+ f.space = false
+ f.unicode = false
+ f.zero = false
+}
+
+func (f *fmt) init(buf *bytes.Buffer) {
+ f.buf = buf
+ f.clearflags()
+}
+
+// Compute left and right padding widths (only one will be non-zero).
+func (f *fmt) computePadding(width int) (padding []byte, leftWidth, rightWidth int) {
+ left := !f.minus
+ w := f.wid
+ if w < 0 {
+ left = false
+ w = -w
+ }
+ w -= width
+ if w > 0 {
+ if left && f.zero {
+ return padZeroBytes, w, 0
+ }
+ if left {
+ return padSpaceBytes, w, 0
+ } else {
+ // can't be zero padding on the right
+ return padSpaceBytes, 0, w
+ }
+ }
+ return
+}
+
+// Generate n bytes of padding.
+func (f *fmt) writePadding(n int, padding []byte) {
+ for n > 0 {
+ m := n
+ if m > nByte {
+ m = nByte
+ }
+ f.buf.Write(padding[0:m])
+ n -= m
+ }
+}
+
+// Append b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus)
+// clear flags aftewards.
+func (f *fmt) pad(b []byte) {
+ var padding []byte
+ var left, right int
+ if f.widPresent && f.wid != 0 {
+ padding, left, right = f.computePadding(len(b))
+ }
+ if left > 0 {
+ f.writePadding(left, padding)
+ }
+ f.buf.Write(b)
+ if right > 0 {
+ f.writePadding(right, padding)
+ }
+}
+
+// append s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
+// clear flags aftewards.
+func (f *fmt) padString(s string) {
+ var padding []byte
+ var left, right int
+ if f.widPresent && f.wid != 0 {
+ padding, left, right = f.computePadding(utf8.RuneCountInString(s))
+ }
+ if left > 0 {
+ f.writePadding(left, padding)
+ }
+ f.buf.WriteString(s)
+ if right > 0 {
+ f.writePadding(right, padding)
+ }
+}
+
+func putint(buf []byte, base, val uint64, digits string) int {
+ i := len(buf) - 1
+ for val >= base {
+ buf[i] = digits[val%base]
+ i--
+ val /= base
+ }
+ buf[i] = digits[val]
+ return i - 1
+}
+
+// fmt_boolean formats a boolean.
+func (f *fmt) fmt_boolean(v bool) {
+ if v {
+ f.padString("true")
+ } else {
+ f.padString("false")
+ }
+}
+
+// integer; interprets prec but not wid. Once formatted, result is sent to pad()
+// and then flags are cleared.
+func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
+ var buf []byte = f.intbuf[0:]
+ negative := signedness == signed && a < 0
+ if negative {
+ a = -a
+ }
+
+ // two ways to ask for extra leading zero digits: %.3d or %03d.
+ // apparently the first cancels the second.
+ prec := 0
+ if f.precPresent {
+ prec = f.prec
+ f.zero = false
+ } else if f.zero && f.widPresent && !f.minus && f.wid > 0 {
+ prec = f.wid
+ if negative || f.plus || f.space {
+ prec-- // leave room for sign
+ }
+ }
+
+ // format a into buf, ending at buf[i]. (printing is easier right-to-left.)
+ // a is made into unsigned ua. we could make things
+ // marginally faster by splitting the 32-bit case out into a separate
+ // block but it's not worth the duplication, so ua has 64 bits.
+ i := len(f.intbuf)
+ ua := uint64(a)
+ for ua >= base {
+ i--
+ buf[i] = digits[ua%base]
+ ua /= base
+ }
+ i--
+ buf[i] = digits[ua]
+ for i > 0 && prec > nByte-i {
+ i--
+ buf[i] = '0'
+ }
+
+ // Various prefixes: 0x, -, etc.
+ if f.sharp {
+ switch base {
+ case 8:
+ if buf[i] != '0' {
+ i--
+ buf[i] = '0'
+ }
+ case 16:
+ i--
+ buf[i] = 'x' + digits[10] - 'a'
+ i--
+ buf[i] = '0'
+ }
+ }
+ if f.unicode {
+ i--
+ buf[i] = '+'
+ i--
+ buf[i] = 'U'
+ }
+
+ if negative {
+ i--
+ buf[i] = '-'
+ } else if f.plus {
+ i--
+ buf[i] = '+'
+ } else if f.space {
+ i--
+ buf[i] = ' '
+ }
+ f.pad(buf[i:])
+}
+
+// fmt_s formats a string.
+func (f *fmt) fmt_s(s string) {
+ if f.precPresent {
+ if f.prec < len(s) {
+ s = s[0:f.prec]
+ }
+ }
+ f.padString(s)
+}
+
+// fmt_sx formats a string as a hexadecimal encoding of its bytes.
+func (f *fmt) fmt_sx(s string) {
+ t := ""
+ for i := 0; i < len(s); i++ {
+ if i > 0 && f.space {
+ t += " "
+ }
+ v := s[i]
+ t += string(ldigits[v>>4])
+ t += string(ldigits[v&0xF])
+ }
+ f.padString(t)
+}
+
+// fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes.
+func (f *fmt) fmt_sX(s string) {
+ t := ""
+ for i := 0; i < len(s); i++ {
+ if i > 0 && f.space {
+ t += " "
+ }
+ v := s[i]
+ t += string(udigits[v>>4])
+ t += string(udigits[v&0xF])
+ }
+ f.padString(t)
+}
+
+// fmt_q formats a string as a double-quoted, escaped Go string constant.
+func (f *fmt) fmt_q(s string) {
+ var quoted string
+ if f.sharp && strconv.CanBackquote(s) {
+ quoted = "`" + s + "`"
+ } else {
+ quoted = strconv.Quote(s)
+ }
+ f.padString(quoted)
+}
+
+// floating-point
+
+func doPrec(f *fmt, def int) int {
+ if f.precPresent {
+ return f.prec
+ }
+ return def
+}
+
+// Add a plus sign or space to the floating-point string representation if missing and required.
+func (f *fmt) plusSpace(s string) {
+ if s[0] != '-' {
+ if f.plus {
+ s = "+" + s
+ } else if f.space {
+ s = " " + s
+ }
+ }
+ f.padString(s)
+}
+
+// fmt_e64 formats a float64 in the form -1.23e+12.
+func (f *fmt) fmt_e64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'e', doPrec(f, 6))) }
+
+// fmt_E64 formats a float64 in the form -1.23E+12.
+func (f *fmt) fmt_E64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'E', doPrec(f, 6))) }
+
+// fmt_f64 formats a float64 in the form -1.23.
+func (f *fmt) fmt_f64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'f', doPrec(f, 6))) }
+
+// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
+func (f *fmt) fmt_g64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'g', doPrec(f, -1))) }
+
+// fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
+func (f *fmt) fmt_G64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'G', doPrec(f, -1))) }
+
+// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
+func (f *fmt) fmt_fb64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'b', 0)) }
+
+// float32
+// cannot defer to float64 versions
+// because it will get rounding wrong in corner cases.
+
+// fmt_e32 formats a float32 in the form -1.23e+12.
+func (f *fmt) fmt_e32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'e', doPrec(f, 6))) }
+
+// fmt_E32 formats a float32 in the form -1.23E+12.
+func (f *fmt) fmt_E32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'E', doPrec(f, 6))) }
+
+// fmt_f32 formats a float32 in the form -1.23.
+func (f *fmt) fmt_f32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'f', doPrec(f, 6))) }
+
+// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
+func (f *fmt) fmt_g32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'g', doPrec(f, -1))) }
+
+// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
+func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'G', doPrec(f, -1))) }
+
+// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
+func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.Ftoa32(v, 'b', 0)) }
+
+// fmt_c64 formats a complex64 according to the verb.
+func (f *fmt) fmt_c64(v complex64, verb int) {
+ f.buf.WriteByte('(')
+ r := real(v)
+ for i := 0; ; i++ {
+ switch verb {
+ case 'e':
+ f.fmt_e32(r)
+ case 'E':
+ f.fmt_E32(r)
+ case 'f':
+ f.fmt_f32(r)
+ case 'g':
+ f.fmt_g32(r)
+ case 'G':
+ f.fmt_G32(r)
+ }
+ if i != 0 {
+ break
+ }
+ f.plus = true
+ r = imag(v)
+ }
+ f.buf.Write(irparenBytes)
+}
+
+// fmt_c128 formats a complex128 according to the verb.
+func (f *fmt) fmt_c128(v complex128, verb int) {
+ f.buf.WriteByte('(')
+ r := real(v)
+ for i := 0; ; i++ {
+ switch verb {
+ case 'e':
+ f.fmt_e64(r)
+ case 'E':
+ f.fmt_E64(r)
+ case 'f':
+ f.fmt_f64(r)
+ case 'g':
+ f.fmt_g64(r)
+ case 'G':
+ f.fmt_G64(r)
+ }
+ if i != 0 {
+ break
+ }
+ f.plus = true
+ r = imag(v)
+ }
+ f.buf.Write(irparenBytes)
+}
diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go
new file mode 100644
index 000000000..96029a878
--- /dev/null
+++ b/libgo/go/fmt/print.go
@@ -0,0 +1,921 @@
+// 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 fmt
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "utf8"
+)
+
+// Some constants in the form of bytes, to avoid string overhead.
+// Needlessly fastidious, I suppose.
+var (
+ commaSpaceBytes = []byte(", ")
+ nilAngleBytes = []byte("<nil>")
+ nilParenBytes = []byte("(nil)")
+ nilBytes = []byte("nil")
+ mapBytes = []byte("map[")
+ missingBytes = []byte("(MISSING)")
+ extraBytes = []byte("%!(EXTRA ")
+ irparenBytes = []byte("i)")
+ bytesBytes = []byte("[]byte{")
+ widthBytes = []byte("%!(BADWIDTH)")
+ precBytes = []byte("%!(BADPREC)")
+ noVerbBytes = []byte("%!(NOVERB)")
+)
+
+// State represents the printer state passed to custom formatters.
+// It provides access to the io.Writer interface plus information about
+// the flags and options for the operand's format specifier.
+type State interface {
+ // Write is the function to call to emit formatted output to be printed.
+ Write(b []byte) (ret int, err os.Error)
+ // Width returns the value of the width option and whether it has been set.
+ Width() (wid int, ok bool)
+ // Precision returns the value of the precision option and whether it has been set.
+ Precision() (prec int, ok bool)
+
+ // Flag returns whether the flag c, a character, has been set.
+ Flag(int) bool
+}
+
+// Formatter is the interface implemented by values with a custom formatter.
+// The implementation of Format may call Sprintf or Fprintf(f) etc.
+// to generate its output.
+type Formatter interface {
+ Format(f State, c int)
+}
+
+// Stringer is implemented by any value that has a String method(),
+// which defines the ``native'' format for that value.
+// The String method is used to print values passed as an operand
+// to a %s or %v format or to an unformatted printer such as Print.
+type Stringer interface {
+ String() string
+}
+
+// GoStringer is implemented by any value that has a GoString() method,
+// which defines the Go syntax for that value.
+// The GoString method is used to print values passed as an operand
+// to a %#v format.
+type GoStringer interface {
+ GoString() string
+}
+
+type pp struct {
+ n int
+ buf bytes.Buffer
+ runeBuf [utf8.UTFMax]byte
+ fmt fmt
+}
+
+// A leaky bucket of reusable pp structures.
+var ppFree = make(chan *pp, 100)
+
+// Allocate a new pp struct. Probably can grab the previous one from ppFree.
+func newPrinter() *pp {
+ p, ok := <-ppFree
+ if !ok {
+ p = new(pp)
+ }
+ p.fmt.init(&p.buf)
+ return p
+}
+
+// Save used pp structs in ppFree; avoids an allocation per invocation.
+func (p *pp) free() {
+ // Don't hold on to pp structs with large buffers.
+ if cap(p.buf.Bytes()) > 1024 {
+ return
+ }
+ p.buf.Reset()
+ _ = ppFree <- p
+}
+
+func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
+
+func (p *pp) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent }
+
+func (p *pp) Flag(b int) bool {
+ switch b {
+ case '-':
+ return p.fmt.minus
+ case '+':
+ return p.fmt.plus
+ case '#':
+ return p.fmt.sharp
+ case ' ':
+ return p.fmt.space
+ case '0':
+ return p.fmt.zero
+ }
+ return false
+}
+
+func (p *pp) add(c int) {
+ p.buf.WriteRune(c)
+}
+
+// Implement Write so we can call Fprintf on a pp (through State), for
+// recursive use in custom verbs.
+func (p *pp) Write(b []byte) (ret int, err os.Error) {
+ return p.buf.Write(b)
+}
+
+// These routines end in 'f' and take a format string.
+
+// Fprintf formats according to a format specifier and writes to w.
+// It returns the number of bytes written and any write error encountered.
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error os.Error) {
+ p := newPrinter()
+ p.doPrintf(format, a)
+ n64, error := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), error
+}
+
+// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
+func Printf(format string, a ...interface{}) (n int, errno os.Error) {
+ n, errno = Fprintf(os.Stdout, format, a...)
+ return n, errno
+}
+
+// Sprintf formats according to a format specifier and returns the resulting string.
+func Sprintf(format string, a ...interface{}) string {
+ p := newPrinter()
+ p.doPrintf(format, a)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+// 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...))
+}
+
+// These routines do not take a format string
+
+// Fprint formats using the default formats for its operands and writes to w.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Fprint(w io.Writer, a ...interface{}) (n int, error os.Error) {
+ p := newPrinter()
+ p.doPrint(a, false, false)
+ n64, error := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), error
+}
+
+// Print formats using the default formats for its operands and writes to standard output.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Print(a ...interface{}) (n int, errno os.Error) {
+ n, errno = Fprint(os.Stdout, a...)
+ return n, errno
+}
+
+// Sprint formats using the default formats for its operands and returns the resulting string.
+// Spaces are added between operands when neither is a string.
+func Sprint(a ...interface{}) string {
+ p := newPrinter()
+ p.doPrint(a, false, false)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+// These routines end in 'ln', do not take a format string,
+// always add spaces between operands, and add a newline
+// after the last operand.
+
+// Fprintln formats using the default formats for its operands and writes to w.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Fprintln(w io.Writer, a ...interface{}) (n int, error os.Error) {
+ p := newPrinter()
+ p.doPrint(a, true, true)
+ n64, error := p.buf.WriteTo(w)
+ p.free()
+ return int(n64), error
+}
+
+// Println formats using the default formats for its operands and writes to standard output.
+// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
+func Println(a ...interface{}) (n int, errno os.Error) {
+ n, errno = Fprintln(os.Stdout, a...)
+ return n, errno
+}
+
+// Sprintln formats using the default formats for its operands and returns the resulting string.
+// Spaces are always added between operands and a newline is appended.
+func Sprintln(a ...interface{}) string {
+ p := newPrinter()
+ p.doPrint(a, true, true)
+ s := p.buf.String()
+ p.free()
+ return s
+}
+
+
+// Get the i'th arg of the struct value.
+// If the arg itself is an interface, return a value for
+// the thing inside the interface, not the interface itself.
+func getField(v *reflect.StructValue, i int) reflect.Value {
+ val := v.Field(i)
+ if i, ok := val.(*reflect.InterfaceValue); ok {
+ if inter := i.Interface(); inter != nil {
+ return reflect.NewValue(inter)
+ }
+ }
+ return val
+}
+
+// Convert ASCII to integer. n is 0 (and got is false) if no number present.
+func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
+ if start >= end {
+ return 0, false, end
+ }
+ for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
+ num = num*10 + int(s[newi]-'0')
+ isnum = true
+ }
+ return
+}
+
+// Reflection values like reflect.FuncValue implement this method. We use it for %p.
+type uintptrGetter interface {
+ Get() uintptr
+}
+
+func (p *pp) unknownType(v interface{}) {
+ if v == nil {
+ p.buf.Write(nilAngleBytes)
+ return
+ }
+ p.buf.WriteByte('?')
+ p.buf.WriteString(reflect.Typeof(v).String())
+ p.buf.WriteByte('?')
+}
+
+func (p *pp) badVerb(verb int, val interface{}) {
+ p.add('%')
+ p.add('!')
+ p.add(verb)
+ p.add('(')
+ if val == nil {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.buf.WriteString(reflect.Typeof(val).String())
+ p.add('=')
+ p.printField(val, 'v', false, false, 0)
+ }
+ p.add(')')
+}
+
+func (p *pp) fmtBool(v bool, verb int, value interface{}) {
+ switch verb {
+ case 't', 'v':
+ p.fmt.fmt_boolean(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+// fmtC formats a rune for the 'c' format.
+func (p *pp) fmtC(c int64) {
+ rune := int(c) // Check for overflow.
+ if int64(rune) != c {
+ rune = utf8.RuneError
+ }
+ w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], rune)
+ p.fmt.pad(p.runeBuf[0:w])
+}
+
+func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.integer(v, 2, signed, ldigits)
+ case 'c':
+ p.fmtC(v)
+ case 'd', 'v':
+ p.fmt.integer(v, 10, signed, ldigits)
+ case 'o':
+ p.fmt.integer(v, 8, signed, ldigits)
+ case 'x':
+ p.fmt.integer(v, 16, signed, ldigits)
+ case 'U':
+ p.fmtUnicode(v)
+ case 'X':
+ p.fmt.integer(v, 16, signed, udigits)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x by
+// temporarily turning on the sharp flag.
+func (p *pp) fmt0x64(v uint64) {
+ sharp := p.fmt.sharp
+ p.fmt.sharp = true // turn on 0x
+ p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ p.fmt.sharp = sharp
+}
+
+// fmtUnicode formats a uint64 in U+1234 form by
+// temporarily turning on the unicode flag and tweaking the precision.
+func (p *pp) fmtUnicode(v int64) {
+ precPresent := p.fmt.precPresent
+ prec := p.fmt.prec
+ if !precPresent {
+ // If prec is already set, leave it alone; otherwise 4 is minimum.
+ p.fmt.prec = 4
+ p.fmt.precPresent = true
+ }
+ p.fmt.unicode = true // turn on U+
+ p.fmt.integer(int64(v), 16, unsigned, udigits)
+ p.fmt.unicode = false
+ p.fmt.prec = prec
+ p.fmt.precPresent = precPresent
+}
+
+func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.integer(int64(v), 2, unsigned, ldigits)
+ case 'c':
+ p.fmtC(int64(v))
+ case 'd':
+ p.fmt.integer(int64(v), 10, unsigned, ldigits)
+ case 'v':
+ if goSyntax {
+ p.fmt0x64(v)
+ } else {
+ p.fmt.integer(int64(v), 10, unsigned, ldigits)
+ }
+ case 'o':
+ p.fmt.integer(int64(v), 8, unsigned, ldigits)
+ case 'x':
+ p.fmt.integer(int64(v), 16, unsigned, ldigits)
+ case 'X':
+ p.fmt.integer(int64(v), 16, unsigned, udigits)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.fmt_fb32(v)
+ case 'e':
+ p.fmt.fmt_e32(v)
+ case 'E':
+ p.fmt.fmt_E32(v)
+ case 'f':
+ p.fmt.fmt_f32(v)
+ case 'g', 'v':
+ p.fmt.fmt_g32(v)
+ case 'G':
+ p.fmt.fmt_G32(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
+ switch verb {
+ case 'b':
+ p.fmt.fmt_fb64(v)
+ case 'e':
+ p.fmt.fmt_e64(v)
+ case 'E':
+ p.fmt.fmt_E64(v)
+ case 'f':
+ p.fmt.fmt_f64(v)
+ case 'g', 'v':
+ p.fmt.fmt_g64(v)
+ case 'G':
+ p.fmt.fmt_G64(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) {
+ switch verb {
+ case 'e', 'E', 'f', 'F', 'g', 'G':
+ p.fmt.fmt_c64(v, verb)
+ case 'v':
+ p.fmt.fmt_c64(v, 'g')
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) {
+ switch verb {
+ case 'e', 'E', 'f', 'F', 'g', 'G':
+ p.fmt.fmt_c128(v, verb)
+ case 'v':
+ p.fmt.fmt_c128(v, 'g')
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
+ switch verb {
+ case 'v':
+ if goSyntax {
+ p.fmt.fmt_q(v)
+ } else {
+ p.fmt.fmt_s(v)
+ }
+ case 's':
+ p.fmt.fmt_s(v)
+ case 'x':
+ p.fmt.fmt_sx(v)
+ case 'X':
+ p.fmt.fmt_sX(v)
+ case 'q':
+ p.fmt.fmt_q(v)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) {
+ if verb == 'v' || verb == 'd' {
+ if goSyntax {
+ p.buf.Write(bytesBytes)
+ } else {
+ p.buf.WriteByte('[')
+ }
+ for i, c := range v {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(c, 'v', p.fmt.plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ return
+ }
+ s := string(v)
+ switch verb {
+ case 's':
+ p.fmt.fmt_s(s)
+ case 'x':
+ p.fmt.fmt_sx(s)
+ case 'X':
+ p.fmt.fmt_sX(s)
+ case 'q':
+ p.fmt.fmt_q(s)
+ default:
+ p.badVerb(verb, value)
+ }
+}
+
+func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
+ v, ok := value.(uintptrGetter)
+ if !ok { // reflect.PtrValue is a uintptrGetter, so failure means it's not a pointer at all.
+ p.badVerb(verb, field)
+ return
+ }
+ u := v.Get()
+ if goSyntax {
+ p.add('(')
+ p.buf.WriteString(reflect.Typeof(field).String())
+ p.add(')')
+ p.add('(')
+ if u == 0 {
+ p.buf.Write(nilBytes)
+ } else {
+ p.fmt0x64(uint64(v.Get()))
+ }
+ p.add(')')
+ } else {
+ p.fmt0x64(uint64(u))
+ }
+}
+
+var (
+ intBits = reflect.Typeof(0).Bits()
+ floatBits = reflect.Typeof(0.0).Bits()
+ complexBits = reflect.Typeof(1i).Bits()
+ uintptrBits = reflect.Typeof(uintptr(0)).Bits()
+)
+
+func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
+ if field == nil {
+ if verb == 'T' || verb == 'v' {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.badVerb(verb, field)
+ }
+ return false
+ }
+
+ // Special processing considerations.
+ // %T (the value's type) and %p (its address) are special; we always do them first.
+ switch verb {
+ case 'T':
+ p.printField(reflect.Typeof(field).String(), 's', false, false, 0)
+ return false
+ case 'p':
+ p.fmtPointer(field, reflect.NewValue(field), verb, goSyntax)
+ return false
+ }
+ // Is it a Formatter?
+ if formatter, ok := field.(Formatter); ok {
+ formatter.Format(p, verb)
+ return false // this value is not a string
+
+ }
+ // Must not touch flags before Formatter looks at them.
+ if plus {
+ p.fmt.plus = false
+ }
+ // If we're doing Go syntax and the field knows how to supply it, take care of it now.
+ if goSyntax {
+ p.fmt.sharp = false
+ if stringer, ok := field.(GoStringer); ok {
+ // Print the result of GoString unadorned.
+ p.fmtString(stringer.GoString(), 's', false, field)
+ return false // this value is not a string
+ }
+ } else {
+ // Is it a Stringer?
+ if stringer, ok := field.(Stringer); ok {
+ p.printField(stringer.String(), verb, plus, false, depth)
+ return false // this value is not a string
+ }
+ }
+
+ // Some types can be done without reflection.
+ switch f := field.(type) {
+ case bool:
+ p.fmtBool(f, verb, field)
+ return false
+ case float32:
+ p.fmtFloat32(f, verb, field)
+ return false
+ case float64:
+ p.fmtFloat64(f, verb, field)
+ return false
+ case complex64:
+ p.fmtComplex64(complex64(f), verb, field)
+ return false
+ case complex128:
+ p.fmtComplex128(f, verb, field)
+ return false
+ case int:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int8:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int16:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int32:
+ p.fmtInt64(int64(f), verb, field)
+ return false
+ case int64:
+ p.fmtInt64(f, verb, field)
+ return false
+ case uint:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint8:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint16:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint32:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case uint64:
+ p.fmtUint64(f, verb, goSyntax, field)
+ return false
+ case uintptr:
+ p.fmtUint64(uint64(f), verb, goSyntax, field)
+ return false
+ case string:
+ p.fmtString(f, verb, goSyntax, field)
+ return verb == 's' || verb == 'v'
+ case []byte:
+ p.fmtBytes(f, verb, goSyntax, depth, field)
+ return verb == 's'
+ }
+
+ // Need to use reflection
+ value := reflect.NewValue(field)
+
+BigSwitch:
+ switch f := value.(type) {
+ case *reflect.BoolValue:
+ p.fmtBool(f.Get(), verb, field)
+ case *reflect.IntValue:
+ p.fmtInt64(f.Get(), verb, field)
+ case *reflect.UintValue:
+ p.fmtUint64(uint64(f.Get()), verb, goSyntax, field)
+ case *reflect.FloatValue:
+ if f.Type().Size() == 4 {
+ p.fmtFloat32(float32(f.Get()), verb, field)
+ } else {
+ p.fmtFloat64(float64(f.Get()), verb, field)
+ }
+ case *reflect.ComplexValue:
+ if f.Type().Size() == 8 {
+ p.fmtComplex64(complex64(f.Get()), verb, field)
+ } else {
+ p.fmtComplex128(complex128(f.Get()), verb, field)
+ }
+ case *reflect.StringValue:
+ p.fmtString(f.Get(), verb, goSyntax, field)
+ case *reflect.MapValue:
+ if goSyntax {
+ p.buf.WriteString(f.Type().String())
+ p.buf.WriteByte('{')
+ } else {
+ p.buf.Write(mapBytes)
+ }
+ keys := f.Keys()
+ for i, key := range keys {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(key.Interface(), verb, plus, goSyntax, depth+1)
+ p.buf.WriteByte(':')
+ p.printField(f.Elem(key).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ case *reflect.StructValue:
+ if goSyntax {
+ p.buf.WriteString(reflect.Typeof(field).String())
+ }
+ p.add('{')
+ v := f
+ t := v.Type().(*reflect.StructType)
+ for i := 0; i < v.NumField(); i++ {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ if plus || goSyntax {
+ if f := t.Field(i); f.Name != "" {
+ p.buf.WriteString(f.Name)
+ p.buf.WriteByte(':')
+ }
+ }
+ p.printField(getField(v, i).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ p.buf.WriteByte('}')
+ case *reflect.InterfaceValue:
+ value := f.Elem()
+ if value == nil {
+ if goSyntax {
+ p.buf.WriteString(reflect.Typeof(field).String())
+ p.buf.Write(nilParenBytes)
+ } else {
+ p.buf.Write(nilAngleBytes)
+ }
+ } else {
+ return p.printField(value.Interface(), verb, plus, goSyntax, depth+1)
+ }
+ case reflect.ArrayOrSliceValue:
+ // Byte slices are special.
+ if f.Type().(reflect.ArrayOrSliceType).Elem().Kind() == reflect.Uint8 {
+ // We know it's a slice of bytes, but we also know it does not have static type
+ // []byte, or it would have been caught above. Therefore we cannot convert
+ // it directly in the (slightly) obvious way: f.Interface().([]byte); it doesn't have
+ // that type, and we can't write an expression of the right type and do a
+ // conversion because we don't have a static way to write the right type.
+ // So we build a slice by hand. This is a rare case but it would be nice
+ // if reflection could help a little more.
+ bytes := make([]byte, f.Len())
+ for i := range bytes {
+ bytes[i] = byte(f.Elem(i).(*reflect.UintValue).Get())
+ }
+ p.fmtBytes(bytes, verb, goSyntax, depth, field)
+ return verb == 's'
+ }
+ if goSyntax {
+ p.buf.WriteString(reflect.Typeof(field).String())
+ p.buf.WriteByte('{')
+ } else {
+ p.buf.WriteByte('[')
+ }
+ for i := 0; i < f.Len(); i++ {
+ if i > 0 {
+ if goSyntax {
+ p.buf.Write(commaSpaceBytes)
+ } else {
+ p.buf.WriteByte(' ')
+ }
+ }
+ p.printField(f.Elem(i).Interface(), verb, plus, goSyntax, depth+1)
+ }
+ if goSyntax {
+ p.buf.WriteByte('}')
+ } else {
+ p.buf.WriteByte(']')
+ }
+ case *reflect.PtrValue:
+ v := f.Get()
+ // pointer to array or slice or struct? ok at top level
+ // but not embedded (avoid loops)
+ if v != 0 && depth == 0 {
+ switch a := f.Elem().(type) {
+ case reflect.ArrayOrSliceValue:
+ p.buf.WriteByte('&')
+ p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ break BigSwitch
+ case *reflect.StructValue:
+ p.buf.WriteByte('&')
+ p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ break BigSwitch
+ }
+ }
+ if goSyntax {
+ p.buf.WriteByte('(')
+ p.buf.WriteString(reflect.Typeof(field).String())
+ p.buf.WriteByte(')')
+ p.buf.WriteByte('(')
+ if v == 0 {
+ p.buf.Write(nilBytes)
+ } else {
+ p.fmt0x64(uint64(v))
+ }
+ p.buf.WriteByte(')')
+ break
+ }
+ if v == 0 {
+ p.buf.Write(nilAngleBytes)
+ break
+ }
+ p.fmt0x64(uint64(v))
+ case uintptrGetter:
+ p.fmtPointer(field, value, verb, goSyntax)
+ default:
+ p.unknownType(f)
+ }
+ return false
+}
+
+// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
+func intFromArg(a []interface{}, end, i, fieldnum int) (num int, isInt bool, newi, newfieldnum int) {
+ newi, newfieldnum = end, fieldnum
+ if i < end && fieldnum < len(a) {
+ num, isInt = a[fieldnum].(int)
+ newi, newfieldnum = i+1, fieldnum+1
+ }
+ return
+}
+
+func (p *pp) doPrintf(format string, a []interface{}) {
+ end := len(format)
+ fieldnum := 0 // we process one field per non-trivial format
+ for i := 0; i < end; {
+ lasti := i
+ for i < end && format[i] != '%' {
+ i++
+ }
+ if i > lasti {
+ p.buf.WriteString(format[lasti:i])
+ }
+ if i >= end {
+ // done processing format string
+ break
+ }
+
+ // Process one verb
+ i++
+ // flags and widths
+ p.fmt.clearflags()
+ F:
+ for ; i < end; i++ {
+ switch format[i] {
+ case '#':
+ p.fmt.sharp = true
+ case '0':
+ p.fmt.zero = true
+ case '+':
+ p.fmt.plus = true
+ case '-':
+ p.fmt.minus = true
+ case ' ':
+ p.fmt.space = true
+ default:
+ break F
+ }
+ }
+ // do we have width?
+ if i < end && format[i] == '*' {
+ p.fmt.wid, p.fmt.widPresent, i, fieldnum = intFromArg(a, end, i, fieldnum)
+ if !p.fmt.widPresent {
+ p.buf.Write(widthBytes)
+ }
+ } else {
+ p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
+ }
+ // do we have precision?
+ if i < end && format[i] == '.' {
+ if format[i+1] == '*' {
+ p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
+ if !p.fmt.precPresent {
+ p.buf.Write(precBytes)
+ }
+ } else {
+ p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
+ }
+ }
+ if i >= end {
+ p.buf.Write(noVerbBytes)
+ continue
+ }
+ c, w := utf8.DecodeRuneInString(format[i:])
+ i += w
+ // percent is special - absorbs no operand
+ if c == '%' {
+ p.buf.WriteByte('%') // We ignore width and prec.
+ continue
+ }
+ if fieldnum >= len(a) { // out of operands
+ p.buf.WriteByte('%')
+ p.add(c)
+ p.buf.Write(missingBytes)
+ continue
+ }
+ field := a[fieldnum]
+ fieldnum++
+
+ goSyntax := c == 'v' && p.fmt.sharp
+ plus := c == 'v' && p.fmt.plus
+ p.printField(field, c, plus, goSyntax, 0)
+ }
+
+ if fieldnum < len(a) {
+ p.buf.Write(extraBytes)
+ for ; fieldnum < len(a); fieldnum++ {
+ field := a[fieldnum]
+ if field != nil {
+ p.buf.WriteString(reflect.Typeof(field).String())
+ p.buf.WriteByte('=')
+ }
+ p.printField(field, 'v', false, false, 0)
+ if fieldnum+1 < len(a) {
+ p.buf.Write(commaSpaceBytes)
+ }
+ }
+ p.buf.WriteByte(')')
+ }
+}
+
+func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
+ prevString := false
+ for fieldnum := 0; fieldnum < len(a); fieldnum++ {
+ p.fmt.clearflags()
+ // always add spaces if we're doing println
+ field := a[fieldnum]
+ if fieldnum > 0 {
+ isString := field != nil && reflect.Typeof(field).Kind() == reflect.String
+ if addspace || !isString && !prevString {
+ p.buf.WriteByte(' ')
+ }
+ }
+ prevString = p.printField(field, 'v', false, false, 0)
+ }
+ if addnewline {
+ p.buf.WriteByte('\n')
+ }
+}
diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go
new file mode 100644
index 000000000..ebbb17155
--- /dev/null
+++ b/libgo/go/fmt/scan.go
@@ -0,0 +1,985 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// readRuner is the interface to something that can read runes. If
+// the object provided to Scan does not satisfy this interface, the
+// object will be wrapped by a readRune object.
+type readRuner interface {
+ ReadRune() (rune int, size int, err os.Error)
+}
+
+// unreadRuner is the interface to something that can unread runes.
+// If the object provided to Scan does not satisfy this interface,
+// a local buffer will be used to back up the input, but its contents
+// will be lost when Scan returns.
+type unreadRuner interface {
+ UnreadRune() os.Error
+}
+
+// ScanState represents the scanner state passed to custom scanners.
+// Scanners may do rune-at-a-time scanning or ask the ScanState
+// to discover the next space-delimited token.
+type ScanState interface {
+ // GetRune reads the next rune (Unicode code point) from the input.
+ GetRune() (rune int, err os.Error)
+ // UngetRune causes the next call to GetRune to return the rune.
+ UngetRune()
+ // Width returns the value of the width option and whether it has been set.
+ // The unit is Unicode code points.
+ Width() (wid int, ok bool)
+ // Token returns the next space-delimited token from the input. If
+ // a width has been specified, the returned token will be no longer
+ // than the width.
+ Token() (token string, err os.Error)
+}
+
+// Scanner is implemented by any value that has a Scan method, which scans
+// the input for the representation of a value and stores the result in the
+// receiver, which must be a pointer to be useful. The Scan method is called
+// for any argument to Scan or Scanln that implements it.
+type Scanner interface {
+ Scan(state ScanState, verb int) os.Error
+}
+
+// Scan scans text read from standard input, storing successive
+// space-separated values into successive arguments. Newlines count
+// as space. It returns the number of items successfully scanned.
+// If that is less than the number of arguments, err will report why.
+func Scan(a ...interface{}) (n int, err os.Error) {
+ return Fscan(os.Stdin, a...)
+}
+
+// Scanln is similar to Scan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Scanln(a ...interface{}) (n int, err os.Error) {
+ return Fscanln(os.Stdin, a...)
+}
+
+// Scanf scans text read from standard input, storing successive
+// space-separated values into successive arguments as determined by
+// the format. It returns the number of items successfully scanned.
+func Scanf(format string, a ...interface{}) (n int, err os.Error) {
+ return Fscanf(os.Stdin, format, a...)
+}
+
+// Sscan scans the argument string, storing successive space-separated
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
+// than the number of arguments, err will report why.
+func Sscan(str string, a ...interface{}) (n int, err os.Error) {
+ return Fscan(strings.NewReader(str), a...)
+}
+
+// Sscanln is similar to Sscan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Sscanln(str string, a ...interface{}) (n int, err os.Error) {
+ return Fscanln(strings.NewReader(str), a...)
+}
+
+// Sscanf scans the argument string, storing successive space-separated
+// values into successive arguments as determined by the format. It
+// returns the number of items successfully parsed.
+func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) {
+ return Fscanf(strings.NewReader(str), format, a...)
+}
+
+// Fscan scans text read from r, storing successive space-separated
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
+// than the number of arguments, err will report why.
+func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
+ s := newScanState(r, true)
+ n, err = s.doScan(a)
+ s.free()
+ return
+}
+
+// Fscanln is similar to Fscan, but stops scanning at a newline and
+// after the final item there must be a newline or EOF.
+func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
+ s := newScanState(r, false)
+ n, err = s.doScan(a)
+ s.free()
+ return
+}
+
+// Fscanf scans text read from r, storing successive space-separated
+// values into successive arguments as determined by the format. It
+// returns the number of items successfully parsed.
+func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
+ s := newScanState(r, false)
+ n, err = s.doScanf(format, a)
+ s.free()
+ return
+}
+
+// scanError represents an error generated by the scanning software.
+// It's used as a unique signature to identify such errors when recovering.
+type scanError struct {
+ err os.Error
+}
+
+const EOF = -1
+
+// ss is the internal implementation of ScanState.
+type ss struct {
+ rr readRuner // where to read input
+ buf bytes.Buffer // token accumulator
+ nlIsSpace bool // whether newline counts as white space
+ peekRune int // one-rune lookahead
+ prevRune int // last rune returned by GetRune
+ atEOF bool // already read EOF
+ maxWid int // max width of field, in runes
+ widPresent bool // width was specified
+ wid int // width consumed so far; used in accept()
+}
+
+func (s *ss) GetRune() (rune int, err os.Error) {
+ if s.peekRune >= 0 {
+ rune = s.peekRune
+ s.prevRune = rune
+ s.peekRune = -1
+ return
+ }
+ rune, _, err = s.rr.ReadRune()
+ if err == nil {
+ s.prevRune = rune
+ }
+ return
+}
+
+func (s *ss) Width() (wid int, ok bool) {
+ return s.maxWid, s.widPresent
+}
+
+// The public method returns an error; this private one panics.
+// If getRune reaches EOF, the return value is EOF (-1).
+func (s *ss) getRune() (rune int) {
+ if s.atEOF {
+ return EOF
+ }
+ if s.peekRune >= 0 {
+ rune = s.peekRune
+ s.prevRune = rune
+ s.peekRune = -1
+ return
+ }
+ rune, _, err := s.rr.ReadRune()
+ if err == nil {
+ s.prevRune = rune
+ } else if err != nil {
+ if err == os.EOF {
+ s.atEOF = true
+ return EOF
+ }
+ s.error(err)
+ }
+ return
+}
+
+// mustGetRune turns os.EOF into a panic(io.ErrUnexpectedEOF).
+// It is called in cases such as string scanning where an EOF is a
+// syntax error.
+func (s *ss) mustGetRune() (rune int) {
+ if s.atEOF {
+ s.error(io.ErrUnexpectedEOF)
+ }
+ if s.peekRune >= 0 {
+ rune = s.peekRune
+ s.peekRune = -1
+ return
+ }
+ rune, _, err := s.rr.ReadRune()
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ s.error(err)
+ }
+ return
+}
+
+
+func (s *ss) UngetRune() {
+ if u, ok := s.rr.(unreadRuner); ok {
+ u.UnreadRune()
+ } else {
+ s.peekRune = s.prevRune
+ }
+}
+
+func (s *ss) error(err os.Error) {
+ panic(scanError{err})
+}
+
+func (s *ss) errorString(err string) {
+ panic(scanError{os.ErrorString(err)})
+}
+
+func (s *ss) Token() (tok string, err os.Error) {
+ defer func() {
+ if e := recover(); e != nil {
+ if se, ok := e.(scanError); ok {
+ err = se.err
+ } else {
+ panic(e)
+ }
+ }
+ }()
+ tok = s.token()
+ return
+}
+
+// readRune is a structure to enable reading UTF-8 encoded code points
+// from an io.Reader. It is used if the Reader given to the scanner does
+// not already implement ReadRuner.
+type readRune struct {
+ reader io.Reader
+ buf [utf8.UTFMax]byte // used only inside ReadRune
+ pending int // number of bytes in pendBuf; only >0 for bad UTF-8
+ pendBuf [utf8.UTFMax]byte // bytes left over
+}
+
+// readByte returns the next byte from the input, which may be
+// left over from a previous read if the UTF-8 was ill-formed.
+func (r *readRune) readByte() (b byte, err os.Error) {
+ if r.pending > 0 {
+ b = r.pendBuf[0]
+ copy(r.pendBuf[0:], r.pendBuf[1:])
+ r.pending--
+ return
+ }
+ _, err = r.reader.Read(r.pendBuf[0:1])
+ return r.pendBuf[0], err
+}
+
+// unread saves the bytes for the next read.
+func (r *readRune) unread(buf []byte) {
+ copy(r.pendBuf[r.pending:], buf)
+ r.pending += len(buf)
+}
+
+// ReadRune returns the next UTF-8 encoded code point from the
+// io.Reader inside r.
+func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
+ r.buf[0], err = r.readByte()
+ if err != nil {
+ return 0, 0, err
+ }
+ if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
+ rune = int(r.buf[0])
+ return
+ }
+ var n int
+ for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
+ r.buf[n], err = r.readByte()
+ if err != nil {
+ if err == os.EOF {
+ err = nil
+ break
+ }
+ return
+ }
+ }
+ rune, size = utf8.DecodeRune(r.buf[0:n])
+ if size < n { // an error
+ r.unread(r.buf[size:n])
+ }
+ return
+}
+
+
+// A leaky bucket of reusable ss structures.
+var ssFree = make(chan *ss, 100)
+
+// Allocate a new ss struct. Probably can grab the previous one from ssFree.
+func newScanState(r io.Reader, nlIsSpace bool) *ss {
+ s, ok := <-ssFree
+ if !ok {
+ s = new(ss)
+ }
+ if rr, ok := r.(readRuner); ok {
+ s.rr = rr
+ } else {
+ s.rr = &readRune{reader: r}
+ }
+ s.nlIsSpace = nlIsSpace
+ s.peekRune = -1
+ s.atEOF = false
+ s.maxWid = 0
+ s.widPresent = false
+ return s
+}
+
+// Save used ss structs in ssFree; avoid an allocation per invocation.
+func (s *ss) free() {
+ // Don't hold on to ss structs with large buffers.
+ if cap(s.buf.Bytes()) > 1024 {
+ return
+ }
+ s.buf.Reset()
+ s.rr = nil
+ _ = ssFree <- s
+}
+
+// skipSpace skips spaces and maybe newlines.
+func (s *ss) skipSpace(stopAtNewline bool) {
+ for {
+ rune := s.getRune()
+ if rune == EOF {
+ return
+ }
+ if rune == '\n' {
+ if stopAtNewline {
+ break
+ }
+ if s.nlIsSpace {
+ continue
+ }
+ s.errorString("unexpected newline")
+ return
+ }
+ if !unicode.IsSpace(rune) {
+ s.UngetRune()
+ break
+ }
+ }
+}
+
+// token returns the next space-delimited string from the input. It
+// skips white space. For Scanln, it stops at newlines. For Scan,
+// newlines are treated as spaces.
+func (s *ss) token() string {
+ s.skipSpace(false)
+ // read until white space or newline
+ for nrunes := 0; !s.widPresent || nrunes < s.maxWid; nrunes++ {
+ rune := s.getRune()
+ if rune == EOF {
+ break
+ }
+ if unicode.IsSpace(rune) {
+ s.UngetRune()
+ break
+ }
+ s.buf.WriteRune(rune)
+ }
+ return s.buf.String()
+}
+
+// typeError indicates that the type of the operand did not match the format
+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")
+
+// 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.
+func (s *ss) consume(ok string, accept bool) bool {
+ if s.wid >= s.maxWid {
+ return false
+ }
+ rune := s.getRune()
+ if rune == EOF {
+ return false
+ }
+ for i := 0; i < len(ok); i++ {
+ if int(ok[i]) == rune {
+ if accept {
+ s.buf.WriteRune(rune)
+ s.wid++
+ }
+ return true
+ }
+ }
+ if rune != EOF && accept {
+ s.UngetRune()
+ }
+ return false
+}
+
+// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
+// buffer and returns true. Otherwise it return false.
+func (s *ss) accept(ok string) bool {
+ return s.consume(ok, true)
+}
+
+// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
+func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
+ for _, v := range okVerbs {
+ if v == verb {
+ return true
+ }
+ }
+ s.errorString("bad verb %" + string(verb) + " for " + typ)
+ return false
+}
+
+// scanBool returns the value of the boolean represented by the next token.
+func (s *ss) scanBool(verb int) bool {
+ if !s.okVerb(verb, "tv", "boolean") {
+ return false
+ }
+ // Syntax-checking a boolean is annoying. We're not fastidious about case.
+ switch s.mustGetRune() {
+ case '0':
+ return false
+ case '1':
+ return true
+ case 't', 'T':
+ if s.accept("rR") && (!s.accept("uU") || !s.accept("eE")) {
+ s.error(boolError)
+ }
+ return true
+ case 'f', 'F':
+ if s.accept("aL") && (!s.accept("lL") || !s.accept("sS") || !s.accept("eE")) {
+ s.error(boolError)
+ }
+ return false
+ }
+ return false
+}
+
+// Numerical elements
+const (
+ binaryDigits = "01"
+ octalDigits = "01234567"
+ decimalDigits = "0123456789"
+ hexadecimalDigits = "0123456789aAbBcCdDeEfF"
+ sign = "+-"
+ period = "."
+ exponent = "eE"
+)
+
+// getBase returns the numeric base represented by the verb and its digit string.
+func (s *ss) getBase(verb int) (base int, digits string) {
+ s.okVerb(verb, "bdoUxXv", "integer") // sets s.err
+ base = 10
+ digits = decimalDigits
+ switch verb {
+ case 'b':
+ base = 2
+ digits = binaryDigits
+ case 'o':
+ base = 8
+ digits = octalDigits
+ case 'x', 'X', 'U':
+ base = 16
+ digits = hexadecimalDigits
+ }
+ return
+}
+
+// scanNumber returns the numerical string with specified digits starting here.
+func (s *ss) scanNumber(digits string) string {
+ if !s.accept(digits) {
+ s.errorString("expected integer")
+ }
+ for s.accept(digits) {
+ }
+ return s.buf.String()
+}
+
+// scanRune returns the next rune value in the input.
+func (s *ss) scanRune(bitSize int) int64 {
+ rune := int64(s.mustGetRune())
+ n := uint(bitSize)
+ x := (rune << (64 - n)) >> (64 - n)
+ if x != rune {
+ s.errorString("overflow on character value " + string(rune))
+ }
+ return rune
+}
+
+// scanInt returns the value of the integer represented by the next
+// token, checking for overflow. Any error is stored in s.err.
+func (s *ss) scanInt(verb int, bitSize int) int64 {
+ if verb == 'c' {
+ return s.scanRune(bitSize)
+ }
+ base, digits := s.getBase(verb)
+ s.skipSpace(false)
+ if verb == 'U' {
+ if !s.consume("U", false) || !s.consume("+", false) {
+ s.errorString("bad unicode format ")
+ }
+ } else {
+ s.accept(sign) // If there's a sign, it will be left in the token buffer.
+ }
+ tok := s.scanNumber(digits)
+ i, err := strconv.Btoi64(tok, base)
+ if err != nil {
+ s.error(err)
+ }
+ n := uint(bitSize)
+ x := (i << (64 - n)) >> (64 - n)
+ if x != i {
+ s.errorString("integer overflow on token " + tok)
+ }
+ return i
+}
+
+// scanUint returns the value of the unsigned integer represented
+// by the next token, checking for overflow. Any error is stored in s.err.
+func (s *ss) scanUint(verb int, bitSize int) uint64 {
+ if verb == 'c' {
+ return uint64(s.scanRune(bitSize))
+ }
+ base, digits := s.getBase(verb)
+ s.skipSpace(false)
+ if verb == 'U' {
+ if !s.consume("U", false) || !s.consume("+", false) {
+ s.errorString("bad unicode format ")
+ }
+ }
+ tok := s.scanNumber(digits)
+ i, err := strconv.Btoui64(tok, base)
+ if err != nil {
+ s.error(err)
+ }
+ n := uint(bitSize)
+ x := (i << (64 - n)) >> (64 - n)
+ if x != i {
+ s.errorString("unsigned integer overflow on token " + tok)
+ }
+ return i
+}
+
+// floatToken returns the floating-point number starting here, no longer than swid
+// if the width is specified. It's not rigorous about syntax because it doesn't check that
+// we have at least some digits, but Atof will do that.
+func (s *ss) floatToken() string {
+ s.buf.Reset()
+ // NaN?
+ if s.accept("nN") && s.accept("aA") && s.accept("nN") {
+ return s.buf.String()
+ }
+ // leading sign?
+ s.accept(sign)
+ // Inf?
+ if s.accept("iI") && s.accept("nN") && s.accept("fF") {
+ return s.buf.String()
+ }
+ // digits?
+ for s.accept(decimalDigits) {
+ }
+ // decimal point?
+ if s.accept(period) {
+ // fraction?
+ for s.accept(decimalDigits) {
+ }
+ }
+ // exponent?
+ if s.accept(exponent) {
+ // leading sign?
+ s.accept(sign)
+ // digits?
+ for s.accept(decimalDigits) {
+ }
+ }
+ return s.buf.String()
+}
+
+// complexTokens returns the real and imaginary parts of the complex number starting here.
+// The number might be parenthesized and has the format (N+Ni) where N is a floating-point
+// number and there are no spaces within.
+func (s *ss) complexTokens() (real, imag string) {
+ // TODO: accept N and Ni independently?
+ parens := s.accept("(")
+ real = s.floatToken()
+ s.buf.Reset()
+ // Must now have a sign.
+ if !s.accept("+-") {
+ s.error(complexError)
+ }
+ // Sign is now in buffer
+ imagSign := s.buf.String()
+ imag = s.floatToken()
+ if !s.accept("i") {
+ s.error(complexError)
+ }
+ if parens && !s.accept(")") {
+ s.error(complexError)
+ }
+ return real, imagSign + imag
+}
+
+// convertFloat converts the string to a float64value.
+func (s *ss) convertFloat(str string, n int) float64 {
+ f, err := strconv.AtofN(str, n)
+ if err != nil {
+ s.error(err)
+ }
+ return f
+}
+
+// convertComplex converts the next token to a complex128 value.
+// The atof argument is a type-specific reader for the underlying type.
+// If we're reading complex64, atof will parse float32s and convert them
+// to float64's to avoid reproducing this code for each complex type.
+func (s *ss) scanComplex(verb int, n int) complex128 {
+ if !s.okVerb(verb, floatVerbs, "complex") {
+ return 0
+ }
+ s.skipSpace(false)
+ sreal, simag := s.complexTokens()
+ real := s.convertFloat(sreal, n/2)
+ imag := s.convertFloat(simag, n/2)
+ return complex(real, imag)
+}
+
+// convertString returns the string represented by the next input characters.
+// The format of the input is determined by the verb.
+func (s *ss) convertString(verb int) (str string) {
+ if !s.okVerb(verb, "svqx", "string") {
+ return ""
+ }
+ s.skipSpace(false)
+ switch verb {
+ case 'q':
+ str = s.quotedString()
+ case 'x':
+ str = s.hexString()
+ default:
+ str = s.token() // %s and %v just return the next word
+ }
+ // Empty strings other than with %q are not OK.
+ if len(str) == 0 && verb != 'q' && s.maxWid > 0 {
+ s.errorString("Scan: no data for string")
+ }
+ return
+}
+
+// quotedString returns the double- or back-quoted string represented by the next input characters.
+func (s *ss) quotedString() string {
+ quote := s.mustGetRune()
+ switch quote {
+ case '`':
+ // Back-quoted: Anything goes until EOF or back quote.
+ for {
+ rune := s.mustGetRune()
+ if rune == quote {
+ break
+ }
+ s.buf.WriteRune(rune)
+ }
+ return s.buf.String()
+ case '"':
+ // Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
+ s.buf.WriteRune(quote)
+ for {
+ rune := s.mustGetRune()
+ s.buf.WriteRune(rune)
+ if rune == '\\' {
+ // In a legal backslash escape, no matter how long, only the character
+ // immediately after the escape can itself be a backslash or quote.
+ // Thus we only need to protect the first character after the backslash.
+ rune := s.mustGetRune()
+ s.buf.WriteRune(rune)
+ } else if rune == '"' {
+ break
+ }
+ }
+ result, err := strconv.Unquote(s.buf.String())
+ if err != nil {
+ s.error(err)
+ }
+ return result
+ default:
+ s.errorString("expected quoted string")
+ }
+ return ""
+}
+
+// hexDigit returns the value of the hexadecimal digit
+func (s *ss) hexDigit(digit int) int {
+ switch digit {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return digit - '0'
+ case 'a', 'b', 'c', 'd', 'e', 'f':
+ return 10 + digit - 'a'
+ case 'A', 'B', 'C', 'D', 'E', 'F':
+ return 10 + digit - 'A'
+ }
+ s.errorString("Scan: illegal hex digit")
+ return 0
+}
+
+// hexByte returns the next hex-encoded (two-character) byte from the input.
+// There must be either two hexadecimal digits or a space character in the input.
+func (s *ss) hexByte() (b byte, ok bool) {
+ rune1 := s.getRune()
+ if rune1 == EOF {
+ return
+ }
+ if unicode.IsSpace(rune1) {
+ s.UngetRune()
+ return
+ }
+ rune2 := s.mustGetRune()
+ return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
+}
+
+// hexString returns the space-delimited hexpair-encoded string.
+func (s *ss) hexString() string {
+ for {
+ b, ok := s.hexByte()
+ if !ok {
+ break
+ }
+ s.buf.WriteByte(b)
+ }
+ if s.buf.Len() == 0 {
+ s.errorString("Scan: no hex data for %x string")
+ return ""
+ }
+ return s.buf.String()
+}
+
+const floatVerbs = "eEfFgGv"
+
+// scanOne scans a single value, deriving the scanner from the type of the argument.
+func (s *ss) scanOne(verb int, field interface{}) {
+ s.buf.Reset()
+ var err os.Error
+ // If the parameter has its own Scan method, use that.
+ if v, ok := field.(Scanner); ok {
+ err = v.Scan(s, verb)
+ if err != nil {
+ s.error(err)
+ }
+ return
+ }
+ if !s.widPresent {
+ s.maxWid = 1 << 30 // Huge
+ }
+ s.wid = 0
+ switch v := field.(type) {
+ case *bool:
+ *v = s.scanBool(verb)
+ case *complex64:
+ *v = complex64(s.scanComplex(verb, 64))
+ case *complex128:
+ *v = s.scanComplex(verb, 128)
+ case *int:
+ *v = int(s.scanInt(verb, intBits))
+ case *int8:
+ *v = int8(s.scanInt(verb, 8))
+ case *int16:
+ *v = int16(s.scanInt(verb, 16))
+ case *int32:
+ *v = int32(s.scanInt(verb, 32))
+ case *int64:
+ *v = s.scanInt(verb, 64)
+ case *uint:
+ *v = uint(s.scanUint(verb, intBits))
+ case *uint8:
+ *v = uint8(s.scanUint(verb, 8))
+ case *uint16:
+ *v = uint16(s.scanUint(verb, 16))
+ case *uint32:
+ *v = uint32(s.scanUint(verb, 32))
+ case *uint64:
+ *v = s.scanUint(verb, 64)
+ case *uintptr:
+ *v = uintptr(s.scanUint(verb, uintptrBits))
+ // Floats are tricky because you want to scan in the precision of the result, not
+ // scan in high precision and convert, in order to preserve the correct error condition.
+ case *float32:
+ if s.okVerb(verb, floatVerbs, "float32") {
+ s.skipSpace(false)
+ *v = float32(s.convertFloat(s.floatToken(), 32))
+ }
+ case *float64:
+ if s.okVerb(verb, floatVerbs, "float64") {
+ s.skipSpace(false)
+ *v = s.convertFloat(s.floatToken(), 64)
+ }
+ case *string:
+ *v = s.convertString(verb)
+ case *[]byte:
+ // We scan to string and convert so we get a copy of the data.
+ // If we scanned to bytes, the slice would point at the buffer.
+ *v = []byte(s.convertString(verb))
+ default:
+ val := reflect.NewValue(v)
+ ptr, ok := val.(*reflect.PtrValue)
+ if !ok {
+ s.errorString("Scan: type not a pointer: " + val.Type().String())
+ return
+ }
+ switch v := ptr.Elem().(type) {
+ case *reflect.BoolValue:
+ v.Set(s.scanBool(verb))
+ case *reflect.IntValue:
+ v.Set(s.scanInt(verb, v.Type().Bits()))
+ case *reflect.UintValue:
+ v.Set(s.scanUint(verb, v.Type().Bits()))
+ case *reflect.StringValue:
+ v.Set(s.convertString(verb))
+ case *reflect.SliceValue:
+ // For now, can only handle (renamed) []byte.
+ typ := v.Type().(*reflect.SliceType)
+ if typ.Elem().Kind() != reflect.Uint8 {
+ goto CantHandle
+ }
+ str := s.convertString(verb)
+ v.Set(reflect.MakeSlice(typ, len(str), len(str)))
+ for i := 0; i < len(str); i++ {
+ v.Elem(i).(*reflect.UintValue).Set(uint64(str[i]))
+ }
+ case *reflect.FloatValue:
+ s.skipSpace(false)
+ v.Set(s.convertFloat(s.floatToken(), v.Type().Bits()))
+ case *reflect.ComplexValue:
+ v.Set(s.scanComplex(verb, v.Type().Bits()))
+ default:
+ CantHandle:
+ s.errorString("Scan: can't handle type: " + val.Type().String())
+ }
+ }
+}
+
+// errorHandler turns local panics into error returns. EOFs are benign.
+func errorHandler(errp *os.Error) {
+ if e := recover(); e != nil {
+ if se, ok := e.(scanError); ok { // catch local error
+ if se.err != os.EOF {
+ *errp = se.err
+ }
+ } else {
+ panic(e)
+ }
+ }
+}
+
+// doScan does the real work for scanning without a format string.
+// At the moment, it handles only pointers to basic types.
+func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
+ defer errorHandler(&err)
+ for _, field := range a {
+ s.scanOne('v', field)
+ numProcessed++
+ }
+ // Check for newline if required.
+ if !s.nlIsSpace {
+ for {
+ rune := s.getRune()
+ if rune == '\n' || rune == EOF {
+ break
+ }
+ if !unicode.IsSpace(rune) {
+ s.errorString("Scan: expected newline")
+ break
+ }
+ }
+ }
+ return
+}
+
+// advance determines whether the next characters in the input match
+// those of the format. It returns the number of bytes (sic) consumed
+// in the format. Newlines included, all runs of space characters in
+// either input or format behave as a single space. This routine also
+// handles the %% case. If the return value is zero, either format
+// starts with a % (with no following %) or the input is empty.
+// If it is negative, the input did not match the string.
+func (s *ss) advance(format string) (i int) {
+ for i < len(format) {
+ fmtc, w := utf8.DecodeRuneInString(format[i:])
+ if fmtc == '%' {
+ // %% acts like a real percent
+ nextc, _ := utf8.DecodeRuneInString(format[i+w:]) // will not match % if string is empty
+ if nextc != '%' {
+ return
+ }
+ i += w // skip the first %
+ }
+ sawSpace := false
+ for unicode.IsSpace(fmtc) && i < len(format) {
+ sawSpace = true
+ i += w
+ fmtc, w = utf8.DecodeRuneInString(format[i:])
+ }
+ if sawSpace {
+ // There was space in the format, so there should be space (EOF)
+ // in the input.
+ inputc := s.getRune()
+ if inputc == EOF {
+ return
+ }
+ if !unicode.IsSpace(inputc) {
+ // Space in format but not in input: error
+ s.errorString("expected space in input to match format")
+ }
+ s.skipSpace(true)
+ continue
+ }
+ inputc := s.mustGetRune()
+ if fmtc != inputc {
+ s.UngetRune()
+ return -1
+ }
+ i += w
+ }
+ return
+}
+
+// doScanf does the real work when scanning with a format string.
+// At the moment, it handles only pointers to basic types.
+func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.Error) {
+ defer errorHandler(&err)
+ end := len(format) - 1
+ // We process one item per non-trivial format
+ for i := 0; i <= end; {
+ w := s.advance(format[i:])
+ if w > 0 {
+ i += w
+ continue
+ }
+ // Either we failed to advance, we have a percent character, or we ran out of input.
+ if format[i] != '%' {
+ // Can't advance format. Why not?
+ if w < 0 {
+ s.errorString("input does not match format")
+ }
+ // Otherwise at EOF; "too many operands" error handled below
+ break
+ }
+ i++ // % is one byte
+
+ // do we have 20 (width)?
+ s.maxWid, s.widPresent, i = parsenum(format, i, end)
+
+ c, w := utf8.DecodeRuneInString(format[i:])
+ i += w
+
+ if numProcessed >= len(a) { // out of operands
+ s.errorString("too few operands for format %" + format[i-w:])
+ break
+ }
+ field := a[numProcessed]
+
+ s.scanOne(c, field)
+ numProcessed++
+ }
+ if numProcessed < len(a) {
+ s.errorString("too many operands")
+ }
+ return
+}
diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go
new file mode 100644
index 000000000..78b9fbb4a
--- /dev/null
+++ b/libgo/go/fmt/scan_test.go
@@ -0,0 +1,659 @@
+// 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 fmt_test
+
+import (
+ "bufio"
+ . "fmt"
+ "io"
+ "math"
+ "os"
+ "reflect"
+ "regexp"
+ "strings"
+ "testing"
+ "utf8"
+)
+
+type ScanTest struct {
+ text string
+ in interface{}
+ out interface{}
+}
+
+type ScanfTest struct {
+ format string
+ text string
+ in interface{}
+ out interface{}
+}
+
+type ScanfMultiTest struct {
+ format string
+ text string
+ in []interface{}
+ out []interface{}
+ err string
+}
+
+var (
+ boolVal bool
+ intVal int
+ int8Val int8
+ int16Val int16
+ int32Val int32
+ int64Val int64
+ uintVal uint
+ uint8Val uint8
+ uint16Val uint16
+ uint32Val uint32
+ uint64Val uint64
+ float32Val float32
+ float64Val float64
+ stringVal string
+ stringVal1 string
+ bytesVal []byte
+ complex64Val complex64
+ complex128Val complex128
+ renamedBoolVal renamedBool
+ renamedIntVal renamedInt
+ renamedInt8Val renamedInt8
+ renamedInt16Val renamedInt16
+ renamedInt32Val renamedInt32
+ renamedInt64Val renamedInt64
+ renamedUintVal renamedUint
+ renamedUint8Val renamedUint8
+ renamedUint16Val renamedUint16
+ renamedUint32Val renamedUint32
+ renamedUint64Val renamedUint64
+ renamedUintptrVal renamedUintptr
+ renamedStringVal renamedString
+ renamedBytesVal renamedBytes
+ renamedFloat32Val renamedFloat32
+ renamedFloat64Val renamedFloat64
+ renamedComplex64Val renamedComplex64
+ renamedComplex128Val renamedComplex128
+)
+
+type FloatTest struct {
+ text string
+ in float64
+ out float64
+}
+
+// Xs accepts any non-empty run of the verb character
+type Xs string
+
+func (x *Xs) Scan(state ScanState, verb int) os.Error {
+ var tok string
+ var c int
+ var err os.Error
+ wid, present := state.Width()
+ if !present {
+ tok, err = state.Token()
+ } else {
+ for i := 0; i < wid; i++ {
+ c, err = state.GetRune()
+ if err != nil {
+ break
+ }
+ tok += string(c)
+ }
+ }
+ if err != nil {
+ return err
+ }
+ if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(tok) {
+ return os.ErrorString("syntax error for xs")
+ }
+ *x = Xs(tok)
+ return nil
+}
+
+var xVal Xs
+
+// myStringReader implements Read but not ReadRune, allowing us to test our readRune wrapper
+// type that creates something that can read runes given only Read().
+type myStringReader struct {
+ r *strings.Reader
+}
+
+func (s *myStringReader) Read(p []byte) (n int, err os.Error) {
+ return s.r.Read(p)
+}
+
+func newReader(s string) *myStringReader {
+ return &myStringReader{strings.NewReader(s)}
+}
+
+var scanTests = []ScanTest{
+ // Numbers
+ {"T\n", &boolVal, true}, // boolean test vals toggle to be sure they are written
+ {"F\n", &boolVal, false}, // restored to zero value
+ {"21\n", &intVal, 21},
+ {"22\n", &int8Val, int8(22)},
+ {"23\n", &int16Val, int16(23)},
+ {"24\n", &int32Val, int32(24)},
+ {"25\n", &int64Val, int64(25)},
+ {"127\n", &int8Val, int8(127)},
+ {"-21\n", &intVal, -21},
+ {"-22\n", &int8Val, int8(-22)},
+ {"-23\n", &int16Val, int16(-23)},
+ {"-24\n", &int32Val, int32(-24)},
+ {"-25\n", &int64Val, int64(-25)},
+ {"-128\n", &int8Val, int8(-128)},
+ {"+21\n", &intVal, +21},
+ {"+22\n", &int8Val, int8(+22)},
+ {"+23\n", &int16Val, int16(+23)},
+ {"+24\n", &int32Val, int32(+24)},
+ {"+25\n", &int64Val, int64(+25)},
+ {"+127\n", &int8Val, int8(+127)},
+ {"26\n", &uintVal, uint(26)},
+ {"27\n", &uint8Val, uint8(27)},
+ {"28\n", &uint16Val, uint16(28)},
+ {"29\n", &uint32Val, uint32(29)},
+ {"30\n", &uint64Val, uint64(30)},
+ {"255\n", &uint8Val, uint8(255)},
+ {"32767\n", &int16Val, int16(32767)},
+ {"2.3\n", &float64Val, 2.3},
+ {"2.3e1\n", &float32Val, float32(2.3e1)},
+ {"2.3e2\n", &float64Val, 2.3e2},
+ {"2.35\n", &stringVal, "2.35"},
+ {"2345678\n", &bytesVal, []byte("2345678")},
+ {"(3.4e1-2i)\n", &complex128Val, 3.4e1 - 2i},
+ {"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)},
+ {"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)},
+ {"hello\n", &stringVal, "hello"},
+
+ // Renamed types
+ {"true\n", &renamedBoolVal, renamedBool(true)},
+ {"F\n", &renamedBoolVal, renamedBool(false)},
+ {"101\n", &renamedIntVal, renamedInt(101)},
+ {"102\n", &renamedIntVal, renamedInt(102)},
+ {"103\n", &renamedUintVal, renamedUint(103)},
+ {"104\n", &renamedUintVal, renamedUint(104)},
+ {"105\n", &renamedInt8Val, renamedInt8(105)},
+ {"106\n", &renamedInt16Val, renamedInt16(106)},
+ {"107\n", &renamedInt32Val, renamedInt32(107)},
+ {"108\n", &renamedInt64Val, renamedInt64(108)},
+ {"109\n", &renamedUint8Val, renamedUint8(109)},
+ {"110\n", &renamedUint16Val, renamedUint16(110)},
+ {"111\n", &renamedUint32Val, renamedUint32(111)},
+ {"112\n", &renamedUint64Val, renamedUint64(112)},
+ {"113\n", &renamedUintptrVal, renamedUintptr(113)},
+ {"114\n", &renamedStringVal, renamedString("114")},
+ {"115\n", &renamedBytesVal, renamedBytes([]byte("115"))},
+
+ // Custom scanner.
+ {" vvv ", &xVal, Xs("vvv")},
+
+ // Fixed bugs
+ {"2147483648\n", &int64Val, int64(2147483648)}, // was: integer overflow
+}
+
+var scanfTests = []ScanfTest{
+ {"%v", "TRUE\n", &boolVal, true},
+ {"%t", "false\n", &boolVal, false},
+ {"%v", "-71\n", &intVal, -71},
+ {"%d", "72\n", &intVal, 72},
+ {"%c", "a\n", &intVal, 'a'},
+ {"%c", "\u5072\n", &intVal, 0x5072},
+ {"%c", "\u1234\n", &intVal, '\u1234'},
+ {"%d", "73\n", &int8Val, int8(73)},
+ {"%d", "+74\n", &int16Val, int16(74)},
+ {"%d", "75\n", &int32Val, int32(75)},
+ {"%d", "76\n", &int64Val, int64(76)},
+ {"%b", "1001001\n", &intVal, 73},
+ {"%o", "075\n", &intVal, 075},
+ {"%x", "a75\n", &intVal, 0xa75},
+ {"%v", "71\n", &uintVal, uint(71)},
+ {"%d", "72\n", &uintVal, uint(72)},
+ {"%d", "73\n", &uint8Val, uint8(73)},
+ {"%d", "74\n", &uint16Val, uint16(74)},
+ {"%d", "75\n", &uint32Val, uint32(75)},
+ {"%d", "76\n", &uint64Val, uint64(76)},
+ {"%b", "1001001\n", &uintVal, uint(73)},
+ {"%o", "075\n", &uintVal, uint(075)},
+ {"%x", "a75\n", &uintVal, uint(0xa75)},
+ {"%x", "A75\n", &uintVal, uint(0xa75)},
+ {"%U", "U+1234\n", &intVal, int(0x1234)},
+ {"%U", "U+4567\n", &uintVal, uint(0x4567)},
+
+ // Strings
+ {"%s", "using-%s\n", &stringVal, "using-%s"},
+ {"%x", "7573696e672d2578\n", &stringVal, "using-%x"},
+ {"%q", `"quoted\twith\\do\u0075bl\x65s"` + "\n", &stringVal, "quoted\twith\\doubles"},
+ {"%q", "`quoted with backs`\n", &stringVal, "quoted with backs"},
+
+ // Byte slices
+ {"%s", "bytes-%s\n", &bytesVal, []byte("bytes-%s")},
+ {"%x", "62797465732d2578\n", &bytesVal, []byte("bytes-%x")},
+ {"%q", `"bytes\rwith\vdo\u0075bl\x65s"` + "\n", &bytesVal, []byte("bytes\rwith\vdoubles")},
+ {"%q", "`bytes with backs`\n", &bytesVal, []byte("bytes with backs")},
+
+ // Renamed types
+ {"%v\n", "true\n", &renamedBoolVal, renamedBool(true)},
+ {"%t\n", "F\n", &renamedBoolVal, renamedBool(false)},
+ {"%v", "101\n", &renamedIntVal, renamedInt(101)},
+ {"%c", "\u0101\n", &renamedIntVal, renamedInt('\u0101')},
+ {"%o", "0146\n", &renamedIntVal, renamedInt(102)},
+ {"%v", "103\n", &renamedUintVal, renamedUint(103)},
+ {"%d", "104\n", &renamedUintVal, renamedUint(104)},
+ {"%d", "105\n", &renamedInt8Val, renamedInt8(105)},
+ {"%d", "106\n", &renamedInt16Val, renamedInt16(106)},
+ {"%d", "107\n", &renamedInt32Val, renamedInt32(107)},
+ {"%d", "108\n", &renamedInt64Val, renamedInt64(108)},
+ {"%x", "6D\n", &renamedUint8Val, renamedUint8(109)},
+ {"%o", "0156\n", &renamedUint16Val, renamedUint16(110)},
+ {"%d", "111\n", &renamedUint32Val, renamedUint32(111)},
+ {"%d", "112\n", &renamedUint64Val, renamedUint64(112)},
+ {"%d", "113\n", &renamedUintptrVal, renamedUintptr(113)},
+ {"%s", "114\n", &renamedStringVal, renamedString("114")},
+ {"%q", "\"1155\"\n", &renamedBytesVal, renamedBytes([]byte("1155"))},
+ {"%g", "116e1\n", &renamedFloat32Val, renamedFloat32(116e1)},
+ {"%g", "-11.7e+1", &renamedFloat64Val, renamedFloat64(-11.7e+1)},
+ {"%g", "11+6e1i\n", &renamedComplex64Val, renamedComplex64(11 + 6e1i)},
+ {"%g", "-11.+7e+1i", &renamedComplex128Val, renamedComplex128(-11. + 7e+1i)},
+
+ // Interesting formats
+ {"here is\tthe value:%d", "here is the\tvalue:118\n", &intVal, 118},
+ {"%% %%:%d", "% %:119\n", &intVal, 119},
+
+ // Corner cases
+ {"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)},
+
+ // Custom scanner.
+ {"%s", " sss ", &xVal, Xs("sss")},
+ {"%2s", "sssss", &xVal, Xs("ss")},
+
+ // Fixed bugs
+ {"%d\n", "27\n", &intVal, 27}, // ok
+ {"%d\n", "28 \n", &intVal, 28}, // was: "unexpected newline"
+}
+
+var overflowTests = []ScanTest{
+ {"128", &int8Val, 0},
+ {"32768", &int16Val, 0},
+ {"-129", &int8Val, 0},
+ {"-32769", &int16Val, 0},
+ {"256", &uint8Val, 0},
+ {"65536", &uint16Val, 0},
+ {"1e100", &float32Val, 0},
+ {"1e500", &float64Val, 0},
+ {"(1e100+0i)", &complex64Val, 0},
+ {"(1+1e100i)", &complex64Val, 0},
+ {"(1-1e500i)", &complex128Val, 0},
+}
+
+var i, j, k int
+var f float64
+var s, t string
+var c complex128
+var x, y Xs
+
+var multiTests = []ScanfMultiTest{
+ {"", "", nil, nil, ""},
+ {"%d", "23", args(&i), args(23), ""},
+ {"%2s%3s", "22333", args(&s, &t), args("22", "333"), ""},
+ {"%2d%3d", "44555", args(&i, &j), args(44, 555), ""},
+ {"%2d.%3d", "66.777", args(&i, &j), args(66, 777), ""},
+ {"%d, %d", "23, 18", args(&i, &j), args(23, 18), ""},
+ {"%3d22%3d", "33322333", args(&i, &j), args(333, 333), ""},
+ {"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), 2.5), ""},
+ {"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""},
+ {"%c%c%c", "2\u50c2X", args(&i, &j, &k), args('2', '\u50c2', 'X'), ""},
+
+ // Custom scanner.
+ {"%2e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
+
+ // Errors
+ {"%t", "23 18", args(&i), nil, "bad verb"},
+ {"%d %d %d", "23 18", args(&i, &j), args(23, 18), "too few operands"},
+ {"%d %d", "23 18 27", args(&i, &j, &k), args(23, 18), "too many operands"},
+ {"%c", "\u0100", args(&int8Val), nil, "overflow"},
+ {"X%d", "10X", args(&intVal), nil, "input does not match format"},
+
+ // Bad UTF-8: should see every byte.
+ {"%c%c%c", "\xc2X\xc2", args(&i, &j, &k), args(utf8.RuneError, 'X', utf8.RuneError), ""},
+}
+
+func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, os.Error)) {
+ for _, test := range scanTests {
+ var r io.Reader
+ if name == "StringReader" {
+ r = strings.NewReader(test.text)
+ } else {
+ r = newReader(test.text)
+ }
+ n, err := scan(r, test.in)
+ if err != nil {
+ t.Errorf("%s got error scanning %q: %s", name, test.text, err)
+ continue
+ }
+ if n != 1 {
+ t.Errorf("%s count error on entry %q: got %d", name, test.text, n)
+ continue
+ }
+ // The incoming value may be a pointer
+ v := reflect.NewValue(test.in)
+ if p, ok := v.(*reflect.PtrValue); ok {
+ v = p.Elem()
+ }
+ val := v.Interface()
+ if !reflect.DeepEqual(val, test.out) {
+ t.Errorf("%s scanning %q: expected %v got %v, type %T", name, test.text, test.out, val, val)
+ }
+ }
+}
+
+func TestScan(t *testing.T) {
+ testScan("StringReader", t, Fscan)
+}
+
+func TestMyReaderScan(t *testing.T) {
+ testScan("myStringReader", t, Fscan)
+}
+
+func TestScanln(t *testing.T) {
+ testScan("StringReader", t, Fscanln)
+}
+
+func TestMyReaderScanln(t *testing.T) {
+ testScan("myStringReader", t, Fscanln)
+}
+
+func TestScanf(t *testing.T) {
+ for _, test := range scanfTests {
+ n, err := Sscanf(test.text, test.format, test.in)
+ if err != nil {
+ t.Errorf("got error scanning (%q, %q): %s", test.format, test.text, err)
+ continue
+ }
+ if n != 1 {
+ t.Errorf("count error on entry (%q, %q): got %d", test.format, test.text, n)
+ continue
+ }
+ // The incoming value may be a pointer
+ v := reflect.NewValue(test.in)
+ if p, ok := v.(*reflect.PtrValue); ok {
+ v = p.Elem()
+ }
+ val := v.Interface()
+ if !reflect.DeepEqual(val, test.out) {
+ t.Errorf("scanning (%q, %q): expected %v got %v, type %T", test.format, test.text, test.out, val, val)
+ }
+ }
+}
+
+func TestScanOverflow(t *testing.T) {
+ // different machines and different types report errors with different strings.
+ re := regexp.MustCompile("overflow|too large|out of range|not representable")
+ for _, test := range overflowTests {
+ _, err := Sscan(test.text, test.in)
+ if err == nil {
+ t.Errorf("expected overflow scanning %q", test.text)
+ continue
+ }
+ if !re.MatchString(err.String()) {
+ t.Errorf("expected overflow error scanning %q: %s", test.text, err)
+ }
+ }
+}
+
+func verifyNaN(str string, t *testing.T) {
+ var f float64
+ var f32 float32
+ var f64 float64
+ text := str + " " + str + " " + str
+ n, err := Fscan(strings.NewReader(text), &f, &f32, &f64)
+ if err != nil {
+ t.Errorf("got error scanning %q: %s", text, err)
+ }
+ if n != 3 {
+ t.Errorf("count error scanning %q: got %d", text, n)
+ }
+ if !math.IsNaN(float64(f)) || !math.IsNaN(float64(f32)) || !math.IsNaN(f64) {
+ t.Errorf("didn't get NaNs scanning %q: got %g %g %g", text, f, f32, f64)
+ }
+}
+
+func TestNaN(t *testing.T) {
+ for _, s := range []string{"nan", "NAN", "NaN"} {
+ verifyNaN(s, t)
+ }
+}
+
+func verifyInf(str string, t *testing.T) {
+ var f float64
+ var f32 float32
+ var f64 float64
+ text := str + " " + str + " " + str
+ n, err := Fscan(strings.NewReader(text), &f, &f32, &f64)
+ if err != nil {
+ t.Errorf("got error scanning %q: %s", text, err)
+ }
+ if n != 3 {
+ t.Errorf("count error scanning %q: got %d", text, n)
+ }
+ sign := 1
+ if str[0] == '-' {
+ sign = -1
+ }
+ if !math.IsInf(float64(f), sign) || !math.IsInf(float64(f32), sign) || !math.IsInf(f64, sign) {
+ t.Errorf("didn't get right Infs scanning %q: got %g %g %g", text, f, f32, f64)
+ }
+}
+
+
+func TestInf(t *testing.T) {
+ for _, s := range []string{"inf", "+inf", "-inf", "INF", "-INF", "+INF", "Inf", "-Inf", "+Inf"} {
+ verifyInf(s, t)
+ }
+}
+
+// TODO: there's no conversion from []T to ...T, but we can fake it. These
+// functions do the faking. We index the table by the length of the param list.
+var fscanf = []func(io.Reader, string, []interface{}) (int, os.Error){
+ 0: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f) },
+ 1: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f, i[0]) },
+ 2: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f, i[0], i[1]) },
+ 3: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f, i[0], i[1], i[2]) },
+}
+
+func testScanfMulti(name string, t *testing.T) {
+ sliceType := reflect.Typeof(make([]interface{}, 1)).(*reflect.SliceType)
+ for _, test := range multiTests {
+ var r io.Reader
+ if name == "StringReader" {
+ r = strings.NewReader(test.text)
+ } else {
+ r = newReader(test.text)
+ }
+ n, err := fscanf[len(test.in)](r, test.format, test.in)
+ if err != nil {
+ if test.err == "" {
+ t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err)
+ } else if strings.Index(err.String(), test.err) < 0 {
+ t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err)
+ }
+ continue
+ }
+ if test.err != "" {
+ t.Errorf("expected error %q error scanning (%q, %q)", test.err, test.format, test.text)
+ }
+ if n != len(test.out) {
+ t.Errorf("count error on entry (%q, %q): expected %d got %d", test.format, test.text, len(test.out), n)
+ continue
+ }
+ // Convert the slice of pointers into a slice of values
+ resultVal := reflect.MakeSlice(sliceType, n, n)
+ for i := 0; i < n; i++ {
+ v := reflect.NewValue(test.in[i]).(*reflect.PtrValue).Elem()
+ resultVal.Elem(i).(*reflect.InterfaceValue).Set(v)
+ }
+ result := resultVal.Interface()
+ if !reflect.DeepEqual(result, test.out) {
+ t.Errorf("scanning (%q, %q): expected %v got %v", test.format, test.text, test.out, result)
+ }
+ }
+}
+
+func TestScanfMulti(t *testing.T) {
+ testScanfMulti("StringReader", t)
+}
+
+func TestMyReaderScanfMulti(t *testing.T) {
+ testScanfMulti("myStringReader", t)
+}
+
+func TestScanMultiple(t *testing.T) {
+ var a int
+ var s string
+ n, err := Sscan("123abc", &a, &s)
+ if n != 2 {
+ t.Errorf("Sscan count error: expected 2: got %d", n)
+ }
+ if err != nil {
+ t.Errorf("Sscan expected no error; got %s", err)
+ }
+ if a != 123 || s != "abc" {
+ t.Errorf("Sscan wrong values: got (%d %q) expected (123 \"abc\")", a, s)
+ }
+ n, err = Sscan("asdf", &s, &a)
+ if n != 1 {
+ t.Errorf("Sscan count error: expected 1: got %d", n)
+ }
+ if err == nil {
+ t.Errorf("Sscan expected error; got none: %s", err)
+ }
+ if s != "asdf" {
+ t.Errorf("Sscan wrong values: got %q expected \"asdf\"", s)
+ }
+}
+
+// Empty strings are not valid input when scanning a string.
+func TestScanEmpty(t *testing.T) {
+ var s1, s2 string
+ n, err := Sscan("abc", &s1, &s2)
+ if n != 1 {
+ t.Errorf("Sscan count error: expected 1: got %d", n)
+ }
+ if err == nil {
+ t.Error("Sscan <one item> expected error; got none")
+ }
+ if s1 != "abc" {
+ t.Errorf("Sscan wrong values: got %q expected \"abc\"", s1)
+ }
+ n, err = Sscan("", &s1, &s2)
+ if n != 0 {
+ t.Errorf("Sscan count error: expected 0: got %d", n)
+ }
+ if err == nil {
+ t.Error("Sscan <empty> expected error; got none")
+ }
+ // Quoted empty string is OK.
+ n, err = Sscanf(`""`, "%q", &s1)
+ if n != 1 {
+ t.Errorf("Sscanf count error: expected 1: got %d", n)
+ }
+ if err != nil {
+ t.Errorf("Sscanf <empty> expected no error with quoted string; got %s", err)
+ }
+}
+
+func TestScanNotPointer(t *testing.T) {
+ r := strings.NewReader("1")
+ var a int
+ _, err := Fscan(r, a)
+ if err == nil {
+ t.Error("expected error scanning non-pointer")
+ } else if strings.Index(err.String(), "pointer") < 0 {
+ t.Errorf("expected pointer error scanning non-pointer, got: %s", err)
+ }
+}
+
+func TestScanlnNoNewline(t *testing.T) {
+ var a int
+ _, err := Sscanln("1 x\n", &a)
+ if err == nil {
+ t.Error("expected error scanning string missing newline")
+ } else if strings.Index(err.String(), "newline") < 0 {
+ t.Errorf("expected newline error scanning string missing newline, got: %s", err)
+ }
+}
+
+func TestScanlnWithMiddleNewline(t *testing.T) {
+ r := strings.NewReader("123\n456\n")
+ var a, b int
+ _, err := Fscanln(r, &a, &b)
+ if err == nil {
+ t.Error("expected error scanning string with extra newline")
+ } else if strings.Index(err.String(), "newline") < 0 {
+ t.Errorf("expected newline error scanning string with extra newline, got: %s", err)
+ }
+}
+
+// Special Reader that counts reads at end of file.
+type eofCounter struct {
+ reader *strings.Reader
+ eofCount int
+}
+
+func (ec *eofCounter) Read(b []byte) (n int, err os.Error) {
+ n, err = ec.reader.Read(b)
+ if n == 0 {
+ ec.eofCount++
+ }
+ return
+}
+
+// Verify that when we scan, we see at most EOF once per call to a Scan function,
+// and then only when it's really an EOF
+func TestEOF(t *testing.T) {
+ ec := &eofCounter{strings.NewReader("123\n"), 0}
+ var a int
+ n, err := Fscanln(ec, &a)
+ if err != nil {
+ t.Error("unexpected error", err)
+ }
+ if n != 1 {
+ t.Error("expected to scan one item, got", n)
+ }
+ if ec.eofCount != 0 {
+ t.Error("expected zero EOFs", ec.eofCount)
+ ec.eofCount = 0 // reset for next test
+ }
+ n, err = Fscanln(ec, &a)
+ if err == nil {
+ t.Error("expected error scanning empty string")
+ }
+ if n != 0 {
+ t.Error("expected to scan zero items, got", n)
+ }
+ if ec.eofCount != 1 {
+ t.Error("expected one EOF, got", ec.eofCount)
+ }
+}
+
+// Verify that, at least when using bufio, successive calls to Fscan do not lose runes.
+func TestUnreadRuneWithBufio(t *testing.T) {
+ r := bufio.NewReader(strings.NewReader("123αb"))
+ var i int
+ var a string
+ n, err := Fscanf(r, "%d", &i)
+ if n != 1 || err != nil {
+ t.Errorf("reading int expected one item, no errors; got %d %q", n, err)
+ }
+ if i != 123 {
+ t.Errorf("expected 123; got %d", i)
+ }
+ n, err = Fscanf(r, "%s", &a)
+ if n != 1 || err != nil {
+ t.Errorf("reading string expected one item, no errors; got %d %q", n, err)
+ }
+ if a != "αb" {
+ t.Errorf("expected αb; got %q", a)
+ }
+}
diff --git a/libgo/go/fmt/stringer_test.go b/libgo/go/fmt/stringer_test.go
new file mode 100644
index 000000000..0ca3f522d
--- /dev/null
+++ b/libgo/go/fmt/stringer_test.go
@@ -0,0 +1,61 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fmt_test
+
+import (
+ . "fmt"
+ "testing"
+)
+
+type TI int
+type TI8 int8
+type TI16 int16
+type TI32 int32
+type TI64 int64
+type TU uint
+type TU8 uint8
+type TU16 uint16
+type TU32 uint32
+type TU64 uint64
+type TUI uintptr
+type TF float64
+type TF32 float32
+type TF64 float64
+type TB bool
+type TS string
+
+func (v TI) String() string { return Sprintf("I: %d", int(v)) }
+func (v TI8) String() string { return Sprintf("I8: %d", int8(v)) }
+func (v TI16) String() string { return Sprintf("I16: %d", int16(v)) }
+func (v TI32) String() string { return Sprintf("I32: %d", int32(v)) }
+func (v TI64) String() string { return Sprintf("I64: %d", int64(v)) }
+func (v TU) String() string { return Sprintf("U: %d", uint(v)) }
+func (v TU8) String() string { return Sprintf("U8: %d", uint8(v)) }
+func (v TU16) String() string { return Sprintf("U16: %d", uint16(v)) }
+func (v TU32) String() string { return Sprintf("U32: %d", uint32(v)) }
+func (v TU64) String() string { return Sprintf("U64: %d", uint64(v)) }
+func (v TUI) String() string { return Sprintf("UI: %d", uintptr(v)) }
+func (v TF) String() string { return Sprintf("F: %f", float64(v)) }
+func (v TF32) String() string { return Sprintf("F32: %f", float32(v)) }
+func (v TF64) String() string { return Sprintf("F64: %f", float64(v)) }
+func (v TB) String() string { return Sprintf("B: %t", bool(v)) }
+func (v TS) String() string { return Sprintf("S: %q", string(v)) }
+
+func check(t *testing.T, got, want string) {
+ if got != want {
+ t.Error(got, "!=", want)
+ }
+}
+
+func TestStringer(t *testing.T) {
+ s := Sprintf("%v %v %v %v %v", TI(0), TI8(1), TI16(2), TI32(3), TI64(4))
+ check(t, s, "I: 0 I8: 1 I16: 2 I32: 3 I64: 4")
+ s = Sprintf("%v %v %v %v %v %v", TU(5), TU8(6), TU16(7), TU32(8), TU64(9), TUI(10))
+ check(t, s, "U: 5 U8: 6 U16: 7 U32: 8 U64: 9 UI: 10")
+ s = Sprintf("%v %v %v", TF(1.0), TF32(2.0), TF64(3.0))
+ check(t, s, "F: 1.000000 F32: 2.000000 F64: 3.000000")
+ s = Sprintf("%v %v", TB(true), TS("x"))
+ check(t, s, "B: true S: \"x\"")
+}
diff --git a/libgo/go/go/ast/ast.go b/libgo/go/go/ast/ast.go
new file mode 100644
index 000000000..cf2ce36df
--- /dev/null
+++ b/libgo/go/go/ast/ast.go
@@ -0,0 +1,959 @@
+// 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.
+
+// The AST package declares the types used to represent
+// syntax trees for Go packages.
+//
+package ast
+
+import (
+ "go/token"
+ "unicode"
+ "utf8"
+)
+
+
+// ----------------------------------------------------------------------------
+// Interfaces
+//
+// There are 3 main classes of nodes: Expressions and type nodes,
+// statement nodes, and declaration nodes. The node names usually
+// match the corresponding Go spec production names to which they
+// correspond. The node fields correspond to the individual parts
+// of the respective productions.
+//
+// All nodes contain position information marking the beginning of
+// the corresponding source text segment; it is accessible via the
+// Pos accessor method. Nodes may contain additional position info
+// for language constructs where comments may be found between parts
+// of the construct (typically any larger, parenthesized subpart).
+// That position information is needed to properly position comments
+// when printing the construct.
+
+
+// All node types implement the Node interface.
+type Node interface {
+ Pos() token.Pos // position of first character belonging to the node
+ End() token.Pos // position of first character immediately after the node
+}
+
+
+// All expression nodes implement the Expr interface.
+type Expr interface {
+ Node
+ exprNode()
+}
+
+
+// All statement nodes implement the Stmt interface.
+type Stmt interface {
+ Node
+ stmtNode()
+}
+
+
+// All declaration nodes implement the Decl interface.
+type Decl interface {
+ Node
+ declNode()
+}
+
+
+// ----------------------------------------------------------------------------
+// Comments
+
+// A Comment node represents a single //-style or /*-style comment.
+type Comment struct {
+ Slash token.Pos // position of "/" starting the comment
+ Text []byte // comment text (excluding '\n' for //-style comments)
+}
+
+
+func (c *Comment) Pos() token.Pos { return c.Slash }
+func (c *Comment) End() token.Pos { return token.Pos(int(c.Slash) + len(c.Text)) }
+
+
+// A CommentGroup represents a sequence of comments
+// with no other tokens and no empty lines between.
+//
+type CommentGroup struct {
+ List []*Comment // len(List) > 0
+}
+
+
+func (g *CommentGroup) Pos() token.Pos { return g.List[0].Pos() }
+func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() }
+
+
+// ----------------------------------------------------------------------------
+// Expressions and types
+
+// A Field represents a Field declaration list in a struct type,
+// a method list in an interface type, or a parameter/result declaration
+// in a signature.
+//
+type Field struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Names []*Ident // field/method/parameter names; or nil if anonymous field
+ Type Expr // field/method/parameter type
+ Tag *BasicLit // field tag; or nil
+ Comment *CommentGroup // line comments; or nil
+}
+
+
+func (f *Field) Pos() token.Pos {
+ if len(f.Names) > 0 {
+ return f.Names[0].Pos()
+ }
+ return f.Type.Pos()
+}
+
+
+func (f *Field) End() token.Pos {
+ if f.Tag != nil {
+ return f.Tag.End()
+ }
+ return f.Type.End()
+}
+
+
+// A FieldList represents a list of Fields, enclosed by parentheses or braces.
+type FieldList struct {
+ Opening token.Pos // position of opening parenthesis/brace, if any
+ List []*Field // field list
+ Closing token.Pos // position of closing parenthesis/brace, if any
+}
+
+
+func (f *FieldList) Pos() token.Pos {
+ if f.Opening.IsValid() {
+ return f.Opening
+ }
+ // the list should not be empty in this case;
+ // be conservative and guard against bad ASTs
+ if len(f.List) > 0 {
+ return f.List[0].Pos()
+ }
+ return token.NoPos
+}
+
+
+func (f *FieldList) End() token.Pos {
+ if f.Closing.IsValid() {
+ return f.Closing + 1
+ }
+ // the list should not be empty in this case;
+ // be conservative and guard against bad ASTs
+ if n := len(f.List); n > 0 {
+ return f.List[n-1].End()
+ }
+ return token.NoPos
+}
+
+
+// NumFields returns the number of (named and anonymous fields) in a FieldList.
+func (f *FieldList) NumFields() int {
+ n := 0
+ if f != nil {
+ for _, g := range f.List {
+ m := len(g.Names)
+ if m == 0 {
+ m = 1 // anonymous field
+ }
+ n += m
+ }
+ }
+ return n
+}
+
+
+// An expression is represented by a tree consisting of one
+// or more of the following concrete expression nodes.
+//
+type (
+ // A BadExpr node is a placeholder for expressions containing
+ // syntax errors for which no correct expression nodes can be
+ // created.
+ //
+ BadExpr struct {
+ From, To token.Pos // position range of bad expression
+ }
+
+ // An Ident node represents an identifier.
+ Ident struct {
+ NamePos token.Pos // identifier position
+ Name string // identifier name
+ Obj *Object // denoted object; or nil
+ }
+
+ // An Ellipsis node stands for the "..." type in a
+ // parameter list or the "..." length in an array type.
+ //
+ Ellipsis struct {
+ Ellipsis token.Pos // position of "..."
+ Elt Expr // ellipsis element type (parameter lists only); or nil
+ }
+
+ // A BasicLit node represents a literal of basic type.
+ BasicLit struct {
+ ValuePos token.Pos // literal position
+ Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING
+ Value []byte // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o`
+ }
+
+ // A FuncLit node represents a function literal.
+ FuncLit struct {
+ Type *FuncType // function type
+ Body *BlockStmt // function body
+ }
+
+ // A CompositeLit node represents a composite literal.
+ CompositeLit struct {
+ Type Expr // literal type; or nil
+ Lbrace token.Pos // position of "{"
+ Elts []Expr // list of composite elements; or nil
+ Rbrace token.Pos // position of "}"
+ }
+
+ // A ParenExpr node represents a parenthesized expression.
+ ParenExpr struct {
+ Lparen token.Pos // position of "("
+ X Expr // parenthesized expression
+ Rparen token.Pos // position of ")"
+ }
+
+ // A SelectorExpr node represents an expression followed by a selector.
+ SelectorExpr struct {
+ X Expr // expression
+ Sel *Ident // field selector
+ }
+
+ // An IndexExpr node represents an expression followed by an index.
+ IndexExpr struct {
+ X Expr // expression
+ Lbrack token.Pos // position of "["
+ Index Expr // index expression
+ Rbrack token.Pos // position of "]"
+ }
+
+ // An SliceExpr node represents an expression followed by slice indices.
+ SliceExpr struct {
+ X Expr // expression
+ Lbrack token.Pos // position of "["
+ Low Expr // begin of slice range; or nil
+ High Expr // end of slice range; or nil
+ Rbrack token.Pos // position of "]"
+ }
+
+ // A TypeAssertExpr node represents an expression followed by a
+ // type assertion.
+ //
+ TypeAssertExpr struct {
+ X Expr // expression
+ Type Expr // asserted type; nil means type switch X.(type)
+ }
+
+ // A CallExpr node represents an expression followed by an argument list.
+ CallExpr struct {
+ Fun Expr // function expression
+ Lparen token.Pos // position of "("
+ Args []Expr // function arguments; or nil
+ Ellipsis token.Pos // position of "...", if any
+ Rparen token.Pos // position of ")"
+ }
+
+ // A StarExpr node represents an expression of the form "*" Expression.
+ // Semantically it could be a unary "*" expression, or a pointer type.
+ //
+ StarExpr struct {
+ Star token.Pos // position of "*"
+ X Expr // operand
+ }
+
+ // A UnaryExpr node represents a unary expression.
+ // Unary "*" expressions are represented via StarExpr nodes.
+ //
+ UnaryExpr struct {
+ OpPos token.Pos // position of Op
+ Op token.Token // operator
+ X Expr // operand
+ }
+
+ // A BinaryExpr node represents a binary expression.
+ BinaryExpr struct {
+ X Expr // left operand
+ OpPos token.Pos // position of Op
+ Op token.Token // operator
+ Y Expr // right operand
+ }
+
+ // A KeyValueExpr node represents (key : value) pairs
+ // in composite literals.
+ //
+ KeyValueExpr struct {
+ Key Expr
+ Colon token.Pos // position of ":"
+ Value Expr
+ }
+)
+
+
+// The direction of a channel type is indicated by one
+// of the following constants.
+//
+type ChanDir int
+
+const (
+ SEND ChanDir = 1 << iota
+ RECV
+)
+
+
+// A type is represented by a tree consisting of one
+// or more of the following type-specific expression
+// nodes.
+//
+type (
+ // An ArrayType node represents an array or slice type.
+ ArrayType struct {
+ Lbrack token.Pos // position of "["
+ Len Expr // Ellipsis node for [...]T array types, nil for slice types
+ Elt Expr // element type
+ }
+
+ // A StructType node represents a struct type.
+ StructType struct {
+ Struct token.Pos // position of "struct" keyword
+ Fields *FieldList // list of field declarations
+ Incomplete bool // true if (source) fields are missing in the Fields list
+ }
+
+ // Pointer types are represented via StarExpr nodes.
+
+ // A FuncType node represents a function type.
+ FuncType struct {
+ Func token.Pos // position of "func" keyword
+ Params *FieldList // (incoming) parameters
+ Results *FieldList // (outgoing) results; or nil
+ }
+
+ // An InterfaceType node represents an interface type.
+ InterfaceType struct {
+ Interface token.Pos // position of "interface" keyword
+ Methods *FieldList // list of methods
+ Incomplete bool // true if (source) methods are missing in the Methods list
+ }
+
+ // A MapType node represents a map type.
+ MapType struct {
+ Map token.Pos // position of "map" keyword
+ Key Expr
+ Value Expr
+ }
+
+ // A ChanType node represents a channel type.
+ ChanType struct {
+ Begin token.Pos // position of "chan" keyword or "<-" (whichever comes first)
+ Dir ChanDir // channel direction
+ Value Expr // value type
+ }
+)
+
+
+// Pos and End implementations for expression/type nodes.
+//
+func (x *BadExpr) Pos() token.Pos { return x.From }
+func (x *Ident) Pos() token.Pos { return x.NamePos }
+func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis }
+func (x *BasicLit) Pos() token.Pos { return x.ValuePos }
+func (x *FuncLit) Pos() token.Pos { return x.Type.Pos() }
+func (x *CompositeLit) Pos() token.Pos {
+ if x.Type != nil {
+ return x.Type.Pos()
+ }
+ return x.Lbrace
+}
+func (x *ParenExpr) Pos() token.Pos { return x.Lparen }
+func (x *SelectorExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *IndexExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *TypeAssertExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() }
+func (x *StarExpr) Pos() token.Pos { return x.Star }
+func (x *UnaryExpr) Pos() token.Pos { return x.OpPos }
+func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *KeyValueExpr) Pos() token.Pos { return x.Key.Pos() }
+func (x *ArrayType) Pos() token.Pos { return x.Lbrack }
+func (x *StructType) Pos() token.Pos { return x.Struct }
+func (x *FuncType) Pos() token.Pos { return x.Func }
+func (x *InterfaceType) Pos() token.Pos { return x.Interface }
+func (x *MapType) Pos() token.Pos { return x.Map }
+func (x *ChanType) Pos() token.Pos { return x.Begin }
+
+
+func (x *BadExpr) End() token.Pos { return x.To }
+func (x *Ident) End() token.Pos { return token.Pos(int(x.NamePos) + len(x.Name)) }
+func (x *Ellipsis) End() token.Pos {
+ if x.Elt != nil {
+ return x.Elt.End()
+ }
+ return x.Ellipsis + 3 // len("...")
+}
+func (x *BasicLit) End() token.Pos { return token.Pos(int(x.ValuePos) + len(x.Value)) }
+func (x *FuncLit) End() token.Pos { return x.Body.End() }
+func (x *CompositeLit) End() token.Pos { return x.Rbrace + 1 }
+func (x *ParenExpr) End() token.Pos { return x.Rparen + 1 }
+func (x *SelectorExpr) End() token.Pos { return x.Sel.End() }
+func (x *IndexExpr) End() token.Pos { return x.Rbrack + 1 }
+func (x *SliceExpr) End() token.Pos { return x.Rbrack + 1 }
+func (x *TypeAssertExpr) End() token.Pos {
+ if x.Type != nil {
+ return x.Type.End()
+ }
+ return x.X.End()
+}
+func (x *CallExpr) End() token.Pos { return x.Rparen + 1 }
+func (x *StarExpr) End() token.Pos { return x.X.End() }
+func (x *UnaryExpr) End() token.Pos { return x.X.End() }
+func (x *BinaryExpr) End() token.Pos { return x.Y.End() }
+func (x *KeyValueExpr) End() token.Pos { return x.Value.End() }
+func (x *ArrayType) End() token.Pos { return x.Elt.End() }
+func (x *StructType) End() token.Pos { return x.Fields.End() }
+func (x *FuncType) End() token.Pos {
+ if x.Results != nil {
+ return x.Results.End()
+ }
+ return x.Params.End()
+}
+func (x *InterfaceType) End() token.Pos { return x.Methods.End() }
+func (x *MapType) End() token.Pos { return x.Value.End() }
+func (x *ChanType) End() token.Pos { return x.Value.End() }
+
+
+// exprNode() ensures that only expression/type nodes can be
+// assigned to an ExprNode.
+//
+func (x *BadExpr) exprNode() {}
+func (x *Ident) exprNode() {}
+func (x *Ellipsis) exprNode() {}
+func (x *BasicLit) exprNode() {}
+func (x *FuncLit) exprNode() {}
+func (x *CompositeLit) exprNode() {}
+func (x *ParenExpr) exprNode() {}
+func (x *SelectorExpr) exprNode() {}
+func (x *IndexExpr) exprNode() {}
+func (x *SliceExpr) exprNode() {}
+func (x *TypeAssertExpr) exprNode() {}
+func (x *CallExpr) exprNode() {}
+func (x *StarExpr) exprNode() {}
+func (x *UnaryExpr) exprNode() {}
+func (x *BinaryExpr) exprNode() {}
+func (x *KeyValueExpr) exprNode() {}
+
+func (x *ArrayType) exprNode() {}
+func (x *StructType) exprNode() {}
+func (x *FuncType) exprNode() {}
+func (x *InterfaceType) exprNode() {}
+func (x *MapType) exprNode() {}
+func (x *ChanType) exprNode() {}
+
+
+// ----------------------------------------------------------------------------
+// Convenience functions for Idents
+
+var noPos token.Pos
+
+// NewIdent creates a new Ident without position.
+// Useful for ASTs generated by code other than the Go parser.
+//
+func NewIdent(name string) *Ident { return &Ident{noPos, name, nil} }
+
+
+// IsExported returns whether name is an exported Go symbol
+// (i.e., whether it begins with an uppercase letter).
+//
+func IsExported(name string) bool {
+ ch, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(ch)
+}
+
+
+// IsExported returns whether id is an exported Go symbol
+// (i.e., whether it begins with an uppercase letter).
+//
+func (id *Ident) IsExported() bool { return IsExported(id.Name) }
+
+
+func (id *Ident) String() string {
+ if id != nil {
+ return id.Name
+ }
+ return "<nil>"
+}
+
+
+// ----------------------------------------------------------------------------
+// Statements
+
+// A statement is represented by a tree consisting of one
+// or more of the following concrete statement nodes.
+//
+type (
+ // A BadStmt node is a placeholder for statements containing
+ // syntax errors for which no correct statement nodes can be
+ // created.
+ //
+ BadStmt struct {
+ From, To token.Pos // position range of bad statement
+ }
+
+ // A DeclStmt node represents a declaration in a statement list.
+ DeclStmt struct {
+ Decl Decl
+ }
+
+ // An EmptyStmt node represents an empty statement.
+ // The "position" of the empty statement is the position
+ // of the immediately preceeding semicolon.
+ //
+ EmptyStmt struct {
+ Semicolon token.Pos // position of preceeding ";"
+ }
+
+ // A LabeledStmt node represents a labeled statement.
+ LabeledStmt struct {
+ Label *Ident
+ Colon token.Pos // position of ":"
+ Stmt Stmt
+ }
+
+ // An ExprStmt node represents a (stand-alone) expression
+ // in a statement list.
+ //
+ ExprStmt struct {
+ X Expr // expression
+ }
+
+ // An IncDecStmt node represents an increment or decrement statement.
+ IncDecStmt struct {
+ X Expr
+ TokPos token.Pos // position of Tok
+ Tok token.Token // INC or DEC
+ }
+
+ // An AssignStmt node represents an assignment or
+ // a short variable declaration.
+ //
+ AssignStmt struct {
+ Lhs []Expr
+ TokPos token.Pos // position of Tok
+ Tok token.Token // assignment token, DEFINE
+ Rhs []Expr
+ }
+
+ // A GoStmt node represents a go statement.
+ GoStmt struct {
+ Go token.Pos // position of "go" keyword
+ Call *CallExpr
+ }
+
+ // A DeferStmt node represents a defer statement.
+ DeferStmt struct {
+ Defer token.Pos // position of "defer" keyword
+ Call *CallExpr
+ }
+
+ // A ReturnStmt node represents a return statement.
+ ReturnStmt struct {
+ Return token.Pos // position of "return" keyword
+ Results []Expr // result expressions; or nil
+ }
+
+ // A BranchStmt node represents a break, continue, goto,
+ // or fallthrough statement.
+ //
+ BranchStmt struct {
+ TokPos token.Pos // position of Tok
+ Tok token.Token // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH)
+ Label *Ident // label name; or nil
+ }
+
+ // A BlockStmt node represents a braced statement list.
+ BlockStmt struct {
+ Lbrace token.Pos // position of "{"
+ List []Stmt
+ Rbrace token.Pos // position of "}"
+ }
+
+ // An IfStmt node represents an if statement.
+ IfStmt struct {
+ If token.Pos // position of "if" keyword
+ Init Stmt // initalization statement; or nil
+ Cond Expr // condition; or nil
+ Body *BlockStmt
+ Else Stmt // else branch; or nil
+ }
+
+ // A CaseClause represents a case of an expression switch statement.
+ CaseClause struct {
+ Case token.Pos // position of "case" or "default" keyword
+ Values []Expr // nil means default case
+ Colon token.Pos // position of ":"
+ Body []Stmt // statement list; or nil
+ }
+
+ // A SwitchStmt node represents an expression switch statement.
+ SwitchStmt struct {
+ Switch token.Pos // position of "switch" keyword
+ Init Stmt // initalization statement; or nil
+ Tag Expr // tag expression; or nil
+ Body *BlockStmt // CaseClauses only
+ }
+
+ // A TypeCaseClause represents a case of a type switch statement.
+ TypeCaseClause struct {
+ Case token.Pos // position of "case" or "default" keyword
+ Types []Expr // nil means default case
+ Colon token.Pos // position of ":"
+ Body []Stmt // statement list; or nil
+ }
+
+ // An TypeSwitchStmt node represents a type switch statement.
+ TypeSwitchStmt struct {
+ Switch token.Pos // position of "switch" keyword
+ Init Stmt // initalization statement; or nil
+ Assign Stmt // x := y.(type)
+ Body *BlockStmt // TypeCaseClauses only
+ }
+
+ // A CommClause node represents a case of a select statement.
+ CommClause struct {
+ Case token.Pos // position of "case" or "default" keyword
+ Tok token.Token // ASSIGN or DEFINE (valid only if Lhs != nil)
+ Lhs, Rhs Expr // Rhs == nil means default case
+ Colon token.Pos // position of ":"
+ Body []Stmt // statement list; or nil
+ }
+
+ // An SelectStmt node represents a select statement.
+ SelectStmt struct {
+ Select token.Pos // position of "select" keyword
+ Body *BlockStmt // CommClauses only
+ }
+
+ // A ForStmt represents a for statement.
+ ForStmt struct {
+ For token.Pos // position of "for" keyword
+ Init Stmt // initalization statement; or nil
+ Cond Expr // condition; or nil
+ Post Stmt // post iteration statement; or nil
+ Body *BlockStmt
+ }
+
+ // A RangeStmt represents a for statement with a range clause.
+ RangeStmt struct {
+ For token.Pos // position of "for" keyword
+ Key, Value Expr // Value may be nil
+ TokPos token.Pos // position of Tok
+ Tok token.Token // ASSIGN, DEFINE
+ X Expr // value to range over
+ Body *BlockStmt
+ }
+)
+
+
+// Pos and End implementations for statement nodes.
+//
+func (s *BadStmt) Pos() token.Pos { return s.From }
+func (s *DeclStmt) Pos() token.Pos { return s.Decl.Pos() }
+func (s *EmptyStmt) Pos() token.Pos { return s.Semicolon }
+func (s *LabeledStmt) Pos() token.Pos { return s.Label.Pos() }
+func (s *ExprStmt) Pos() token.Pos { return s.X.Pos() }
+func (s *IncDecStmt) Pos() token.Pos { return s.X.Pos() }
+func (s *AssignStmt) Pos() token.Pos { return s.Lhs[0].Pos() }
+func (s *GoStmt) Pos() token.Pos { return s.Go }
+func (s *DeferStmt) Pos() token.Pos { return s.Defer }
+func (s *ReturnStmt) Pos() token.Pos { return s.Return }
+func (s *BranchStmt) Pos() token.Pos { return s.TokPos }
+func (s *BlockStmt) Pos() token.Pos { return s.Lbrace }
+func (s *IfStmt) Pos() token.Pos { return s.If }
+func (s *CaseClause) Pos() token.Pos { return s.Case }
+func (s *SwitchStmt) Pos() token.Pos { return s.Switch }
+func (s *TypeCaseClause) Pos() token.Pos { return s.Case }
+func (s *TypeSwitchStmt) Pos() token.Pos { return s.Switch }
+func (s *CommClause) Pos() token.Pos { return s.Case }
+func (s *SelectStmt) Pos() token.Pos { return s.Select }
+func (s *ForStmt) Pos() token.Pos { return s.For }
+func (s *RangeStmt) Pos() token.Pos { return s.For }
+
+
+func (s *BadStmt) End() token.Pos { return s.To }
+func (s *DeclStmt) End() token.Pos { return s.Decl.End() }
+func (s *EmptyStmt) End() token.Pos {
+ return s.Semicolon + 1 /* len(";") */
+}
+func (s *LabeledStmt) End() token.Pos { return s.Stmt.End() }
+func (s *ExprStmt) End() token.Pos { return s.X.End() }
+func (s *IncDecStmt) End() token.Pos {
+ return s.TokPos + 2 /* len("++") */
+}
+func (s *AssignStmt) End() token.Pos { return s.Rhs[len(s.Rhs)-1].End() }
+func (s *GoStmt) End() token.Pos { return s.Call.End() }
+func (s *DeferStmt) End() token.Pos { return s.Call.End() }
+func (s *ReturnStmt) End() token.Pos {
+ if n := len(s.Results); n > 0 {
+ return s.Results[n-1].End()
+ }
+ return s.Return + 6 // len("return")
+}
+func (s *BranchStmt) End() token.Pos {
+ if s.Label != nil {
+ return s.Label.End()
+ }
+ return token.Pos(int(s.TokPos) + len(s.Tok.String()))
+}
+func (s *BlockStmt) End() token.Pos { return s.Rbrace + 1 }
+func (s *IfStmt) End() token.Pos {
+ if s.Else != nil {
+ return s.Else.End()
+ }
+ return s.Body.End()
+}
+func (s *CaseClause) End() token.Pos {
+ if n := len(s.Body); n > 0 {
+ return s.Body[n-1].End()
+ }
+ return s.Colon + 1
+}
+func (s *SwitchStmt) End() token.Pos { return s.Body.End() }
+func (s *TypeCaseClause) End() token.Pos {
+ if n := len(s.Body); n > 0 {
+ return s.Body[n-1].End()
+ }
+ return s.Colon + 1
+}
+func (s *TypeSwitchStmt) End() token.Pos { return s.Body.End() }
+func (s *CommClause) End() token.Pos {
+ if n := len(s.Body); n > 0 {
+ return s.Body[n-1].End()
+ }
+ return s.Colon + 1
+}
+func (s *SelectStmt) End() token.Pos { return s.Body.End() }
+func (s *ForStmt) End() token.Pos { return s.Body.End() }
+func (s *RangeStmt) End() token.Pos { return s.Body.End() }
+
+
+// stmtNode() ensures that only statement nodes can be
+// assigned to a StmtNode.
+//
+func (s *BadStmt) stmtNode() {}
+func (s *DeclStmt) stmtNode() {}
+func (s *EmptyStmt) stmtNode() {}
+func (s *LabeledStmt) stmtNode() {}
+func (s *ExprStmt) stmtNode() {}
+func (s *IncDecStmt) stmtNode() {}
+func (s *AssignStmt) stmtNode() {}
+func (s *GoStmt) stmtNode() {}
+func (s *DeferStmt) stmtNode() {}
+func (s *ReturnStmt) stmtNode() {}
+func (s *BranchStmt) stmtNode() {}
+func (s *BlockStmt) stmtNode() {}
+func (s *IfStmt) stmtNode() {}
+func (s *CaseClause) stmtNode() {}
+func (s *SwitchStmt) stmtNode() {}
+func (s *TypeCaseClause) stmtNode() {}
+func (s *TypeSwitchStmt) stmtNode() {}
+func (s *CommClause) stmtNode() {}
+func (s *SelectStmt) stmtNode() {}
+func (s *ForStmt) stmtNode() {}
+func (s *RangeStmt) stmtNode() {}
+
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// A Spec node represents a single (non-parenthesized) import,
+// constant, type, or variable declaration.
+//
+type (
+ // The Spec type stands for any of *ImportSpec, *ValueSpec, and *TypeSpec.
+ Spec interface {
+ Node
+ specNode()
+ }
+
+ // An ImportSpec node represents a single package import.
+ ImportSpec struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Name *Ident // local package name (including "."); or nil
+ Path *BasicLit // package path
+ Comment *CommentGroup // line comments; or nil
+ }
+
+ // A ValueSpec node represents a constant or variable declaration
+ // (ConstSpec or VarSpec production).
+ //
+ ValueSpec struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Names []*Ident // value names (len(Names) > 0)
+ Type Expr // value type; or nil
+ Values []Expr // initial values; or nil
+ Comment *CommentGroup // line comments; or nil
+ }
+
+ // A TypeSpec node represents a type declaration (TypeSpec production).
+ TypeSpec struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Name *Ident // type name
+ Type Expr // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
+ Comment *CommentGroup // line comments; or nil
+ }
+)
+
+
+// Pos and End implementations for spec nodes.
+//
+func (s *ImportSpec) Pos() token.Pos {
+ if s.Name != nil {
+ return s.Name.Pos()
+ }
+ return s.Path.Pos()
+}
+func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() }
+func (s *TypeSpec) Pos() token.Pos { return s.Name.Pos() }
+
+
+func (s *ImportSpec) End() token.Pos { return s.Path.End() }
+func (s *ValueSpec) End() token.Pos {
+ if n := len(s.Values); n > 0 {
+ return s.Values[n-1].End()
+ }
+ if s.Type != nil {
+ return s.Type.End()
+ }
+ return s.Names[len(s.Names)-1].End()
+}
+func (s *TypeSpec) End() token.Pos { return s.Type.End() }
+
+
+// specNode() ensures that only spec nodes can be
+// assigned to a Spec.
+//
+func (s *ImportSpec) specNode() {}
+func (s *ValueSpec) specNode() {}
+func (s *TypeSpec) specNode() {}
+
+
+// A declaration is represented by one of the following declaration nodes.
+//
+type (
+ // A BadDecl node is a placeholder for declarations containing
+ // syntax errors for which no correct declaration nodes can be
+ // created.
+ //
+ BadDecl struct {
+ From, To token.Pos // position range of bad declaration
+ }
+
+ // A GenDecl node (generic declaration node) represents an import,
+ // constant, type or variable declaration. A valid Lparen position
+ // (Lparen.Line > 0) indicates a parenthesized declaration.
+ //
+ // Relationship between Tok value and Specs element type:
+ //
+ // token.IMPORT *ImportSpec
+ // token.CONST *ValueSpec
+ // token.TYPE *TypeSpec
+ // token.VAR *ValueSpec
+ //
+ GenDecl struct {
+ Doc *CommentGroup // associated documentation; or nil
+ TokPos token.Pos // position of Tok
+ Tok token.Token // IMPORT, CONST, TYPE, VAR
+ Lparen token.Pos // position of '(', if any
+ Specs []Spec
+ Rparen token.Pos // position of ')', if any
+ }
+
+ // A FuncDecl node represents a function declaration.
+ FuncDecl struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Recv *FieldList // receiver (methods); or nil (functions)
+ Name *Ident // function/method name
+ Type *FuncType // position of Func keyword, parameters and results
+ Body *BlockStmt // function body; or nil (forward declaration)
+ }
+)
+
+
+// Pos and End implementations for declaration nodes.
+//
+func (d *BadDecl) Pos() token.Pos { return d.From }
+func (d *GenDecl) Pos() token.Pos { return d.TokPos }
+func (d *FuncDecl) Pos() token.Pos { return d.Type.Pos() }
+
+
+func (d *BadDecl) End() token.Pos { return d.To }
+func (d *GenDecl) End() token.Pos {
+ if d.Rparen.IsValid() {
+ return d.Rparen + 1
+ }
+ return d.Specs[0].End()
+}
+func (d *FuncDecl) End() token.Pos {
+ if d.Body != nil {
+ return d.Body.End()
+ }
+ return d.Type.End()
+}
+
+
+// declNode() ensures that only declaration nodes can be
+// assigned to a DeclNode.
+//
+func (d *BadDecl) declNode() {}
+func (d *GenDecl) declNode() {}
+func (d *FuncDecl) declNode() {}
+
+
+// ----------------------------------------------------------------------------
+// Files and packages
+
+// A File node represents a Go source file.
+//
+// The Comments list contains all comments in the source file in order of
+// appearance, including the comments that are pointed to from other nodes
+// via Doc and Comment fields.
+//
+type File struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Package token.Pos // position of "package" keyword
+ Name *Ident // package name
+ Decls []Decl // top-level declarations; or nil
+ Comments []*CommentGroup // list of all comments in the source file
+}
+
+
+func (f *File) Pos() token.Pos { return f.Package }
+func (f *File) End() token.Pos {
+ if n := len(f.Decls); n > 0 {
+ return f.Decls[n-1].End()
+ }
+ return f.Name.End()
+}
+
+
+// A Package node represents a set of source files
+// collectively building a Go package.
+//
+type Package struct {
+ Name string // package name
+ Scope *Scope // package scope; or nil
+ Files map[string]*File // Go source files by filename
+}
+
+
+func (p *Package) Pos() token.Pos { return token.NoPos }
+func (p *Package) End() token.Pos { return token.NoPos }
diff --git a/libgo/go/go/ast/filter.go b/libgo/go/go/ast/filter.go
new file mode 100644
index 000000000..0c3cef4b2
--- /dev/null
+++ b/libgo/go/go/ast/filter.go
@@ -0,0 +1,429 @@
+// 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 ast
+
+import "go/token"
+
+// ----------------------------------------------------------------------------
+// Export filtering
+
+func identListExports(list []*Ident) []*Ident {
+ j := 0
+ for _, x := range list {
+ if x.IsExported() {
+ list[j] = x
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+
+// isExportedType assumes that typ is a correct type.
+func isExportedType(typ Expr) bool {
+ switch t := typ.(type) {
+ case *Ident:
+ return t.IsExported()
+ case *ParenExpr:
+ return isExportedType(t.X)
+ case *SelectorExpr:
+ // assume t.X is a typename
+ return t.Sel.IsExported()
+ case *StarExpr:
+ return isExportedType(t.X)
+ }
+ return false
+}
+
+
+func fieldListExports(fields *FieldList, incomplete *bool) {
+ if fields == nil {
+ return
+ }
+ list := fields.List
+ j := 0
+ for _, f := range list {
+ exported := false
+ if len(f.Names) == 0 {
+ // anonymous field
+ // (Note that a non-exported anonymous field
+ // may still refer to a type with exported
+ // fields, so this is not absolutely correct.
+ // However, this cannot be done w/o complete
+ // type information.)
+ exported = isExportedType(f.Type)
+ } else {
+ n := len(f.Names)
+ f.Names = identListExports(f.Names)
+ if len(f.Names) < n {
+ *incomplete = true
+ }
+ exported = len(f.Names) > 0
+ }
+ if exported {
+ typeExports(f.Type)
+ list[j] = f
+ j++
+ }
+ }
+ if j < len(list) {
+ *incomplete = true
+ }
+ fields.List = list[0:j]
+}
+
+
+func paramListExports(fields *FieldList) {
+ if fields == nil {
+ return
+ }
+ for _, f := range fields.List {
+ typeExports(f.Type)
+ }
+}
+
+
+func typeExports(typ Expr) {
+ switch t := typ.(type) {
+ case *ArrayType:
+ typeExports(t.Elt)
+ case *StructType:
+ fieldListExports(t.Fields, &t.Incomplete)
+ case *FuncType:
+ paramListExports(t.Params)
+ paramListExports(t.Results)
+ case *InterfaceType:
+ fieldListExports(t.Methods, &t.Incomplete)
+ case *MapType:
+ typeExports(t.Key)
+ typeExports(t.Value)
+ case *ChanType:
+ typeExports(t.Value)
+ }
+}
+
+
+func specExports(spec Spec) bool {
+ switch s := spec.(type) {
+ case *ValueSpec:
+ s.Names = identListExports(s.Names)
+ if len(s.Names) > 0 {
+ typeExports(s.Type)
+ return true
+ }
+ case *TypeSpec:
+ if s.Name.IsExported() {
+ typeExports(s.Type)
+ return true
+ }
+ }
+ return false
+}
+
+
+func specListExports(list []Spec) []Spec {
+ j := 0
+ for _, s := range list {
+ if specExports(s) {
+ list[j] = s
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+
+func declExports(decl Decl) bool {
+ switch d := decl.(type) {
+ case *GenDecl:
+ d.Specs = specListExports(d.Specs)
+ return len(d.Specs) > 0
+ case *FuncDecl:
+ d.Body = nil // strip body
+ return d.Name.IsExported()
+ }
+ return false
+}
+
+
+// FileExports trims the AST for a Go source file in place such that only
+// exported nodes remain: all top-level identifiers which are not exported
+// and their associated information (such as type, initial value, or function
+// body) are removed. Non-exported fields and methods of exported types are
+// stripped, and the function bodies of exported functions are set to nil.
+// The File.comments list is not changed.
+//
+// FileExports returns true if there is an exported declaration; it returns
+// false otherwise.
+//
+func FileExports(src *File) bool {
+ j := 0
+ for _, d := range src.Decls {
+ if declExports(d) {
+ src.Decls[j] = d
+ j++
+ }
+ }
+ src.Decls = src.Decls[0:j]
+ return j > 0
+}
+
+
+// PackageExports trims the AST for a Go package in place such that only
+// exported nodes remain. The pkg.Files list is not changed, so that file
+// names and top-level package comments don't get lost.
+//
+// PackageExports returns true if there is an exported declaration; it
+// returns false otherwise.
+//
+func PackageExports(pkg *Package) bool {
+ hasExports := false
+ for _, f := range pkg.Files {
+ if FileExports(f) {
+ hasExports = true
+ }
+ }
+ return hasExports
+}
+
+
+// ----------------------------------------------------------------------------
+// General filtering
+
+type Filter func(string) bool
+
+func filterIdentList(list []*Ident, f Filter) []*Ident {
+ j := 0
+ for _, x := range list {
+ if f(x.Name) {
+ list[j] = x
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+
+func filterSpec(spec Spec, f Filter) bool {
+ switch s := spec.(type) {
+ case *ValueSpec:
+ s.Names = filterIdentList(s.Names, f)
+ return len(s.Names) > 0
+ case *TypeSpec:
+ return f(s.Name.Name)
+ }
+ return false
+}
+
+
+func filterSpecList(list []Spec, f Filter) []Spec {
+ j := 0
+ for _, s := range list {
+ if filterSpec(s, f) {
+ list[j] = s
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+
+func filterDecl(decl Decl, f Filter) bool {
+ switch d := decl.(type) {
+ case *GenDecl:
+ d.Specs = filterSpecList(d.Specs, f)
+ return len(d.Specs) > 0
+ case *FuncDecl:
+ return f(d.Name.Name)
+ }
+ return false
+}
+
+
+// FilterFile trims the AST for a Go file in place by removing all
+// names from top-level declarations (but not from parameter lists
+// or inside types) that don't pass through the filter f. If the
+// declaration is empty afterwards, the declaration is removed from
+// the AST.
+// The File.comments list is not changed.
+//
+// FilterFile returns true if there are any top-level declarations
+// left after filtering; it returns false otherwise.
+//
+func FilterFile(src *File, f Filter) bool {
+ j := 0
+ for _, d := range src.Decls {
+ if filterDecl(d, f) {
+ src.Decls[j] = d
+ j++
+ }
+ }
+ src.Decls = src.Decls[0:j]
+ return j > 0
+}
+
+
+// FilterPackage trims the AST for a Go package in place by removing all
+// names from top-level declarations (but not from parameter lists
+// or inside types) that don't pass through the filter f. If the
+// declaration is empty afterwards, the declaration is removed from
+// the AST.
+// The pkg.Files list is not changed, so that file names and top-level
+// package comments don't get lost.
+//
+// FilterPackage returns true if there are any top-level declarations
+// left after filtering; it returns false otherwise.
+//
+func FilterPackage(pkg *Package, f Filter) bool {
+ hasDecls := false
+ for _, src := range pkg.Files {
+ if FilterFile(src, f) {
+ hasDecls = true
+ }
+ }
+ return hasDecls
+}
+
+
+// ----------------------------------------------------------------------------
+// Merging of package files
+
+// The MergeMode flags control the behavior of MergePackageFiles.
+type MergeMode uint
+
+const (
+ // If set, duplicate function declarations are excluded.
+ FilterFuncDuplicates MergeMode = 1 << iota
+ // If set, comments that are not associated with a specific
+ // AST node (as Doc or Comment) are excluded.
+ FilterUnassociatedComments
+)
+
+// separator is an empty //-style comment that is interspersed between
+// different comment groups when they are concatenated into a single group
+//
+var separator = &Comment{noPos, []byte("//")}
+
+
+// MergePackageFiles creates a file AST by merging the ASTs of the
+// files belonging to a package. The mode flags control merging behavior.
+//
+func MergePackageFiles(pkg *Package, mode MergeMode) *File {
+ // Count the number of package docs, comments and declarations across
+ // all package files.
+ ndocs := 0
+ ncomments := 0
+ ndecls := 0
+ for _, f := range pkg.Files {
+ if f.Doc != nil {
+ ndocs += len(f.Doc.List) + 1 // +1 for separator
+ }
+ ncomments += len(f.Comments)
+ ndecls += len(f.Decls)
+ }
+
+ // Collect package comments from all package files into a single
+ // CommentGroup - the collected package documentation. The order
+ // is unspecified. In general there should be only one file with
+ // a package comment; but it's better to collect extra comments
+ // than drop them on the floor.
+ var doc *CommentGroup
+ var pos token.Pos
+ if ndocs > 0 {
+ list := make([]*Comment, ndocs-1) // -1: no separator before first group
+ i := 0
+ for _, f := range pkg.Files {
+ if f.Doc != nil {
+ if i > 0 {
+ // not the first group - add separator
+ list[i] = separator
+ i++
+ }
+ for _, c := range f.Doc.List {
+ list[i] = c
+ i++
+ }
+ if f.Package > pos {
+ // Keep the maximum package clause position as
+ // position for the package clause of the merged
+ // files.
+ pos = f.Package
+ }
+ }
+ }
+ doc = &CommentGroup{list}
+ }
+
+ // Collect declarations from all package files.
+ var decls []Decl
+ if ndecls > 0 {
+ decls = make([]Decl, ndecls)
+ funcs := make(map[string]int) // map of global function name -> decls index
+ i := 0 // current index
+ n := 0 // number of filtered entries
+ for _, f := range pkg.Files {
+ for _, d := range f.Decls {
+ if mode&FilterFuncDuplicates != 0 {
+ // A language entity may be declared multiple
+ // times in different package files; only at
+ // build time declarations must be unique.
+ // For now, exclude multiple declarations of
+ // functions - keep the one with documentation.
+ //
+ // TODO(gri): Expand this filtering to other
+ // entities (const, type, vars) if
+ // multiple declarations are common.
+ if f, isFun := d.(*FuncDecl); isFun {
+ name := f.Name.Name
+ if j, exists := funcs[name]; exists {
+ // function declared already
+ if decls[j] != nil && decls[j].(*FuncDecl).Doc == nil {
+ // existing declaration has no documentation;
+ // ignore the existing declaration
+ decls[j] = nil
+ } else {
+ // ignore the new declaration
+ d = nil
+ }
+ n++ // filtered an entry
+ } else {
+ funcs[name] = i
+ }
+ }
+ }
+ decls[i] = d
+ i++
+ }
+ }
+
+ // Eliminate nil entries from the decls list if entries were
+ // filtered. We do this using a 2nd pass in order to not disturb
+ // the original declaration order in the source (otherwise, this
+ // would also invalidate the monotonically increasing position
+ // info within a single file).
+ if n > 0 {
+ i = 0
+ for _, d := range decls {
+ if d != nil {
+ decls[i] = d
+ i++
+ }
+ }
+ decls = decls[0:i]
+ }
+ }
+
+ // Collect comments from all package files.
+ var comments []*CommentGroup
+ if mode&FilterUnassociatedComments == 0 {
+ comments = make([]*CommentGroup, ncomments)
+ i := 0
+ for _, f := range pkg.Files {
+ i += copy(comments[i:], f.Comments)
+ }
+ }
+
+ return &File{doc, pos, NewIdent(pkg.Name), decls, comments}
+}
diff --git a/libgo/go/go/ast/print.go b/libgo/go/go/ast/print.go
new file mode 100644
index 000000000..d71490d4a
--- /dev/null
+++ b/libgo/go/go/ast/print.go
@@ -0,0 +1,217 @@
+// 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.
+
+// This file contains printing suppport for ASTs.
+
+package ast
+
+import (
+ "fmt"
+ "go/token"
+ "io"
+ "os"
+ "reflect"
+)
+
+
+// A FieldFilter may be provided to Fprint to control the output.
+type FieldFilter func(name string, value reflect.Value) bool
+
+
+// NotNilFilter returns true for field values that are not nil;
+// it returns false otherwise.
+func NotNilFilter(_ string, value reflect.Value) bool {
+ v, ok := value.(interface {
+ IsNil() bool
+ })
+ return !ok || !v.IsNil()
+}
+
+
+// Fprint prints the (sub-)tree starting at AST node x to w.
+//
+// A non-nil FieldFilter f may be provided to control the output:
+// struct fields for which f(fieldname, fieldvalue) is true are
+// are printed; all others are filtered from the output.
+//
+func Fprint(w io.Writer, x interface{}, f FieldFilter) (n int, err os.Error) {
+ // setup printer
+ p := printer{
+ output: w,
+ filter: f,
+ ptrmap: make(map[interface{}]int),
+ last: '\n', // force printing of line number on first line
+ }
+
+ // install error handler
+ defer func() {
+ n = p.written
+ if e := recover(); e != nil {
+ err = e.(localError).err // re-panics if it's not a localError
+ }
+ }()
+
+ // print x
+ if x == nil {
+ p.printf("nil\n")
+ return
+ }
+ p.print(reflect.NewValue(x))
+ p.printf("\n")
+
+ return
+}
+
+
+// Print prints x to standard output, skipping nil fields.
+// Print(x) is the same as Fprint(os.Stdout, x, NotNilFilter).
+func Print(x interface{}) (int, os.Error) {
+ return Fprint(os.Stdout, x, NotNilFilter)
+}
+
+
+type printer struct {
+ output io.Writer
+ filter FieldFilter
+ ptrmap map[interface{}]int // *reflect.PtrValue -> line number
+ written int // number of bytes written to output
+ indent int // current indentation level
+ last byte // the last byte processed by Write
+ line int // current line number
+}
+
+
+var indent = []byte(". ")
+
+func (p *printer) Write(data []byte) (n int, err os.Error) {
+ var m int
+ for i, b := range data {
+ // invariant: data[0:n] has been written
+ if b == '\n' {
+ m, err = p.output.Write(data[n : i+1])
+ n += m
+ if err != nil {
+ return
+ }
+ p.line++
+ } else if p.last == '\n' {
+ _, err = fmt.Fprintf(p.output, "%6d ", p.line)
+ if err != nil {
+ return
+ }
+ for j := p.indent; j > 0; j-- {
+ _, err = p.output.Write(indent)
+ if err != nil {
+ return
+ }
+ }
+ }
+ p.last = b
+ }
+ m, err = p.output.Write(data[n:])
+ n += m
+ return
+}
+
+
+// localError wraps locally caught os.Errors so we can distinguish
+// them from genuine panics which we don't want to return as errors.
+type localError struct {
+ err os.Error
+}
+
+
+// printf is a convenience wrapper that takes care of print errors.
+func (p *printer) printf(format string, args ...interface{}) {
+ n, err := fmt.Fprintf(p, format, args...)
+ p.written += n
+ if err != nil {
+ panic(localError{err})
+ }
+}
+
+
+// Implementation note: Print is written for AST nodes but could be
+// used to print arbitrary data structures; such a version should
+// probably be in a different package.
+
+func (p *printer) print(x reflect.Value) {
+ // Note: This test is only needed because AST nodes
+ // embed a token.Position, and thus all of them
+ // understand the String() method (but it only
+ // applies to the Position field).
+ // TODO: Should reconsider this AST design decision.
+ if pos, ok := x.Interface().(token.Position); ok {
+ p.printf("%s", pos)
+ return
+ }
+
+ if !NotNilFilter("", x) {
+ p.printf("nil")
+ return
+ }
+
+ switch v := x.(type) {
+ case *reflect.InterfaceValue:
+ p.print(v.Elem())
+
+ case *reflect.MapValue:
+ p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
+ p.indent++
+ for _, key := range v.Keys() {
+ p.print(key)
+ p.printf(": ")
+ p.print(v.Elem(key))
+ }
+ p.indent--
+ p.printf("}")
+
+ case *reflect.PtrValue:
+ p.printf("*")
+ // type-checked ASTs may contain cycles - use ptrmap
+ // to keep track of objects that have been printed
+ // already and print the respective line number instead
+ ptr := v.Interface()
+ if line, exists := p.ptrmap[ptr]; exists {
+ p.printf("(obj @ %d)", line)
+ } else {
+ p.ptrmap[ptr] = p.line
+ p.print(v.Elem())
+ }
+
+ case *reflect.SliceValue:
+ if s, ok := v.Interface().([]byte); ok {
+ p.printf("%#q", s)
+ return
+ }
+ p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
+ p.indent++
+ for i, n := 0, v.Len(); i < n; i++ {
+ p.printf("%d: ", i)
+ p.print(v.Elem(i))
+ p.printf("\n")
+ }
+ p.indent--
+ p.printf("}")
+
+ case *reflect.StructValue:
+ p.printf("%s {\n", x.Type().String())
+ p.indent++
+ t := v.Type().(*reflect.StructType)
+ for i, n := 0, t.NumField(); i < n; i++ {
+ name := t.Field(i).Name
+ value := v.Field(i)
+ if p.filter == nil || p.filter(name, value) {
+ p.printf("%s: ", name)
+ p.print(value)
+ p.printf("\n")
+ }
+ }
+ p.indent--
+ p.printf("}")
+
+ default:
+ p.printf("%v", x.Interface())
+ }
+}
diff --git a/libgo/go/go/ast/scope.go b/libgo/go/go/ast/scope.go
new file mode 100644
index 000000000..956a208ae
--- /dev/null
+++ b/libgo/go/go/ast/scope.go
@@ -0,0 +1,242 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements scopes, the objects they contain,
+// and object types.
+
+package ast
+
+// A Scope maintains the set of named language entities declared
+// in the scope and a link to the immediately surrounding (outer)
+// scope.
+//
+type Scope struct {
+ Outer *Scope
+ Objects []*Object // in declaration order
+ // Implementation note: In some cases (struct fields,
+ // function parameters) we need the source order of
+ // variables. Thus for now, we store scope entries
+ // in a linear list. If scopes become very large
+ // (say, for packages), we may need to change this
+ // to avoid slow lookups.
+}
+
+
+// NewScope creates a new scope nested in the outer scope.
+func NewScope(outer *Scope) *Scope {
+ const n = 4 // initial scope capacity, must be > 0
+ return &Scope{outer, make([]*Object, 0, n)}
+}
+
+
+// Lookup returns the object with the given name if it is
+// found in scope s, otherwise it returns nil. Outer scopes
+// are ignored.
+//
+// Lookup always returns nil if name is "_", even if the scope
+// contains objects with that name.
+//
+func (s *Scope) Lookup(name string) *Object {
+ if name != "_" {
+ for _, obj := range s.Objects {
+ if obj.Name == name {
+ return obj
+ }
+ }
+ }
+ return nil
+}
+
+
+// Insert attempts to insert a named object into the scope s.
+// If the scope does not contain an object with that name yet
+// or if the object is named "_", Insert inserts the object
+// and returns it. Otherwise, Insert leaves the scope unchanged
+// and returns the object found in the scope instead.
+//
+func (s *Scope) Insert(obj *Object) *Object {
+ alt := s.Lookup(obj.Name)
+ if alt == nil {
+ s.append(obj)
+ alt = obj
+ }
+ return alt
+}
+
+
+func (s *Scope) append(obj *Object) {
+ s.Objects = append(s.Objects, obj)
+}
+
+// ----------------------------------------------------------------------------
+// Objects
+
+// An Object describes a language entity such as a package,
+// constant, type, variable, or function (incl. methods).
+//
+type Object struct {
+ Kind Kind
+ Name string // declared name
+ Type *Type
+ Decl interface{} // corresponding Field, XxxSpec or FuncDecl
+ N int // value of iota for this declaration
+}
+
+
+// NewObj creates a new object of a given kind and name.
+func NewObj(kind Kind, name string) *Object {
+ return &Object{Kind: kind, Name: name}
+}
+
+
+// Kind describes what an object represents.
+type Kind int
+
+// The list of possible Object kinds.
+const (
+ Bad Kind = iota // for error handling
+ Pkg // package
+ Con // constant
+ Typ // type
+ Var // variable
+ Fun // function or method
+)
+
+
+var objKindStrings = [...]string{
+ Bad: "bad",
+ Pkg: "package",
+ Con: "const",
+ Typ: "type",
+ Var: "var",
+ Fun: "func",
+}
+
+
+func (kind Kind) String() string { return objKindStrings[kind] }
+
+
+// IsExported returns whether obj is exported.
+func (obj *Object) IsExported() bool { return IsExported(obj.Name) }
+
+
+// ----------------------------------------------------------------------------
+// Types
+
+// A Type represents a Go type.
+type Type struct {
+ Form Form
+ Obj *Object // corresponding type name, or nil
+ Scope *Scope // fields and methods, always present
+ N uint // basic type id, array length, number of function results, or channel direction
+ Key, Elt *Type // map key and array, pointer, slice, map or channel element
+ Params *Scope // function (receiver, input and result) parameters, tuple expressions (results of function calls), or nil
+ Expr Expr // corresponding AST expression
+}
+
+
+// NewType creates a new type of a given form.
+func NewType(form Form) *Type {
+ return &Type{Form: form, Scope: NewScope(nil)}
+}
+
+
+// Form describes the form of a type.
+type Form int
+
+// The list of possible type forms.
+const (
+ BadType Form = iota // for error handling
+ Unresolved // type not fully setup
+ Basic
+ Array
+ Struct
+ Pointer
+ Function
+ Method
+ Interface
+ Slice
+ Map
+ Channel
+ Tuple
+)
+
+
+var formStrings = [...]string{
+ BadType: "badType",
+ Unresolved: "unresolved",
+ Basic: "basic",
+ Array: "array",
+ Struct: "struct",
+ Pointer: "pointer",
+ Function: "function",
+ Method: "method",
+ Interface: "interface",
+ Slice: "slice",
+ Map: "map",
+ Channel: "channel",
+ Tuple: "tuple",
+}
+
+
+func (form Form) String() string { return formStrings[form] }
+
+
+// The list of basic type id's.
+const (
+ Bool = iota
+ Byte
+ Uint
+ Int
+ Float
+ Complex
+ Uintptr
+ String
+
+ Uint8
+ Uint16
+ Uint32
+ Uint64
+
+ Int8
+ Int16
+ Int32
+ Int64
+
+ Float32
+ Float64
+
+ Complex64
+ Complex128
+
+ // TODO(gri) ideal types are missing
+)
+
+
+var BasicTypes = map[uint]string{
+ Bool: "bool",
+ Byte: "byte",
+ Uint: "uint",
+ Int: "int",
+ Float: "float",
+ Complex: "complex",
+ Uintptr: "uintptr",
+ String: "string",
+
+ Uint8: "uint8",
+ Uint16: "uint16",
+ Uint32: "uint32",
+ Uint64: "uint64",
+
+ Int8: "int8",
+ Int16: "int16",
+ Int32: "int32",
+ Int64: "int64",
+
+ Float32: "float32",
+ Float64: "float64",
+
+ Complex64: "complex64",
+ Complex128: "complex128",
+}
diff --git a/libgo/go/go/ast/walk.go b/libgo/go/go/ast/walk.go
new file mode 100644
index 000000000..875a92f3f
--- /dev/null
+++ b/libgo/go/go/ast/walk.go
@@ -0,0 +1,396 @@
+// 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 ast
+
+import "fmt"
+
+// A Visitor's Visit method is invoked for each node encountered by Walk.
+// If the result visitor w is not nil, Walk visits each of the children
+// of node with the visitor w, followed by a call of w.Visit(nil).
+type Visitor interface {
+ Visit(node Node) (w Visitor)
+}
+
+
+// Helper functions for common node lists. They may be empty.
+
+func walkIdentList(v Visitor, list []*Ident) {
+ for _, x := range list {
+ Walk(v, x)
+ }
+}
+
+
+func walkExprList(v Visitor, list []Expr) {
+ for _, x := range list {
+ Walk(v, x)
+ }
+}
+
+
+func walkStmtList(v Visitor, list []Stmt) {
+ for _, x := range list {
+ Walk(v, x)
+ }
+}
+
+
+func walkDeclList(v Visitor, list []Decl) {
+ for _, x := range list {
+ Walk(v, x)
+ }
+}
+
+
+// TODO(gri): Investigate if providing a closure to Walk leads to
+// simpler use (and may help eliminate Inspect in turn).
+
+// Walk traverses an AST in depth-first order: It starts by calling
+// v.Visit(node); node must not be nil. If the visitor w returned by
+// v.Visit(node) is not nil, Walk is invoked recursively with visitor
+// w for each of the non-nil children of node, followed by a call of
+// w.Visit(nil).
+//
+func Walk(v Visitor, node Node) {
+ if v = v.Visit(node); v == nil {
+ return
+ }
+
+ // walk children
+ // (the order of the cases matches the order
+ // of the corresponding node types in ast.go)
+ switch n := node.(type) {
+ // Comments and fields
+ case *Comment:
+ // nothing to do
+
+ case *CommentGroup:
+ for _, c := range n.List {
+ Walk(v, c)
+ }
+
+ case *Field:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ walkIdentList(v, n.Names)
+ Walk(v, n.Type)
+ if n.Tag != nil {
+ Walk(v, n.Tag)
+ }
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
+
+ case *FieldList:
+ for _, f := range n.List {
+ Walk(v, f)
+ }
+
+ // Expressions
+ case *BadExpr, *Ident, *BasicLit:
+ // nothing to do
+
+ case *Ellipsis:
+ if n.Elt != nil {
+ Walk(v, n.Elt)
+ }
+
+ case *FuncLit:
+ Walk(v, n.Type)
+ Walk(v, n.Body)
+
+ case *CompositeLit:
+ if n.Type != nil {
+ Walk(v, n.Type)
+ }
+ walkExprList(v, n.Elts)
+
+ case *ParenExpr:
+ Walk(v, n.X)
+
+ case *SelectorExpr:
+ Walk(v, n.X)
+ Walk(v, n.Sel)
+
+ case *IndexExpr:
+ Walk(v, n.X)
+ Walk(v, n.Index)
+
+ case *SliceExpr:
+ Walk(v, n.X)
+ if n.Low != nil {
+ Walk(v, n.Low)
+ }
+ if n.High != nil {
+ Walk(v, n.High)
+ }
+
+ case *TypeAssertExpr:
+ Walk(v, n.X)
+ if n.Type != nil {
+ Walk(v, n.Type)
+ }
+
+ case *CallExpr:
+ Walk(v, n.Fun)
+ walkExprList(v, n.Args)
+
+ case *StarExpr:
+ Walk(v, n.X)
+
+ case *UnaryExpr:
+ Walk(v, n.X)
+
+ case *BinaryExpr:
+ Walk(v, n.X)
+ Walk(v, n.Y)
+
+ case *KeyValueExpr:
+ Walk(v, n.Key)
+ Walk(v, n.Value)
+
+ // Types
+ case *ArrayType:
+ if n.Len != nil {
+ Walk(v, n.Len)
+ }
+ Walk(v, n.Elt)
+
+ case *StructType:
+ Walk(v, n.Fields)
+
+ case *FuncType:
+ Walk(v, n.Params)
+ if n.Results != nil {
+ Walk(v, n.Results)
+ }
+
+ case *InterfaceType:
+ Walk(v, n.Methods)
+
+ case *MapType:
+ Walk(v, n.Key)
+ Walk(v, n.Value)
+
+ case *ChanType:
+ Walk(v, n.Value)
+
+ // Statements
+ case *BadStmt:
+ // nothing to do
+
+ case *DeclStmt:
+ Walk(v, n.Decl)
+
+ case *EmptyStmt:
+ // nothing to do
+
+ case *LabeledStmt:
+ Walk(v, n.Label)
+ Walk(v, n.Stmt)
+
+ case *ExprStmt:
+ Walk(v, n.X)
+
+ case *IncDecStmt:
+ Walk(v, n.X)
+
+ case *AssignStmt:
+ walkExprList(v, n.Lhs)
+ walkExprList(v, n.Rhs)
+
+ case *GoStmt:
+ Walk(v, n.Call)
+
+ case *DeferStmt:
+ Walk(v, n.Call)
+
+ case *ReturnStmt:
+ walkExprList(v, n.Results)
+
+ case *BranchStmt:
+ if n.Label != nil {
+ Walk(v, n.Label)
+ }
+
+ case *BlockStmt:
+ walkStmtList(v, n.List)
+
+ case *IfStmt:
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
+ if n.Cond != nil {
+ Walk(v, n.Cond)
+ }
+ Walk(v, n.Body)
+ if n.Else != nil {
+ Walk(v, n.Else)
+ }
+
+ case *CaseClause:
+ walkExprList(v, n.Values)
+ walkStmtList(v, n.Body)
+
+ case *SwitchStmt:
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
+ if n.Tag != nil {
+ Walk(v, n.Tag)
+ }
+ Walk(v, n.Body)
+
+ case *TypeCaseClause:
+ for _, x := range n.Types {
+ Walk(v, x)
+ }
+ walkStmtList(v, n.Body)
+
+ case *TypeSwitchStmt:
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
+ Walk(v, n.Assign)
+ Walk(v, n.Body)
+
+ case *CommClause:
+ if n.Lhs != nil {
+ Walk(v, n.Lhs)
+ }
+ if n.Rhs != nil {
+ Walk(v, n.Rhs)
+ }
+ walkStmtList(v, n.Body)
+
+ case *SelectStmt:
+ Walk(v, n.Body)
+
+ case *ForStmt:
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
+ if n.Cond != nil {
+ Walk(v, n.Cond)
+ }
+ if n.Post != nil {
+ Walk(v, n.Post)
+ }
+ Walk(v, n.Body)
+
+ case *RangeStmt:
+ Walk(v, n.Key)
+ if n.Value != nil {
+ Walk(v, n.Value)
+ }
+ Walk(v, n.X)
+ Walk(v, n.Body)
+
+ // Declarations
+ case *ImportSpec:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ if n.Name != nil {
+ Walk(v, n.Name)
+ }
+ Walk(v, n.Path)
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
+
+ case *ValueSpec:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ walkIdentList(v, n.Names)
+ if n.Type != nil {
+ Walk(v, n.Type)
+ }
+ walkExprList(v, n.Values)
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
+
+ case *TypeSpec:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ Walk(v, n.Name)
+ Walk(v, n.Type)
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
+
+ case *BadDecl:
+ // nothing to do
+
+ case *GenDecl:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ for _, s := range n.Specs {
+ Walk(v, s)
+ }
+
+ case *FuncDecl:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ if n.Recv != nil {
+ Walk(v, n.Recv)
+ }
+ Walk(v, n.Name)
+ Walk(v, n.Type)
+ if n.Body != nil {
+ Walk(v, n.Body)
+ }
+
+ // Files and packages
+ case *File:
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ Walk(v, n.Name)
+ walkDeclList(v, n.Decls)
+ for _, g := range n.Comments {
+ Walk(v, g)
+ }
+ // don't walk n.Comments - they have been
+ // visited already through the individual
+ // nodes
+
+ case *Package:
+ for _, f := range n.Files {
+ Walk(v, f)
+ }
+
+ default:
+ fmt.Printf("ast.Walk: unexpected node type %T", n)
+ panic("ast.Walk")
+ }
+
+ v.Visit(nil)
+}
+
+
+type inspector func(Node) bool
+
+func (f inspector) Visit(node Node) Visitor {
+ if f(node) {
+ return f
+ }
+ return nil
+}
+
+
+// Inspect traverses an AST in depth-first order: It starts by calling
+// f(node); node must not be nil. If f returns true, Inspect invokes f
+// for all the non-nil children of node, recursively.
+//
+func Inspect(node Node, f func(Node) bool) {
+ Walk(inspector(f), node)
+}
diff --git a/libgo/go/go/doc/comment.go b/libgo/go/go/doc/comment.go
new file mode 100644
index 000000000..9ff0bd536
--- /dev/null
+++ b/libgo/go/go/doc/comment.go
@@ -0,0 +1,357 @@
+// 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.
+
+// Godoc comment extraction and comment -> HTML formatting.
+
+package doc
+
+import (
+ "go/ast"
+ "io"
+ "regexp"
+ "strings"
+ "template" // for htmlEscape
+)
+
+
+func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' }
+
+
+func stripTrailingWhitespace(s string) string {
+ i := len(s)
+ for i > 0 && isWhitespace(s[i-1]) {
+ i--
+ }
+ return s[0:i]
+}
+
+
+// CommentText returns the text of comment,
+// with the comment markers - //, /*, and */ - removed.
+func CommentText(comment *ast.CommentGroup) string {
+ if comment == nil {
+ return ""
+ }
+ comments := make([]string, len(comment.List))
+ for i, c := range comment.List {
+ comments[i] = string(c.Text)
+ }
+
+ lines := make([]string, 0, 10) // most comments are less than 10 lines
+ for _, c := range comments {
+ // Remove comment markers.
+ // The parser has given us exactly the comment text.
+ switch c[1] {
+ case '/':
+ //-style comment
+ c = c[2:]
+ // Remove leading space after //, if there is one.
+ // TODO(gri) This appears to be necessary in isolated
+ // cases (bignum.RatFromString) - why?
+ if len(c) > 0 && c[0] == ' ' {
+ c = c[1:]
+ }
+ case '*':
+ /*-style comment */
+ c = c[2 : len(c)-2]
+ }
+
+ // Split on newlines.
+ cl := strings.Split(c, "\n", -1)
+
+ // Walk lines, stripping trailing white space and adding to list.
+ for _, l := range cl {
+ lines = append(lines, stripTrailingWhitespace(l))
+ }
+ }
+
+ // Remove leading blank lines; convert runs of
+ // interior blank lines to a single blank line.
+ n := 0
+ for _, line := range lines {
+ if line != "" || n > 0 && lines[n-1] != "" {
+ lines[n] = line
+ n++
+ }
+ }
+ lines = lines[0:n]
+
+ // Add final "" entry to get trailing newline from Join.
+ if n > 0 && lines[n-1] != "" {
+ lines = append(lines, "")
+ }
+
+ return strings.Join(lines, "\n")
+}
+
+
+// Split bytes into lines.
+func split(text []byte) [][]byte {
+ // count lines
+ n := 0
+ last := 0
+ for i, c := range text {
+ if c == '\n' {
+ last = i + 1
+ n++
+ }
+ }
+ if last < len(text) {
+ n++
+ }
+
+ // split
+ out := make([][]byte, n)
+ last = 0
+ n = 0
+ for i, c := range text {
+ if c == '\n' {
+ out[n] = text[last : i+1]
+ last = i + 1
+ n++
+ }
+ }
+ if last < len(text) {
+ out[n] = text[last:]
+ }
+
+ return out
+}
+
+
+var (
+ ldquo = []byte("&ldquo;")
+ rdquo = []byte("&rdquo;")
+)
+
+// Escape comment text for HTML. If nice is set,
+// also turn `` into &ldquo; and '' into &rdquo;.
+func commentEscape(w io.Writer, s []byte, nice bool) {
+ last := 0
+ if nice {
+ for i := 0; i < len(s)-1; i++ {
+ ch := s[i]
+ if ch == s[i+1] && (ch == '`' || ch == '\'') {
+ template.HTMLEscape(w, s[last:i])
+ last = i + 2
+ switch ch {
+ case '`':
+ w.Write(ldquo)
+ case '\'':
+ w.Write(rdquo)
+ }
+ i++ // loop will add one more
+ }
+ }
+ }
+ template.HTMLEscape(w, s[last:])
+}
+
+
+const (
+ // Regexp for Go identifiers
+ identRx = `[a-zA-Z_][a-zA-Z_0-9]*` // TODO(gri) ASCII only for now - fix this
+
+ // Regexp for URLs
+ protocol = `(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero):`
+ hostPart = `[a-zA-Z0-9_@\-]+`
+ filePart = `[a-zA-Z0-9_?%#~&/\-+=]+`
+ urlRx = protocol + `//` + // http://
+ hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/
+ filePart + `([:.,]` + filePart + `)*`
+)
+
+var matchRx = regexp.MustCompile(`(` + identRx + `)|(` + urlRx + `)`)
+
+var (
+ html_a = []byte(`<a href="`)
+ html_aq = []byte(`">`)
+ html_enda = []byte("</a>")
+ html_i = []byte("<i>")
+ html_endi = []byte("</i>")
+ html_p = []byte("<p>\n")
+ html_endp = []byte("</p>\n")
+ html_pre = []byte("<pre>")
+ html_endpre = []byte("</pre>\n")
+)
+
+
+// Emphasize and escape a line of text for HTML. URLs are converted into links;
+// if the URL also appears in the words map, the link is taken from the map (if
+// the corresponding map value is the empty string, the URL is not converted
+// into a link). Go identifiers that appear in the words map are italicized; if
+// the corresponding map value is not the empty string, it is considered a URL
+// and the word is converted into a link. If nice is set, the remaining text's
+// appearance is improved where it makes sense (e.g., `` is turned into &ldquo;
+// and '' into &rdquo;).
+func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
+ for {
+ m := matchRx.FindSubmatchIndex(line)
+ if m == nil {
+ break
+ }
+ // m >= 6 (two parenthesized sub-regexps in matchRx, 1st one is identRx)
+
+ // write text before match
+ commentEscape(w, line[0:m[0]], nice)
+
+ // analyze match
+ match := line[m[0]:m[1]]
+ url := ""
+ italics := false
+ if words != nil {
+ url, italics = words[string(match)]
+ }
+ if m[2] < 0 {
+ // didn't match against first parenthesized sub-regexp; must be match against urlRx
+ if !italics {
+ // no alternative URL in words list, use match instead
+ url = string(match)
+ }
+ italics = false // don't italicize URLs
+ }
+
+ // write match
+ if len(url) > 0 {
+ w.Write(html_a)
+ template.HTMLEscape(w, []byte(url))
+ w.Write(html_aq)
+ }
+ if italics {
+ w.Write(html_i)
+ }
+ commentEscape(w, match, nice)
+ if italics {
+ w.Write(html_endi)
+ }
+ if len(url) > 0 {
+ w.Write(html_enda)
+ }
+
+ // advance
+ line = line[m[1]:]
+ }
+ commentEscape(w, line, nice)
+}
+
+
+func indentLen(s []byte) int {
+ i := 0
+ for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
+ i++
+ }
+ return i
+}
+
+
+func isBlank(s []byte) bool { return len(s) == 0 || (len(s) == 1 && s[0] == '\n') }
+
+
+func commonPrefix(a, b []byte) []byte {
+ i := 0
+ for i < len(a) && i < len(b) && a[i] == b[i] {
+ i++
+ }
+ return a[0:i]
+}
+
+
+func unindent(block [][]byte) {
+ if len(block) == 0 {
+ return
+ }
+
+ // compute maximum common white prefix
+ prefix := block[0][0:indentLen(block[0])]
+ for _, line := range block {
+ if !isBlank(line) {
+ prefix = commonPrefix(prefix, line[0:indentLen(line)])
+ }
+ }
+ n := len(prefix)
+
+ // remove
+ for i, line := range block {
+ if !isBlank(line) {
+ block[i] = line[n:]
+ }
+ }
+}
+
+
+// Convert comment text to formatted HTML.
+// The comment was prepared by DocReader,
+// so it is known not to have leading, trailing blank lines
+// nor to have trailing spaces at the end of lines.
+// The comment markers have already been removed.
+//
+// Turn each run of multiple \n into </p><p>
+// Turn each run of indented lines into a <pre> block without indent.
+//
+// URLs in the comment text are converted into links; if the URL also appears
+// in the words map, the link is taken from the map (if the corresponding map
+// value is the empty string, the URL is not converted into a link).
+//
+// Go identifiers that appear in the words map are italicized; if the corresponding
+// map value is not the empty string, it is considered a URL and the word is converted
+// into a link.
+func ToHTML(w io.Writer, s []byte, words map[string]string) {
+ inpara := false
+
+ close := func() {
+ if inpara {
+ w.Write(html_endp)
+ inpara = false
+ }
+ }
+ open := func() {
+ if !inpara {
+ w.Write(html_p)
+ inpara = true
+ }
+ }
+
+ lines := split(s)
+ unindent(lines)
+ for i := 0; i < len(lines); {
+ line := lines[i]
+ if isBlank(line) {
+ // close paragraph
+ close()
+ i++
+ continue
+ }
+ if indentLen(line) > 0 {
+ // close paragraph
+ close()
+
+ // count indented or blank lines
+ j := i + 1
+ for j < len(lines) && (isBlank(lines[j]) || indentLen(lines[j]) > 0) {
+ j++
+ }
+ // but not trailing blank lines
+ for j > i && isBlank(lines[j-1]) {
+ j--
+ }
+ block := lines[i:j]
+ i = j
+
+ unindent(block)
+
+ // put those lines in a pre block
+ w.Write(html_pre)
+ for _, line := range block {
+ emphasize(w, line, nil, false) // no nice text formatting
+ }
+ w.Write(html_endpre)
+ continue
+ }
+ // open paragraph
+ open()
+ emphasize(w, lines[i], words, true) // nice text formatting
+ i++
+ }
+ close()
+}
diff --git a/libgo/go/go/doc/doc.go b/libgo/go/go/doc/doc.go
new file mode 100644
index 000000000..e46857cb8
--- /dev/null
+++ b/libgo/go/go/doc/doc.go
@@ -0,0 +1,650 @@
+// 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.
+
+// The doc package extracts source code documentation from a Go AST.
+package doc
+
+import (
+ "go/ast"
+ "go/token"
+ "regexp"
+ "sort"
+)
+
+
+// ----------------------------------------------------------------------------
+
+type typeDoc struct {
+ // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
+ // if the type declaration hasn't been seen yet, decl is nil
+ decl *ast.GenDecl
+ // values, factory functions, and methods associated with the type
+ values []*ast.GenDecl // consts and vars
+ factories map[string]*ast.FuncDecl
+ methods map[string]*ast.FuncDecl
+}
+
+
+// docReader accumulates documentation for a single package.
+// It modifies the AST: Comments (declaration documentation)
+// that have been collected by the DocReader are set to nil
+// in the respective AST nodes so that they are not printed
+// twice (once when printing the documentation and once when
+// printing the corresponding AST node).
+//
+type docReader struct {
+ doc *ast.CommentGroup // package documentation, if any
+ pkgName string
+ values []*ast.GenDecl // consts and vars
+ types map[string]*typeDoc
+ funcs map[string]*ast.FuncDecl
+ bugs []*ast.CommentGroup
+}
+
+
+func (doc *docReader) init(pkgName string) {
+ doc.pkgName = pkgName
+ doc.types = make(map[string]*typeDoc)
+ doc.funcs = make(map[string]*ast.FuncDecl)
+}
+
+
+func (doc *docReader) addDoc(comments *ast.CommentGroup) {
+ if doc.doc == nil {
+ // common case: just one package comment
+ doc.doc = comments
+ return
+ }
+
+ // More than one package comment: Usually there will be only
+ // one file with a package comment, but it's better to collect
+ // all comments than drop them on the floor.
+ // (This code isn't particularly clever - no amortized doubling is
+ // used - but this situation occurs rarely and is not time-critical.)
+ n1 := len(doc.doc.List)
+ n2 := len(comments.List)
+ list := make([]*ast.Comment, n1+1+n2) // + 1 for separator line
+ copy(list, doc.doc.List)
+ list[n1] = &ast.Comment{token.NoPos, []byte("//")} // separator line
+ copy(list[n1+1:], comments.List)
+ doc.doc = &ast.CommentGroup{list}
+}
+
+
+func (doc *docReader) addType(decl *ast.GenDecl) {
+ spec := decl.Specs[0].(*ast.TypeSpec)
+ typ := doc.lookupTypeDoc(spec.Name.Name)
+ // typ should always be != nil since declared types
+ // are always named - be conservative and check
+ if typ != nil {
+ // a type should be added at most once, so typ.decl
+ // should be nil - if it isn't, simply overwrite it
+ typ.decl = decl
+ }
+}
+
+
+func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
+ if name == "" {
+ return nil // no type docs for anonymous types
+ }
+ if tdoc, found := doc.types[name]; found {
+ return tdoc
+ }
+ // type wasn't found - add one without declaration
+ tdoc := &typeDoc{nil, nil, make(map[string]*ast.FuncDecl), make(map[string]*ast.FuncDecl)}
+ doc.types[name] = tdoc
+ return tdoc
+}
+
+
+func baseTypeName(typ ast.Expr) string {
+ switch t := typ.(type) {
+ case *ast.Ident:
+ // if the type is not exported, the effect to
+ // a client is as if there were no type name
+ if t.IsExported() {
+ return string(t.Name)
+ }
+ case *ast.StarExpr:
+ return baseTypeName(t.X)
+ }
+ return ""
+}
+
+
+func (doc *docReader) addValue(decl *ast.GenDecl) {
+ // determine if decl should be associated with a type
+ // Heuristic: For each typed entry, determine the type name, if any.
+ // If there is exactly one type name that is sufficiently
+ // frequent, associate the decl with the respective type.
+ domName := ""
+ domFreq := 0
+ prev := ""
+ for _, s := range decl.Specs {
+ if v, ok := s.(*ast.ValueSpec); ok {
+ name := ""
+ switch {
+ case v.Type != nil:
+ // a type is present; determine its name
+ name = baseTypeName(v.Type)
+ case decl.Tok == token.CONST:
+ // no type is present but we have a constant declaration;
+ // use the previous type name (w/o more type information
+ // we cannot handle the case of unnamed variables with
+ // initializer expressions except for some trivial cases)
+ name = prev
+ }
+ if name != "" {
+ // entry has a named type
+ if domName != "" && domName != name {
+ // more than one type name - do not associate
+ // with any type
+ domName = ""
+ break
+ }
+ domName = name
+ domFreq++
+ }
+ prev = name
+ }
+ }
+
+ // determine values list
+ const threshold = 0.75
+ values := &doc.values
+ if domName != "" && domFreq >= int(float64(len(decl.Specs))*threshold) {
+ // typed entries are sufficiently frequent
+ typ := doc.lookupTypeDoc(domName)
+ if typ != nil {
+ values = &typ.values // associate with that type
+ }
+ }
+
+ *values = append(*values, decl)
+}
+
+
+// Helper function to set the table entry for function f. Makes sure that
+// at least one f with associated documentation is stored in table, if there
+// are multiple f's with the same name.
+func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
+ name := f.Name.Name
+ if g, exists := table[name]; exists && g.Doc != nil {
+ // a function with the same name has already been registered;
+ // since it has documentation, assume f is simply another
+ // implementation and ignore it
+ // TODO(gri) consider collecting all functions, or at least
+ // all comments
+ return
+ }
+ // function doesn't exist or has no documentation; use f
+ table[name] = f
+}
+
+
+func (doc *docReader) addFunc(fun *ast.FuncDecl) {
+ name := fun.Name.Name
+
+ // determine if it should be associated with a type
+ if fun.Recv != nil {
+ // method
+ typ := doc.lookupTypeDoc(baseTypeName(fun.Recv.List[0].Type))
+ if typ != nil {
+ // exported receiver type
+ setFunc(typ.methods, fun)
+ }
+ // otherwise don't show the method
+ // TODO(gri): There may be exported methods of non-exported types
+ // that can be called because of exported values (consts, vars, or
+ // function results) of that type. Could determine if that is the
+ // case and then show those methods in an appropriate section.
+ return
+ }
+
+ // perhaps a factory function
+ // determine result type, if any
+ if fun.Type.Results.NumFields() >= 1 {
+ res := fun.Type.Results.List[0]
+ if len(res.Names) <= 1 {
+ // exactly one (named or anonymous) result associated
+ // with the first type in result signature (there may
+ // be more than one result)
+ tname := baseTypeName(res.Type)
+ typ := doc.lookupTypeDoc(tname)
+ if typ != nil {
+ // named and exported result type
+
+ // Work-around for failure of heuristic: In package os
+ // too many functions are considered factory functions
+ // for the Error type. Eliminate manually for now as
+ // this appears to be the only important case in the
+ // current library where the heuristic fails.
+ if doc.pkgName == "os" && tname == "Error" &&
+ name != "NewError" && name != "NewSyscallError" {
+ // not a factory function for os.Error
+ setFunc(doc.funcs, fun) // treat as ordinary function
+ return
+ }
+
+ setFunc(typ.factories, fun)
+ return
+ }
+ }
+ }
+
+ // ordinary function
+ setFunc(doc.funcs, fun)
+}
+
+
+func (doc *docReader) addDecl(decl ast.Decl) {
+ switch d := decl.(type) {
+ case *ast.GenDecl:
+ if len(d.Specs) > 0 {
+ switch d.Tok {
+ case token.CONST, token.VAR:
+ // constants and variables are always handled as a group
+ doc.addValue(d)
+ case token.TYPE:
+ // types are handled individually
+ for _, spec := range d.Specs {
+ // make a (fake) GenDecl node for this TypeSpec
+ // (we need to do this here - as opposed to just
+ // for printing - so we don't lose the GenDecl
+ // documentation)
+ //
+ // TODO(gri): Consider just collecting the TypeSpec
+ // node (and copy in the GenDecl.doc if there is no
+ // doc in the TypeSpec - this is currently done in
+ // makeTypeDocs below). Simpler data structures, but
+ // would lose GenDecl documentation if the TypeSpec
+ // has documentation as well.
+ doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, token.NoPos, []ast.Spec{spec}, token.NoPos})
+ // A new GenDecl node is created, no need to nil out d.Doc.
+ }
+ }
+ }
+ case *ast.FuncDecl:
+ doc.addFunc(d)
+ }
+}
+
+
+func copyCommentList(list []*ast.Comment) []*ast.Comment {
+ return append([]*ast.Comment(nil), list...)
+}
+
+var (
+ bug_markers = regexp.MustCompile("^/[/*][ \t]*BUG\\(.*\\):[ \t]*") // BUG(uid):
+ bug_content = regexp.MustCompile("[^ \n\r\t]+") // at least one non-whitespace char
+)
+
+
+// addFile adds the AST for a source file to the docReader.
+// Adding the same AST multiple times is a no-op.
+//
+func (doc *docReader) addFile(src *ast.File) {
+ // add package documentation
+ if src.Doc != nil {
+ doc.addDoc(src.Doc)
+ src.Doc = nil // doc consumed - remove from ast.File node
+ }
+
+ // add all declarations
+ for _, decl := range src.Decls {
+ doc.addDecl(decl)
+ }
+
+ // collect BUG(...) comments
+ for _, c := range src.Comments {
+ text := c.List[0].Text
+ if m := bug_markers.FindIndex(text); m != nil {
+ // found a BUG comment; maybe empty
+ if btxt := text[m[1]:]; bug_content.Match(btxt) {
+ // non-empty BUG comment; collect comment without BUG prefix
+ list := copyCommentList(c.List)
+ list[0].Text = text[m[1]:]
+ doc.bugs = append(doc.bugs, &ast.CommentGroup{list})
+ }
+ }
+ }
+ src.Comments = nil // consumed unassociated comments - remove from ast.File node
+}
+
+
+func NewFileDoc(file *ast.File) *PackageDoc {
+ var r docReader
+ r.init(file.Name.Name)
+ r.addFile(file)
+ return r.newDoc("", nil)
+}
+
+
+func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
+ var r docReader
+ r.init(pkg.Name)
+ filenames := make([]string, len(pkg.Files))
+ i := 0
+ for filename, f := range pkg.Files {
+ r.addFile(f)
+ filenames[i] = filename
+ i++
+ }
+ return r.newDoc(importpath, filenames)
+}
+
+
+// ----------------------------------------------------------------------------
+// Conversion to external representation
+
+// ValueDoc is the documentation for a group of declared
+// values, either vars or consts.
+//
+type ValueDoc struct {
+ Doc string
+ Decl *ast.GenDecl
+ order int
+}
+
+type sortValueDoc []*ValueDoc
+
+func (p sortValueDoc) Len() int { return len(p) }
+func (p sortValueDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+
+func declName(d *ast.GenDecl) string {
+ if len(d.Specs) != 1 {
+ return ""
+ }
+
+ switch v := d.Specs[0].(type) {
+ case *ast.ValueSpec:
+ return v.Names[0].Name
+ case *ast.TypeSpec:
+ return v.Name.Name
+ }
+
+ return ""
+}
+
+
+func (p sortValueDoc) Less(i, j int) bool {
+ // sort by name
+ // pull blocks (name = "") up to top
+ // in original order
+ if ni, nj := declName(p[i].Decl), declName(p[j].Decl); ni != nj {
+ return ni < nj
+ }
+ return p[i].order < p[j].order
+}
+
+
+func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {
+ d := make([]*ValueDoc, len(list)) // big enough in any case
+ n := 0
+ for i, decl := range list {
+ if decl.Tok == tok {
+ d[n] = &ValueDoc{CommentText(decl.Doc), decl, i}
+ n++
+ decl.Doc = nil // doc consumed - removed from AST
+ }
+ }
+ d = d[0:n]
+ sort.Sort(sortValueDoc(d))
+ return d
+}
+
+
+// FuncDoc is the documentation for a func declaration,
+// either a top-level function or a method function.
+//
+type FuncDoc struct {
+ Doc string
+ Recv ast.Expr // TODO(rsc): Would like string here
+ Name string
+ Decl *ast.FuncDecl
+}
+
+type sortFuncDoc []*FuncDoc
+
+func (p sortFuncDoc) Len() int { return len(p) }
+func (p sortFuncDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p sortFuncDoc) Less(i, j int) bool { return p[i].Name < p[j].Name }
+
+
+func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
+ d := make([]*FuncDoc, len(m))
+ i := 0
+ for _, f := range m {
+ doc := new(FuncDoc)
+ doc.Doc = CommentText(f.Doc)
+ f.Doc = nil // doc consumed - remove from ast.FuncDecl node
+ if f.Recv != nil {
+ doc.Recv = f.Recv.List[0].Type
+ }
+ doc.Name = f.Name.Name
+ doc.Decl = f
+ d[i] = doc
+ i++
+ }
+ sort.Sort(sortFuncDoc(d))
+ return d
+}
+
+
+// TypeDoc is the documentation for a declared type.
+// Consts and Vars are sorted lists of constants and variables of (mostly) that type.
+// Factories is a sorted list of factory functions that return that type.
+// Methods is a sorted list of method functions on that type.
+type TypeDoc struct {
+ Doc string
+ Type *ast.TypeSpec
+ Consts []*ValueDoc
+ Vars []*ValueDoc
+ Factories []*FuncDoc
+ Methods []*FuncDoc
+ Decl *ast.GenDecl
+ order int
+}
+
+type sortTypeDoc []*TypeDoc
+
+func (p sortTypeDoc) Len() int { return len(p) }
+func (p sortTypeDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p sortTypeDoc) Less(i, j int) bool {
+ // sort by name
+ // pull blocks (name = "") up to top
+ // in original order
+ if ni, nj := p[i].Type.Name.Name, p[j].Type.Name.Name; ni != nj {
+ return ni < nj
+ }
+ return p[i].order < p[j].order
+}
+
+
+// NOTE(rsc): This would appear not to be correct for type ( )
+// blocks, but the doc extractor above has split them into
+// individual declarations.
+func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
+ d := make([]*TypeDoc, len(m))
+ i := 0
+ for _, old := range m {
+ // all typeDocs should have a declaration associated with
+ // them after processing an entire package - be conservative
+ // and check
+ if decl := old.decl; decl != nil {
+ typespec := decl.Specs[0].(*ast.TypeSpec)
+ t := new(TypeDoc)
+ doc := typespec.Doc
+ typespec.Doc = nil // doc consumed - remove from ast.TypeSpec node
+ if doc == nil {
+ // no doc associated with the spec, use the declaration doc, if any
+ doc = decl.Doc
+ }
+ decl.Doc = nil // doc consumed - remove from ast.Decl node
+ t.Doc = CommentText(doc)
+ t.Type = typespec
+ t.Consts = makeValueDocs(old.values, token.CONST)
+ t.Vars = makeValueDocs(old.values, token.VAR)
+ t.Factories = makeFuncDocs(old.factories)
+ t.Methods = makeFuncDocs(old.methods)
+ t.Decl = old.decl
+ t.order = i
+ d[i] = t
+ i++
+ } else {
+ // no corresponding type declaration found - move any associated
+ // values, factory functions, and methods back to the top-level
+ // so that they are not lost (this should only happen if a package
+ // file containing the explicit type declaration is missing or if
+ // an unqualified type name was used after a "." import)
+ // 1) move values
+ doc.values = append(doc.values, old.values...)
+ // 2) move factory functions
+ for name, f := range old.factories {
+ doc.funcs[name] = f
+ }
+ // 3) move methods
+ for name, f := range old.methods {
+ // don't overwrite functions with the same name
+ if _, found := doc.funcs[name]; !found {
+ doc.funcs[name] = f
+ }
+ }
+ }
+ }
+ d = d[0:i] // some types may have been ignored
+ sort.Sort(sortTypeDoc(d))
+ return d
+}
+
+
+func makeBugDocs(list []*ast.CommentGroup) []string {
+ d := make([]string, len(list))
+ for i, g := range list {
+ d[i] = CommentText(g)
+ }
+ return d
+}
+
+
+// PackageDoc is the documentation for an entire package.
+//
+type PackageDoc struct {
+ PackageName string
+ ImportPath string
+ Filenames []string
+ Doc string
+ Consts []*ValueDoc
+ Types []*TypeDoc
+ Vars []*ValueDoc
+ Funcs []*FuncDoc
+ Bugs []string
+}
+
+
+// newDoc returns the accumulated documentation for the package.
+//
+func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc {
+ p := new(PackageDoc)
+ p.PackageName = doc.pkgName
+ p.ImportPath = importpath
+ sort.SortStrings(filenames)
+ p.Filenames = filenames
+ p.Doc = CommentText(doc.doc)
+ // makeTypeDocs may extend the list of doc.values and
+ // doc.funcs and thus must be called before any other
+ // function consuming those lists
+ p.Types = doc.makeTypeDocs(doc.types)
+ p.Consts = makeValueDocs(doc.values, token.CONST)
+ p.Vars = makeValueDocs(doc.values, token.VAR)
+ p.Funcs = makeFuncDocs(doc.funcs)
+ p.Bugs = makeBugDocs(doc.bugs)
+ return p
+}
+
+
+// ----------------------------------------------------------------------------
+// Filtering by name
+
+type Filter func(string) bool
+
+
+func matchDecl(d *ast.GenDecl, f Filter) bool {
+ for _, d := range d.Specs {
+ switch v := d.(type) {
+ case *ast.ValueSpec:
+ for _, name := range v.Names {
+ if f(name.Name) {
+ return true
+ }
+ }
+ case *ast.TypeSpec:
+ if f(v.Name.Name) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+
+func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
+ w := 0
+ for _, vd := range a {
+ if matchDecl(vd.Decl, f) {
+ a[w] = vd
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+
+func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
+ w := 0
+ for _, fd := range a {
+ if f(fd.Name) {
+ a[w] = fd
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+
+func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
+ w := 0
+ for _, td := range a {
+ n := 0 // number of matches
+ if matchDecl(td.Decl, f) {
+ n = 1
+ } else {
+ // type name doesn't match, but we may have matching consts, vars, factories or methods
+ td.Consts = filterValueDocs(td.Consts, f)
+ td.Vars = filterValueDocs(td.Vars, f)
+ td.Factories = filterFuncDocs(td.Factories, f)
+ td.Methods = filterFuncDocs(td.Methods, f)
+ n += len(td.Consts) + len(td.Vars) + len(td.Factories) + len(td.Methods)
+ }
+ if n > 0 {
+ a[w] = td
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+
+// Filter eliminates documentation for names that don't pass through the filter f.
+// TODO: Recognize "Type.Method" as a name.
+//
+func (p *PackageDoc) Filter(f Filter) {
+ p.Consts = filterValueDocs(p.Consts, f)
+ p.Vars = filterValueDocs(p.Vars, f)
+ p.Types = filterTypeDocs(p.Types, f)
+ p.Funcs = filterFuncDocs(p.Funcs, f)
+ p.Doc = "" // don't show top-level package doc
+}
diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go
new file mode 100644
index 000000000..84d699a67
--- /dev/null
+++ b/libgo/go/go/parser/interface.go
@@ -0,0 +1,208 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the exported entry points for invoking the parser.
+
+package parser
+
+import (
+ "bytes"
+ "go/ast"
+ "go/scanner"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "os"
+ pathutil "path"
+)
+
+
+// If src != nil, readSource converts src to a []byte if possible;
+// otherwise it returns an error. If src == nil, readSource returns
+// the result of reading the file specified by filename.
+//
+func readSource(filename string, src interface{}) ([]byte, os.Error) {
+ if src != nil {
+ switch s := src.(type) {
+ case string:
+ return []byte(s), nil
+ case []byte:
+ return s, nil
+ case *bytes.Buffer:
+ // is io.Reader, but src is already available in []byte form
+ if s != nil {
+ return s.Bytes(), nil
+ }
+ case io.Reader:
+ var buf bytes.Buffer
+ _, err := io.Copy(&buf, s)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+ default:
+ return nil, os.ErrorString("invalid source")
+ }
+ }
+
+ return ioutil.ReadFile(filename)
+}
+
+
+func (p *parser) parseEOF() os.Error {
+ p.expect(token.EOF)
+ return p.GetError(scanner.Sorted)
+}
+
+
+// ParseExpr parses a Go expression and returns the corresponding
+// AST node. The fset, filename, and src arguments have the same interpretation
+// as for ParseFile. If there is an error, the result expression
+// may be nil or contain a partial AST.
+//
+func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr, os.Error) {
+ data, err := readSource(filename, src)
+ if err != nil {
+ return nil, err
+ }
+
+ var p parser
+ p.init(fset, filename, data, 0)
+ x := p.parseExpr()
+ if p.tok == token.SEMICOLON {
+ p.next() // consume automatically inserted semicolon, if any
+ }
+ return x, p.parseEOF()
+}
+
+
+// ParseStmtList parses a list of Go statements and returns the list
+// of corresponding AST nodes. The fset, filename, and src arguments have the same
+// interpretation as for ParseFile. If there is an error, the node
+// list may be nil or contain partial ASTs.
+//
+func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast.Stmt, os.Error) {
+ data, err := readSource(filename, src)
+ if err != nil {
+ return nil, err
+ }
+
+ var p parser
+ p.init(fset, filename, data, 0)
+ return p.parseStmtList(), p.parseEOF()
+}
+
+
+// ParseDeclList parses a list of Go declarations and returns the list
+// of corresponding AST nodes. The fset, filename, and src arguments have the same
+// interpretation as for ParseFile. If there is an error, the node
+// list may be nil or contain partial ASTs.
+//
+func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast.Decl, os.Error) {
+ data, err := readSource(filename, src)
+ if err != nil {
+ return nil, err
+ }
+
+ var p parser
+ p.init(fset, filename, data, 0)
+ return p.parseDeclList(), p.parseEOF()
+}
+
+
+// ParseFile parses the source code of a single Go source file and returns
+// the corresponding ast.File node. The source code may be provided via
+// the filename of the source file, or via the src parameter.
+//
+// If src != nil, ParseFile parses the source from src and the filename is
+// only used when recording position information. The type of the argument
+// for the src parameter must be string, []byte, or io.Reader.
+//
+// If src == nil, ParseFile parses the file specified by filename.
+//
+// The mode parameter controls the amount of source text parsed and other
+// optional parser functionality. Position information is recorded in the
+// file set fset.
+//
+// If the source couldn't be read, the returned AST is nil and the error
+// indicates the specific failure. If the source was read but syntax
+// errors were found, the result is a partial AST (with ast.BadX nodes
+// representing the fragments of erroneous source code). Multiple errors
+// are returned via a scanner.ErrorList which is sorted by file position.
+//
+func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint) (*ast.File, os.Error) {
+ data, err := readSource(filename, src)
+ if err != nil {
+ return nil, err
+ }
+
+ var p parser
+ p.init(fset, filename, data, mode)
+ return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
+}
+
+
+// ParseFiles calls ParseFile for each file in the filenames list and returns
+// a map of package name -> package AST with all the packages found. The mode
+// bits are passed to ParseFile unchanged. Position information is recorded
+// in the file set fset.
+//
+// Files with parse errors are ignored. In this case the map of packages may
+// be incomplete (missing packages and/or incomplete packages) and the first
+// error encountered is returned.
+//
+func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[string]*ast.Package, first os.Error) {
+ pkgs = make(map[string]*ast.Package)
+ for _, filename := range filenames {
+ if src, err := ParseFile(fset, filename, nil, mode); err == nil {
+ name := src.Name.Name
+ pkg, found := pkgs[name]
+ if !found {
+ pkg = &ast.Package{name, nil, make(map[string]*ast.File)}
+ pkgs[name] = pkg
+ }
+ pkg.Files[filename] = src
+ } else if first == nil {
+ first = err
+ }
+ }
+ return
+}
+
+
+// ParseDir calls ParseFile for the files in the directory specified by path and
+// returns a map of package name -> package AST with all the packages found. If
+// filter != nil, only the files with os.FileInfo entries passing through the filter
+// are considered. The mode bits are passed to ParseFile unchanged. Position
+// information is recorded in the file set fset.
+//
+// If the directory couldn't be read, a nil map and the respective error are
+// returned. If a parse error occurred, a non-nil but incomplete map and the
+// error are returned.
+//
+func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) {
+ fd, err := os.Open(path, os.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer fd.Close()
+
+ list, err := fd.Readdir(-1)
+ if err != nil {
+ return nil, err
+ }
+
+ filenames := make([]string, len(list))
+ n := 0
+ for i := 0; i < len(list); i++ {
+ d := &list[i]
+ if filter == nil || filter(d) {
+ filenames[n] = pathutil.Join(path, d.Name)
+ n++
+ }
+ }
+ filenames = filenames[0:n]
+
+ return ParseFiles(fset, filenames, mode)
+}
diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go
new file mode 100644
index 000000000..f1746e040
--- /dev/null
+++ b/libgo/go/go/parser/parser.go
@@ -0,0 +1,1885 @@
+// 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 parser for Go source files. Input may be provided in a variety of
+// forms (see the various Parse* functions); the output is an abstract
+// syntax tree (AST) representing the Go source. The parser is invoked
+// through one of the Parse* functions.
+//
+package parser
+
+import (
+ "fmt"
+ "go/ast"
+ "go/scanner"
+ "go/token"
+)
+
+
+// noPos is used when there is no corresponding source position for a token.
+var noPos token.Position
+
+
+// The mode parameter to the Parse* functions is a set of flags (or 0).
+// They control the amount of source code parsed and other optional
+// parser functionality.
+//
+const (
+ PackageClauseOnly uint = 1 << iota // parsing stops after package clause
+ ImportsOnly // parsing stops after import declarations
+ ParseComments // parse comments and add them to AST
+ Trace // print a trace of parsed productions
+)
+
+
+// The parser structure holds the parser's internal state.
+type parser struct {
+ file *token.File
+ scanner.ErrorVector
+ scanner scanner.Scanner
+
+ // Tracing/debugging
+ mode uint // parsing mode
+ trace bool // == (mode & Trace != 0)
+ indent uint // indentation used for tracing output
+
+ // Comments
+ comments []*ast.CommentGroup
+ leadComment *ast.CommentGroup // the last lead comment
+ lineComment *ast.CommentGroup // the last line comment
+
+ // Next token
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit []byte // token literal
+
+ // Non-syntactic parser control
+ exprLev int // < 0: in control clause, >= 0: in expression
+}
+
+
+// scannerMode returns the scanner mode bits given the parser's mode bits.
+func scannerMode(mode uint) uint {
+ var m uint = scanner.InsertSemis
+ if mode&ParseComments != 0 {
+ m |= scanner.ScanComments
+ }
+ return m
+}
+
+
+func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
+ p.file = fset.AddFile(filename, fset.Base(), len(src))
+ p.scanner.Init(p.file, src, p, scannerMode(mode))
+ p.mode = mode
+ p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
+ p.next()
+}
+
+
+// ----------------------------------------------------------------------------
+// Parsing support
+
+func (p *parser) printTrace(a ...interface{}) {
+ const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " +
+ ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
+ const n = uint(len(dots))
+ pos := p.file.Position(p.pos)
+ fmt.Printf("%5d:%3d: ", pos.Line, pos.Column)
+ i := 2 * p.indent
+ for ; i > n; i -= n {
+ fmt.Print(dots)
+ }
+ fmt.Print(dots[0:i])
+ fmt.Println(a...)
+}
+
+
+func trace(p *parser, msg string) *parser {
+ p.printTrace(msg, "(")
+ p.indent++
+ return p
+}
+
+
+// Usage pattern: defer un(trace(p, "..."));
+func un(p *parser) {
+ p.indent--
+ p.printTrace(")")
+}
+
+
+// Advance to the next token.
+func (p *parser) next0() {
+ // Because of one-token look-ahead, print the previous token
+ // when tracing as it provides a more readable output. The
+ // very first token (!p.pos.IsValid()) is not initialized
+ // (it is token.ILLEGAL), so don't print it .
+ if p.trace && p.pos.IsValid() {
+ s := p.tok.String()
+ switch {
+ case p.tok.IsLiteral():
+ p.printTrace(s, string(p.lit))
+ case p.tok.IsOperator(), p.tok.IsKeyword():
+ p.printTrace("\"" + s + "\"")
+ default:
+ p.printTrace(s)
+ }
+ }
+
+ p.pos, p.tok, p.lit = p.scanner.Scan()
+}
+
+// Consume a comment and return it and the line on which it ends.
+func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
+ // /*-style comments may end on a different line than where they start.
+ // Scan the comment for '\n' chars and adjust endline accordingly.
+ endline = p.file.Line(p.pos)
+ if p.lit[1] == '*' {
+ for _, b := range p.lit {
+ if b == '\n' {
+ endline++
+ }
+ }
+ }
+
+ comment = &ast.Comment{p.pos, p.lit}
+ p.next0()
+
+ return
+}
+
+
+// Consume a group of adjacent comments, add it to the parser's
+// comments list, and return it together with the line at which
+// the last comment in the group ends. An empty line or non-comment
+// token terminates a comment group.
+//
+func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int) {
+ var list []*ast.Comment
+ endline = p.file.Line(p.pos)
+ for p.tok == token.COMMENT && endline+1 >= p.file.Line(p.pos) {
+ var comment *ast.Comment
+ comment, endline = p.consumeComment()
+ list = append(list, comment)
+ }
+
+ // add comment group to the comments list
+ comments = &ast.CommentGroup{list}
+ p.comments = append(p.comments, comments)
+
+ return
+}
+
+
+// Advance to the next non-comment token. In the process, collect
+// any comment groups encountered, and remember the last lead and
+// and line comments.
+//
+// A lead comment is a comment group that starts and ends in a
+// line without any other tokens and that is followed by a non-comment
+// token on the line immediately after the comment group.
+//
+// A line comment is a comment group that follows a non-comment
+// token on the same line, and that has no tokens after it on the line
+// where it ends.
+//
+// Lead and line comments may be considered documentation that is
+// stored in the AST.
+//
+func (p *parser) next() {
+ p.leadComment = nil
+ p.lineComment = nil
+ line := p.file.Line(p.pos) // current line
+ p.next0()
+
+ if p.tok == token.COMMENT {
+ var comment *ast.CommentGroup
+ var endline int
+
+ if p.file.Line(p.pos) == line {
+ // The comment is on same line as previous token; it
+ // cannot be a lead comment but may be a line comment.
+ comment, endline = p.consumeCommentGroup()
+ if p.file.Line(p.pos) != endline {
+ // The next token is on a different line, thus
+ // the last comment group is a line comment.
+ p.lineComment = comment
+ }
+ }
+
+ // consume successor comments, if any
+ endline = -1
+ for p.tok == token.COMMENT {
+ comment, endline = p.consumeCommentGroup()
+ }
+
+ if endline+1 == p.file.Line(p.pos) {
+ // The next token is following on the line immediately after the
+ // comment group, thus the last comment group is a lead comment.
+ p.leadComment = comment
+ }
+ }
+}
+
+
+func (p *parser) error(pos token.Pos, msg string) {
+ p.Error(p.file.Position(pos), msg)
+}
+
+
+func (p *parser) errorExpected(pos token.Pos, msg string) {
+ msg = "expected " + msg
+ if pos == p.pos {
+ // the error happened at the current position;
+ // make the error message more specific
+ if p.tok == token.SEMICOLON && p.lit[0] == '\n' {
+ msg += ", found newline"
+ } else {
+ msg += ", found '" + p.tok.String() + "'"
+ if p.tok.IsLiteral() {
+ msg += " " + string(p.lit)
+ }
+ }
+ }
+ p.error(pos, msg)
+}
+
+
+func (p *parser) expect(tok token.Token) token.Pos {
+ pos := p.pos
+ if p.tok != tok {
+ p.errorExpected(pos, "'"+tok.String()+"'")
+ }
+ p.next() // make progress
+ return pos
+}
+
+
+func (p *parser) expectSemi() {
+ if p.tok != token.RPAREN && p.tok != token.RBRACE {
+ p.expect(token.SEMICOLON)
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// Identifiers
+
+func (p *parser) parseIdent() *ast.Ident {
+ pos := p.pos
+ name := "_"
+ if p.tok == token.IDENT {
+ name = string(p.lit)
+ p.next()
+ } else {
+ p.expect(token.IDENT) // use expect() error handling
+ }
+ return &ast.Ident{pos, name, nil}
+}
+
+
+func (p *parser) parseIdentList() (list []*ast.Ident) {
+ if p.trace {
+ defer un(trace(p, "IdentList"))
+ }
+
+ list = append(list, p.parseIdent())
+ for p.tok == token.COMMA {
+ p.next()
+ list = append(list, p.parseIdent())
+ }
+
+ return
+}
+
+
+// ----------------------------------------------------------------------------
+// Common productions
+
+func (p *parser) parseExprList() (list []ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "ExpressionList"))
+ }
+
+ list = append(list, p.parseExpr())
+ for p.tok == token.COMMA {
+ p.next()
+ list = append(list, p.parseExpr())
+ }
+
+ return
+}
+
+
+// ----------------------------------------------------------------------------
+// Types
+
+func (p *parser) parseType() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Type"))
+ }
+
+ typ := p.tryType()
+
+ if typ == nil {
+ pos := p.pos
+ p.errorExpected(pos, "type")
+ p.next() // make progress
+ return &ast.BadExpr{pos, p.pos}
+ }
+
+ return typ
+}
+
+
+func (p *parser) parseQualifiedIdent() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "QualifiedIdent"))
+ }
+
+ var x ast.Expr = p.parseIdent()
+ if p.tok == token.PERIOD {
+ // first identifier is a package identifier
+ p.next()
+ sel := p.parseIdent()
+ x = &ast.SelectorExpr{x, sel}
+ }
+ return x
+}
+
+
+func (p *parser) parseTypeName() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "TypeName"))
+ }
+
+ return p.parseQualifiedIdent()
+}
+
+
+func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "ArrayType"))
+ }
+
+ lbrack := p.expect(token.LBRACK)
+ var len ast.Expr
+ if ellipsisOk && p.tok == token.ELLIPSIS {
+ len = &ast.Ellipsis{p.pos, nil}
+ p.next()
+ } else if p.tok != token.RBRACK {
+ len = p.parseExpr()
+ }
+ p.expect(token.RBRACK)
+ elt := p.parseType()
+
+ return &ast.ArrayType{lbrack, len, elt}
+}
+
+
+func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
+ idents := make([]*ast.Ident, len(list))
+ for i, x := range list {
+ ident, isIdent := x.(*ast.Ident)
+ if !isIdent {
+ pos := x.(ast.Expr).Pos()
+ p.errorExpected(pos, "identifier")
+ ident = &ast.Ident{pos, "_", nil}
+ }
+ idents[i] = ident
+ }
+ return idents
+}
+
+
+func (p *parser) parseFieldDecl() *ast.Field {
+ if p.trace {
+ defer un(trace(p, "FieldDecl"))
+ }
+
+ doc := p.leadComment
+
+ // fields
+ list, typ := p.parseVarList(false)
+
+ // optional tag
+ var tag *ast.BasicLit
+ if p.tok == token.STRING {
+ tag = &ast.BasicLit{p.pos, p.tok, p.lit}
+ p.next()
+ }
+
+ // analyze case
+ var idents []*ast.Ident
+ if typ != nil {
+ // IdentifierList Type
+ idents = p.makeIdentList(list)
+ } else {
+ // ["*"] TypeName (AnonymousField)
+ typ = list[0] // we always have at least one element
+ if n := len(list); n > 1 || !isTypeName(deref(typ)) {
+ pos := typ.Pos()
+ p.errorExpected(pos, "anonymous field")
+ typ = &ast.BadExpr{pos, list[n-1].End()}
+ }
+ }
+
+ p.expectSemi()
+
+ return &ast.Field{doc, idents, typ, tag, p.lineComment}
+}
+
+
+func (p *parser) parseStructType() *ast.StructType {
+ if p.trace {
+ defer un(trace(p, "StructType"))
+ }
+
+ pos := p.expect(token.STRUCT)
+ lbrace := p.expect(token.LBRACE)
+ var list []*ast.Field
+ for p.tok == token.IDENT || p.tok == token.MUL || p.tok == token.LPAREN {
+ // a field declaration cannot start with a '(' but we accept
+ // it here for more robust parsing and better error messages
+ // (parseFieldDecl will check and complain if necessary)
+ list = append(list, p.parseFieldDecl())
+ }
+ rbrace := p.expect(token.RBRACE)
+
+ return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+}
+
+
+func (p *parser) parsePointerType() *ast.StarExpr {
+ if p.trace {
+ defer un(trace(p, "PointerType"))
+ }
+
+ star := p.expect(token.MUL)
+ base := p.parseType()
+
+ return &ast.StarExpr{star, base}
+}
+
+
+func (p *parser) tryVarType(isParam bool) ast.Expr {
+ if isParam && p.tok == token.ELLIPSIS {
+ pos := p.pos
+ p.next()
+ typ := p.tryType() // don't use parseType so we can provide better error message
+ if typ == nil {
+ p.error(pos, "'...' parameter is missing type")
+ typ = &ast.BadExpr{pos, p.pos}
+ }
+ if p.tok != token.RPAREN {
+ p.error(pos, "can use '...' with last parameter type only")
+ }
+ return &ast.Ellipsis{pos, typ}
+ }
+ return p.tryType()
+}
+
+
+func (p *parser) parseVarType(isParam bool) ast.Expr {
+ typ := p.tryVarType(isParam)
+ if typ == nil {
+ pos := p.pos
+ p.errorExpected(pos, "type")
+ p.next() // make progress
+ typ = &ast.BadExpr{pos, p.pos}
+ }
+ return typ
+}
+
+
+func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "VarList"))
+ }
+
+ // a list of identifiers looks like a list of type names
+ for {
+ // parseVarType accepts any type (including parenthesized ones)
+ // even though the syntax does not permit them here: we
+ // accept them all for more robust parsing and complain
+ // afterwards
+ list = append(list, p.parseVarType(isParam))
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+
+ // if we had a list of identifiers, it must be followed by a type
+ typ = p.tryVarType(isParam)
+
+ return
+}
+
+
+func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) {
+ if p.trace {
+ defer un(trace(p, "ParameterList"))
+ }
+
+ list, typ := p.parseVarList(ellipsisOk)
+ if typ != nil {
+ // IdentifierList Type
+ idents := p.makeIdentList(list)
+ params = append(params, &ast.Field{nil, idents, typ, nil, nil})
+ if p.tok == token.COMMA {
+ p.next()
+ }
+
+ for p.tok != token.RPAREN && p.tok != token.EOF {
+ idents := p.parseIdentList()
+ typ := p.parseVarType(ellipsisOk)
+ params = append(params, &ast.Field{nil, idents, typ, nil, nil})
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+
+ } else {
+ // Type { "," Type } (anonymous parameters)
+ params = make([]*ast.Field, len(list))
+ for i, x := range list {
+ params[i] = &ast.Field{Type: x}
+ }
+ }
+
+ return
+}
+
+
+func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList {
+ if p.trace {
+ defer un(trace(p, "Parameters"))
+ }
+
+ var params []*ast.Field
+ lparen := p.expect(token.LPAREN)
+ if p.tok != token.RPAREN {
+ params = p.parseParameterList(ellipsisOk)
+ }
+ rparen := p.expect(token.RPAREN)
+
+ return &ast.FieldList{lparen, params, rparen}
+}
+
+
+func (p *parser) parseResult() *ast.FieldList {
+ if p.trace {
+ defer un(trace(p, "Result"))
+ }
+
+ if p.tok == token.LPAREN {
+ return p.parseParameters(false)
+ }
+
+ typ := p.tryType()
+ if typ != nil {
+ list := make([]*ast.Field, 1)
+ list[0] = &ast.Field{Type: typ}
+ return &ast.FieldList{List: list}
+ }
+
+ return nil
+}
+
+
+func (p *parser) parseSignature() (params, results *ast.FieldList) {
+ if p.trace {
+ defer un(trace(p, "Signature"))
+ }
+
+ params = p.parseParameters(true)
+ results = p.parseResult()
+
+ return
+}
+
+
+func (p *parser) parseFuncType() *ast.FuncType {
+ if p.trace {
+ defer un(trace(p, "FuncType"))
+ }
+
+ pos := p.expect(token.FUNC)
+ params, results := p.parseSignature()
+
+ return &ast.FuncType{pos, params, results}
+}
+
+
+func (p *parser) parseMethodSpec() *ast.Field {
+ if p.trace {
+ defer un(trace(p, "MethodSpec"))
+ }
+
+ doc := p.leadComment
+ var idents []*ast.Ident
+ var typ ast.Expr
+ x := p.parseQualifiedIdent()
+ if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
+ // method
+ idents = []*ast.Ident{ident}
+ params, results := p.parseSignature()
+ typ = &ast.FuncType{token.NoPos, params, results}
+ } else {
+ // embedded interface
+ typ = x
+ }
+ p.expectSemi()
+
+ return &ast.Field{doc, idents, typ, nil, p.lineComment}
+}
+
+
+func (p *parser) parseInterfaceType() *ast.InterfaceType {
+ if p.trace {
+ defer un(trace(p, "InterfaceType"))
+ }
+
+ pos := p.expect(token.INTERFACE)
+ lbrace := p.expect(token.LBRACE)
+ var list []*ast.Field
+ for p.tok == token.IDENT {
+ list = append(list, p.parseMethodSpec())
+ }
+ rbrace := p.expect(token.RBRACE)
+
+ return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+}
+
+
+func (p *parser) parseMapType() *ast.MapType {
+ if p.trace {
+ defer un(trace(p, "MapType"))
+ }
+
+ pos := p.expect(token.MAP)
+ p.expect(token.LBRACK)
+ key := p.parseType()
+ p.expect(token.RBRACK)
+ value := p.parseType()
+
+ return &ast.MapType{pos, key, value}
+}
+
+
+func (p *parser) parseChanType() *ast.ChanType {
+ if p.trace {
+ defer un(trace(p, "ChanType"))
+ }
+
+ pos := p.pos
+ dir := ast.SEND | ast.RECV
+ if p.tok == token.CHAN {
+ p.next()
+ if p.tok == token.ARROW {
+ p.next()
+ dir = ast.SEND
+ }
+ } else {
+ p.expect(token.ARROW)
+ p.expect(token.CHAN)
+ dir = ast.RECV
+ }
+ value := p.parseType()
+
+ return &ast.ChanType{pos, dir, value}
+}
+
+
+func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
+ switch p.tok {
+ case token.IDENT:
+ return p.parseTypeName()
+ case token.LBRACK:
+ return p.parseArrayType(ellipsisOk)
+ case token.STRUCT:
+ return p.parseStructType()
+ case token.MUL:
+ return p.parsePointerType()
+ case token.FUNC:
+ return p.parseFuncType()
+ case token.INTERFACE:
+ return p.parseInterfaceType()
+ case token.MAP:
+ return p.parseMapType()
+ case token.CHAN, token.ARROW:
+ return p.parseChanType()
+ case token.LPAREN:
+ lparen := p.pos
+ p.next()
+ typ := p.parseType()
+ rparen := p.expect(token.RPAREN)
+ return &ast.ParenExpr{lparen, typ, rparen}
+ }
+
+ // no type found
+ return nil
+}
+
+
+func (p *parser) tryType() ast.Expr { return p.tryRawType(false) }
+
+
+// ----------------------------------------------------------------------------
+// Blocks
+
+func (p *parser) parseStmtList() (list []ast.Stmt) {
+ if p.trace {
+ defer un(trace(p, "StatementList"))
+ }
+
+ for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF {
+ list = append(list, p.parseStmt())
+ }
+
+ return
+}
+
+
+func (p *parser) parseBody() *ast.BlockStmt {
+ if p.trace {
+ defer un(trace(p, "Body"))
+ }
+
+ lbrace := p.expect(token.LBRACE)
+ list := p.parseStmtList()
+ rbrace := p.expect(token.RBRACE)
+
+ return &ast.BlockStmt{lbrace, list, rbrace}
+}
+
+
+func (p *parser) parseBlockStmt() *ast.BlockStmt {
+ if p.trace {
+ defer un(trace(p, "BlockStmt"))
+ }
+
+ lbrace := p.expect(token.LBRACE)
+ list := p.parseStmtList()
+ rbrace := p.expect(token.RBRACE)
+
+ return &ast.BlockStmt{lbrace, list, rbrace}
+}
+
+
+// ----------------------------------------------------------------------------
+// Expressions
+
+func (p *parser) parseFuncTypeOrLit() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "FuncTypeOrLit"))
+ }
+
+ typ := p.parseFuncType()
+ if p.tok != token.LBRACE {
+ // function type only
+ return typ
+ }
+
+ p.exprLev++
+ body := p.parseBody()
+ p.exprLev--
+
+ return &ast.FuncLit{typ, body}
+}
+
+
+// parseOperand may return an expression or a raw type (incl. array
+// types of the form [...]T. Callers must verify the result.
+//
+func (p *parser) parseOperand() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Operand"))
+ }
+
+ switch p.tok {
+ case token.IDENT:
+ return p.parseIdent()
+
+ case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
+ x := &ast.BasicLit{p.pos, p.tok, p.lit}
+ p.next()
+ return x
+
+ case token.LPAREN:
+ lparen := p.pos
+ p.next()
+ p.exprLev++
+ x := p.parseExpr()
+ p.exprLev--
+ rparen := p.expect(token.RPAREN)
+ return &ast.ParenExpr{lparen, x, rparen}
+
+ case token.FUNC:
+ return p.parseFuncTypeOrLit()
+
+ default:
+ t := p.tryRawType(true) // could be type for composite literal or conversion
+ if t != nil {
+ return t
+ }
+ }
+
+ pos := p.pos
+ p.errorExpected(pos, "operand")
+ p.next() // make progress
+ return &ast.BadExpr{pos, p.pos}
+}
+
+
+func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "SelectorOrTypeAssertion"))
+ }
+
+ p.expect(token.PERIOD)
+ if p.tok == token.IDENT {
+ // selector
+ sel := p.parseIdent()
+ return &ast.SelectorExpr{x, sel}
+ }
+
+ // type assertion
+ p.expect(token.LPAREN)
+ var typ ast.Expr
+ if p.tok == token.TYPE {
+ // type switch: typ == nil
+ p.next()
+ } else {
+ typ = p.parseType()
+ }
+ p.expect(token.RPAREN)
+
+ return &ast.TypeAssertExpr{x, typ}
+}
+
+
+func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "IndexOrSlice"))
+ }
+
+ lbrack := p.expect(token.LBRACK)
+ p.exprLev++
+ var low, high ast.Expr
+ isSlice := false
+ if p.tok != token.COLON {
+ low = p.parseExpr()
+ }
+ if p.tok == token.COLON {
+ isSlice = true
+ p.next()
+ if p.tok != token.RBRACK {
+ high = p.parseExpr()
+ }
+ }
+ p.exprLev--
+ rbrack := p.expect(token.RBRACK)
+
+ if isSlice {
+ return &ast.SliceExpr{x, lbrack, low, high, rbrack}
+ }
+ return &ast.IndexExpr{x, lbrack, low, rbrack}
+}
+
+
+func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
+ if p.trace {
+ defer un(trace(p, "CallOrConversion"))
+ }
+
+ lparen := p.expect(token.LPAREN)
+ p.exprLev++
+ var list []ast.Expr
+ var ellipsis token.Pos
+ for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() {
+ list = append(list, p.parseExpr())
+ if p.tok == token.ELLIPSIS {
+ ellipsis = p.pos
+ p.next()
+ }
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+ p.exprLev--
+ rparen := p.expect(token.RPAREN)
+
+ return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
+}
+
+
+func (p *parser) parseElement(keyOk bool) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Element"))
+ }
+
+ if p.tok == token.LBRACE {
+ return p.parseLiteralValue(nil)
+ }
+
+ x := p.parseExpr()
+ if keyOk && p.tok == token.COLON {
+ colon := p.pos
+ p.next()
+ x = &ast.KeyValueExpr{x, colon, p.parseElement(false)}
+ }
+ return x
+}
+
+
+func (p *parser) parseElementList() (list []ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "ElementList"))
+ }
+
+ for p.tok != token.RBRACE && p.tok != token.EOF {
+ list = append(list, p.parseElement(true))
+ if p.tok != token.COMMA {
+ break
+ }
+ p.next()
+ }
+
+ return
+}
+
+
+func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "LiteralValue"))
+ }
+
+ lbrace := p.expect(token.LBRACE)
+ var elts []ast.Expr
+ p.exprLev++
+ if p.tok != token.RBRACE {
+ elts = p.parseElementList()
+ }
+ p.exprLev--
+ rbrace := p.expect(token.RBRACE)
+ return &ast.CompositeLit{typ, lbrace, elts, rbrace}
+}
+
+
+// checkExpr checks that x is an expression (and not a type).
+func (p *parser) checkExpr(x ast.Expr) ast.Expr {
+ switch t := unparen(x).(type) {
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.BasicLit:
+ case *ast.FuncLit:
+ case *ast.CompositeLit:
+ case *ast.ParenExpr:
+ panic("unreachable")
+ case *ast.SelectorExpr:
+ case *ast.IndexExpr:
+ case *ast.SliceExpr:
+ case *ast.TypeAssertExpr:
+ if t.Type == nil {
+ // the form X.(type) is only allowed in type switch expressions
+ p.errorExpected(x.Pos(), "expression")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ case *ast.CallExpr:
+ case *ast.StarExpr:
+ case *ast.UnaryExpr:
+ if t.Op == token.RANGE {
+ // the range operator is only allowed at the top of a for statement
+ p.errorExpected(x.Pos(), "expression")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ case *ast.BinaryExpr:
+ default:
+ // all other nodes are not proper expressions
+ p.errorExpected(x.Pos(), "expression")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ return x
+}
+
+
+// isTypeName returns true iff x is a (qualified) TypeName.
+func isTypeName(x ast.Expr) bool {
+ switch t := x.(type) {
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.SelectorExpr:
+ _, isIdent := t.X.(*ast.Ident)
+ return isIdent
+ default:
+ return false // all other nodes are not type names
+ }
+ return true
+}
+
+
+// isLiteralType returns true iff x is a legal composite literal type.
+func isLiteralType(x ast.Expr) bool {
+ switch t := x.(type) {
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.SelectorExpr:
+ _, isIdent := t.X.(*ast.Ident)
+ return isIdent
+ case *ast.ArrayType:
+ case *ast.StructType:
+ case *ast.MapType:
+ default:
+ return false // all other nodes are not legal composite literal types
+ }
+ return true
+}
+
+
+// If x is of the form *T, deref returns T, otherwise it returns x.
+func deref(x ast.Expr) ast.Expr {
+ if p, isPtr := x.(*ast.StarExpr); isPtr {
+ x = p.X
+ }
+ return x
+}
+
+
+// If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
+func unparen(x ast.Expr) ast.Expr {
+ if p, isParen := x.(*ast.ParenExpr); isParen {
+ x = unparen(p.X)
+ }
+ return x
+}
+
+
+// checkExprOrType checks that x is an expression or a type
+// (and not a raw type such as [...]T).
+//
+func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
+ switch t := unparen(x).(type) {
+ case *ast.ParenExpr:
+ panic("unreachable")
+ case *ast.UnaryExpr:
+ if t.Op == token.RANGE {
+ // the range operator is only allowed at the top of a for statement
+ p.errorExpected(x.Pos(), "expression")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ case *ast.ArrayType:
+ if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
+ p.error(len.Pos(), "expected array length, found '...'")
+ x = &ast.BadExpr{x.Pos(), x.End()}
+ }
+ }
+
+ // all other nodes are expressions or types
+ return x
+}
+
+
+func (p *parser) parsePrimaryExpr() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "PrimaryExpr"))
+ }
+
+ x := p.parseOperand()
+L:
+ for {
+ switch p.tok {
+ case token.PERIOD:
+ x = p.parseSelectorOrTypeAssertion(p.checkExpr(x))
+ case token.LBRACK:
+ x = p.parseIndexOrSlice(p.checkExpr(x))
+ case token.LPAREN:
+ x = p.parseCallOrConversion(p.checkExprOrType(x))
+ case token.LBRACE:
+ if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
+ x = p.parseLiteralValue(x)
+ } else {
+ break L
+ }
+ default:
+ break L
+ }
+ }
+
+ return x
+}
+
+
+func (p *parser) parseUnaryExpr() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "UnaryExpr"))
+ }
+
+ switch p.tok {
+ case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.RANGE:
+ pos, op := p.pos, p.tok
+ p.next()
+ x := p.parseUnaryExpr()
+ return &ast.UnaryExpr{pos, op, p.checkExpr(x)}
+
+ case token.ARROW:
+ // channel type or receive expression
+ pos := p.pos
+ p.next()
+ if p.tok == token.CHAN {
+ p.next()
+ value := p.parseType()
+ return &ast.ChanType{pos, ast.RECV, value}
+ }
+
+ x := p.parseUnaryExpr()
+ return &ast.UnaryExpr{pos, token.ARROW, p.checkExpr(x)}
+
+ case token.MUL:
+ // pointer type or unary "*" expression
+ pos := p.pos
+ p.next()
+ x := p.parseUnaryExpr()
+ return &ast.StarExpr{pos, p.checkExprOrType(x)}
+ }
+
+ return p.parsePrimaryExpr()
+}
+
+
+func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
+ if p.trace {
+ defer un(trace(p, "BinaryExpr"))
+ }
+
+ x := p.parseUnaryExpr()
+ for prec := p.tok.Precedence(); prec >= prec1; prec-- {
+ for p.tok.Precedence() == prec {
+ pos, op := p.pos, p.tok
+ p.next()
+ y := p.parseBinaryExpr(prec + 1)
+ x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)}
+ }
+ }
+
+ return x
+}
+
+
+// TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
+// should reject when a type/raw type is obviously not allowed
+func (p *parser) parseExpr() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "Expression"))
+ }
+
+ return p.parseBinaryExpr(token.LowestPrec + 1)
+}
+
+
+// ----------------------------------------------------------------------------
+// Statements
+
+func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "SimpleStmt"))
+ }
+
+ x := p.parseExprList()
+
+ switch p.tok {
+ case token.COLON:
+ // labeled statement
+ colon := p.pos
+ p.next()
+ if labelOk && len(x) == 1 {
+ if label, isIdent := x[0].(*ast.Ident); isIdent {
+ return &ast.LabeledStmt{label, colon, p.parseStmt()}
+ }
+ }
+ p.error(x[0].Pos(), "illegal label declaration")
+ return &ast.BadStmt{x[0].Pos(), colon + 1}
+
+ case
+ token.DEFINE, token.ASSIGN, token.ADD_ASSIGN,
+ token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN,
+ token.REM_ASSIGN, token.AND_ASSIGN, token.OR_ASSIGN,
+ token.XOR_ASSIGN, token.SHL_ASSIGN, token.SHR_ASSIGN, token.AND_NOT_ASSIGN:
+ // assignment statement
+ pos, tok := p.pos, p.tok
+ p.next()
+ y := p.parseExprList()
+ return &ast.AssignStmt{x, pos, tok, y}
+ }
+
+ if len(x) > 1 {
+ p.error(x[0].Pos(), "only one expression allowed")
+ // continue with first expression
+ }
+
+ if p.tok == token.INC || p.tok == token.DEC {
+ // increment or decrement
+ s := &ast.IncDecStmt{x[0], p.pos, p.tok}
+ p.next() // consume "++" or "--"
+ return s
+ }
+
+ // expression
+ return &ast.ExprStmt{x[0]}
+}
+
+
+func (p *parser) parseCallExpr() *ast.CallExpr {
+ x := p.parseExpr()
+ if call, isCall := x.(*ast.CallExpr); isCall {
+ return call
+ }
+ p.errorExpected(x.Pos(), "function/method call")
+ return nil
+}
+
+
+func (p *parser) parseGoStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "GoStmt"))
+ }
+
+ pos := p.expect(token.GO)
+ call := p.parseCallExpr()
+ p.expectSemi()
+ if call == nil {
+ return &ast.BadStmt{pos, pos + 2} // len("go")
+ }
+
+ return &ast.GoStmt{pos, call}
+}
+
+
+func (p *parser) parseDeferStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "DeferStmt"))
+ }
+
+ pos := p.expect(token.DEFER)
+ call := p.parseCallExpr()
+ p.expectSemi()
+ if call == nil {
+ return &ast.BadStmt{pos, pos + 5} // len("defer")
+ }
+
+ return &ast.DeferStmt{pos, call}
+}
+
+
+func (p *parser) parseReturnStmt() *ast.ReturnStmt {
+ if p.trace {
+ defer un(trace(p, "ReturnStmt"))
+ }
+
+ pos := p.pos
+ p.expect(token.RETURN)
+ var x []ast.Expr
+ if p.tok != token.SEMICOLON && p.tok != token.RBRACE {
+ x = p.parseExprList()
+ }
+ p.expectSemi()
+
+ return &ast.ReturnStmt{pos, x}
+}
+
+
+func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
+ if p.trace {
+ defer un(trace(p, "BranchStmt"))
+ }
+
+ s := &ast.BranchStmt{p.pos, tok, nil}
+ p.expect(tok)
+ if tok != token.FALLTHROUGH && p.tok == token.IDENT {
+ s.Label = p.parseIdent()
+ }
+ p.expectSemi()
+
+ return s
+}
+
+
+func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
+ if s == nil {
+ return nil
+ }
+ if es, isExpr := s.(*ast.ExprStmt); isExpr {
+ return p.checkExpr(es.X)
+ }
+ p.error(s.Pos(), "expected condition, found simple statement")
+ return &ast.BadExpr{s.Pos(), s.End()}
+}
+
+
+func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
+ if p.tok != token.LBRACE {
+ prevLev := p.exprLev
+ p.exprLev = -1
+
+ if p.tok != token.SEMICOLON {
+ s1 = p.parseSimpleStmt(false)
+ }
+ if p.tok == token.SEMICOLON {
+ p.next()
+ if p.tok != token.LBRACE && p.tok != token.SEMICOLON {
+ s2 = p.parseSimpleStmt(false)
+ }
+ if isForStmt {
+ // for statements have a 3rd section
+ p.expectSemi()
+ if p.tok != token.LBRACE {
+ s3 = p.parseSimpleStmt(false)
+ }
+ }
+ } else {
+ s1, s2 = nil, s1
+ }
+
+ p.exprLev = prevLev
+ }
+
+ return s1, s2, s3
+}
+
+
+func (p *parser) parseIfStmt() *ast.IfStmt {
+ if p.trace {
+ defer un(trace(p, "IfStmt"))
+ }
+
+ pos := p.expect(token.IF)
+ s1, s2, _ := p.parseControlClause(false)
+ body := p.parseBlockStmt()
+ var else_ ast.Stmt
+ if p.tok == token.ELSE {
+ p.next()
+ else_ = p.parseStmt()
+ } else {
+ p.expectSemi()
+ }
+
+ return &ast.IfStmt{pos, s1, p.makeExpr(s2), body, else_}
+}
+
+
+func (p *parser) parseCaseClause() *ast.CaseClause {
+ if p.trace {
+ defer un(trace(p, "CaseClause"))
+ }
+
+ // SwitchCase
+ pos := p.pos
+ var x []ast.Expr
+ if p.tok == token.CASE {
+ p.next()
+ x = p.parseExprList()
+ } else {
+ p.expect(token.DEFAULT)
+ }
+
+ colon := p.expect(token.COLON)
+ body := p.parseStmtList()
+
+ return &ast.CaseClause{pos, x, colon, body}
+}
+
+
+func (p *parser) parseTypeList() (list []ast.Expr) {
+ if p.trace {
+ defer un(trace(p, "TypeList"))
+ }
+
+ list = append(list, p.parseType())
+ for p.tok == token.COMMA {
+ p.next()
+ list = append(list, p.parseType())
+ }
+
+ return
+}
+
+
+func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
+ if p.trace {
+ defer un(trace(p, "TypeCaseClause"))
+ }
+
+ // TypeSwitchCase
+ pos := p.pos
+ var types []ast.Expr
+ if p.tok == token.CASE {
+ p.next()
+ types = p.parseTypeList()
+ } else {
+ p.expect(token.DEFAULT)
+ }
+
+ colon := p.expect(token.COLON)
+ body := p.parseStmtList()
+
+ return &ast.TypeCaseClause{pos, types, colon, body}
+}
+
+
+func isExprSwitch(s ast.Stmt) bool {
+ if s == nil {
+ return true
+ }
+ if e, ok := s.(*ast.ExprStmt); ok {
+ if a, ok := e.X.(*ast.TypeAssertExpr); ok {
+ return a.Type != nil // regular type assertion
+ }
+ return true
+ }
+ return false
+}
+
+
+func (p *parser) parseSwitchStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "SwitchStmt"))
+ }
+
+ pos := p.expect(token.SWITCH)
+ s1, s2, _ := p.parseControlClause(false)
+
+ if isExprSwitch(s2) {
+ lbrace := p.expect(token.LBRACE)
+ var list []ast.Stmt
+ for p.tok == token.CASE || p.tok == token.DEFAULT {
+ list = append(list, p.parseCaseClause())
+ }
+ rbrace := p.expect(token.RBRACE)
+ body := &ast.BlockStmt{lbrace, list, rbrace}
+ p.expectSemi()
+ return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body}
+ }
+
+ // type switch
+ // TODO(gri): do all the checks!
+ lbrace := p.expect(token.LBRACE)
+ var list []ast.Stmt
+ for p.tok == token.CASE || p.tok == token.DEFAULT {
+ list = append(list, p.parseTypeCaseClause())
+ }
+ rbrace := p.expect(token.RBRACE)
+ p.expectSemi()
+ body := &ast.BlockStmt{lbrace, list, rbrace}
+ return &ast.TypeSwitchStmt{pos, s1, s2, body}
+}
+
+
+func (p *parser) parseCommClause() *ast.CommClause {
+ if p.trace {
+ defer un(trace(p, "CommClause"))
+ }
+
+ // CommCase
+ pos := p.pos
+ var tok token.Token
+ var lhs, rhs ast.Expr
+ if p.tok == token.CASE {
+ p.next()
+ if p.tok == token.ARROW {
+ // RecvExpr without assignment
+ rhs = p.parseExpr()
+ } else {
+ // SendExpr or RecvExpr
+ rhs = p.parseExpr()
+ if p.tok == token.ASSIGN || p.tok == token.DEFINE {
+ // RecvExpr with assignment
+ tok = p.tok
+ p.next()
+ lhs = rhs
+ if p.tok == token.ARROW {
+ rhs = p.parseExpr()
+ } else {
+ p.expect(token.ARROW) // use expect() error handling
+ }
+ }
+ // else SendExpr
+ }
+ } else {
+ p.expect(token.DEFAULT)
+ }
+
+ colon := p.expect(token.COLON)
+ body := p.parseStmtList()
+
+ return &ast.CommClause{pos, tok, lhs, rhs, colon, body}
+}
+
+
+func (p *parser) parseSelectStmt() *ast.SelectStmt {
+ if p.trace {
+ defer un(trace(p, "SelectStmt"))
+ }
+
+ pos := p.expect(token.SELECT)
+ lbrace := p.expect(token.LBRACE)
+ var list []ast.Stmt
+ for p.tok == token.CASE || p.tok == token.DEFAULT {
+ list = append(list, p.parseCommClause())
+ }
+ rbrace := p.expect(token.RBRACE)
+ p.expectSemi()
+ body := &ast.BlockStmt{lbrace, list, rbrace}
+
+ return &ast.SelectStmt{pos, body}
+}
+
+
+func (p *parser) parseForStmt() ast.Stmt {
+ if p.trace {
+ defer un(trace(p, "ForStmt"))
+ }
+
+ pos := p.expect(token.FOR)
+ s1, s2, s3 := p.parseControlClause(true)
+ body := p.parseBlockStmt()
+ p.expectSemi()
+
+ if as, isAssign := s2.(*ast.AssignStmt); isAssign {
+ // possibly a for statement with a range clause; check assignment operator
+ if as.Tok != token.ASSIGN && as.Tok != token.DEFINE {
+ p.errorExpected(as.TokPos, "'=' or ':='")
+ return &ast.BadStmt{pos, body.End()}
+ }
+ // check lhs
+ var key, value ast.Expr
+ switch len(as.Lhs) {
+ case 2:
+ key, value = as.Lhs[0], as.Lhs[1]
+ case 1:
+ key = as.Lhs[0]
+ default:
+ p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
+ return &ast.BadStmt{pos, body.End()}
+ }
+ // check rhs
+ if len(as.Rhs) != 1 {
+ p.errorExpected(as.Rhs[0].Pos(), "1 expressions")
+ return &ast.BadStmt{pos, body.End()}
+ }
+ if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE {
+ // rhs is range expression; check lhs
+ return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
+ } else {
+ p.errorExpected(s2.Pos(), "range clause")
+ return &ast.BadStmt{pos, body.End()}
+ }
+ } else {
+ // regular for statement
+ return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
+ }
+
+ panic("unreachable")
+}
+
+
+func (p *parser) parseStmt() (s ast.Stmt) {
+ if p.trace {
+ defer un(trace(p, "Statement"))
+ }
+
+ switch p.tok {
+ case token.CONST, token.TYPE, token.VAR:
+ s = &ast.DeclStmt{p.parseDecl()}
+ case
+ // tokens that may start a top-level expression
+ token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand
+ token.LBRACK, token.STRUCT, // composite type
+ token.MUL, token.AND, token.ARROW, token.ADD, token.SUB, token.XOR: // unary operators
+ s = p.parseSimpleStmt(true)
+ // because of the required look-ahead, labeled statements are
+ // parsed by parseSimpleStmt - don't expect a semicolon after
+ // them
+ if _, isLabeledStmt := s.(*ast.LabeledStmt); !isLabeledStmt {
+ p.expectSemi()
+ }
+ case token.GO:
+ s = p.parseGoStmt()
+ case token.DEFER:
+ s = p.parseDeferStmt()
+ case token.RETURN:
+ s = p.parseReturnStmt()
+ case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH:
+ s = p.parseBranchStmt(p.tok)
+ case token.LBRACE:
+ s = p.parseBlockStmt()
+ p.expectSemi()
+ case token.IF:
+ s = p.parseIfStmt()
+ case token.SWITCH:
+ s = p.parseSwitchStmt()
+ case token.SELECT:
+ s = p.parseSelectStmt()
+ case token.FOR:
+ s = p.parseForStmt()
+ case token.SEMICOLON:
+ s = &ast.EmptyStmt{p.pos}
+ p.next()
+ case token.RBRACE:
+ // a semicolon may be omitted before a closing "}"
+ s = &ast.EmptyStmt{p.pos}
+ default:
+ // no statement found
+ pos := p.pos
+ p.errorExpected(pos, "statement")
+ p.next() // make progress
+ s = &ast.BadStmt{pos, p.pos}
+ }
+
+ return
+}
+
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+type parseSpecFunction func(p *parser, doc *ast.CommentGroup) ast.Spec
+
+
+func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "ImportSpec"))
+ }
+
+ var ident *ast.Ident
+ if p.tok == token.PERIOD {
+ ident = &ast.Ident{p.pos, ".", nil}
+ p.next()
+ } else if p.tok == token.IDENT {
+ ident = p.parseIdent()
+ }
+
+ var path *ast.BasicLit
+ if p.tok == token.STRING {
+ path = &ast.BasicLit{p.pos, p.tok, p.lit}
+ p.next()
+ } else {
+ p.expect(token.STRING) // use expect() error handling
+ }
+ p.expectSemi()
+
+ return &ast.ImportSpec{doc, ident, path, p.lineComment}
+}
+
+
+func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "ConstSpec"))
+ }
+
+ idents := p.parseIdentList()
+ typ := p.tryType()
+ var values []ast.Expr
+ if typ != nil || p.tok == token.ASSIGN {
+ p.expect(token.ASSIGN)
+ values = p.parseExprList()
+ }
+ p.expectSemi()
+
+ return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+}
+
+
+func parseTypeSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "TypeSpec"))
+ }
+
+ ident := p.parseIdent()
+ typ := p.parseType()
+ p.expectSemi()
+
+ return &ast.TypeSpec{doc, ident, typ, p.lineComment}
+}
+
+
+func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+ if p.trace {
+ defer un(trace(p, "VarSpec"))
+ }
+
+ idents := p.parseIdentList()
+ typ := p.tryType()
+ var values []ast.Expr
+ if typ == nil || p.tok == token.ASSIGN {
+ p.expect(token.ASSIGN)
+ values = p.parseExprList()
+ }
+ p.expectSemi()
+
+ return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+}
+
+
+func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
+ if p.trace {
+ defer un(trace(p, "GenDecl("+keyword.String()+")"))
+ }
+
+ doc := p.leadComment
+ pos := p.expect(keyword)
+ var lparen, rparen token.Pos
+ var list []ast.Spec
+ if p.tok == token.LPAREN {
+ lparen = p.pos
+ p.next()
+ for p.tok != token.RPAREN && p.tok != token.EOF {
+ list = append(list, f(p, p.leadComment))
+ }
+ rparen = p.expect(token.RPAREN)
+ p.expectSemi()
+ } else {
+ list = append(list, f(p, nil))
+ }
+
+ return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
+}
+
+
+func (p *parser) parseReceiver() *ast.FieldList {
+ if p.trace {
+ defer un(trace(p, "Receiver"))
+ }
+
+ pos := p.pos
+ par := p.parseParameters(false)
+
+ // must have exactly one receiver
+ if par.NumFields() != 1 {
+ p.errorExpected(pos, "exactly one receiver")
+ // TODO determine a better range for BadExpr below
+ par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{pos, pos}}}
+ return par
+ }
+
+ // recv type must be of the form ["*"] identifier
+ recv := par.List[0]
+ base := deref(recv.Type)
+ if _, isIdent := base.(*ast.Ident); !isIdent {
+ p.errorExpected(base.Pos(), "(unqualified) identifier")
+ par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{recv.Pos(), recv.End()}}}
+ }
+
+ return par
+}
+
+
+func (p *parser) parseFuncDecl() *ast.FuncDecl {
+ if p.trace {
+ defer un(trace(p, "FunctionDecl"))
+ }
+
+ doc := p.leadComment
+ pos := p.expect(token.FUNC)
+
+ var recv *ast.FieldList
+ if p.tok == token.LPAREN {
+ recv = p.parseReceiver()
+ }
+
+ ident := p.parseIdent()
+ params, results := p.parseSignature()
+
+ var body *ast.BlockStmt
+ if p.tok == token.LBRACE {
+ body = p.parseBody()
+ }
+ p.expectSemi()
+
+ return &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body}
+}
+
+
+func (p *parser) parseDecl() ast.Decl {
+ if p.trace {
+ defer un(trace(p, "Declaration"))
+ }
+
+ var f parseSpecFunction
+ switch p.tok {
+ case token.CONST:
+ f = parseConstSpec
+
+ case token.TYPE:
+ f = parseTypeSpec
+
+ case token.VAR:
+ f = parseVarSpec
+
+ case token.FUNC:
+ return p.parseFuncDecl()
+
+ default:
+ pos := p.pos
+ p.errorExpected(pos, "declaration")
+ p.next() // make progress
+ decl := &ast.BadDecl{pos, p.pos}
+ return decl
+ }
+
+ return p.parseGenDecl(p.tok, f)
+}
+
+
+func (p *parser) parseDeclList() (list []ast.Decl) {
+ if p.trace {
+ defer un(trace(p, "DeclList"))
+ }
+
+ for p.tok != token.EOF {
+ list = append(list, p.parseDecl())
+ }
+
+ return
+}
+
+
+// ----------------------------------------------------------------------------
+// Source files
+
+func (p *parser) parseFile() *ast.File {
+ if p.trace {
+ defer un(trace(p, "File"))
+ }
+
+ // package clause
+ doc := p.leadComment
+ pos := p.expect(token.PACKAGE)
+ ident := p.parseIdent()
+ p.expectSemi()
+
+ var decls []ast.Decl
+
+ // Don't bother parsing the rest if we had errors already.
+ // Likely not a Go source file at all.
+
+ if p.ErrorCount() == 0 && p.mode&PackageClauseOnly == 0 {
+ // import decls
+ for p.tok == token.IMPORT {
+ decls = append(decls, p.parseGenDecl(token.IMPORT, parseImportSpec))
+ }
+
+ if p.mode&ImportsOnly == 0 {
+ // rest of package body
+ for p.tok != token.EOF {
+ decls = append(decls, p.parseDecl())
+ }
+ }
+ }
+
+ return &ast.File{doc, pos, ident, decls, p.comments}
+}
diff --git a/libgo/go/go/parser/parser_test.go b/libgo/go/go/parser/parser_test.go
new file mode 100644
index 000000000..56bd80ef1
--- /dev/null
+++ b/libgo/go/go/parser/parser_test.go
@@ -0,0 +1,112 @@
+// 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 parser
+
+import (
+ "go/token"
+ "os"
+ "testing"
+)
+
+
+var fset = token.NewFileSet()
+
+var illegalInputs = []interface{}{
+ nil,
+ 3.14,
+ []byte(nil),
+ "foo!",
+}
+
+
+func TestParseIllegalInputs(t *testing.T) {
+ for _, src := range illegalInputs {
+ _, err := ParseFile(fset, "", src, 0)
+ if err == nil {
+ t.Errorf("ParseFile(%v) should have failed", src)
+ }
+ }
+}
+
+
+var validPrograms = []interface{}{
+ "package main\n",
+ `package main;`,
+ `package main; import "fmt"; func main() { fmt.Println("Hello, World!") };`,
+ `package main; func main() { if f(T{}) {} };`,
+ `package main; func main() { _ = (<-chan int)(x) };`,
+ `package main; func main() { _ = (<-chan <-chan int)(x) };`,
+ `package main; func f(func() func() func());`,
+ `package main; func f(...T);`,
+ `package main; func f(float, ...int);`,
+ `package main; func f(x int, a ...int) { f(0, a...); f(1, a...,) };`,
+ `package main; type T []int; var a []bool; func f() { if a[T{42}[0]] {} };`,
+ `package main; type T []int; func g(int) bool { return true }; func f() { if g(T{42}[0]) {} };`,
+ `package main; type T []int; func f() { for _ = range []int{T{42}[0]} {} };`,
+ `package main; var a = T{{1, 2}, {3, 4}}`,
+}
+
+
+func TestParseValidPrograms(t *testing.T) {
+ for _, src := range validPrograms {
+ _, err := ParseFile(fset, "", src, 0)
+ if err != nil {
+ t.Errorf("ParseFile(%q): %v", src, err)
+ }
+ }
+}
+
+
+var validFiles = []string{
+ "parser.go",
+ "parser_test.go",
+}
+
+
+func TestParse3(t *testing.T) {
+ for _, filename := range validFiles {
+ _, err := ParseFile(fset, filename, nil, 0)
+ if err != nil {
+ t.Errorf("ParseFile(%s): %v", filename, err)
+ }
+ }
+}
+
+
+func nameFilter(filename string) bool {
+ switch filename {
+ case "parser.go":
+ case "interface.go":
+ case "parser_test.go":
+ default:
+ return false
+ }
+ return true
+}
+
+
+func dirFilter(f *os.FileInfo) bool { return nameFilter(f.Name) }
+
+
+func TestParse4(t *testing.T) {
+ path := "."
+ pkgs, err := ParseDir(fset, path, dirFilter, 0)
+ if err != nil {
+ t.Fatalf("ParseDir(%s): %v", path, err)
+ }
+ if len(pkgs) != 1 {
+ t.Errorf("incorrect number of packages: %d", len(pkgs))
+ }
+ pkg := pkgs["parser"]
+ if pkg == nil {
+ t.Errorf(`package "parser" not found`)
+ return
+ }
+ for filename := range pkg.Files {
+ if !nameFilter(filename) {
+ t.Errorf("unexpected package file: %s", filename)
+ }
+ }
+}
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go
new file mode 100644
index 000000000..8207996dc
--- /dev/null
+++ b/libgo/go/go/printer/nodes.go
@@ -0,0 +1,1493 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements printing of AST nodes; specifically
+// expressions, statements, declarations, and files. It uses
+// the print functionality implemented in printer.go.
+
+package printer
+
+import (
+ "bytes"
+ "go/ast"
+ "go/token"
+)
+
+
+// Other formatting issues:
+// - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
+// when the comment spans multiple lines; if such a comment is just two lines, formatting is
+// not idempotent
+// - formatting of expression lists
+// - should use blank instead of tab to separate one-line function bodies from
+// the function header unless there is a group of consecutive one-liners
+
+
+// ----------------------------------------------------------------------------
+// Common AST nodes.
+
+// Print as many newlines as necessary (but at least min newlines) to get to
+// the current line. ws is printed before the first line break. If newSection
+// is set, the first line break is printed as formfeed. Returns true if any
+// line break was printed; returns false otherwise.
+//
+// TODO(gri): linebreak may add too many lines if the next statement at "line"
+// is preceeded by comments because the computation of n assumes
+// the current position before the comment and the target position
+// after the comment. Thus, after interspersing such comments, the
+// space taken up by them is not considered to reduce the number of
+// linebreaks. At the moment there is no easy way to know about
+// future (not yet interspersed) comments in this function.
+//
+func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
+ n := p.nlines(line-p.pos.Line, min)
+ if n > 0 {
+ p.print(ws)
+ if newSection {
+ p.print(formfeed)
+ n--
+ }
+ for ; n > 0; n-- {
+ p.print(newline)
+ }
+ printedBreak = true
+ }
+ return
+}
+
+
+// setComment sets g as the next comment if g != nil and if node comments
+// are enabled - this mode is used when printing source code fragments such
+// as exports only. It assumes that there are no other pending comments to
+// intersperse.
+func (p *printer) setComment(g *ast.CommentGroup) {
+ if g == nil || !p.useNodeComments {
+ return
+ }
+ if p.comments == nil {
+ // initialize p.comments lazily
+ p.comments = make([]*ast.CommentGroup, 1)
+ } else if p.cindex < len(p.comments) {
+ // for some reason there are pending comments; this
+ // should never happen - handle gracefully and flush
+ // all comments up to g, ignore anything after that
+ p.flush(p.fset.Position(g.List[0].Pos()), token.ILLEGAL)
+ }
+ p.comments[0] = g
+ p.cindex = 0
+}
+
+
+type exprListMode uint
+
+const (
+ blankStart exprListMode = 1 << iota // print a blank before a non-empty list
+ blankEnd // print a blank after a non-empty list
+ commaSep // elements are separated by commas
+ commaTerm // list is optionally terminated by a comma
+ noIndent // no extra indentation in multi-line lists
+ periodSep // elements are separated by periods
+)
+
+
+// Sets multiLine to true if the identifier list spans multiple lines.
+// If indent is set, a multi-line identifier list is indented after the
+// first linebreak encountered.
+func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
+ // convert into an expression list so we can re-use exprList formatting
+ xlist := make([]ast.Expr, len(list))
+ for i, x := range list {
+ xlist[i] = x
+ }
+ mode := commaSep
+ if !indent {
+ mode |= noIndent
+ }
+ p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos)
+}
+
+
+// Compute the key size of a key:value expression.
+// Returns 0 if the expression doesn't fit onto a single line.
+func (p *printer) keySize(pair *ast.KeyValueExpr) int {
+ if p.nodeSize(pair, infinity) <= infinity {
+ // entire expression fits on one line - return key size
+ return p.nodeSize(pair.Key, infinity)
+ }
+ return 0
+}
+
+
+// Print a list of expressions. If the list spans multiple
+// source lines, the original line breaks are respected between
+// expressions. Sets multiLine to true if the list spans multiple
+// lines.
+//
+// TODO(gri) Consider rewriting this to be independent of []ast.Expr
+// so that we can use the algorithm for any kind of list
+// (e.g., pass list via a channel over which to range).
+func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next0 token.Pos) {
+ if len(list) == 0 {
+ return
+ }
+
+ if mode&blankStart != 0 {
+ p.print(blank)
+ }
+
+ prev := p.fset.Position(prev0)
+ next := p.fset.Position(next0)
+ line := p.fset.Position(list[0].Pos()).Line
+ endLine := p.fset.Position(list[len(list)-1].End()).Line
+
+ if prev.IsValid() && prev.Line == line && line == endLine {
+ // all list entries on a single line
+ for i, x := range list {
+ if i > 0 {
+ if mode&commaSep != 0 {
+ p.print(token.COMMA)
+ }
+ p.print(blank)
+ }
+ p.expr0(x, depth, multiLine)
+ }
+ if mode&blankEnd != 0 {
+ p.print(blank)
+ }
+ return
+ }
+
+ // list entries span multiple lines;
+ // use source code positions to guide line breaks
+
+ // don't add extra indentation if noIndent is set;
+ // i.e., pretend that the first line is already indented
+ ws := ignore
+ if mode&noIndent == 0 {
+ ws = indent
+ }
+
+ // the first linebreak is always a formfeed since this section must not
+ // depend on any previous formatting
+ prevBreak := -1 // index of last expression that was followed by a linebreak
+ linebreakMin := 1
+ if mode&periodSep != 0 {
+ // Make fragments like
+ //
+ // a.Bar(1,
+ // 2).Foo
+ //
+ // format correctly (a linebreak shouldn't be added before Foo) when
+ // doing period-separated expr lists by setting minimum linebreak to 0
+ // lines for them.
+ linebreakMin = 0
+ }
+ if prev.IsValid() && prev.Line < line && p.linebreak(line, linebreakMin, ws, true) {
+ ws = ignore
+ *multiLine = true
+ prevBreak = 0
+ }
+
+ // initialize expression/key size: a zero value indicates expr/key doesn't fit on a single line
+ size := 0
+
+ // print all list elements
+ for i, x := range list {
+ prevLine := line
+ line = p.fset.Position(x.Pos()).Line
+
+ // determine if the next linebreak, if any, needs to use formfeed:
+ // in general, use the entire node size to make the decision; for
+ // key:value expressions, use the key size
+ // TODO(gri) for a better result, should probably incorporate both
+ // the key and the node size into the decision process
+ useFF := true
+
+ // determine size
+ prevSize := size
+ const infinity = 1e6 // larger than any source line
+ size = p.nodeSize(x, infinity)
+ pair, isPair := x.(*ast.KeyValueExpr)
+ if size <= infinity {
+ // x fits on a single line
+ if isPair {
+ size = p.nodeSize(pair.Key, infinity) // size <= infinity
+ }
+ } else {
+ size = 0
+ }
+
+ // if the previous line and the current line had single-
+ // line-expressions and the key sizes are small or the
+ // the ratio between the key sizes does not exceed a
+ // threshold, align columns and do not use formfeed
+ if prevSize > 0 && size > 0 {
+ const smallSize = 20
+ if prevSize <= smallSize && size <= smallSize {
+ useFF = false
+ } else {
+ const r = 4 // threshold
+ ratio := float64(size) / float64(prevSize)
+ useFF = ratio <= 1/r || r <= ratio
+ }
+ }
+
+ if i > 0 {
+ if mode&commaSep != 0 {
+ p.print(token.COMMA)
+ }
+ if mode&periodSep != 0 {
+ p.print(token.PERIOD)
+ }
+ if prevLine < line && prevLine > 0 && line > 0 {
+ // lines are broken using newlines so comments remain aligned
+ // unless forceFF is set or there are multiple expressions on
+ // the same line in which case formfeed is used
+ // broken with a formfeed
+ if p.linebreak(line, linebreakMin, ws, useFF || prevBreak+1 < i) {
+ ws = ignore
+ *multiLine = true
+ prevBreak = i
+ }
+ } else if mode&periodSep == 0 {
+ p.print(blank)
+ }
+ // period-separated list elements don't need a blank
+ }
+
+ if isPair && size > 0 && len(list) > 1 {
+ // we have a key:value expression that fits onto one line and
+ // is in a list with more then one entry: use a column for the
+ // key such that consecutive entries can align if possible
+ p.expr(pair.Key, multiLine)
+ p.print(pair.Colon, token.COLON, vtab)
+ p.expr(pair.Value, multiLine)
+ } else {
+ p.expr0(x, depth, multiLine)
+ }
+ }
+
+ if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line {
+ // print a terminating comma if the next token is on a new line
+ p.print(token.COMMA)
+ if ws == ignore && mode&noIndent == 0 {
+ // unindent if we indented
+ p.print(unindent)
+ }
+ p.print(formfeed) // terminating comma needs a line break to look good
+ return
+ }
+
+ if mode&blankEnd != 0 {
+ p.print(blank)
+ }
+
+ if ws == ignore && mode&noIndent == 0 {
+ // unindent if we indented
+ p.print(unindent)
+ }
+}
+
+
+// Sets multiLine to true if the the parameter list spans multiple lines.
+func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
+ p.print(fields.Opening, token.LPAREN)
+ if len(fields.List) > 0 {
+ var prevLine, line int
+ for i, par := range fields.List {
+ if i > 0 {
+ p.print(token.COMMA)
+ if len(par.Names) > 0 {
+ line = p.fset.Position(par.Names[0].Pos()).Line
+ } else {
+ line = p.fset.Position(par.Type.Pos()).Line
+ }
+ if 0 < prevLine && prevLine < line && p.linebreak(line, 0, ignore, true) {
+ *multiLine = true
+ } else {
+ p.print(blank)
+ }
+ }
+ if len(par.Names) > 0 {
+ p.identList(par.Names, false, multiLine)
+ p.print(blank)
+ }
+ p.expr(par.Type, multiLine)
+ prevLine = p.fset.Position(par.Type.Pos()).Line
+ }
+ }
+ p.print(fields.Closing, token.RPAREN)
+}
+
+
+// Sets multiLine to true if the signature spans multiple lines.
+func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
+ p.parameters(params, multiLine)
+ n := result.NumFields()
+ if n > 0 {
+ p.print(blank)
+ if n == 1 && result.List[0].Names == nil {
+ // single anonymous result; no ()'s
+ p.expr(result.List[0].Type, multiLine)
+ return
+ }
+ p.parameters(result, multiLine)
+ }
+}
+
+
+func identListSize(list []*ast.Ident, maxSize int) (size int) {
+ for i, x := range list {
+ if i > 0 {
+ size += 2 // ", "
+ }
+ size += len(x.Name)
+ if size >= maxSize {
+ break
+ }
+ }
+ return
+}
+
+
+func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
+ if len(list) != 1 {
+ return false // allow only one field
+ }
+ f := list[0]
+ if f.Tag != nil || f.Comment != nil {
+ return false // don't allow tags or comments
+ }
+ // only name(s) and type
+ const maxSize = 30 // adjust as appropriate, this is an approximate value
+ namesSize := identListSize(f.Names, maxSize)
+ if namesSize > 0 {
+ namesSize = 1 // blank between names and types
+ }
+ typeSize := p.nodeSize(f.Type, maxSize)
+ return namesSize+typeSize <= maxSize
+}
+
+
+func (p *printer) setLineComment(text string) {
+ p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, []byte(text)}}})
+}
+
+
+func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprContext) {
+ p.nesting++
+ defer func() {
+ p.nesting--
+ }()
+
+ lbrace := fields.Opening
+ list := fields.List
+ rbrace := fields.Closing
+
+ if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) {
+ // possibly a one-line struct/interface
+ if len(list) == 0 {
+ // no blank between keyword and {} in this case
+ p.print(lbrace, token.LBRACE, rbrace, token.RBRACE)
+ return
+ } else if ctxt&(compositeLit|structType) == compositeLit|structType &&
+ p.isOneLineFieldList(list) { // for now ignore interfaces
+ // small enough - print on one line
+ // (don't use identList and ignore source line breaks)
+ p.print(lbrace, token.LBRACE, blank)
+ f := list[0]
+ for i, x := range f.Names {
+ if i > 0 {
+ p.print(token.COMMA, blank)
+ }
+ p.expr(x, ignoreMultiLine)
+ }
+ if len(f.Names) > 0 {
+ p.print(blank)
+ }
+ p.expr(f.Type, ignoreMultiLine)
+ p.print(blank, rbrace, token.RBRACE)
+ return
+ }
+ }
+
+ // at least one entry or incomplete
+ p.print(blank, lbrace, token.LBRACE, indent, formfeed)
+ if ctxt&structType != 0 {
+
+ sep := vtab
+ if len(list) == 1 {
+ sep = blank
+ }
+ var ml bool
+ for i, f := range list {
+ if i > 0 {
+ p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
+ }
+ ml = false
+ extraTabs := 0
+ p.setComment(f.Doc)
+ if len(f.Names) > 0 {
+ // named fields
+ p.identList(f.Names, false, &ml)
+ p.print(sep)
+ p.expr(f.Type, &ml)
+ extraTabs = 1
+ } else {
+ // anonymous field
+ p.expr(f.Type, &ml)
+ extraTabs = 2
+ }
+ if f.Tag != nil {
+ if len(f.Names) > 0 && sep == vtab {
+ p.print(sep)
+ }
+ p.print(sep)
+ p.expr(f.Tag, &ml)
+ extraTabs = 0
+ }
+ if f.Comment != nil {
+ for ; extraTabs > 0; extraTabs-- {
+ p.print(sep)
+ }
+ p.setComment(f.Comment)
+ }
+ }
+ if isIncomplete {
+ if len(list) > 0 {
+ p.print(formfeed)
+ }
+ p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't loose the last line comment
+ p.setLineComment("// contains unexported fields")
+ }
+
+ } else { // interface
+
+ var ml bool
+ for i, f := range list {
+ if i > 0 {
+ p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
+ }
+ ml = false
+ p.setComment(f.Doc)
+ if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
+ // method
+ p.expr(f.Names[0], &ml)
+ p.signature(ftyp.Params, ftyp.Results, &ml)
+ } else {
+ // embedded interface
+ p.expr(f.Type, &ml)
+ }
+ p.setComment(f.Comment)
+ }
+ if isIncomplete {
+ if len(list) > 0 {
+ p.print(formfeed)
+ }
+ p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't loose the last line comment
+ p.setLineComment("// contains unexported methods")
+ }
+
+ }
+ p.print(unindent, formfeed, rbrace, token.RBRACE)
+}
+
+
+// ----------------------------------------------------------------------------
+// Expressions
+
+// exprContext describes the syntactic environment in which an expression node is printed.
+type exprContext uint
+
+const (
+ compositeLit exprContext = 1 << iota
+ structType
+)
+
+
+func walkBinary(e *ast.BinaryExpr) (has5, has6 bool, maxProblem int) {
+ switch e.Op.Precedence() {
+ case 5:
+ has5 = true
+ case 6:
+ has6 = true
+ }
+
+ switch l := e.X.(type) {
+ case *ast.BinaryExpr:
+ if l.Op.Precedence() < e.Op.Precedence() {
+ // parens will be inserted.
+ // pretend this is an *ast.ParenExpr and do nothing.
+ break
+ }
+ h5, h6, mp := walkBinary(l)
+ has5 = has5 || h5
+ has6 = has6 || h6
+ if maxProblem < mp {
+ maxProblem = mp
+ }
+ }
+
+ switch r := e.Y.(type) {
+ case *ast.BinaryExpr:
+ if r.Op.Precedence() <= e.Op.Precedence() {
+ // parens will be inserted.
+ // pretend this is an *ast.ParenExpr and do nothing.
+ break
+ }
+ h5, h6, mp := walkBinary(r)
+ has5 = has5 || h5
+ has6 = has6 || h6
+ if maxProblem < mp {
+ maxProblem = mp
+ }
+
+ case *ast.StarExpr:
+ if e.Op.String() == "/" {
+ maxProblem = 6
+ }
+
+ case *ast.UnaryExpr:
+ switch e.Op.String() + r.Op.String() {
+ case "/*", "&&", "&^":
+ maxProblem = 6
+ case "++", "--":
+ if maxProblem < 5 {
+ maxProblem = 5
+ }
+ }
+ }
+ return
+}
+
+
+func cutoff(e *ast.BinaryExpr, depth int) int {
+ has5, has6, maxProblem := walkBinary(e)
+ if maxProblem > 0 {
+ return maxProblem + 1
+ }
+ if has5 && has6 {
+ if depth == 1 {
+ return 6
+ }
+ return 5
+ }
+ if depth == 1 {
+ return 7
+ }
+ return 5
+}
+
+
+func diffPrec(expr ast.Expr, prec int) int {
+ x, ok := expr.(*ast.BinaryExpr)
+ if !ok || prec != x.Op.Precedence() {
+ return 1
+ }
+ return 0
+}
+
+
+func reduceDepth(depth int) int {
+ depth--
+ if depth < 1 {
+ depth = 1
+ }
+ return depth
+}
+
+
+// Format the binary expression: decide the cutoff and then format.
+// Let's call depth == 1 Normal mode, and depth > 1 Compact mode.
+// (Algorithm suggestion by Russ Cox.)
+//
+// The precedences are:
+// 6 * / % << >> & &^
+// 5 + - | ^
+// 4 == != < <= > >=
+// 3 <-
+// 2 &&
+// 1 ||
+//
+// The only decision is whether there will be spaces around levels 5 and 6.
+// There are never spaces at level 7 (unary), and always spaces at levels 4 and below.
+//
+// To choose the cutoff, look at the whole expression but excluding primary
+// expressions (function calls, parenthesized exprs), and apply these rules:
+//
+// 1) If there is a binary operator with a right side unary operand
+// that would clash without a space, the cutoff must be (in order):
+//
+// /* 7
+// && 7
+// &^ 7
+// ++ 6
+// -- 6
+//
+// (Comparison operators always have spaces around them.)
+//
+// 2) If there is a mix of level 6 and level 5 operators, then the cutoff
+// is 6 (use spaces to distinguish precedence) in Normal mode
+// and 5 (never use spaces) in Compact mode.
+//
+// 3) If there are no level 5 operators or no level 6 operators, then the
+// cutoff is 7 (always use spaces) in Normal mode
+// and 5 (never use spaces) in Compact mode.
+//
+// Sets multiLine to true if the binary expression spans multiple lines.
+func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiLine *bool) {
+ prec := x.Op.Precedence()
+ if prec < prec1 {
+ // parenthesis needed
+ // Note: The parser inserts an ast.ParenExpr node; thus this case
+ // can only occur if the AST is created in a different way.
+ p.print(token.LPAREN)
+ p.expr0(x, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ p.print(token.RPAREN)
+ return
+ }
+
+ printBlank := prec < cutoff
+
+ ws := indent
+ p.expr1(x.X, prec, depth+diffPrec(x.X, prec), 0, multiLine)
+ if printBlank {
+ p.print(blank)
+ }
+ xline := p.pos.Line // before the operator (it may be on the next line!)
+ yline := p.fset.Position(x.Y.Pos()).Line
+ p.print(x.OpPos, x.Op)
+ if xline != yline && xline > 0 && yline > 0 {
+ // at least one line break, but respect an extra empty line
+ // in the source
+ if p.linebreak(yline, 1, ws, true) {
+ ws = ignore
+ *multiLine = true
+ printBlank = false // no blank after line break
+ }
+ }
+ if printBlank {
+ p.print(blank)
+ }
+ p.expr1(x.Y, prec+1, depth+1, 0, multiLine)
+ if ws == ignore {
+ p.print(unindent)
+ }
+}
+
+
+func isBinary(expr ast.Expr) bool {
+ _, ok := expr.(*ast.BinaryExpr)
+ return ok
+}
+
+
+// If the expression contains one or more selector expressions, splits it into
+// two expressions at the rightmost period. Writes entire expr to suffix when
+// selector isn't found. Rewrites AST nodes for calls, index expressions and
+// type assertions, all of which may be found in selector chains, to make them
+// parts of the chain.
+func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
+ switch x := expr.(type) {
+ case *ast.SelectorExpr:
+ body, suffix = x.X, x.Sel
+ return
+ case *ast.CallExpr:
+ body, suffix = splitSelector(x.Fun)
+ if body != nil {
+ suffix = &ast.CallExpr{suffix, x.Lparen, x.Args, x.Ellipsis, x.Rparen}
+ return
+ }
+ case *ast.IndexExpr:
+ body, suffix = splitSelector(x.X)
+ if body != nil {
+ suffix = &ast.IndexExpr{suffix, x.Lbrack, x.Index, x.Rbrack}
+ return
+ }
+ case *ast.SliceExpr:
+ body, suffix = splitSelector(x.X)
+ if body != nil {
+ suffix = &ast.SliceExpr{suffix, x.Lbrack, x.Low, x.High, x.Rbrack}
+ return
+ }
+ case *ast.TypeAssertExpr:
+ body, suffix = splitSelector(x.X)
+ if body != nil {
+ suffix = &ast.TypeAssertExpr{suffix, x.Type}
+ return
+ }
+ }
+ suffix = expr
+ return
+}
+
+
+// Convert an expression into an expression list split at the periods of
+// selector expressions.
+func selectorExprList(expr ast.Expr) (list []ast.Expr) {
+ // split expression
+ for expr != nil {
+ var suffix ast.Expr
+ expr, suffix = splitSelector(expr)
+ list = append(list, suffix)
+ }
+
+ // reverse list
+ for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
+ list[i], list[j] = list[j], list[i]
+ }
+
+ return
+}
+
+
+// Sets multiLine to true if the expression spans multiple lines.
+func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multiLine *bool) {
+ p.print(expr.Pos())
+
+ switch x := expr.(type) {
+ case *ast.BadExpr:
+ p.print("BadExpr")
+
+ case *ast.Ident:
+ p.print(x)
+
+ case *ast.BinaryExpr:
+ if depth < 1 {
+ p.internalError("depth < 1:", depth)
+ depth = 1
+ }
+ p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine)
+
+ case *ast.KeyValueExpr:
+ p.expr(x.Key, multiLine)
+ p.print(x.Colon, token.COLON, blank)
+ p.expr(x.Value, multiLine)
+
+ case *ast.StarExpr:
+ const prec = token.UnaryPrec
+ if prec < prec1 {
+ // parenthesis needed
+ p.print(token.LPAREN)
+ p.print(token.MUL)
+ p.expr(x.X, multiLine)
+ p.print(token.RPAREN)
+ } else {
+ // no parenthesis needed
+ p.print(token.MUL)
+ p.expr(x.X, multiLine)
+ }
+
+ case *ast.UnaryExpr:
+ const prec = token.UnaryPrec
+ if prec < prec1 {
+ // parenthesis needed
+ p.print(token.LPAREN)
+ p.expr(x, multiLine)
+ p.print(token.RPAREN)
+ } else {
+ // no parenthesis needed
+ p.print(x.Op)
+ if x.Op == token.RANGE {
+ // TODO(gri) Remove this code if it cannot be reached.
+ p.print(blank)
+ }
+ p.expr1(x.X, prec, depth, 0, multiLine)
+ }
+
+ case *ast.BasicLit:
+ p.print(x)
+
+ case *ast.FuncLit:
+ p.expr(x.Type, multiLine)
+ p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiLine)
+
+ case *ast.ParenExpr:
+ if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
+ // don't print parentheses around an already parenthesized expression
+ // TODO(gri) consider making this more general and incorporate precedence levels
+ p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ } else {
+ p.print(token.LPAREN)
+ p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ p.print(x.Rparen, token.RPAREN)
+ }
+
+ case *ast.SelectorExpr:
+ parts := selectorExprList(expr)
+ p.exprList(token.NoPos, parts, depth, periodSep, multiLine, token.NoPos)
+
+ case *ast.TypeAssertExpr:
+ p.expr1(x.X, token.HighestPrec, depth, 0, multiLine)
+ p.print(token.PERIOD, token.LPAREN)
+ if x.Type != nil {
+ p.expr(x.Type, multiLine)
+ } else {
+ p.print(token.TYPE)
+ }
+ p.print(token.RPAREN)
+
+ case *ast.IndexExpr:
+ // TODO(gri): should treat[] like parentheses and undo one level of depth
+ p.expr1(x.X, token.HighestPrec, 1, 0, multiLine)
+ p.print(x.Lbrack, token.LBRACK)
+ p.expr0(x.Index, depth+1, multiLine)
+ p.print(x.Rbrack, token.RBRACK)
+
+ case *ast.SliceExpr:
+ // TODO(gri): should treat[] like parentheses and undo one level of depth
+ p.expr1(x.X, token.HighestPrec, 1, 0, multiLine)
+ p.print(x.Lbrack, token.LBRACK)
+ if x.Low != nil {
+ p.expr0(x.Low, depth+1, multiLine)
+ }
+ // blanks around ":" if both sides exist and either side is a binary expression
+ if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Low) || isBinary(x.High)) {
+ p.print(blank, token.COLON, blank)
+ } else {
+ p.print(token.COLON)
+ }
+ if x.High != nil {
+ p.expr0(x.High, depth+1, multiLine)
+ }
+ p.print(x.Rbrack, token.RBRACK)
+
+ case *ast.CallExpr:
+ if len(x.Args) > 1 {
+ depth++
+ }
+ p.expr1(x.Fun, token.HighestPrec, depth, 0, multiLine)
+ p.print(x.Lparen, token.LPAREN)
+ p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen)
+ if x.Ellipsis.IsValid() {
+ p.print(x.Ellipsis, token.ELLIPSIS)
+ }
+ p.print(x.Rparen, token.RPAREN)
+
+ case *ast.CompositeLit:
+ // composite literal elements that are composite literals themselves may have the type omitted
+ if x.Type != nil {
+ p.expr1(x.Type, token.HighestPrec, depth, compositeLit, multiLine)
+ }
+ p.print(x.Lbrace, token.LBRACE)
+ p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace)
+ // do not insert extra line breaks because of comments before
+ // the closing '}' as it might break the code if there is no
+ // trailing ','
+ p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak)
+
+ case *ast.Ellipsis:
+ p.print(token.ELLIPSIS)
+ if x.Elt != nil {
+ p.expr(x.Elt, multiLine)
+ }
+
+ case *ast.ArrayType:
+ p.print(token.LBRACK)
+ if x.Len != nil {
+ p.expr(x.Len, multiLine)
+ }
+ p.print(token.RBRACK)
+ p.expr(x.Elt, multiLine)
+
+ case *ast.StructType:
+ p.print(token.STRUCT)
+ p.fieldList(x.Fields, x.Incomplete, ctxt|structType)
+
+ case *ast.FuncType:
+ p.print(token.FUNC)
+ p.signature(x.Params, x.Results, multiLine)
+
+ case *ast.InterfaceType:
+ p.print(token.INTERFACE)
+ p.fieldList(x.Methods, x.Incomplete, ctxt)
+
+ case *ast.MapType:
+ p.print(token.MAP, token.LBRACK)
+ p.expr(x.Key, multiLine)
+ p.print(token.RBRACK)
+ p.expr(x.Value, multiLine)
+
+ case *ast.ChanType:
+ switch x.Dir {
+ case ast.SEND | ast.RECV:
+ p.print(token.CHAN)
+ case ast.RECV:
+ p.print(token.ARROW, token.CHAN)
+ case ast.SEND:
+ p.print(token.CHAN, token.ARROW)
+ }
+ p.print(blank)
+ p.expr(x.Value, multiLine)
+
+ default:
+ panic("unreachable")
+ }
+
+ return
+}
+
+
+func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) {
+ p.expr1(x, token.LowestPrec, depth, 0, multiLine)
+}
+
+
+// Sets multiLine to true if the expression spans multiple lines.
+func (p *printer) expr(x ast.Expr, multiLine *bool) {
+ const depth = 1
+ p.expr1(x, token.LowestPrec, depth, 0, multiLine)
+}
+
+
+// ----------------------------------------------------------------------------
+// Statements
+
+// Print the statement list indented, but without a newline after the last statement.
+// Extra line breaks between statements in the source are respected but at most one
+// empty line is printed between statements.
+func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
+ // TODO(gri): fix _indent code
+ if _indent > 0 {
+ p.print(indent)
+ }
+ var multiLine bool
+ for i, s := range list {
+ // _indent == 0 only for lists of switch/select case clauses;
+ // in those cases each clause is a new section
+ p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, i == 0 || _indent == 0 || multiLine)
+ multiLine = false
+ p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine)
+ }
+ if _indent > 0 {
+ p.print(unindent)
+ }
+}
+
+
+// block prints an *ast.BlockStmt; it always spans at least two lines.
+func (p *printer) block(s *ast.BlockStmt, indent int) {
+ p.print(s.Pos(), token.LBRACE)
+ p.stmtList(s.List, indent, true)
+ p.linebreak(p.fset.Position(s.Rbrace).Line, 1, ignore, true)
+ p.print(s.Rbrace, token.RBRACE)
+}
+
+
+func isTypeName(x ast.Expr) bool {
+ switch t := x.(type) {
+ case *ast.Ident:
+ return true
+ case *ast.SelectorExpr:
+ return isTypeName(t.X)
+ }
+ return false
+}
+
+
+func stripParens(x ast.Expr) ast.Expr {
+ if px, strip := x.(*ast.ParenExpr); strip {
+ // parentheses must not be stripped if there are any
+ // unparenthesized composite literals starting with
+ // a type name
+ ast.Inspect(px.X, func(node ast.Node) bool {
+ switch x := node.(type) {
+ case *ast.ParenExpr:
+ // parentheses protect enclosed composite literals
+ return false
+ case *ast.CompositeLit:
+ if isTypeName(x.Type) {
+ strip = false // do not strip parentheses
+ }
+ return false
+ }
+ // in all other cases, keep inspecting
+ return true
+ })
+ if strip {
+ return stripParens(px.X)
+ }
+ }
+ return x
+}
+
+
+func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
+ p.print(blank)
+ needsBlank := false
+ if init == nil && post == nil {
+ // no semicolons required
+ if expr != nil {
+ p.expr(stripParens(expr), ignoreMultiLine)
+ needsBlank = true
+ }
+ } else {
+ // all semicolons required
+ // (they are not separators, print them explicitly)
+ if init != nil {
+ p.stmt(init, false, ignoreMultiLine)
+ }
+ p.print(token.SEMICOLON, blank)
+ if expr != nil {
+ p.expr(stripParens(expr), ignoreMultiLine)
+ needsBlank = true
+ }
+ if isForStmt {
+ p.print(token.SEMICOLON, blank)
+ needsBlank = false
+ if post != nil {
+ p.stmt(post, false, ignoreMultiLine)
+ needsBlank = true
+ }
+ }
+ }
+ if needsBlank {
+ p.print(blank)
+ }
+}
+
+
+// Sets multiLine to true if the statements spans multiple lines.
+func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
+ p.print(stmt.Pos())
+
+ switch s := stmt.(type) {
+ case *ast.BadStmt:
+ p.print("BadStmt")
+
+ case *ast.DeclStmt:
+ p.decl(s.Decl, multiLine)
+
+ case *ast.EmptyStmt:
+ // nothing to do
+
+ case *ast.LabeledStmt:
+ // a "correcting" unindent immediately following a line break
+ // is applied before the line break if there is no comment
+ // between (see writeWhitespace)
+ p.print(unindent)
+ p.expr(s.Label, multiLine)
+ p.print(s.Colon, token.COLON, indent)
+ if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
+ if !nextIsRBrace {
+ p.print(newline, e.Pos(), token.SEMICOLON)
+ break
+ }
+ } else {
+ p.linebreak(p.fset.Position(s.Stmt.Pos()).Line, 1, ignore, true)
+ }
+ p.stmt(s.Stmt, nextIsRBrace, multiLine)
+
+ case *ast.ExprStmt:
+ const depth = 1
+ p.expr0(s.X, depth, multiLine)
+
+ case *ast.IncDecStmt:
+ const depth = 1
+ p.expr0(s.X, depth+1, multiLine)
+ p.print(s.TokPos, s.Tok)
+
+ case *ast.AssignStmt:
+ var depth = 1
+ if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
+ depth++
+ }
+ p.exprList(s.Pos(), s.Lhs, depth, commaSep, multiLine, s.TokPos)
+ p.print(blank, s.TokPos, s.Tok)
+ p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, multiLine, token.NoPos)
+
+ case *ast.GoStmt:
+ p.print(token.GO, blank)
+ p.expr(s.Call, multiLine)
+
+ case *ast.DeferStmt:
+ p.print(token.DEFER, blank)
+ p.expr(s.Call, multiLine)
+
+ case *ast.ReturnStmt:
+ p.print(token.RETURN)
+ if s.Results != nil {
+ p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, token.NoPos)
+ }
+
+ case *ast.BranchStmt:
+ p.print(s.Tok)
+ if s.Label != nil {
+ p.print(blank)
+ p.expr(s.Label, multiLine)
+ }
+
+ case *ast.BlockStmt:
+ p.block(s, 1)
+ *multiLine = true
+
+ case *ast.IfStmt:
+ p.print(token.IF)
+ p.controlClause(false, s.Init, s.Cond, nil)
+ p.block(s.Body, 1)
+ *multiLine = true
+ if s.Else != nil {
+ p.print(blank, token.ELSE, blank)
+ switch s.Else.(type) {
+ case *ast.BlockStmt, *ast.IfStmt:
+ p.stmt(s.Else, nextIsRBrace, ignoreMultiLine)
+ default:
+ p.print(token.LBRACE, indent, formfeed)
+ p.stmt(s.Else, true, ignoreMultiLine)
+ p.print(unindent, formfeed, token.RBRACE)
+ }
+ }
+
+ case *ast.CaseClause:
+ if s.Values != nil {
+ p.print(token.CASE)
+ p.exprList(s.Pos(), s.Values, 1, blankStart|commaSep, multiLine, s.Colon)
+ } else {
+ p.print(token.DEFAULT)
+ }
+ p.print(s.Colon, token.COLON)
+ p.stmtList(s.Body, 1, nextIsRBrace)
+
+ case *ast.SwitchStmt:
+ p.print(token.SWITCH)
+ p.controlClause(false, s.Init, s.Tag, nil)
+ p.block(s.Body, 0)
+ *multiLine = true
+
+ case *ast.TypeCaseClause:
+ if s.Types != nil {
+ p.print(token.CASE)
+ p.exprList(s.Pos(), s.Types, 1, blankStart|commaSep, multiLine, s.Colon)
+ } else {
+ p.print(token.DEFAULT)
+ }
+ p.print(s.Colon, token.COLON)
+ p.stmtList(s.Body, 1, nextIsRBrace)
+
+ case *ast.TypeSwitchStmt:
+ p.print(token.SWITCH)
+ if s.Init != nil {
+ p.print(blank)
+ p.stmt(s.Init, false, ignoreMultiLine)
+ p.print(token.SEMICOLON)
+ }
+ p.print(blank)
+ p.stmt(s.Assign, false, ignoreMultiLine)
+ p.print(blank)
+ p.block(s.Body, 0)
+ *multiLine = true
+
+ case *ast.CommClause:
+ if s.Rhs != nil {
+ p.print(token.CASE, blank)
+ if s.Lhs != nil {
+ p.expr(s.Lhs, multiLine)
+ p.print(blank, s.Tok, blank)
+ }
+ p.expr(s.Rhs, multiLine)
+ } else {
+ p.print(token.DEFAULT)
+ }
+ p.print(s.Colon, token.COLON)
+ p.stmtList(s.Body, 1, nextIsRBrace)
+
+ case *ast.SelectStmt:
+ p.print(token.SELECT, blank)
+ p.block(s.Body, 0)
+ *multiLine = true
+
+ case *ast.ForStmt:
+ p.print(token.FOR)
+ p.controlClause(true, s.Init, s.Cond, s.Post)
+ p.block(s.Body, 1)
+ *multiLine = true
+
+ case *ast.RangeStmt:
+ p.print(token.FOR, blank)
+ p.expr(s.Key, multiLine)
+ if s.Value != nil {
+ p.print(token.COMMA, blank)
+ p.expr(s.Value, multiLine)
+ }
+ p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
+ p.expr(stripParens(s.X), multiLine)
+ p.print(blank)
+ p.block(s.Body, 1)
+ *multiLine = true
+
+ default:
+ panic("unreachable")
+ }
+
+ return
+}
+
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// The parameter n is the number of specs in the group. If doIndent is set,
+// multi-line identifier lists in the spec are indented when the first
+// linebreak is encountered.
+// Sets multiLine to true if the spec spans multiple lines.
+//
+func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
+ switch s := spec.(type) {
+ case *ast.ImportSpec:
+ p.setComment(s.Doc)
+ if s.Name != nil {
+ p.expr(s.Name, multiLine)
+ p.print(vtab)
+ }
+ p.expr(s.Path, multiLine)
+ p.setComment(s.Comment)
+
+ case *ast.ValueSpec:
+ p.setComment(s.Doc)
+ p.identList(s.Names, doIndent, multiLine) // always present
+ if n == 1 {
+ if s.Type != nil {
+ p.print(blank)
+ p.expr(s.Type, multiLine)
+ }
+ if s.Values != nil {
+ p.print(blank, token.ASSIGN)
+ p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
+ }
+ p.setComment(s.Comment)
+
+ } else {
+ extraTabs := 3
+ if s.Type != nil {
+ p.print(vtab)
+ p.expr(s.Type, multiLine)
+ extraTabs--
+ }
+ if s.Values != nil {
+ p.print(vtab, token.ASSIGN)
+ p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
+ extraTabs--
+ }
+ if s.Comment != nil {
+ for ; extraTabs > 0; extraTabs-- {
+ p.print(vtab)
+ }
+ p.setComment(s.Comment)
+ }
+ }
+
+ case *ast.TypeSpec:
+ p.setComment(s.Doc)
+ p.expr(s.Name, multiLine)
+ if n == 1 {
+ p.print(blank)
+ } else {
+ p.print(vtab)
+ }
+ p.expr(s.Type, multiLine)
+ p.setComment(s.Comment)
+
+ default:
+ panic("unreachable")
+ }
+}
+
+
+// Sets multiLine to true if the declaration spans multiple lines.
+func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
+ p.setComment(d.Doc)
+ p.print(d.Pos(), d.Tok, blank)
+
+ if d.Lparen.IsValid() {
+ // group of parenthesized declarations
+ p.print(d.Lparen, token.LPAREN)
+ if len(d.Specs) > 0 {
+ p.print(indent, formfeed)
+ var ml bool
+ for i, s := range d.Specs {
+ if i > 0 {
+ p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
+ }
+ ml = false
+ p.spec(s, len(d.Specs), false, &ml)
+ }
+ p.print(unindent, formfeed)
+ *multiLine = true
+ }
+ p.print(d.Rparen, token.RPAREN)
+
+ } else {
+ // single declaration
+ p.spec(d.Specs[0], 1, true, multiLine)
+ }
+}
+
+
+// nodeSize determines the size of n in chars after formatting.
+// The result is <= maxSize if the node fits on one line with at
+// most maxSize chars and the formatted output doesn't contain
+// any control chars. Otherwise, the result is > maxSize.
+//
+func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
+ size = maxSize + 1 // assume n doesn't fit
+ // nodeSize computation must be indendent of particular
+ // style so that we always get the same decision; print
+ // in RawFormat
+ cfg := Config{Mode: RawFormat}
+ var buf bytes.Buffer
+ if _, err := cfg.Fprint(&buf, p.fset, n); err != nil {
+ return
+ }
+ if buf.Len() <= maxSize {
+ for _, ch := range buf.Bytes() {
+ if ch < ' ' {
+ return
+ }
+ }
+ size = buf.Len() // n fits
+ }
+ return
+}
+
+
+func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
+ pos1 := b.Pos()
+ pos2 := b.Rbrace
+ if pos1.IsValid() && pos2.IsValid() && p.fset.Position(pos1).Line != p.fset.Position(pos2).Line {
+ // opening and closing brace are on different lines - don't make it a one-liner
+ return false
+ }
+ if len(b.List) > 5 || p.commentBefore(p.fset.Position(pos2)) {
+ // too many statements or there is a comment inside - don't make it a one-liner
+ return false
+ }
+ // otherwise, estimate body size
+ const maxSize = 100
+ bodySize := 0
+ for i, s := range b.List {
+ if i > 0 {
+ bodySize += 2 // space for a semicolon and blank
+ }
+ bodySize += p.nodeSize(s, maxSize)
+ }
+ return headerSize+bodySize <= maxSize
+}
+
+
+// Sets multiLine to true if the function body spans multiple lines.
+func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLine *bool) {
+ if b == nil {
+ return
+ }
+
+ p.nesting++
+ defer func() {
+ p.nesting--
+ }()
+
+ if p.isOneLineFunc(b, headerSize) {
+ sep := vtab
+ if isLit {
+ sep = blank
+ }
+ p.print(sep, b.Lbrace, token.LBRACE)
+ if len(b.List) > 0 {
+ p.print(blank)
+ for i, s := range b.List {
+ if i > 0 {
+ p.print(token.SEMICOLON, blank)
+ }
+ p.stmt(s, i == len(b.List)-1, ignoreMultiLine)
+ }
+ p.print(blank)
+ }
+ p.print(b.Rbrace, token.RBRACE)
+ return
+ }
+
+ p.print(blank)
+ p.block(b, 1)
+ *multiLine = true
+}
+
+
+// distance returns the column difference between from and to if both
+// are on the same line; if they are on different lines (or unknown)
+// the result is infinity.
+func (p *printer) distance(from0 token.Pos, to token.Position) int {
+ from := p.fset.Position(from0)
+ if from.IsValid() && to.IsValid() && from.Line == to.Line {
+ return to.Column - from.Column
+ }
+ return infinity
+}
+
+
+// Sets multiLine to true if the declaration spans multiple lines.
+func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
+ p.setComment(d.Doc)
+ p.print(d.Pos(), token.FUNC, blank)
+ if d.Recv != nil {
+ p.parameters(d.Recv, multiLine) // method: print receiver
+ p.print(blank)
+ }
+ p.expr(d.Name, multiLine)
+ p.signature(d.Type.Params, d.Type.Results, multiLine)
+ p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine)
+}
+
+
+// Sets multiLine to true if the declaration spans multiple lines.
+func (p *printer) decl(decl ast.Decl, multiLine *bool) {
+ switch d := decl.(type) {
+ case *ast.BadDecl:
+ p.print(d.Pos(), "BadDecl")
+ case *ast.GenDecl:
+ p.genDecl(d, multiLine)
+ case *ast.FuncDecl:
+ p.funcDecl(d, multiLine)
+ default:
+ panic("unreachable")
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// Files
+
+func declToken(decl ast.Decl) (tok token.Token) {
+ tok = token.ILLEGAL
+ switch d := decl.(type) {
+ case *ast.GenDecl:
+ tok = d.Tok
+ case *ast.FuncDecl:
+ tok = token.FUNC
+ }
+ return
+}
+
+
+func (p *printer) file(src *ast.File) {
+ p.setComment(src.Doc)
+ p.print(src.Pos(), token.PACKAGE, blank)
+ p.expr(src.Name, ignoreMultiLine)
+
+ if len(src.Decls) > 0 {
+ tok := token.ILLEGAL
+ for _, d := range src.Decls {
+ prev := tok
+ tok = declToken(d)
+ // if the declaration token changed (e.g., from CONST to TYPE)
+ // print an empty line between top-level declarations
+ min := 1
+ if prev != tok {
+ min = 2
+ }
+ p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false)
+ p.decl(d, ignoreMultiLine)
+ }
+ }
+
+ p.print(newline)
+}
diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go
new file mode 100644
index 000000000..34b0c4e2d
--- /dev/null
+++ b/libgo/go/go/printer/printer.go
@@ -0,0 +1,1140 @@
+// 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.
+
+// The printer package implements printing of AST nodes.
+package printer
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "io"
+ "os"
+ "path"
+ "runtime"
+ "tabwriter"
+)
+
+
+const debug = false // enable for debugging
+
+
+type whiteSpace int
+
+const (
+ ignore = whiteSpace(0)
+ blank = whiteSpace(' ')
+ vtab = whiteSpace('\v')
+ newline = whiteSpace('\n')
+ formfeed = whiteSpace('\f')
+ indent = whiteSpace('>')
+ unindent = whiteSpace('<')
+)
+
+
+var (
+ esc = []byte{tabwriter.Escape}
+ htab = []byte{'\t'}
+ htabs = []byte("\t\t\t\t\t\t\t\t")
+ newlines = []byte("\n\n\n\n\n\n\n\n") // more than the max determined by nlines
+ formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines
+
+ esc_quot = []byte("&#34;") // shorter than "&quot;"
+ esc_apos = []byte("&#39;") // shorter than "&apos;"
+ esc_amp = []byte("&amp;")
+ esc_lt = []byte("&lt;")
+ esc_gt = []byte("&gt;")
+)
+
+
+// Special positions
+var noPos token.Position // use noPos when a position is needed but not known
+var infinity = 1 << 30
+
+
+// Use ignoreMultiLine if the multiLine information is not important.
+var ignoreMultiLine = new(bool)
+
+
+// A pmode value represents the current printer mode.
+type pmode int
+
+const (
+ inLiteral pmode = 1 << iota
+ noExtraLinebreak
+)
+
+
+type printer struct {
+ // Configuration (does not change after initialization)
+ output io.Writer
+ Config
+ fset *token.FileSet
+ errors chan os.Error
+
+ // Current state
+ nesting int // nesting level (0: top-level (package scope), >0: functions/decls.)
+ written int // number of bytes written
+ indent int // current indentation
+ mode pmode // current printer mode
+ lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace)
+
+ // Buffered whitespace
+ buffer []whiteSpace
+
+ // The (possibly estimated) position in the generated output;
+ // in AST space (i.e., pos is set whenever a token position is
+ // known accurately, and updated dependending on what has been
+ // written).
+ pos token.Position
+
+ // The value of pos immediately after the last item has been
+ // written using writeItem.
+ last token.Position
+
+ // HTML support
+ lastTaggedLine int // last line for which a line tag was written
+
+ // The list of all source comments, in order of appearance.
+ comments []*ast.CommentGroup // may be nil
+ cindex int // current comment index
+ useNodeComments bool // if not set, ignore lead and line comments of nodes
+}
+
+
+func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet) {
+ p.output = output
+ p.Config = *cfg
+ p.fset = fset
+ p.errors = make(chan os.Error)
+ p.buffer = make([]whiteSpace, 0, 16) // whitespace sequences are short
+}
+
+
+func (p *printer) internalError(msg ...interface{}) {
+ if debug {
+ fmt.Print(p.pos.String() + ": ")
+ fmt.Println(msg...)
+ panic("go/printer")
+ }
+}
+
+
+// nlines returns the adjusted number of linebreaks given the desired number
+// of breaks n such that min <= result <= max where max depends on the current
+// nesting level.
+//
+func (p *printer) nlines(n, min int) int {
+ if n < min {
+ return min
+ }
+ max := 3 // max. number of newlines at the top level (p.nesting == 0)
+ if p.nesting > 0 {
+ max = 2 // max. number of newlines everywhere else
+ }
+ if n > max {
+ return max
+ }
+ return n
+}
+
+
+// write0 writes raw (uninterpreted) data to p.output and handles errors.
+// write0 does not indent after newlines, and does not HTML-escape or update p.pos.
+//
+func (p *printer) write0(data []byte) {
+ n, err := p.output.Write(data)
+ p.written += n
+ if err != nil {
+ p.errors <- err
+ runtime.Goexit()
+ }
+}
+
+
+// write interprets data and writes it to p.output. It inserts indentation
+// after a line break unless in a tabwriter escape sequence, and it HTML-
+// escapes characters if GenHTML is set. It updates p.pos as a side-effect.
+//
+func (p *printer) write(data []byte) {
+ i0 := 0
+ for i, b := range data {
+ switch b {
+ case '\n', '\f':
+ // write segment ending in b
+ p.write0(data[i0 : i+1])
+
+ // update p.pos
+ p.pos.Offset += i + 1 - i0
+ p.pos.Line++
+ p.pos.Column = 1
+
+ if p.mode&inLiteral == 0 {
+ // write indentation
+ // use "hard" htabs - indentation columns
+ // must not be discarded by the tabwriter
+ j := p.indent
+ for ; j > len(htabs); j -= len(htabs) {
+ p.write0(htabs)
+ }
+ p.write0(htabs[0:j])
+
+ // update p.pos
+ p.pos.Offset += p.indent
+ p.pos.Column += p.indent
+ }
+
+ // next segment start
+ i0 = i + 1
+
+ case '"', '\'', '&', '<', '>':
+ if p.Mode&GenHTML != 0 {
+ // write segment ending in b
+ p.write0(data[i0:i])
+
+ // write HTML-escaped b
+ var esc []byte
+ switch b {
+ case '"':
+ esc = esc_quot
+ case '\'':
+ esc = esc_apos
+ case '&':
+ esc = esc_amp
+ case '<':
+ esc = esc_lt
+ case '>':
+ esc = esc_gt
+ }
+ p.write0(esc)
+
+ // update p.pos
+ d := i + 1 - i0
+ p.pos.Offset += d
+ p.pos.Column += d
+
+ // next segment start
+ i0 = i + 1
+ }
+
+ case tabwriter.Escape:
+ p.mode ^= inLiteral
+
+ // ignore escape chars introduced by printer - they are
+ // invisible and must not affect p.pos (was issue #1089)
+ p.pos.Offset--
+ p.pos.Column--
+ }
+ }
+
+ // write remaining segment
+ p.write0(data[i0:])
+
+ // update p.pos
+ d := len(data) - i0
+ p.pos.Offset += d
+ p.pos.Column += d
+}
+
+
+func (p *printer) writeNewlines(n int, useFF bool) {
+ if n > 0 {
+ n = p.nlines(n, 0)
+ if useFF {
+ p.write(formfeeds[0:n])
+ } else {
+ p.write(newlines[0:n])
+ }
+ }
+}
+
+
+func (p *printer) writeTaggedItem(data []byte, tag HTMLTag) {
+ // write start tag, if any
+ // (no html-escaping and no p.pos update for tags - use write0)
+ if tag.Start != "" {
+ p.write0([]byte(tag.Start))
+ }
+ p.write(data)
+ // write end tag, if any
+ if tag.End != "" {
+ p.write0([]byte(tag.End))
+ }
+}
+
+
+// writeItem writes data at position pos. data is the text corresponding to
+// a single lexical token, but may also be comment text. pos is the actual
+// (or at least very accurately estimated) position of the data in the original
+// source text. If tags are present and GenHTML is set, the tags are written
+// before and after the data. writeItem updates p.last to the position
+// immediately following the data.
+//
+func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) {
+ fileChanged := false
+ if pos.IsValid() {
+ // continue with previous position if we don't have a valid pos
+ if p.last.IsValid() && p.last.Filename != pos.Filename {
+ // the file has changed - reset state
+ // (used when printing merged ASTs of different files
+ // e.g., the result of ast.MergePackageFiles)
+ p.indent = 0
+ p.mode = 0
+ p.buffer = p.buffer[0:0]
+ fileChanged = true
+ }
+ p.pos = pos
+ }
+ if debug {
+ // do not update p.pos - use write0
+ _, filename := path.Split(pos.Filename)
+ p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, pos.Column)))
+ }
+ if p.Mode&GenHTML != 0 {
+ // write line tag if on a new line
+ // TODO(gri): should write line tags on each line at the start
+ // will be more useful (e.g. to show line numbers)
+ if p.Styler != nil && (pos.Line != p.lastTaggedLine || fileChanged) {
+ p.writeTaggedItem(p.Styler.LineTag(pos.Line))
+ p.lastTaggedLine = pos.Line
+ }
+ p.writeTaggedItem(data, tag)
+ } else {
+ p.write(data)
+ }
+ p.last = p.pos
+}
+
+
+// writeCommentPrefix writes the whitespace before a comment.
+// If there is any pending whitespace, it consumes as much of
+// it as is likely to help position the comment nicely.
+// pos is the comment position, next the position of the item
+// after all pending comments, isFirst indicates if this is the
+// first comment in a group of comments, and isKeyword indicates
+// if the next item is a keyword.
+//
+func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeyword bool) {
+ if !p.last.IsValid() {
+ // there was no preceeding item and the comment is the
+ // first item to be printed - don't write any whitespace
+ return
+ }
+
+ if pos.IsValid() && pos.Filename != p.last.Filename {
+ // comment in a different file - separate with newlines (writeNewlines will limit the number)
+ p.writeNewlines(10, true)
+ return
+ }
+
+ if pos.IsValid() && pos.Line == p.last.Line {
+ // comment on the same line as last item:
+ // separate with at least one separator
+ hasSep := false
+ if isFirst {
+ j := 0
+ for i, ch := range p.buffer {
+ switch ch {
+ case blank:
+ // ignore any blanks before a comment
+ p.buffer[i] = ignore
+ continue
+ case vtab:
+ // respect existing tabs - important
+ // for proper formatting of commented structs
+ hasSep = true
+ continue
+ case indent:
+ // apply pending indentation
+ continue
+ }
+ j = i
+ break
+ }
+ p.writeWhitespace(j)
+ }
+ // make sure there is at least one separator
+ if !hasSep {
+ if pos.Line == next.Line {
+ // next item is on the same line as the comment
+ // (which must be a /*-style comment): separate
+ // with a blank instead of a tab
+ p.write([]byte{' '})
+ } else {
+ p.write(htab)
+ }
+ }
+
+ } else {
+ // comment on a different line:
+ // separate with at least one line break
+ if isFirst {
+ j := 0
+ for i, ch := range p.buffer {
+ switch ch {
+ case blank, vtab:
+ // ignore any horizontal whitespace before line breaks
+ p.buffer[i] = ignore
+ continue
+ case indent:
+ // apply pending indentation
+ continue
+ case unindent:
+ // if the next token is a keyword, apply the outdent
+ // if it appears that the comment is aligned with the
+ // keyword; otherwise assume the outdent is part of a
+ // closing block and stop (this scenario appears with
+ // comments before a case label where the comments
+ // apply to the next case instead of the current one)
+ if isKeyword && pos.Column == next.Column {
+ continue
+ }
+ case newline, formfeed:
+ // TODO(gri): may want to keep formfeed info in some cases
+ p.buffer[i] = ignore
+ }
+ j = i
+ break
+ }
+ p.writeWhitespace(j)
+ }
+ // use formfeeds to break columns before a comment;
+ // this is analogous to using formfeeds to separate
+ // individual lines of /*-style comments
+ // (if !pos.IsValid(), pos.Line == 0, and this will
+ // print no newlines)
+ p.writeNewlines(pos.Line-p.last.Line, true)
+ }
+}
+
+
+func (p *printer) writeCommentLine(comment *ast.Comment, pos token.Position, line []byte) {
+ // line must pass through unchanged, bracket it with tabwriter.Escape
+ line = bytes.Join([][]byte{esc, line, esc}, nil)
+
+ // apply styler, if any
+ var tag HTMLTag
+ if p.Styler != nil {
+ line, tag = p.Styler.Comment(comment, line)
+ }
+
+ p.writeItem(pos, line, tag)
+}
+
+
+// TODO(gri): Similar (but not quite identical) functionality for
+// comment processing can be found in go/doc/comment.go.
+// Perhaps this can be factored eventually.
+
+// Split comment text into lines
+func split(text []byte) [][]byte {
+ // count lines (comment text never ends in a newline)
+ n := 1
+ for _, c := range text {
+ if c == '\n' {
+ n++
+ }
+ }
+
+ // split
+ lines := make([][]byte, n)
+ n = 0
+ i := 0
+ for j, c := range text {
+ if c == '\n' {
+ lines[n] = text[i:j] // exclude newline
+ i = j + 1 // discard newline
+ n++
+ }
+ }
+ lines[n] = text[i:]
+
+ return lines
+}
+
+
+func isBlank(s []byte) bool {
+ for _, b := range s {
+ if b > ' ' {
+ return false
+ }
+ }
+ return true
+}
+
+
+func commonPrefix(a, b []byte) []byte {
+ i := 0
+ for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') {
+ i++
+ }
+ return a[0:i]
+}
+
+
+func stripCommonPrefix(lines [][]byte) {
+ if len(lines) < 2 {
+ return // at most one line - nothing to do
+ }
+ // len(lines) >= 2
+
+ // The heuristic in this function tries to handle a few
+ // common patterns of /*-style comments: Comments where
+ // the opening /* and closing */ are aligned and the
+ // rest of the comment text is aligned and indented with
+ // blanks or tabs, cases with a vertical "line of stars"
+ // on the left, and cases where the closing */ is on the
+ // same line as the last comment text.
+
+ // Compute maximum common white prefix of all but the first,
+ // last, and blank lines, and replace blank lines with empty
+ // lines (the first line starts with /* and has no prefix).
+ // In case of two-line comments, consider the last line for
+ // the prefix computation since otherwise the prefix would
+ // be empty.
+ //
+ // Note that the first and last line are never empty (they
+ // contain the opening /* and closing */ respectively) and
+ // thus they can be ignored by the blank line check.
+ var prefix []byte
+ if len(lines) > 2 {
+ for i, line := range lines[1 : len(lines)-1] {
+ switch {
+ case isBlank(line):
+ lines[1+i] = nil // range starts at line 1
+ case prefix == nil:
+ prefix = commonPrefix(line, line)
+ default:
+ prefix = commonPrefix(prefix, line)
+ }
+ }
+ } else { // len(lines) == 2
+ line := lines[1]
+ prefix = commonPrefix(line, line)
+ }
+
+ /*
+ * Check for vertical "line of stars" and correct prefix accordingly.
+ */
+ lineOfStars := false
+ if i := bytes.Index(prefix, []byte{'*'}); i >= 0 {
+ // Line of stars present.
+ if i > 0 && prefix[i-1] == ' ' {
+ i-- // remove trailing blank from prefix so stars remain aligned
+ }
+ prefix = prefix[0:i]
+ lineOfStars = true
+ } else {
+ // No line of stars present.
+ // Determine the white space on the first line after the /*
+ // and before the beginning of the comment text, assume two
+ // blanks instead of the /* unless the first character after
+ // the /* is a tab. If the first comment line is empty but
+ // for the opening /*, assume up to 3 blanks or a tab. This
+ // whitespace may be found as suffix in the common prefix.
+ first := lines[0]
+ if isBlank(first[2:]) {
+ // no comment text on the first line:
+ // reduce prefix by up to 3 blanks or a tab
+ // if present - this keeps comment text indented
+ // relative to the /* and */'s if it was indented
+ // in the first place
+ i := len(prefix)
+ for n := 0; n < 3 && i > 0 && prefix[i-1] == ' '; n++ {
+ i--
+ }
+ if i == len(prefix) && i > 0 && prefix[i-1] == '\t' {
+ i--
+ }
+ prefix = prefix[0:i]
+ } else {
+ // comment text on the first line
+ suffix := make([]byte, len(first))
+ n := 2 // start after opening /*
+ for n < len(first) && first[n] <= ' ' {
+ suffix[n] = first[n]
+ n++
+ }
+ if n > 2 && suffix[2] == '\t' {
+ // assume the '\t' compensates for the /*
+ suffix = suffix[2:n]
+ } else {
+ // otherwise assume two blanks
+ suffix[0], suffix[1] = ' ', ' '
+ suffix = suffix[0:n]
+ }
+ // Shorten the computed common prefix by the length of
+ // suffix, if it is found as suffix of the prefix.
+ if bytes.HasSuffix(prefix, suffix) {
+ prefix = prefix[0 : len(prefix)-len(suffix)]
+ }
+ }
+ }
+
+ // Handle last line: If it only contains a closing */, align it
+ // with the opening /*, otherwise align the text with the other
+ // lines.
+ last := lines[len(lines)-1]
+ closing := []byte("*/")
+ i := bytes.Index(last, closing)
+ if isBlank(last[0:i]) {
+ // last line only contains closing */
+ var sep []byte
+ if lineOfStars {
+ // insert an aligning blank
+ sep = []byte{' '}
+ }
+ lines[len(lines)-1] = bytes.Join([][]byte{prefix, closing}, sep)
+ } else {
+ // last line contains more comment text - assume
+ // it is aligned like the other lines
+ prefix = commonPrefix(prefix, last)
+ }
+
+ // Remove the common prefix from all but the first and empty lines.
+ for i, line := range lines[1:] {
+ if len(line) != 0 {
+ lines[1+i] = line[len(prefix):] // range starts at line 1
+ }
+ }
+}
+
+
+func (p *printer) writeComment(comment *ast.Comment) {
+ text := comment.Text
+
+ // shortcut common case of //-style comments
+ if text[1] == '/' {
+ p.writeCommentLine(comment, p.fset.Position(comment.Pos()), text)
+ return
+ }
+
+ // for /*-style comments, print line by line and let the
+ // write function take care of the proper indentation
+ lines := split(text)
+ stripCommonPrefix(lines)
+
+ // write comment lines, separated by formfeed,
+ // without a line break after the last line
+ linebreak := formfeeds[0:1]
+ pos := p.fset.Position(comment.Pos())
+ for i, line := range lines {
+ if i > 0 {
+ p.write(linebreak)
+ pos = p.pos
+ }
+ if len(line) > 0 {
+ p.writeCommentLine(comment, pos, line)
+ }
+ }
+}
+
+
+// writeCommentSuffix writes a line break after a comment if indicated
+// and processes any leftover indentation information. If a line break
+// is needed, the kind of break (newline vs formfeed) depends on the
+// pending whitespace. writeCommentSuffix returns true if a pending
+// formfeed was dropped from the whitespace buffer.
+//
+func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
+ for i, ch := range p.buffer {
+ switch ch {
+ case blank, vtab:
+ // ignore trailing whitespace
+ p.buffer[i] = ignore
+ case indent, unindent:
+ // don't loose indentation information
+ case newline, formfeed:
+ // if we need a line break, keep exactly one
+ // but remember if we dropped any formfeeds
+ if needsLinebreak {
+ needsLinebreak = false
+ } else {
+ if ch == formfeed {
+ droppedFF = true
+ }
+ p.buffer[i] = ignore
+ }
+ }
+ }
+ p.writeWhitespace(len(p.buffer))
+
+ // make sure we have a line break
+ if needsLinebreak {
+ p.write([]byte{'\n'})
+ }
+
+ return
+}
+
+
+// intersperseComments consumes all comments that appear before the next token
+// tok and prints it together with the buffered whitespace (i.e., the whitespace
+// that needs to be written before the next token). A heuristic is used to mix
+// the comments and whitespace. intersperseComments returns true if a pending
+// formfeed was dropped from the whitespace buffer.
+//
+func (p *printer) intersperseComments(next token.Position, tok token.Token) (droppedFF bool) {
+ var last *ast.Comment
+ for ; p.commentBefore(next); p.cindex++ {
+ for _, c := range p.comments[p.cindex].List {
+ p.writeCommentPrefix(p.fset.Position(c.Pos()), next, last == nil, tok.IsKeyword())
+ p.writeComment(c)
+ last = c
+ }
+ }
+
+ if last != nil {
+ if last.Text[1] == '*' && p.fset.Position(last.Pos()).Line == next.Line {
+ // the last comment is a /*-style comment and the next item
+ // follows on the same line: separate with an extra blank
+ p.write([]byte{' '})
+ }
+ // ensure that there is a line break after a //-style comment,
+ // before a closing '}' unless explicitly disabled, or at eof
+ needsLinebreak :=
+ last.Text[1] == '/' ||
+ tok == token.RBRACE && p.mode&noExtraLinebreak == 0 ||
+ tok == token.EOF
+ return p.writeCommentSuffix(needsLinebreak)
+ }
+
+ // no comment was written - we should never reach here since
+ // intersperseComments should not be called in that case
+ p.internalError("intersperseComments called without pending comments")
+ return false
+}
+
+
+// whiteWhitespace writes the first n whitespace entries.
+func (p *printer) writeWhitespace(n int) {
+ // write entries
+ var data [1]byte
+ for i := 0; i < n; i++ {
+ switch ch := p.buffer[i]; ch {
+ case ignore:
+ // ignore!
+ case indent:
+ p.indent++
+ case unindent:
+ p.indent--
+ if p.indent < 0 {
+ p.internalError("negative indentation:", p.indent)
+ p.indent = 0
+ }
+ case newline, formfeed:
+ // A line break immediately followed by a "correcting"
+ // unindent is swapped with the unindent - this permits
+ // proper label positioning. If a comment is between
+ // the line break and the label, the unindent is not
+ // part of the comment whitespace prefix and the comment
+ // will be positioned correctly indented.
+ if i+1 < n && p.buffer[i+1] == unindent {
+ // Use a formfeed to terminate the current section.
+ // Otherwise, a long label name on the next line leading
+ // to a wide column may increase the indentation column
+ // of lines before the label; effectively leading to wrong
+ // indentation.
+ p.buffer[i], p.buffer[i+1] = unindent, formfeed
+ i-- // do it again
+ continue
+ }
+ fallthrough
+ default:
+ data[0] = byte(ch)
+ p.write(data[0:])
+ }
+ }
+
+ // shift remaining entries down
+ i := 0
+ for ; n < len(p.buffer); n++ {
+ p.buffer[i] = p.buffer[n]
+ i++
+ }
+ p.buffer = p.buffer[0:i]
+}
+
+
+// ----------------------------------------------------------------------------
+// Printing interface
+
+
+func mayCombine(prev token.Token, next byte) (b bool) {
+ switch prev {
+ case token.INT:
+ b = next == '.' // 1.
+ case token.ADD:
+ b = next == '+' // ++
+ case token.SUB:
+ b = next == '-' // --
+ case token.QUO:
+ b = next == '*' // /*
+ case token.LSS:
+ b = next == '-' || next == '<' // <- or <<
+ case token.AND:
+ b = next == '&' || next == '^' // && or &^
+ }
+ return
+}
+
+
+// print prints a list of "items" (roughly corresponding to syntactic
+// tokens, but also including whitespace and formatting information).
+// It is the only print function that should be called directly from
+// any of the AST printing functions in nodes.go.
+//
+// Whitespace is accumulated until a non-whitespace token appears. Any
+// comments that need to appear before that token are printed first,
+// taking into account the amount and structure of any pending white-
+// space for best comment placement. Then, any leftover whitespace is
+// printed, followed by the actual token.
+//
+func (p *printer) print(args ...interface{}) {
+ for _, f := range args {
+ next := p.pos // estimated position of next item
+ var data []byte
+ var tag HTMLTag
+ var tok token.Token
+
+ switch x := f.(type) {
+ case pmode:
+ // toggle printer mode
+ p.mode ^= x
+ case whiteSpace:
+ if x == ignore {
+ // don't add ignore's to the buffer; they
+ // may screw up "correcting" unindents (see
+ // LabeledStmt)
+ break
+ }
+ i := len(p.buffer)
+ if i == cap(p.buffer) {
+ // Whitespace sequences are very short so this should
+ // never happen. Handle gracefully (but possibly with
+ // bad comment placement) if it does happen.
+ p.writeWhitespace(i)
+ i = 0
+ }
+ p.buffer = p.buffer[0 : i+1]
+ p.buffer[i] = x
+ case *ast.Ident:
+ if p.Styler != nil {
+ data, tag = p.Styler.Ident(x)
+ } else {
+ data = []byte(x.Name)
+ }
+ tok = token.IDENT
+ case *ast.BasicLit:
+ if p.Styler != nil {
+ data, tag = p.Styler.BasicLit(x)
+ } else {
+ data = x.Value
+ }
+ // escape all literals so they pass through unchanged
+ // (note that valid Go programs cannot contain
+ // tabwriter.Escape bytes since they do not appear in
+ // legal UTF-8 sequences)
+ escData := make([]byte, 0, len(data)+2)
+ escData = append(escData, tabwriter.Escape)
+ escData = append(escData, data...)
+ escData = append(escData, tabwriter.Escape)
+ data = escData
+ tok = x.Kind
+ case token.Token:
+ s := x.String()
+ if mayCombine(p.lastTok, s[0]) {
+ // the previous and the current token must be
+ // separated by a blank otherwise they combine
+ // into a different incorrect token sequence
+ // (except for token.INT followed by a '.' this
+ // should never happen because it is taken care
+ // of via binary expression formatting)
+ if len(p.buffer) != 0 {
+ p.internalError("whitespace buffer not empty")
+ }
+ p.buffer = p.buffer[0:1]
+ p.buffer[0] = ' '
+ }
+ if p.Styler != nil {
+ data, tag = p.Styler.Token(x)
+ } else {
+ data = []byte(s)
+ }
+ tok = x
+ case token.Pos:
+ if x.IsValid() {
+ next = p.fset.Position(x) // accurate position of next item
+ }
+ tok = p.lastTok
+ default:
+ fmt.Fprintf(os.Stderr, "print: unsupported argument type %T\n", f)
+ panic("go/printer type")
+ }
+ p.lastTok = tok
+ p.pos = next
+
+ if data != nil {
+ droppedFF := p.flush(next, tok)
+
+ // intersperse extra newlines if present in the source
+ // (don't do this in flush as it will cause extra newlines
+ // at the end of a file) - use formfeeds if we dropped one
+ // before
+ p.writeNewlines(next.Line-p.pos.Line, droppedFF)
+
+ p.writeItem(next, data, tag)
+ }
+ }
+}
+
+
+// commentBefore returns true iff the current comment occurs
+// before the next position in the source code.
+//
+func (p *printer) commentBefore(next token.Position) bool {
+ return p.cindex < len(p.comments) && p.fset.Position(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset
+}
+
+
+// Flush prints any pending comments and whitespace occurring
+// textually before the position of the next token tok. Flush
+// returns true if a pending formfeed character was dropped
+// from the whitespace buffer as a result of interspersing
+// comments.
+//
+func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
+ if p.commentBefore(next) {
+ // if there are comments before the next item, intersperse them
+ droppedFF = p.intersperseComments(next, tok)
+ } else {
+ // otherwise, write any leftover whitespace
+ p.writeWhitespace(len(p.buffer))
+ }
+ return
+}
+
+
+// ----------------------------------------------------------------------------
+// Trimmer
+
+// A trimmer is an io.Writer filter for stripping tabwriter.Escape
+// characters, trailing blanks and tabs, and for converting formfeed
+// and vtab characters into newlines and htabs (in case no tabwriter
+// is used). Text bracketed by tabwriter.Escape characters is passed
+// through unchanged.
+//
+type trimmer struct {
+ output io.Writer
+ space bytes.Buffer
+ state int
+}
+
+
+// trimmer is implemented as a state machine.
+// It can be in one of the following states:
+const (
+ inSpace = iota
+ inEscape
+ inText
+)
+
+
+// Design note: It is tempting to eliminate extra blanks occurring in
+// whitespace in this function as it could simplify some
+// of the blanks logic in the node printing functions.
+// However, this would mess up any formatting done by
+// the tabwriter.
+
+func (p *trimmer) Write(data []byte) (n int, err os.Error) {
+ m := 0 // if p.state != inSpace, data[m:n] is unwritten
+ var b byte
+ for n, b = range data {
+ if b == '\v' {
+ b = '\t' // convert to htab
+ }
+ switch p.state {
+ case inSpace:
+ switch b {
+ case '\t', ' ':
+ p.space.WriteByte(b) // WriteByte returns no errors
+ case '\f', '\n':
+ p.space.Reset() // discard trailing space
+ _, err = p.output.Write(newlines[0:1]) // write newline
+ case tabwriter.Escape:
+ _, err = p.output.Write(p.space.Bytes())
+ p.space.Reset()
+ p.state = inEscape
+ m = n + 1 // drop tabwriter.Escape
+ default:
+ _, err = p.output.Write(p.space.Bytes())
+ p.space.Reset()
+ p.state = inText
+ m = n
+ }
+ case inEscape:
+ if b == tabwriter.Escape {
+ _, err = p.output.Write(data[m:n])
+ p.state = inSpace
+ }
+ case inText:
+ switch b {
+ case '\t', ' ':
+ _, err = p.output.Write(data[m:n])
+ p.state = inSpace
+ p.space.WriteByte(b) // WriteByte returns no errors
+ case '\f':
+ data[n] = '\n' // convert to newline
+ case tabwriter.Escape:
+ _, err = p.output.Write(data[m:n])
+ p.state = inEscape
+ m = n + 1 // drop tabwriter.Escape
+ }
+ }
+ if err != nil {
+ return
+ }
+ }
+ n = len(data)
+
+ if p.state != inSpace {
+ _, err = p.output.Write(data[m:n])
+ p.state = inSpace
+ }
+
+ return
+}
+
+
+// ----------------------------------------------------------------------------
+// Public interface
+
+// General printing is controlled with these Config.Mode flags.
+const (
+ GenHTML uint = 1 << iota // generate HTML
+ RawFormat // do not use a tabwriter; if set, UseSpaces is ignored
+ TabIndent // use tabs for indentation independent of UseSpaces
+ UseSpaces // use spaces instead of tabs for alignment
+)
+
+
+// An HTMLTag specifies a start and end tag.
+type HTMLTag struct {
+ Start, End string // empty if tags are absent
+}
+
+
+// A Styler specifies formatting of line tags and elementary Go words.
+// A format consists of text and a (possibly empty) surrounding HTML tag.
+//
+type Styler interface {
+ LineTag(line int) ([]byte, HTMLTag)
+ Comment(c *ast.Comment, line []byte) ([]byte, HTMLTag)
+ BasicLit(x *ast.BasicLit) ([]byte, HTMLTag)
+ Ident(id *ast.Ident) ([]byte, HTMLTag)
+ Token(tok token.Token) ([]byte, HTMLTag)
+}
+
+
+// A Config node controls the output of Fprint.
+type Config struct {
+ Mode uint // default: 0
+ Tabwidth int // default: 8
+ Styler Styler // default: nil
+}
+
+
+// Fprint "pretty-prints" an AST node to output and returns the number
+// of bytes written and an error (if any) for a given configuration cfg.
+// Position information is interpreted relative to the file set fset.
+// The node type must be *ast.File, or assignment-compatible to ast.Expr,
+// ast.Decl, ast.Spec, or ast.Stmt.
+//
+func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) (int, os.Error) {
+ // redirect output through a trimmer to eliminate trailing whitespace
+ // (Input to a tabwriter must be untrimmed since trailing tabs provide
+ // formatting information. The tabwriter could provide trimming
+ // functionality but no tabwriter is used when RawFormat is set.)
+ output = &trimmer{output: output}
+
+ // setup tabwriter if needed and redirect output
+ var tw *tabwriter.Writer
+ if cfg.Mode&RawFormat == 0 {
+ minwidth := cfg.Tabwidth
+
+ padchar := byte('\t')
+ if cfg.Mode&UseSpaces != 0 {
+ padchar = ' '
+ }
+
+ twmode := tabwriter.DiscardEmptyColumns
+ if cfg.Mode&GenHTML != 0 {
+ twmode |= tabwriter.FilterHTML
+ }
+ if cfg.Mode&TabIndent != 0 {
+ minwidth = 0
+ twmode |= tabwriter.TabIndent
+ }
+
+ tw = tabwriter.NewWriter(output, minwidth, cfg.Tabwidth, 1, padchar, twmode)
+ output = tw
+ }
+
+ // setup printer and print node
+ var p printer
+ p.init(output, cfg, fset)
+ go func() {
+ switch n := node.(type) {
+ case ast.Expr:
+ p.nesting = 1
+ p.useNodeComments = true
+ p.expr(n, ignoreMultiLine)
+ case ast.Stmt:
+ p.nesting = 1
+ p.useNodeComments = true
+ // A labeled statement will un-indent to position the
+ // label. Set indent to 1 so we don't get indent "underflow".
+ if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt {
+ p.indent = 1
+ }
+ p.stmt(n, false, ignoreMultiLine)
+ case ast.Decl:
+ p.nesting = 1
+ p.useNodeComments = true
+ p.decl(n, ignoreMultiLine)
+ case ast.Spec:
+ p.nesting = 1
+ p.useNodeComments = true
+ p.spec(n, 1, false, ignoreMultiLine)
+ case *ast.File:
+ p.nesting = 0
+ p.comments = n.Comments
+ p.useNodeComments = n.Comments == nil
+ p.file(n)
+ default:
+ p.errors <- fmt.Errorf("printer.Fprint: unsupported node type %T", n)
+ runtime.Goexit()
+ }
+ p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF)
+ p.errors <- nil // no errors
+ }()
+ err := <-p.errors // wait for completion of goroutine
+
+ // flush tabwriter, if any
+ if tw != nil {
+ tw.Flush() // ignore errors
+ }
+
+ return p.written, err
+}
+
+
+// Fprint "pretty-prints" an AST node to output.
+// It calls Config.Fprint with default settings.
+//
+func Fprint(output io.Writer, fset *token.FileSet, node interface{}) os.Error {
+ _, err := (&Config{Tabwidth: 8}).Fprint(output, fset, node) // don't care about number of bytes written
+ return err
+}
diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go
new file mode 100644
index 000000000..c66471b92
--- /dev/null
+++ b/libgo/go/go/printer/printer_test.go
@@ -0,0 +1,138 @@
+// 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 printer
+
+import (
+ "bytes"
+ "flag"
+ "io/ioutil"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "path"
+ "testing"
+)
+
+
+const (
+ dataDir = "testdata"
+ tabwidth = 8
+)
+
+
+var update = flag.Bool("update", false, "update golden files")
+
+
+var fset = token.NewFileSet()
+
+
+func lineString(text []byte, i int) string {
+ i0 := i
+ for i < len(text) && text[i] != '\n' {
+ i++
+ }
+ return string(text[i0:i])
+}
+
+
+type checkMode uint
+
+const (
+ export checkMode = 1 << iota
+ rawFormat
+)
+
+
+func check(t *testing.T, source, golden string, mode checkMode) {
+ // parse source
+ prog, err := parser.ParseFile(fset, source, nil, parser.ParseComments)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // filter exports if necessary
+ if mode&export != 0 {
+ ast.FileExports(prog) // ignore result
+ prog.Comments = nil // don't print comments that are not in AST
+ }
+
+ // determine printer configuration
+ cfg := Config{Tabwidth: tabwidth}
+ if mode&rawFormat != 0 {
+ cfg.Mode |= RawFormat
+ }
+
+ // format source
+ var buf bytes.Buffer
+ if _, err := cfg.Fprint(&buf, fset, prog); err != nil {
+ t.Error(err)
+ }
+ res := buf.Bytes()
+
+ // update golden files if necessary
+ if *update {
+ if err := ioutil.WriteFile(golden, res, 0644); err != nil {
+ t.Error(err)
+ }
+ return
+ }
+
+ // get golden
+ gld, err := ioutil.ReadFile(golden)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // compare lengths
+ if len(res) != len(gld) {
+ t.Errorf("len = %d, expected %d (= len(%s))", len(res), len(gld), golden)
+ }
+
+ // compare contents
+ for i, line, offs := 0, 1, 0; i < len(res) && i < len(gld); i++ {
+ ch := res[i]
+ if ch != gld[i] {
+ t.Errorf("%s:%d:%d: %s", source, line, i-offs+1, lineString(res, offs))
+ t.Errorf("%s:%d:%d: %s", golden, line, i-offs+1, lineString(gld, offs))
+ t.Error()
+ return
+ }
+ if ch == '\n' {
+ line++
+ offs = i + 1
+ }
+ }
+}
+
+
+type entry struct {
+ source, golden string
+ mode checkMode
+}
+
+// Use gotest -update to create/update the respective golden files.
+var data = []entry{
+ {"empty.input", "empty.golden", 0},
+ {"comments.input", "comments.golden", 0},
+ {"comments.input", "comments.x", export},
+ {"linebreaks.input", "linebreaks.golden", 0},
+ {"expressions.input", "expressions.golden", 0},
+ {"expressions.input", "expressions.raw", rawFormat},
+ {"declarations.input", "declarations.golden", 0},
+ {"statements.input", "statements.golden", 0},
+}
+
+
+func Test(t *testing.T) {
+ for _, e := range data {
+ source := path.Join(dataDir, e.source)
+ golden := path.Join(dataDir, e.golden)
+ check(t, source, golden, e.mode)
+ // TODO(gri) check that golden is idempotent
+ //check(t, golden, golden, e.mode);
+ }
+}
diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden
new file mode 100644
index 000000000..a86d66174
--- /dev/null
+++ b/libgo/go/go/printer/testdata/comments.golden
@@ -0,0 +1,483 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a package for testing comment placement by go/printer.
+//
+package main
+
+import "fmt" // fmt
+
+const c0 = 0 // zero
+const (
+ c1 = iota // c1
+ c2 // c2
+)
+
+// Alignment of comments in declarations>
+const (
+ _ T = iota // comment
+ _ // comment
+ _ // comment
+ _ = iota + 10
+ _ // comments
+
+ _ = 10 // comment
+ _ T = 20 // comment
+)
+
+const (
+ _____ = iota // foo
+ _ // bar
+ _ = 0 // bal
+ _ // bat
+)
+
+const (
+ _ T = iota // comment
+ _ // comment
+ _ // comment
+ _ = iota + 10
+ _ // comment
+ _ = 10
+ _ = 20 // comment
+ _ T = 0 // comment
+)
+
+// The SZ struct; it is empty.
+type SZ struct{}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+ int
+ x, y, z int // 3 unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+ S0
+ A, B, C float // 3 exported fields
+ D, b, c int // 2 unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+ S1
+ A, B, C float // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface{}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+ f(x int) int // unexported method
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+ I0
+ F(x float) float // exported methods
+ g(x int) int // unexported method
+}
+
+// The I2 interface; all methods are exported.
+type I2 interface {
+ I0
+ F(x float) float // exported method
+ G(x float) float // exported method
+}
+
+// The S3 struct; all comments except for the last one must appear in the export.
+type S3 struct {
+ // lead comment for F1
+ F1 int // line comment for F1
+ // lead comment for F2
+ F2 int // line comment for F2
+ f3 int // f3 is not exported
+}
+
+// This comment group should be separated
+// with a newline from the next comment
+// group.
+
+// This comment should NOT be associated with the next declaration.
+
+var x int // x
+var ()
+
+
+// This comment SHOULD be associated with the next declaration.
+func f0() {
+ const pi = 3.14 // pi
+ var s1 struct{} /* an empty struct */ /* foo */
+ // a struct constructor
+ // --------------------
+ var s2 struct{} = struct{}{}
+ x := pi
+}
+//
+// NO SPACE HERE
+//
+func f1() {
+ f0()
+ /* 1 */
+ // 2
+ /* 3 */
+ /* 4 */
+ f0()
+}
+
+
+func _() {
+ // this comment should be properly indented
+}
+
+
+func _(x int) int {
+ if x < 0 { // the tab printed before this comment's // must not affect the remaining lines
+ return -x // this statement should be properly indented
+ }
+ if x < 0 { /* the tab printed before this comment's /* must not affect the remaining lines */
+ return -x // this statement should be properly indented
+ }
+ return x
+}
+
+
+func typeswitch(x interface{}) {
+ switch v := x.(type) {
+ case bool, int, float:
+ case string:
+ default:
+ }
+
+ switch x.(type) {
+ }
+
+ switch v0, ok := x.(int); v := x.(type) {
+ }
+
+ switch v0, ok := x.(int); x.(type) {
+ case byte: // this comment should be on the same line as the keyword
+ // this comment should be normally indented
+ _ = 0
+ case bool, int, float:
+ // this comment should be indented
+ case string:
+ default:
+ // this comment should be indented
+ }
+ // this comment should not be indented
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line */
+}
+
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line */
+}
+
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line */
+}
+
+/*
+ * line
+ * of
+ * stars
+ */
+
+/* another line
+ * of
+ * stars */
+
+/* and another line
+ * of
+ * stars */
+
+/* a line of
+ * stars */
+
+/* and another line of
+ * stars */
+
+/* a line of stars
+ */
+
+/* and another line of
+ */
+
+/* a line of stars
+ */
+
+/* and another line of
+ */
+
+/*
+aligned in middle
+here
+ not here
+*/
+
+/*
+blank line in middle:
+
+with no leading spaces on blank line.
+*/
+
+/*
+ aligned in middle
+ here
+ not here
+*/
+
+/*
+ blank line in middle:
+
+ with no leading spaces on blank line.
+*/
+
+func _() {
+ /*
+ * line
+ * of
+ * stars
+ */
+
+ /*
+ aligned in middle
+ here
+ not here
+ */
+
+ /*
+ blank line in middle:
+
+ with no leading spaces on blank line.
+ */
+}
+
+
+// Some interesting interspersed comments
+func _( /* this */ x /* is */ /* an */ int) {
+}
+
+func _( /* no params */ ) {}
+
+func _() {
+ f( /* no args */ )
+}
+
+func ( /* comment1 */ T /* comment2 */ ) _() {}
+
+func _() { /* one-line functions with comments are formatted as multi-line functions */
+}
+
+func _() {
+ _ = 0
+ /* closing curly brace should be on new line */
+}
+
+func _() {
+ _ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */ }
+}
+
+
+// Comments immediately adjacent to punctuation (for which the go/printer
+// may obly have estimated position information) must remain after the punctuation.
+func _() {
+ _ = T{
+ 1, // comment after comma
+ 2, /* comment after comma */
+ 3, // comment after comma
+ }
+ _ = T{
+ 1, // comment after comma
+ 2, /* comment after comma */
+ 3, // comment after comma
+ }
+ _ = T{
+ /* comment before literal */ 1,
+ 2, /* comment before comma - ok to move after comma */
+ 3, /* comment before comma - ok to move after comma */
+ }
+
+ for i = 0; // comment after semicolon
+ i < 9; /* comment after semicolon */
+ i++ { // comment after opening curly brace
+ }
+
+ // TODO(gri) the last comment in this example should be aligned */
+ for i = 0; // comment after semicolon
+ i < 9; /* comment before semicolon - ok to move after semicolon */
+ i++ /* comment before opening curly brace */ {
+ }
+}
+
+
+// Line comments with tabs
+func _() {
+ var finput *bufio.Reader // input file
+ var stderr *bufio.Writer
+ var ftable *bufio.Writer // y.go file
+ var foutput *bufio.Writer // y.output file
+
+ var oflag string // -o [y.go] - y.go file
+ var vflag string // -v [y.output] - y.output file
+ var lflag bool // -l - disable line directives
+}
+
+
+/* This comment is the last entry in this file. It must be printed and should be followed by a newline */
diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input
new file mode 100644
index 000000000..14cd4cf7a
--- /dev/null
+++ b/libgo/go/go/printer/testdata/comments.input
@@ -0,0 +1,483 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a package for testing comment placement by go/printer.
+//
+package main
+
+import "fmt" // fmt
+
+const c0 = 0 // zero
+const (
+ c1 = iota // c1
+ c2 // c2
+)
+
+// Alignment of comments in declarations>
+const (
+ _ T = iota // comment
+ _ // comment
+ _ // comment
+ _ = iota+10
+ _ // comments
+
+ _ = 10 // comment
+ _ T = 20 // comment
+)
+
+const (
+ _____ = iota // foo
+ _ // bar
+ _ = 0 // bal
+ _ // bat
+)
+
+const (
+ _ T = iota // comment
+ _ // comment
+ _ // comment
+ _ = iota + 10
+ _ // comment
+ _ = 10
+ _ = 20 // comment
+ _ T = 0 // comment
+)
+
+// The SZ struct; it is empty.
+type SZ struct {}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+ int
+ x, y, z int // 3 unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+ S0
+ A, B, C float // 3 exported fields
+ D, b, c int // 2 unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+ S1
+ A, B, C float // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface {}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+ f(x int) int // unexported method
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+ I0
+ F(x float) float // exported methods
+ g(x int) int // unexported method
+}
+
+// The I2 interface; all methods are exported.
+type I2 interface {
+ I0
+ F(x float) float // exported method
+ G(x float) float // exported method
+}
+
+// The S3 struct; all comments except for the last one must appear in the export.
+type S3 struct {
+ // lead comment for F1
+ F1 int // line comment for F1
+ // lead comment for F2
+ F2 int // line comment for F2
+ f3 int // f3 is not exported
+}
+
+// This comment group should be separated
+// with a newline from the next comment
+// group.
+
+// This comment should NOT be associated with the next declaration.
+
+var x int // x
+var ()
+
+
+// This comment SHOULD be associated with the next declaration.
+func f0() {
+ const pi = 3.14 // pi
+ var s1 struct {} /* an empty struct */ /* foo */
+ // a struct constructor
+ // --------------------
+ var s2 struct {} = struct {}{}
+ x := pi
+}
+//
+// NO SPACE HERE
+//
+func f1() {
+ f0()
+ /* 1 */
+ // 2
+ /* 3 */
+ /* 4 */
+ f0()
+}
+
+
+func _() {
+ // this comment should be properly indented
+}
+
+
+func _(x int) int {
+ if x < 0 { // the tab printed before this comment's // must not affect the remaining lines
+ return -x // this statement should be properly indented
+ }
+ if x < 0 { /* the tab printed before this comment's /* must not affect the remaining lines */
+ return -x // this statement should be properly indented
+ }
+ return x
+}
+
+
+func typeswitch(x interface{}) {
+ switch v := x.(type) {
+ case bool, int, float:
+ case string:
+ default:
+ }
+
+ switch x.(type) {
+ }
+
+ switch v0, ok := x.(int); v := x.(type) {
+ }
+
+ switch v0, ok := x.(int); x.(type) {
+ case byte: // this comment should be on the same line as the keyword
+ // this comment should be normally indented
+ _ = 0
+ case bool, int, float:
+ // this comment should be indented
+ case string:
+ default:
+ // this comment should be indented
+ }
+ // this comment should not be indented
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ aligned line */
+}
+
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /* freestanding comment
+ aligned line */
+}
+
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line
+ */
+}
+
+func _() {
+ /*
+ freestanding comment
+ aligned line */
+}
+
+/*
+ * line
+ * of
+ * stars
+ */
+
+/* another line
+ * of
+ * stars */
+
+/* and another line
+ * of
+ * stars */
+
+/* a line of
+ * stars */
+
+/* and another line of
+ * stars */
+
+/* a line of stars
+*/
+
+/* and another line of
+*/
+
+/* a line of stars
+ */
+
+/* and another line of
+ */
+
+/*
+aligned in middle
+here
+ not here
+*/
+
+/*
+blank line in middle:
+
+with no leading spaces on blank line.
+*/
+
+/*
+ aligned in middle
+ here
+ not here
+*/
+
+/*
+ blank line in middle:
+
+ with no leading spaces on blank line.
+*/
+
+func _() {
+ /*
+ * line
+ * of
+ * stars
+ */
+
+ /*
+ aligned in middle
+ here
+ not here
+ */
+
+ /*
+ blank line in middle:
+
+ with no leading spaces on blank line.
+*/
+}
+
+
+// Some interesting interspersed comments
+func _(/* this */x/* is *//* an */ int) {
+}
+
+func _(/* no params */) {}
+
+func _() {
+ f(/* no args */)
+}
+
+func (/* comment1 */ T /* comment2 */) _() {}
+
+func _() { /* one-line functions with comments are formatted as multi-line functions */ }
+
+func _() {
+ _ = 0
+ /* closing curly brace should be on new line */ }
+
+func _() {
+ _ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */}
+}
+
+
+// Comments immediately adjacent to punctuation (for which the go/printer
+// may obly have estimated position information) must remain after the punctuation.
+func _() {
+ _ = T{
+ 1, // comment after comma
+ 2, /* comment after comma */
+ 3 , // comment after comma
+ }
+ _ = T{
+ 1 ,// comment after comma
+ 2 ,/* comment after comma */
+ 3,// comment after comma
+ }
+ _ = T{
+ /* comment before literal */1,
+ 2/* comment before comma - ok to move after comma */,
+ 3 /* comment before comma - ok to move after comma */ ,
+ }
+
+ for
+ i=0;// comment after semicolon
+ i<9;/* comment after semicolon */
+ i++{// comment after opening curly brace
+ }
+
+ // TODO(gri) the last comment in this example should be aligned */
+ for
+ i=0;// comment after semicolon
+ i<9/* comment before semicolon - ok to move after semicolon */;
+ i++ /* comment before opening curly brace */ {
+ }
+}
+
+
+// Line comments with tabs
+func _() {
+var finput *bufio.Reader // input file
+var stderr *bufio.Writer
+var ftable *bufio.Writer // y.go file
+var foutput *bufio.Writer // y.output file
+
+var oflag string // -o [y.go] - y.go file
+var vflag string // -v [y.output] - y.output file
+var lflag bool // -l - disable line directives
+}
+
+
+/* This comment is the last entry in this file. It must be printed and should be followed by a newline */
diff --git a/libgo/go/go/printer/testdata/comments.x b/libgo/go/go/printer/testdata/comments.x
new file mode 100644
index 000000000..4d7a928ae
--- /dev/null
+++ b/libgo/go/go/printer/testdata/comments.x
@@ -0,0 +1,57 @@
+// This is a package for testing comment placement by go/printer.
+//
+package main
+
+
+// The SZ struct; it is empty.
+type SZ struct{}
+
+// The S0 struct; no field is exported.
+type S0 struct {
+ // contains unexported fields
+}
+
+// The S1 struct; some fields are not exported.
+type S1 struct {
+ S0
+ A, B, C float // 3 exported fields
+ D int // 2 unexported fields
+ // contains unexported fields
+}
+
+// The S2 struct; all fields are exported.
+type S2 struct {
+ S1
+ A, B, C float // 3 exported fields
+}
+
+// The IZ interface; it is empty.
+type SZ interface{}
+
+// The I0 interface; no method is exported.
+type I0 interface {
+ // contains unexported methods
+}
+
+// The I1 interface; some methods are not exported.
+type I1 interface {
+ I0
+ F(x float) float // exported methods
+ // contains unexported methods
+}
+
+// The I2 interface; all methods are exported.
+type I2 interface {
+ I0
+ F(x float) float // exported method
+ G(x float) float // exported method
+}
+
+// The S3 struct; all comments except for the last one must appear in the export.
+type S3 struct {
+ // lead comment for F1
+ F1 int // line comment for F1
+ // lead comment for F2
+ F2 int // line comment for F2
+ // contains unexported fields
+}
diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden
new file mode 100644
index 000000000..1c091b929
--- /dev/null
+++ b/libgo/go/go/printer/testdata/declarations.golden
@@ -0,0 +1,715 @@
+// 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 imports
+
+import "io"
+
+import (
+ _ "io"
+)
+
+import _ "io"
+
+import (
+ "io"
+ "io"
+ "io"
+)
+
+import (
+ "io"
+ aLongRename "io"
+
+ b "io"
+)
+
+import (
+ "unrenamed"
+ renamed "renameMe"
+ . "io"
+ _ "io"
+ "io"
+ . "os"
+)
+
+// no newlines between consecutive single imports, but
+// respect extra line breaks in the source (at most one empty line)
+import _ "io"
+import _ "io"
+import _ "io"
+
+import _ "os"
+import _ "os"
+import _ "os"
+
+
+import _ "fmt"
+import _ "fmt"
+import _ "fmt"
+
+import "foo" // a comment
+import "bar" // a comment
+
+import (
+ _ "foo"
+ // a comment
+ "bar"
+ "foo" // a comment
+ "bar" // a comment
+)
+
+// comments + renames
+import (
+ "unrenamed" // a comment
+ renamed "renameMe"
+ . "io" /* a comment */
+ _ "io/ioutil" // a comment
+ "io" // testing alignment
+ . "os"
+ // a comment
+)
+
+// a case that caused problems in the past (comment placement)
+import (
+ . "fmt"
+ "io"
+ "malloc" // for the malloc count test only
+ "math"
+ "strings"
+ "testing"
+)
+
+
+// at least one empty line between declarations of different kind
+import _ "io"
+
+var _ int
+
+
+// printing of constant literals
+const (
+ _ = "foobar"
+ _ = "a۰۱۸"
+ _ = "foo६४"
+ _ = "bar9876"
+ _ = 0
+ _ = 1
+ _ = 123456789012345678890
+ _ = 01234567
+ _ = 0xcafebabe
+ _ = 0.
+ _ = .0
+ _ = 3.14159265
+ _ = 1e0
+ _ = 1e+100
+ _ = 1e-100
+ _ = 2.71828e-1000
+ _ = 0i
+ _ = 1i
+ _ = 012345678901234567889i
+ _ = 123456789012345678890i
+ _ = 0.i
+ _ = .0i
+ _ = 3.14159265i
+ _ = 1e0i
+ _ = 1e+100i
+ _ = 1e-100i
+ _ = 2.71828e-1000i
+ _ = 'a'
+ _ = '\000'
+ _ = '\xFF'
+ _ = '\uff16'
+ _ = '\U0000ff16'
+ _ = `foobar`
+ _ = `foo
+---
+---
+bar`
+)
+
+
+func _() {
+ // the following decls need a semicolon at the end
+ type _ int
+ type _ *int
+ type _ []int
+ type _ map[string]int
+ type _ chan int
+ type _ func() int
+
+ var _ int
+ var _ *int
+ var _ []int
+ var _ map[string]int
+ var _ chan int
+ var _ func() int
+
+ // the following decls don't need a semicolon at the end
+ type _ struct{}
+ type _ *struct{}
+ type _ []struct{}
+ type _ map[string]struct{}
+ type _ chan struct{}
+ type _ func() struct{}
+
+ type _ interface{}
+ type _ *interface{}
+ type _ []interface{}
+ type _ map[string]interface{}
+ type _ chan interface{}
+ type _ func() interface{}
+
+ var _ struct{}
+ var _ *struct{}
+ var _ []struct{}
+ var _ map[string]struct{}
+ var _ chan struct{}
+ var _ func() struct{}
+
+ var _ interface{}
+ var _ *interface{}
+ var _ []interface{}
+ var _ map[string]interface{}
+ var _ chan interface{}
+ var _ func() interface{}
+}
+
+
+// don't lose blank lines in grouped declarations
+const (
+ _ int = 0
+ _ float = 1
+
+ _ string = "foo"
+
+ _ = iota
+ _
+
+ // a comment
+ _
+
+ _
+)
+
+
+type (
+ _ int
+ _ struct{}
+
+ _ interface{}
+
+ // a comment
+ _ map[string]int
+)
+
+
+var (
+ _ int = 0
+ _ float = 1
+
+ _ string = "foo"
+
+ _ bool
+
+ // a comment
+ _ bool
+)
+
+
+// don't lose blank lines in this struct
+type _ struct {
+ String struct {
+ Str, Len int
+ }
+ Slice struct {
+ Array, Len, Cap int
+ }
+ Eface struct {
+ Typ, Ptr int
+ }
+
+ UncommonType struct {
+ Name, PkgPath int
+ }
+ CommonType struct {
+ Size, Hash, Alg, Align, FieldAlign, String, UncommonType int
+ }
+ Type struct {
+ Typ, Ptr int
+ }
+ StructField struct {
+ Name, PkgPath, Typ, Tag, Offset int
+ }
+ StructType struct {
+ Fields int
+ }
+ PtrType struct {
+ Elem int
+ }
+ SliceType struct {
+ Elem int
+ }
+ ArrayType struct {
+ Elem, Len int
+ }
+
+ Stktop struct {
+ Stackguard, Stackbase, Gobuf int
+ }
+ Gobuf struct {
+ Sp, Pc, G int
+ }
+ G struct {
+ Stackbase, Sched, Status, Alllink int
+ }
+}
+
+
+// no tabs for single or ungrouped decls
+func _() {
+ const xxxxxx = 0
+ type x int
+ var xxx int
+ var yyyy float = 3.14
+ var zzzzz = "bar"
+
+ const (
+ xxxxxx = 0
+ )
+ type (
+ x int
+ )
+ var (
+ xxx int
+ )
+ var (
+ yyyy float = 3.14
+ )
+ var (
+ zzzzz = "bar"
+ )
+}
+
+// tabs for multiple or grouped decls
+func _() {
+ // no entry has a type
+ const (
+ zzzzzz = 1
+ z = 2
+ zzz = 3
+ )
+ // some entries have a type
+ const (
+ xxxxxx = 1
+ x = 2
+ xxx = 3
+ yyyyyyyy float = iota
+ yyyy = "bar"
+ yyy
+ yy = 2
+ )
+}
+
+func _() {
+ // no entry has a type
+ var (
+ zzzzzz = 1
+ z = 2
+ zzz = 3
+ )
+ // no entry has a value
+ var (
+ _ int
+ _ float
+ _ string
+
+ _ int // comment
+ _ float // comment
+ _ string // comment
+ )
+ // some entries have a type
+ var (
+ xxxxxx int
+ x float
+ xxx string
+ yyyyyyyy int = 1234
+ y float = 3.14
+ yyyy = "bar"
+ yyy string = "foo"
+ )
+ // mixed entries - all comments should be aligned
+ var (
+ a, b, c int
+ x = 10
+ d int // comment
+ y = 20 // comment
+ f, ff, fff, ffff int = 0, 1, 2, 3 // comment
+ )
+ // respect original line breaks
+ var _ = []T{
+ T{0x20, "Telugu"},
+ }
+ var _ = []T{
+ // respect original line breaks
+ T{0x20, "Telugu"},
+ }
+}
+
+func _() {
+ type (
+ xxxxxx int
+ x float
+ xxx string
+ xxxxx []x
+ xx struct{}
+ xxxxxxx struct {
+ _, _ int
+ _ float
+ }
+ xxxx chan<- string
+ )
+}
+
+
+// formatting of structs
+type _ struct{}
+
+type _ struct { /* this comment should be visible */
+}
+
+type _ struct {
+ // this comment should be visible and properly indented
+}
+
+type _ struct { // this comment must not change indentation
+ f int
+ f, ff, fff, ffff int
+}
+
+type _ struct {
+ string
+}
+
+type _ struct {
+ string // comment
+}
+
+type _ struct {
+ string "tag"
+}
+
+type _ struct {
+ string "tag" // comment
+}
+
+type _ struct {
+ f int
+}
+
+type _ struct {
+ f int // comment
+}
+
+type _ struct {
+ f int "tag"
+}
+
+type _ struct {
+ f int "tag" // comment
+}
+
+type _ struct {
+ bool
+ a, b, c int
+ int "tag"
+ ES // comment
+ float "tag" // comment
+ f int // comment
+ f, ff, fff, ffff int // comment
+ g float "tag"
+ h float "tag" // comment
+}
+
+type _ struct {
+ a, b,
+ c, d int // this line should be indented
+ u, v, w, x float // this line should be indented
+ p, q,
+ r, s float // this line should be indented
+}
+
+
+// difficult cases
+type _ struct {
+ bool // comment
+ text []byte // comment
+}
+
+
+// formatting of interfaces
+type EI interface{}
+
+type _ interface {
+ EI
+}
+
+type _ interface {
+ f()
+ fffff()
+}
+
+type _ interface {
+ EI
+ f()
+ fffffg()
+}
+
+type _ interface { // this comment must not change indentation
+ EI // here's a comment
+ f() // no blank between identifier and ()
+ fffff() // no blank between identifier and ()
+ gggggggggggg(x, y, z int) // hurray
+}
+
+
+// formatting of variable declarations
+func _() {
+ type day struct {
+ n int
+ short, long string
+ }
+ var (
+ Sunday = day{0, "SUN", "Sunday"}
+ Monday = day{1, "MON", "Monday"}
+ Tuesday = day{2, "TUE", "Tuesday"}
+ Wednesday = day{3, "WED", "Wednesday"}
+ Thursday = day{4, "THU", "Thursday"}
+ Friday = day{5, "FRI", "Friday"}
+ Saturday = day{6, "SAT", "Saturday"}
+ )
+}
+
+
+// formatting of multi-line variable declarations
+var a1, b1, c1 int // all on one line
+
+var a2, b2,
+ c2 int // this line should be indented
+
+var (
+ a3, b3,
+ c3, d3 int // this line should be indented
+ a4, b4, c4 int // this line should be indented
+)
+
+
+func _() {
+ var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
+ Headers: map[string]string{},
+ Bytes: []uint8{0x30, 0x82, 0x1, 0x3a, 0x2, 0x1, 0x0, 0x2,
+ 0x41, 0x0, 0xb2, 0x99, 0xf, 0x49, 0xc4, 0x7d, 0xfa, 0x8c,
+ 0xd4, 0x0, 0xae, 0x6a, 0x4d, 0x1b, 0x8a, 0x3b, 0x6a, 0x13,
+ 0x64, 0x2b, 0x23, 0xf2, 0x8b, 0x0, 0x3b, 0xfb, 0x97, 0x79,
+ },
+ }
+}
+
+
+func _() {
+ var Universe = Scope{
+ Names: map[string]*Ident{
+ // basic types
+ "bool": nil,
+ "byte": nil,
+ "int8": nil,
+ "int16": nil,
+ "int32": nil,
+ "int64": nil,
+ "uint8": nil,
+ "uint16": nil,
+ "uint32": nil,
+ "uint64": nil,
+ "float32": nil,
+ "float64": nil,
+ "string": nil,
+
+ // convenience types
+ "int": nil,
+ "uint": nil,
+ "uintptr": nil,
+ "float": nil,
+
+ // constants
+ "false": nil,
+ "true": nil,
+ "iota": nil,
+ "nil": nil,
+
+ // functions
+ "cap": nil,
+ "len": nil,
+ "new": nil,
+ "make": nil,
+ "panic": nil,
+ "panicln": nil,
+ "print": nil,
+ "println": nil,
+ },
+ }
+}
+
+
+// alignment of map composite entries
+var _ = map[int]int{
+ // small key sizes: always align even if size ratios are large
+ a: a,
+ abcdefghabcdefgh: a,
+ ab: a,
+ abc: a,
+ abcdefgabcdefg: a,
+ abcd: a,
+ abcde: a,
+ abcdef: a,
+
+ // mixed key sizes: align when key sizes change within accepted ratio
+ abcdefgh: a,
+ abcdefghabcdefg: a,
+ abcdefghij: a,
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // outlier - do not align with previous line
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // align with previous line
+
+ ab: a, // do not align with previous line
+ abcde: a, // align with previous line
+}
+
+
+func _() {
+ var _ = T{
+ a, // must introduce trailing comma
+ }
+}
+
+
+// formatting of function results
+func _() func() {}
+func _() func(int) { return nil }
+func _() func(int) int { return nil }
+func _() func(int) func(int) func() { return nil }
+
+
+// formatting of consecutive single-line functions
+func _() {}
+func _() {}
+func _() {}
+
+func _() {} // an empty line before this function
+func _() {}
+func _() {}
+
+func _() { f(1, 2, 3) }
+func _(x int) int { y := x; return y + 1 }
+func _() int { type T struct{}; var x T; return x }
+
+// these must remain multi-line since they are multi-line in the source
+func _() {
+ f(1, 2, 3)
+}
+func _(x int) int {
+ y := x
+ return y + 1
+}
+func _() int {
+ type T struct{}
+ var x T
+ return x
+}
+
+
+// making function declarations safe for new semicolon rules
+func _() { /* multi-line func because of comment */
+}
+
+func _() {
+ /* multi-line func because block is on multiple lines */
+}
+
+
+// ellipsis parameters
+func _(...int)
+func _(...*int)
+func _(...[]int)
+func _(...struct{})
+func _(bool, ...interface{})
+func _(bool, ...func())
+func _(bool, ...func(...int))
+func _(bool, ...map[string]int)
+func _(bool, ...chan int)
+
+func _(b bool, x ...int)
+func _(b bool, x ...*int)
+func _(b bool, x ...[]int)
+func _(b bool, x ...struct{})
+func _(x ...interface{})
+func _(x ...func())
+func _(x ...func(...int))
+func _(x ...map[string]int)
+func _(x ...chan int)
+
+
+// these parameter lists must remain multi-line since they are multi-line in the source
+func _(bool,
+int) {
+}
+func _(x bool,
+y int) {
+}
+func _(x,
+y bool) {
+}
+func _(bool, // comment
+int) {
+}
+func _(x bool, // comment
+y int) {
+}
+func _(x, // comment
+y bool) {
+}
+func _(bool, // comment
+// comment
+int) {
+}
+func _(x bool, // comment
+// comment
+y int) {
+}
+func _(x, // comment
+// comment
+y bool) {
+}
+func _(bool,
+// comment
+int) {
+}
+func _(x bool,
+// comment
+y int) {
+}
+func _(x,
+// comment
+y bool) {
+}
+func _(x, // comment
+y, // comment
+z bool) {
+}
+func _(x, // comment
+y, // comment
+z bool) {
+}
+func _(x int, // comment
+y float, // comment
+z bool) {
+}
diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input
new file mode 100644
index 000000000..c826462f9
--- /dev/null
+++ b/libgo/go/go/printer/testdata/declarations.input
@@ -0,0 +1,703 @@
+// 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 imports
+
+import "io"
+
+import (
+ _ "io"
+)
+
+import _ "io"
+
+import (
+ "io"
+ "io"
+ "io"
+)
+
+import (
+ "io"
+ aLongRename "io"
+
+ b "io"
+)
+
+import (
+ "unrenamed"
+ renamed "renameMe"
+ . "io"
+ _ "io"
+ "io"
+ . "os"
+)
+
+// no newlines between consecutive single imports, but
+// respect extra line breaks in the source (at most one empty line)
+import _ "io"
+import _ "io"
+import _ "io"
+
+import _ "os"
+import _ "os"
+import _ "os"
+
+
+import _ "fmt"
+import _ "fmt"
+import _ "fmt"
+
+import "foo" // a comment
+import "bar" // a comment
+
+import (
+ _ "foo"
+ // a comment
+ "bar"
+ "foo" // a comment
+ "bar" // a comment
+)
+
+// comments + renames
+import (
+ "unrenamed" // a comment
+ renamed "renameMe"
+ . "io" /* a comment */
+ _ "io/ioutil" // a comment
+ "io" // testing alignment
+ . "os"
+ // a comment
+)
+
+// a case that caused problems in the past (comment placement)
+import (
+ . "fmt"
+ "io"
+ "malloc" // for the malloc count test only
+ "math"
+ "strings"
+ "testing"
+)
+
+
+// at least one empty line between declarations of different kind
+import _ "io"
+var _ int
+
+
+// printing of constant literals
+const (
+ _ = "foobar"
+ _ = "a۰۱۸"
+ _ = "foo६४"
+ _ = "bar9876"
+ _ = 0
+ _ = 1
+ _ = 123456789012345678890
+ _ = 01234567
+ _ = 0xcafebabe
+ _ = 0.
+ _ = .0
+ _ = 3.14159265
+ _ = 1e0
+ _ = 1e+100
+ _ = 1e-100
+ _ = 2.71828e-1000
+ _ = 0i
+ _ = 1i
+ _ = 012345678901234567889i
+ _ = 123456789012345678890i
+ _ = 0.i
+ _ = .0i
+ _ = 3.14159265i
+ _ = 1e0i
+ _ = 1e+100i
+ _ = 1e-100i
+ _ = 2.71828e-1000i
+ _ = 'a'
+ _ = '\000'
+ _ = '\xFF'
+ _ = '\uff16'
+ _ = '\U0000ff16'
+ _ = `foobar`
+ _ = `foo
+---
+---
+bar`
+)
+
+
+func _() {
+ // the following decls need a semicolon at the end
+ type _ int
+ type _ *int
+ type _ []int
+ type _ map[string]int
+ type _ chan int
+ type _ func() int
+
+ var _ int
+ var _ *int
+ var _ []int
+ var _ map[string]int
+ var _ chan int
+ var _ func() int
+
+ // the following decls don't need a semicolon at the end
+ type _ struct{}
+ type _ *struct{}
+ type _ []struct{}
+ type _ map[string]struct{}
+ type _ chan struct{}
+ type _ func() struct{}
+
+ type _ interface{}
+ type _ *interface{}
+ type _ []interface{}
+ type _ map[string]interface{}
+ type _ chan interface{}
+ type _ func() interface{}
+
+ var _ struct{}
+ var _ *struct{}
+ var _ []struct{}
+ var _ map[string]struct{}
+ var _ chan struct{}
+ var _ func() struct{}
+
+ var _ interface{}
+ var _ *interface{}
+ var _ []interface{}
+ var _ map[string]interface{}
+ var _ chan interface{}
+ var _ func() interface{}
+}
+
+
+// don't lose blank lines in grouped declarations
+const (
+ _ int = 0
+ _ float = 1
+
+ _ string = "foo"
+
+ _ = iota
+ _
+
+ // a comment
+ _
+
+ _
+)
+
+
+type (
+ _ int
+ _ struct {}
+
+ _ interface{}
+
+ // a comment
+ _ map[string]int
+)
+
+
+var (
+ _ int = 0
+ _ float = 1
+
+ _ string = "foo"
+
+ _ bool
+
+ // a comment
+ _ bool
+)
+
+
+// don't lose blank lines in this struct
+type _ struct {
+ String struct {
+ Str, Len int
+ }
+ Slice struct {
+ Array, Len, Cap int
+ }
+ Eface struct {
+ Typ, Ptr int
+ }
+
+ UncommonType struct {
+ Name, PkgPath int
+ }
+ CommonType struct {
+ Size, Hash, Alg, Align, FieldAlign, String, UncommonType int
+ }
+ Type struct {
+ Typ, Ptr int
+ }
+ StructField struct {
+ Name, PkgPath, Typ, Tag, Offset int
+ }
+ StructType struct {
+ Fields int
+ }
+ PtrType struct {
+ Elem int
+ }
+ SliceType struct {
+ Elem int
+ }
+ ArrayType struct {
+ Elem, Len int
+ }
+
+ Stktop struct {
+ Stackguard, Stackbase, Gobuf int
+ }
+ Gobuf struct {
+ Sp, Pc, G int
+ }
+ G struct {
+ Stackbase, Sched, Status, Alllink int
+ }
+}
+
+
+// no tabs for single or ungrouped decls
+func _() {
+ const xxxxxx = 0
+ type x int
+ var xxx int
+ var yyyy float = 3.14
+ var zzzzz = "bar"
+
+ const (
+ xxxxxx = 0
+ )
+ type (
+ x int
+ )
+ var (
+ xxx int
+ )
+ var (
+ yyyy float = 3.14
+ )
+ var (
+ zzzzz = "bar"
+ )
+}
+
+// tabs for multiple or grouped decls
+func _() {
+ // no entry has a type
+ const (
+ zzzzzz = 1
+ z = 2
+ zzz = 3
+ )
+ // some entries have a type
+ const (
+ xxxxxx = 1
+ x = 2
+ xxx = 3
+ yyyyyyyy float = iota
+ yyyy = "bar"
+ yyy
+ yy = 2
+ )
+}
+
+func _() {
+ // no entry has a type
+ var (
+ zzzzzz = 1
+ z = 2
+ zzz = 3
+ )
+ // no entry has a value
+ var (
+ _ int
+ _ float
+ _ string
+
+ _ int // comment
+ _ float // comment
+ _ string // comment
+ )
+ // some entries have a type
+ var (
+ xxxxxx int
+ x float
+ xxx string
+ yyyyyyyy int = 1234
+ y float = 3.14
+ yyyy = "bar"
+ yyy string = "foo"
+ )
+ // mixed entries - all comments should be aligned
+ var (
+ a, b, c int
+ x = 10
+ d int // comment
+ y = 20 // comment
+ f, ff, fff, ffff int = 0, 1, 2, 3 // comment
+ )
+ // respect original line breaks
+ var _ = []T {
+ T{0x20, "Telugu"},
+ }
+ var _ = []T {
+ // respect original line breaks
+ T{0x20, "Telugu"},
+ }
+}
+
+func _() {
+ type (
+ xxxxxx int
+ x float
+ xxx string
+ xxxxx []x
+ xx struct{}
+ xxxxxxx struct {
+ _, _ int
+ _ float
+ }
+ xxxx chan<- string
+ )
+}
+
+
+// formatting of structs
+type _ struct{}
+
+type _ struct{ /* this comment should be visible */ }
+
+type _ struct{
+ // this comment should be visible and properly indented
+}
+
+type _ struct { // this comment must not change indentation
+ f int
+ f, ff, fff, ffff int
+}
+
+type _ struct {
+ string
+}
+
+type _ struct {
+ string // comment
+}
+
+type _ struct {
+ string "tag"
+}
+
+type _ struct {
+ string "tag" // comment
+}
+
+type _ struct {
+ f int
+}
+
+type _ struct {
+ f int // comment
+}
+
+type _ struct {
+ f int "tag"
+}
+
+type _ struct {
+ f int "tag" // comment
+}
+
+type _ struct {
+ bool
+ a, b, c int
+ int "tag"
+ ES // comment
+ float "tag" // comment
+ f int // comment
+ f, ff, fff, ffff int // comment
+ g float "tag"
+ h float "tag" // comment
+}
+
+type _ struct { a, b,
+c, d int // this line should be indented
+u, v, w, x float // this line should be indented
+p, q,
+r, s float // this line should be indented
+}
+
+
+// difficult cases
+type _ struct {
+ bool // comment
+ text []byte // comment
+}
+
+
+// formatting of interfaces
+type EI interface{}
+
+type _ interface {
+ EI
+}
+
+type _ interface {
+ f()
+ fffff()
+}
+
+type _ interface {
+ EI
+ f()
+ fffffg()
+}
+
+type _ interface { // this comment must not change indentation
+ EI // here's a comment
+ f() // no blank between identifier and ()
+ fffff() // no blank between identifier and ()
+ gggggggggggg(x, y, z int) () // hurray
+}
+
+
+// formatting of variable declarations
+func _() {
+ type day struct { n int; short, long string }
+ var (
+ Sunday = day{ 0, "SUN", "Sunday" }
+ Monday = day{ 1, "MON", "Monday" }
+ Tuesday = day{ 2, "TUE", "Tuesday" }
+ Wednesday = day{ 3, "WED", "Wednesday" }
+ Thursday = day{ 4, "THU", "Thursday" }
+ Friday = day{ 5, "FRI", "Friday" }
+ Saturday = day{ 6, "SAT", "Saturday" }
+ )
+}
+
+
+// formatting of multi-line variable declarations
+var a1, b1, c1 int // all on one line
+
+var a2, b2,
+c2 int // this line should be indented
+
+var (a3, b3,
+c3, d3 int // this line should be indented
+a4, b4, c4 int // this line should be indented
+)
+
+
+func _() {
+ var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
+ Headers: map[string]string{},
+ Bytes: []uint8{0x30, 0x82, 0x1, 0x3a, 0x2, 0x1, 0x0, 0x2,
+ 0x41, 0x0, 0xb2, 0x99, 0xf, 0x49, 0xc4, 0x7d, 0xfa, 0x8c,
+ 0xd4, 0x0, 0xae, 0x6a, 0x4d, 0x1b, 0x8a, 0x3b, 0x6a, 0x13,
+ 0x64, 0x2b, 0x23, 0xf2, 0x8b, 0x0, 0x3b, 0xfb, 0x97, 0x79,
+ },
+ }
+}
+
+
+func _() {
+ var Universe = Scope {
+ Names: map[string]*Ident {
+ // basic types
+ "bool": nil,
+ "byte": nil,
+ "int8": nil,
+ "int16": nil,
+ "int32": nil,
+ "int64": nil,
+ "uint8": nil,
+ "uint16": nil,
+ "uint32": nil,
+ "uint64": nil,
+ "float32": nil,
+ "float64": nil,
+ "string": nil,
+
+ // convenience types
+ "int": nil,
+ "uint": nil,
+ "uintptr": nil,
+ "float": nil,
+
+ // constants
+ "false": nil,
+ "true": nil,
+ "iota": nil,
+ "nil": nil,
+
+ // functions
+ "cap": nil,
+ "len": nil,
+ "new": nil,
+ "make": nil,
+ "panic": nil,
+ "panicln": nil,
+ "print": nil,
+ "println": nil,
+ },
+ }
+}
+
+
+// alignment of map composite entries
+var _ = map[int]int{
+ // small key sizes: always align even if size ratios are large
+ a: a,
+ abcdefghabcdefgh: a,
+ ab: a,
+ abc: a,
+ abcdefgabcdefg: a,
+ abcd: a,
+ abcde: a,
+ abcdef: a,
+
+ // mixed key sizes: align when key sizes change within accepted ratio
+ abcdefgh: a,
+ abcdefghabcdefg: a,
+ abcdefghij: a,
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // outlier - do not align with previous line
+ abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij: a, // align with previous line
+
+ ab: a, // do not align with previous line
+ abcde: a, // align with previous line
+}
+
+
+func _() {
+ var _ = T{
+ a, // must introduce trailing comma
+ }
+}
+
+
+// formatting of function results
+func _() func() {}
+func _() func(int) { return nil }
+func _() func(int) int { return nil }
+func _() func(int) func(int) func() { return nil }
+
+
+// formatting of consecutive single-line functions
+func _() {}
+func _() {}
+func _() {}
+
+func _() {} // an empty line before this function
+func _() {}
+func _() {}
+
+func _() { f(1, 2, 3) }
+func _(x int) int { y := x; return y+1 }
+func _() int { type T struct{}; var x T; return x }
+
+// these must remain multi-line since they are multi-line in the source
+func _() {
+ f(1, 2, 3)
+}
+func _(x int) int {
+ y := x; return y+1
+}
+func _() int {
+ type T struct{}; var x T; return x
+}
+
+
+// making function declarations safe for new semicolon rules
+func _() { /* multi-line func because of comment */ }
+
+func _() {
+/* multi-line func because block is on multiple lines */ }
+
+
+// ellipsis parameters
+func _(...int)
+func _(...*int)
+func _(...[]int)
+func _(...struct{})
+func _(bool, ...interface{})
+func _(bool, ...func())
+func _(bool, ...func(...int))
+func _(bool, ...map[string]int)
+func _(bool, ...chan int)
+
+func _(b bool, x ...int)
+func _(b bool, x ...*int)
+func _(b bool, x ...[]int)
+func _(b bool, x ...struct{})
+func _(x ...interface{})
+func _(x ...func())
+func _(x ...func(...int))
+func _(x ...map[string]int)
+func _(x ...chan int)
+
+
+// these parameter lists must remain multi-line since they are multi-line in the source
+func _(bool,
+int) {
+}
+func _(x bool,
+y int) {
+}
+func _(x,
+y bool) {
+}
+func _(bool, // comment
+int) {
+}
+func _(x bool, // comment
+y int) {
+}
+func _(x, // comment
+y bool) {
+}
+func _(bool, // comment
+// comment
+int) {
+}
+func _(x bool, // comment
+// comment
+y int) {
+}
+func _(x, // comment
+// comment
+y bool) {
+}
+func _(bool,
+// comment
+int) {
+}
+func _(x bool,
+// comment
+y int) {
+}
+func _(x,
+// comment
+y bool) {
+}
+func _(x, // comment
+y,// comment
+z bool) {
+}
+func _(x, // comment
+ y,// comment
+ z bool) {
+}
+func _(x int, // comment
+ y float, // comment
+ z bool) {
+}
diff --git a/libgo/go/go/printer/testdata/empty.golden b/libgo/go/go/printer/testdata/empty.golden
new file mode 100644
index 000000000..a055f4758
--- /dev/null
+++ b/libgo/go/go/printer/testdata/empty.golden
@@ -0,0 +1,5 @@
+// a comment at the beginning of the file
+
+package empty
+
+// a comment at the end of the file
diff --git a/libgo/go/go/printer/testdata/empty.input b/libgo/go/go/printer/testdata/empty.input
new file mode 100644
index 000000000..a055f4758
--- /dev/null
+++ b/libgo/go/go/printer/testdata/empty.input
@@ -0,0 +1,5 @@
+// a comment at the beginning of the file
+
+package empty
+
+// a comment at the end of the file
diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden
new file mode 100644
index 000000000..882c7624c
--- /dev/null
+++ b/libgo/go/go/printer/testdata/expressions.golden
@@ -0,0 +1,554 @@
+// 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 expressions
+
+type T struct {
+ x, y, z int
+}
+
+var (
+ a, b, c, d, e int
+ under_bar int
+ longIdentifier1, longIdentifier2, longIdentifier3 int
+ t0, t1, t2 T
+ s string
+ p *int
+)
+
+
+func _() {
+ // no spaces around simple or parenthesized expressions
+ _ = (a + 0)
+ _ = a + b
+ _ = a + b + c
+ _ = a + b - c
+ _ = a - b - c
+ _ = a + (b * c)
+ _ = a + (b / c)
+ _ = a - (b % c)
+ _ = 1 + a
+ _ = a + 1
+ _ = a + b + 1
+ _ = s[a]
+ _ = s[a:]
+ _ = s[:b]
+ _ = s[1:2]
+ _ = s[a:b]
+ _ = s[0:len(s)]
+ _ = s[0] << 1
+ _ = (s[0] << 1) & 0xf
+ _ = s[0]<<2 | s[1]>>4
+ _ = "foo" + s
+ _ = s + "foo"
+ _ = 'a' + 'b'
+ _ = len(s) / 2
+ _ = len(t0.x) / a
+
+ // spaces around expressions of different precedence or expressions containing spaces
+ _ = a + -b
+ _ = a - ^b
+ _ = a / *p
+ _ = a + b*c
+ _ = 1 + b*c
+ _ = a + 2*c
+ _ = a + c*2
+ _ = 1 + 2*3
+ _ = s[1 : 2*3]
+ _ = s[a : b-c]
+ _ = s[0:]
+ _ = s[a+b]
+ _ = s[:b-c]
+ _ = s[a+b:]
+ _ = a[a<<b+1]
+ _ = a[a<<b+1:]
+ _ = s[a+b : len(s)]
+ _ = s[len(s):-a]
+ _ = s[a : len(s)+1]
+ _ = s[a:len(s)+1] + s
+
+ // spaces around operators with equal or lower precedence than comparisons
+ _ = a == b
+ _ = a != b
+ _ = a > b
+ _ = a >= b
+ _ = a < b
+ _ = a <= b
+ _ = a < b && c > d
+ _ = a < b || c > d
+
+ // spaces around "long" operands
+ _ = a + longIdentifier1
+ _ = longIdentifier1 + a
+ _ = longIdentifier1 + longIdentifier2*longIdentifier3
+ _ = s + "a longer string"
+
+ // some selected cases
+ _ = a + t0.x
+ _ = a + t0.x + t1.x*t2.x
+ _ = a + b + c + d + e + 2*3
+ _ = a + b + c + 2*3 + d + e
+ _ = (a + b + c) * 2
+ _ = a - b + c - d + (a + b + c) + d&e
+ _ = under_bar - 1
+ _ = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
+ _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+}
+
+
+func _() {
+ a + b
+ a + b + c
+ a + b*c
+ a + (b * c)
+ (a + b) * c
+ a + (b * c * d)
+ a + (b*c + d)
+
+ 1 << x
+ -1 << x
+ 1<<x - 1
+ -1<<x - 1
+
+ f(a + b)
+ f(a + b + c)
+ f(a + b*c)
+ f(a + (b * c))
+ f(1<<x-1, 1<<x-2)
+
+ 1<<d.logWindowSize - 1
+
+ buf = make(x, 2*cap(b.buf)+n)
+
+ dst[i*3+2] = dbuf[0] << 2
+ dst[i*3+2] = dbuf[0]<<2 | dbuf[1]>>4
+
+ b.buf = b.buf[0 : b.off+m+n]
+ b.buf = b.buf[0 : b.off+m*n]
+ f(b.buf[0 : b.off+m+n])
+
+ signed += ' ' * 8
+ tw.octal(header[148:155], chksum)
+
+ x > 0 && i >= 0
+
+ x1, x0 := x>>w2, x&m2
+ z0 = t1<<w2 + t0
+ z1 = (t1 + t0>>w2) >> w2
+ q1, r1 := x1/d1, x1%d1
+ r1 = r1*b2 | x0>>w2
+ x1 = (x1 << z) | (x0 >> (uint(w) - z))
+ x1 = x1<<z | x0>>(uint(w)-z)
+
+ buf[0 : len(buf)+1]
+ buf[0 : n+1]
+
+ a, b = b, a
+ a = b + c
+ a = b*c + d
+ a*b + c
+ a - b - c
+ a - (b - c)
+ a - b*c
+ a - (b * c)
+ a * b / c
+ a / *b
+ x[a|^b]
+ x[a / *b]
+ a & ^b
+ a + +b
+ a - -b
+ x[a*-b]
+ x[a + +b]
+ x ^ y ^ z
+ b[a>>24] ^ b[(a>>16)&0xFF] ^ b[(a>>8)&0xFF] ^ b[a&0xFF]
+ len(longVariableName) * 2
+
+ token(matchType + xlength<<lengthShift + xoffset)
+}
+
+
+func f(x int, args ...int) {
+ f(0, args...)
+ f(1, args)
+ f(2, args[0])
+
+ // make sure syntactically legal code remains syntactically legal
+ f(3, 42 ...) // a blank must remain between 42 and ...
+ f(4, 42....)
+ f(5, 42....)
+ f(6, 42.0...)
+ f(7, 42.0...)
+ f(8, .42...)
+ f(9, .42...)
+ f(10, 42e0...)
+ f(11, 42e0...)
+
+ _ = 42 .x // a blank must remain between 42 and .x
+ _ = 42..x
+ _ = 42..x
+ _ = 42.0.x
+ _ = 42.0.x
+ _ = .42.x
+ _ = .42.x
+ _ = 42e0.x
+ _ = 42e0.x
+
+ // a blank must remain between the binary operator and the 2nd operand
+ _ = x / *y
+ _ = x < -1
+ _ = x < <-1
+ _ = x + +1
+ _ = x - -1
+ _ = x & &x
+ _ = x & ^x
+
+ _ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
+}
+
+
+func _() {
+ _ = T{}
+ _ = struct{}{}
+ _ = [10]T{}
+ _ = [...]T{}
+ _ = []T{}
+ _ = map[int]T{}
+}
+
+
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+ _ = struct{}{}
+ _ = struct{ x int }{0}
+ _ = struct{ x, y, z int }{0, 1, 2}
+ _ = struct{ int }{0}
+ _ = struct {
+ s struct {
+ int
+ }
+ }{struct{ int }{0}} // compositeLit context not propagated => multiLine result
+}
+
+
+func _() {
+ // do not modify literals
+ _ = "tab1 tab2 tab3 end" // string contains 3 tabs
+ _ = "tab1 tab2 tab3 end" // same string with 3 blanks - may be unaligned because editors see tabs in strings
+ _ = "" // this comment should be aligned with the one on the previous line
+ _ = ``
+ _ = `
+`
+ _ = `foo
+ bar`
+ _ = `three spaces before the end of the line starting here:
+they must not be removed`
+}
+
+
+func _() {
+ // one-line function literals (body is on a single line)
+ _ = func() {}
+ _ = func() int { return 0 }
+ _ = func(x, y int) bool { m := (x + y) / 2; return m < 0 }
+
+ // multi-line function literals (body is not on one line)
+ _ = func() {
+ }
+ _ = func() int {
+ return 0
+ }
+ _ = func(x, y int) bool {
+ m := (x + y) / 2
+ return x < y
+ }
+
+ f(func() {
+ })
+ f(func() int {
+ return 0
+ })
+ f(func(x, y int) bool {
+ m := (x + y) / 2
+ return x < y
+ })
+}
+
+
+func _() {
+ _ = [][]int{
+ []int{1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ {1, 2},
+ {1, 2, 3},
+ }
+ _ = [][]int{{1}, {1, 2}, {1, 2, 3}}
+}
+
+
+// various multi-line expressions
+func _() {
+ // do not add extra indentation to multi-line string lists
+ _ = "foo" + "bar"
+ _ = "foo" +
+ "bar" +
+ "bah"
+ _ = []string{
+ "abc" +
+ "def",
+ "foo" +
+ "bar",
+ }
+}
+
+
+const _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+
+const _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+
+const _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+
+func _() {
+ _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+ _ =
+ `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+ _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+}
+
+
+func _() {
+ // respect source lines in multi-line expressions
+ _ = a +
+ b +
+ c
+ _ = a < b ||
+ b < a
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+}
+
+
+// Alignment after overlong lines
+const (
+ _ = "991"
+ _ = "2432902008176640000" // 20!
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+)
+
+
+// Correct placement of operators and comments in multi-line expressions
+func _() {
+ _ = a + // comment
+ b + // comment
+ c
+ _ = "a" +
+ "b" + // comment
+ "c"
+ _ = "ba0408" + "7265717569726564" // field 71, encoding 2, string "required"
+}
+
+
+// Correct placement of terminating comma/closing parentheses in multi-line calls.
+func _() {
+ f(1,
+ 2,
+ 3)
+ f(1,
+ 2,
+ 3,
+ )
+ f(1,
+ 2,
+ 3) // comment
+ f(1,
+ 2,
+ 3, // comment
+ )
+ f(1,
+ 2,
+ 3) // comment
+ f(1,
+ 2,
+ 3, // comment
+ )
+}
+
+
+// Align comments in multi-line lists of single-line expressions.
+var txpix = [NCOL]draw.Color{
+ draw.Yellow, // yellow
+ draw.Cyan, // cyan
+ draw.Green, // lime green
+ draw.GreyBlue, // slate
+ draw.Red, /* red */
+ draw.GreyGreen, /* olive green */
+ draw.Blue, /* blue */
+ draw.Color(0xFF55AAFF), /* pink */
+ draw.Color(0xFFAAFFFF), /* lavender */
+ draw.Color(0xBB005DFF), /* maroon */
+}
+
+
+func same(t, u *Time) bool {
+ // respect source lines in multi-line expressions
+ return t.Year == u.Year &&
+ t.Month == u.Month &&
+ t.Day == u.Day &&
+ t.Hour == u.Hour &&
+ t.Minute == u.Minute &&
+ t.Second == u.Second &&
+ t.Weekday == u.Weekday &&
+ t.ZoneOffset == u.ZoneOffset &&
+ t.Zone == u.Zone
+}
+
+
+func (p *parser) charClass() {
+ // respect source lines in multi-line expressions
+ if cc.negate && len(cc.ranges) == 2 &&
+ cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+ nl := new(_NotNl)
+ p.re.add(nl)
+ }
+}
+
+
+func addState(s []state, inst instr, match []int) {
+ // handle comments correctly in multi-line expressions
+ for i := 0; i < l; i++ {
+ if s[i].inst.index() == index && // same instruction
+ s[i].match[0] < pos { // earlier match already going; leftmost wins
+ return s
+ }
+ }
+}
+
+func (self *T) foo(x int) *T { return self }
+
+func _() { module.Func1().Func2() }
+
+func _() {
+ _ = new(T).
+ foo(1).
+ foo(2).
+ foo(3)
+
+ _ = new(T).
+ foo(1).
+ foo(2). // inline comments
+ foo(3)
+
+ _ = new(T).foo(1).foo(2).foo(3)
+
+ // handle multiline argument list correctly
+ _ = new(T).
+ foo(
+ 1).
+ foo(2)
+
+ _ = new(T).foo(
+ 1).foo(2)
+
+ _ = Array[3+
+ 4]
+
+ _ = Method(1, 2,
+ 3)
+
+ _ = new(T).
+ foo().
+ bar().(*Type)
+
+ _ = new(T).
+ foo().
+ bar().(*Type).
+ baz()
+
+ _ = new(T).
+ foo().
+ bar()["idx"]
+
+ _ = new(T).
+ foo().
+ bar()["idx"].
+ baz()
+
+ _ = new(T).
+ foo().
+ bar()[1:2]
+
+ _ = new(T).
+ foo().
+ bar()[1:2].
+ baz()
+
+ _ = new(T).
+ Field.
+ Array[3+
+ 4].
+ Table["foo"].
+ Blob.(*Type).
+ Slices[1:4].
+ Method(1, 2,
+ 3).
+ Thingy
+
+ _ = a.b.c
+ _ = a.
+ b.
+ c
+ _ = a.b().c
+ _ = a.
+ b().
+ c
+ _ = a.b[0].c
+ _ = a.
+ b[0].
+ c
+ _ = a.b[0:].c
+ _ = a.
+ b[0:].
+ c
+ _ = a.b.(T).c
+ _ = a.
+ b.(T).
+ c
+}
diff --git a/libgo/go/go/printer/testdata/expressions.input b/libgo/go/go/printer/testdata/expressions.input
new file mode 100644
index 000000000..647706b09
--- /dev/null
+++ b/libgo/go/go/printer/testdata/expressions.input
@@ -0,0 +1,548 @@
+// 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 expressions
+
+type T struct {
+ x, y, z int
+}
+
+var (
+ a, b, c, d, e int
+ under_bar int
+ longIdentifier1, longIdentifier2, longIdentifier3 int
+ t0, t1, t2 T
+ s string
+ p *int
+)
+
+
+func _() {
+ // no spaces around simple or parenthesized expressions
+ _ = (a+0)
+ _ = a+b
+ _ = a+b+c
+ _ = a+b-c
+ _ = a-b-c
+ _ = a+(b*c)
+ _ = a+(b/c)
+ _ = a-(b%c)
+ _ = 1+a
+ _ = a+1
+ _ = a+b+1
+ _ = s[a]
+ _ = s[a:]
+ _ = s[:b]
+ _ = s[1:2]
+ _ = s[a:b]
+ _ = s[0:len(s)]
+ _ = s[0]<<1
+ _ = (s[0]<<1)&0xf
+ _ = s[0] << 2 | s[1] >> 4
+ _ = "foo"+s
+ _ = s+"foo"
+ _ = 'a'+'b'
+ _ = len(s)/2
+ _ = len(t0.x)/a
+
+ // spaces around expressions of different precedence or expressions containing spaces
+ _ = a + -b
+ _ = a - ^b
+ _ = a / *p
+ _ = a + b*c
+ _ = 1 + b*c
+ _ = a + 2*c
+ _ = a + c*2
+ _ = 1 + 2*3
+ _ = s[1 : 2*3]
+ _ = s[a : b-c]
+ _ = s[0:]
+ _ = s[a+b]
+ _ = s[: b-c]
+ _ = s[a+b :]
+ _ = a[a<<b+1]
+ _ = a[a<<b+1 :]
+ _ = s[a+b : len(s)]
+ _ = s[len(s) : -a]
+ _ = s[a : len(s)+1]
+ _ = s[a : len(s)+1]+s
+
+ // spaces around operators with equal or lower precedence than comparisons
+ _ = a == b
+ _ = a != b
+ _ = a > b
+ _ = a >= b
+ _ = a < b
+ _ = a <= b
+ _ = a < b && c > d
+ _ = a < b || c > d
+
+ // spaces around "long" operands
+ _ = a + longIdentifier1
+ _ = longIdentifier1 + a
+ _ = longIdentifier1 + longIdentifier2 * longIdentifier3
+ _ = s + "a longer string"
+
+ // some selected cases
+ _ = a + t0.x
+ _ = a + t0.x + t1.x * t2.x
+ _ = a + b + c + d + e + 2*3
+ _ = a + b + c + 2*3 + d + e
+ _ = (a+b+c)*2
+ _ = a - b + c - d + (a+b+c) + d&e
+ _ = under_bar-1
+ _ = Open(dpath + "/file", O_WRONLY | O_CREAT, 0666)
+ _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+}
+
+
+func _() {
+ a+b
+ a+b+c
+ a+b*c
+ a+(b*c)
+ (a+b)*c
+ a+(b*c*d)
+ a+(b*c+d)
+
+ 1<<x
+ -1<<x
+ 1<<x-1
+ -1<<x-1
+
+ f(a+b)
+ f(a+b+c)
+ f(a+b*c)
+ f(a+(b*c))
+ f(1<<x-1, 1<<x-2)
+
+ 1<<d.logWindowSize-1
+
+ buf = make(x, 2*cap(b.buf) + n)
+
+ dst[i*3+2] = dbuf[0]<<2
+ dst[i*3+2] = dbuf[0]<<2 | dbuf[1]>>4
+
+ b.buf = b.buf[0:b.off+m+n]
+ b.buf = b.buf[0:b.off+m*n]
+ f(b.buf[0:b.off+m+n])
+
+ signed += ' '*8
+ tw.octal(header[148:155], chksum)
+
+ x > 0 && i >= 0
+
+ x1, x0 := x>>w2, x&m2
+ z0 = t1<<w2+t0
+ z1 = (t1+t0>>w2)>>w2
+ q1, r1 := x1/d1, x1%d1
+ r1 = r1*b2 | x0>>w2
+ x1 = (x1<<z)|(x0>>(uint(w)-z))
+ x1 = x1<<z | x0>>(uint(w)-z)
+
+ buf[0:len(buf)+1]
+ buf[0:n+1]
+
+ a,b = b,a
+ a = b+c
+ a = b*c+d
+ a*b+c
+ a-b-c
+ a-(b-c)
+ a-b*c
+ a-(b*c)
+ a*b/c
+ a/ *b
+ x[a|^b]
+ x[a/ *b]
+ a& ^b
+ a+ +b
+ a- -b
+ x[a*-b]
+ x[a+ +b]
+ x^y^z
+ b[a>>24] ^ b[(a>>16)&0xFF] ^ b[(a>>8)&0xFF] ^ b[a&0xFF]
+ len(longVariableName)*2
+
+ token(matchType + xlength<<lengthShift + xoffset)
+}
+
+
+func f(x int, args ...int) {
+ f(0, args...)
+ f(1, args)
+ f(2, args[0])
+
+ // make sure syntactically legal code remains syntactically legal
+ f(3, 42 ...) // a blank must remain between 42 and ...
+ f(4, 42. ...)
+ f(5, 42....)
+ f(6, 42.0 ...)
+ f(7, 42.0...)
+ f(8, .42 ...)
+ f(9, .42...)
+ f(10, 42e0 ...)
+ f(11, 42e0...)
+
+ _ = 42 .x // a blank must remain between 42 and .x
+ _ = 42. .x
+ _ = 42..x
+ _ = 42.0 .x
+ _ = 42.0.x
+ _ = .42 .x
+ _ = .42.x
+ _ = 42e0 .x
+ _ = 42e0.x
+
+ // a blank must remain between the binary operator and the 2nd operand
+ _ = x/ *y
+ _ = x< -1
+ _ = x< <-1
+ _ = x+ +1
+ _ = x- -1
+ _ = x& &x
+ _ = x& ^x
+
+ _ = f(x/ *y, x< -1, x< <-1, x+ +1, x- -1, x& &x, x& ^x)
+}
+
+
+func _() {
+ _ = T{}
+ _ = struct{}{}
+ _ = [10]T{}
+ _ = [...]T{}
+ _ = []T{}
+ _ = map[int]T{}
+}
+
+
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+ _ = struct{}{}
+ _ = struct{ x int }{0}
+ _ = struct{ x, y, z int }{0, 1, 2}
+ _ = struct{ int }{0}
+ _ = struct{ s struct { int } }{struct{ int}{0}} // compositeLit context not propagated => multiLine result
+}
+
+
+func _() {
+ // do not modify literals
+ _ = "tab1 tab2 tab3 end" // string contains 3 tabs
+ _ = "tab1 tab2 tab3 end" // same string with 3 blanks - may be unaligned because editors see tabs in strings
+ _ = "" // this comment should be aligned with the one on the previous line
+ _ = ``
+ _ = `
+`
+_ = `foo
+ bar`
+ _ = `three spaces before the end of the line starting here:
+they must not be removed`
+}
+
+
+func _() {
+ // one-line function literals (body is on a single line)
+ _ = func() {}
+ _ = func() int { return 0 }
+ _ = func(x, y int) bool { m := (x+y)/2; return m < 0 }
+
+ // multi-line function literals (body is not on one line)
+ _ = func() {
+ }
+ _ = func() int {
+ return 0
+ }
+ _ = func(x, y int) bool {
+ m := (x+y)/2; return x < y }
+
+ f(func() {
+ })
+ f(func() int {
+ return 0
+ })
+ f(func(x, y int) bool {
+ m := (x+y)/2; return x < y })
+}
+
+
+func _() {
+ _ = [][]int {
+ []int{1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int {
+ {1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int {
+ {1},
+ {1, 2},
+ {1, 2, 3},
+ }
+ _ = [][]int {{1}, {1, 2}, {1, 2, 3}}
+}
+
+
+// various multi-line expressions
+func _() {
+ // do not add extra indentation to multi-line string lists
+ _ = "foo" + "bar"
+ _ = "foo" +
+ "bar" +
+ "bah"
+ _ = []string {
+ "abc" +
+ "def",
+ "foo" +
+ "bar",
+ }
+}
+
+
+const _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+
+const _ =
+ `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+
+const _ = `datafmt "datafmt";` +
+`default = "%v";` +
+`array = *;` +
+`datafmt.T3 = s {" " a a / ","};`
+
+
+func _() {
+ _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+ _ =
+ `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+ _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+}
+
+
+func _() {
+ // respect source lines in multi-line expressions
+ _ = a+
+ b+
+ c
+ _ = a < b ||
+ b < a
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+}
+
+
+// Alignment after overlong lines
+const (
+ _ = "991"
+ _ = "2432902008176640000" // 20!
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+)
+
+
+// Correct placement of operators and comments in multi-line expressions
+func _() {
+ _ = a + // comment
+ b + // comment
+ c
+ _ = "a" +
+ "b" + // comment
+ "c"
+ _ = "ba0408" + "7265717569726564" // field 71, encoding 2, string "required"
+}
+
+
+// Correct placement of terminating comma/closing parentheses in multi-line calls.
+func _() {
+ f(1,
+ 2,
+ 3)
+ f(1,
+ 2,
+ 3,
+ )
+ f(1,
+ 2,
+ 3) // comment
+ f(1,
+ 2,
+ 3, // comment
+ )
+ f(1,
+ 2,
+ 3)// comment
+ f(1,
+ 2,
+ 3,// comment
+ )
+}
+
+
+// Align comments in multi-line lists of single-line expressions.
+var txpix = [NCOL]draw.Color{
+ draw.Yellow, // yellow
+ draw.Cyan, // cyan
+ draw.Green, // lime green
+ draw.GreyBlue, // slate
+ draw.Red, /* red */
+ draw.GreyGreen, /* olive green */
+ draw.Blue, /* blue */
+ draw.Color(0xFF55AAFF), /* pink */
+ draw.Color(0xFFAAFFFF), /* lavender */
+ draw.Color(0xBB005DFF), /* maroon */
+}
+
+
+func same(t, u *Time) bool {
+ // respect source lines in multi-line expressions
+ return t.Year == u.Year &&
+ t.Month == u.Month &&
+ t.Day == u.Day &&
+ t.Hour == u.Hour &&
+ t.Minute == u.Minute &&
+ t.Second == u.Second &&
+ t.Weekday == u.Weekday &&
+ t.ZoneOffset == u.ZoneOffset &&
+ t.Zone == u.Zone
+}
+
+
+func (p *parser) charClass() {
+ // respect source lines in multi-line expressions
+ if cc.negate && len(cc.ranges) == 2 &&
+ cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+ nl := new(_NotNl)
+ p.re.add(nl)
+ }
+}
+
+
+func addState(s []state, inst instr, match []int) {
+ // handle comments correctly in multi-line expressions
+ for i := 0; i < l; i++ {
+ if s[i].inst.index() == index && // same instruction
+ s[i].match[0] < pos { // earlier match already going; leftmost wins
+ return s
+ }
+ }
+}
+
+func (self *T) foo(x int) *T { return self }
+
+func _() { module.Func1().Func2() }
+
+func _() {
+ _ = new(T).
+ foo(1).
+ foo(2).
+ foo(3)
+
+ _ = new(T).
+ foo(1).
+ foo(2). // inline comments
+ foo(3)
+
+ _ = new(T).foo(1).foo(2).foo(3)
+
+ // handle multiline argument list correctly
+ _ = new(T).
+ foo(
+ 1).
+ foo(2)
+
+ _ = new(T).foo(
+ 1).foo(2)
+
+ _ = Array[3 +
+4]
+
+ _ = Method(1, 2,
+ 3)
+
+ _ = new(T).
+ foo().
+ bar() . (*Type)
+
+ _ = new(T).
+foo().
+bar().(*Type).
+baz()
+
+ _ = new(T).
+ foo().
+ bar()["idx"]
+
+ _ = new(T).
+ foo().
+ bar()["idx"] .
+ baz()
+
+ _ = new(T).
+ foo().
+ bar()[1:2]
+
+ _ = new(T).
+ foo().
+ bar()[1:2].
+ baz()
+
+ _ = new(T).
+ Field.
+ Array[3+
+ 4].
+ Table ["foo"].
+ Blob. (*Type).
+ Slices[1:4].
+ Method(1, 2,
+ 3).
+ Thingy
+
+ _ = a.b.c
+ _ = a.
+ b.
+ c
+ _ = a.b().c
+ _ = a.
+ b().
+ c
+ _ = a.b[0].c
+ _ = a.
+ b[0].
+ c
+ _ = a.b[0:].c
+ _ = a.
+ b[0:].
+ c
+ _ = a.b.(T).c
+ _ = a.
+ b.
+ (T).
+ c
+}
diff --git a/libgo/go/go/printer/testdata/expressions.raw b/libgo/go/go/printer/testdata/expressions.raw
new file mode 100644
index 000000000..62be00cc3
--- /dev/null
+++ b/libgo/go/go/printer/testdata/expressions.raw
@@ -0,0 +1,554 @@
+// 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 expressions
+
+type T struct {
+ x, y, z int
+}
+
+var (
+ a, b, c, d, e int
+ under_bar int
+ longIdentifier1, longIdentifier2, longIdentifier3 int
+ t0, t1, t2 T
+ s string
+ p *int
+)
+
+
+func _() {
+ // no spaces around simple or parenthesized expressions
+ _ = (a + 0)
+ _ = a + b
+ _ = a + b + c
+ _ = a + b - c
+ _ = a - b - c
+ _ = a + (b * c)
+ _ = a + (b / c)
+ _ = a - (b % c)
+ _ = 1 + a
+ _ = a + 1
+ _ = a + b + 1
+ _ = s[a]
+ _ = s[a:]
+ _ = s[:b]
+ _ = s[1:2]
+ _ = s[a:b]
+ _ = s[0:len(s)]
+ _ = s[0] << 1
+ _ = (s[0] << 1) & 0xf
+ _ = s[0]<<2 | s[1]>>4
+ _ = "foo" + s
+ _ = s + "foo"
+ _ = 'a' + 'b'
+ _ = len(s) / 2
+ _ = len(t0.x) / a
+
+ // spaces around expressions of different precedence or expressions containing spaces
+ _ = a + -b
+ _ = a - ^b
+ _ = a / *p
+ _ = a + b*c
+ _ = 1 + b*c
+ _ = a + 2*c
+ _ = a + c*2
+ _ = 1 + 2*3
+ _ = s[1 : 2*3]
+ _ = s[a : b-c]
+ _ = s[0:]
+ _ = s[a+b]
+ _ = s[:b-c]
+ _ = s[a+b:]
+ _ = a[a<<b+1]
+ _ = a[a<<b+1:]
+ _ = s[a+b : len(s)]
+ _ = s[len(s):-a]
+ _ = s[a : len(s)+1]
+ _ = s[a:len(s)+1] + s
+
+ // spaces around operators with equal or lower precedence than comparisons
+ _ = a == b
+ _ = a != b
+ _ = a > b
+ _ = a >= b
+ _ = a < b
+ _ = a <= b
+ _ = a < b && c > d
+ _ = a < b || c > d
+
+ // spaces around "long" operands
+ _ = a + longIdentifier1
+ _ = longIdentifier1 + a
+ _ = longIdentifier1 + longIdentifier2*longIdentifier3
+ _ = s + "a longer string"
+
+ // some selected cases
+ _ = a + t0.x
+ _ = a + t0.x + t1.x*t2.x
+ _ = a + b + c + d + e + 2*3
+ _ = a + b + c + 2*3 + d + e
+ _ = (a + b + c) * 2
+ _ = a - b + c - d + (a + b + c) + d&e
+ _ = under_bar - 1
+ _ = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
+ _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+}
+
+
+func _() {
+ a + b
+ a + b + c
+ a + b*c
+ a + (b * c)
+ (a + b) * c
+ a + (b * c * d)
+ a + (b*c + d)
+
+ 1 << x
+ -1 << x
+ 1<<x - 1
+ -1<<x - 1
+
+ f(a + b)
+ f(a + b + c)
+ f(a + b*c)
+ f(a + (b * c))
+ f(1<<x-1, 1<<x-2)
+
+ 1<<d.logWindowSize - 1
+
+ buf = make(x, 2*cap(b.buf)+n)
+
+ dst[i*3+2] = dbuf[0] << 2
+ dst[i*3+2] = dbuf[0]<<2 | dbuf[1]>>4
+
+ b.buf = b.buf[0 : b.off+m+n]
+ b.buf = b.buf[0 : b.off+m*n]
+ f(b.buf[0 : b.off+m+n])
+
+ signed += ' ' * 8
+ tw.octal(header[148:155], chksum)
+
+ x > 0 && i >= 0
+
+ x1, x0 := x>>w2, x&m2
+ z0 = t1<<w2 + t0
+ z1 = (t1 + t0>>w2) >> w2
+ q1, r1 := x1/d1, x1%d1
+ r1 = r1*b2 | x0>>w2
+ x1 = (x1 << z) | (x0 >> (uint(w) - z))
+ x1 = x1<<z | x0>>(uint(w)-z)
+
+ buf[0 : len(buf)+1]
+ buf[0 : n+1]
+
+ a, b = b, a
+ a = b + c
+ a = b*c + d
+ a*b + c
+ a - b - c
+ a - (b - c)
+ a - b*c
+ a - (b * c)
+ a * b / c
+ a / *b
+ x[a|^b]
+ x[a / *b]
+ a & ^b
+ a + +b
+ a - -b
+ x[a*-b]
+ x[a + +b]
+ x ^ y ^ z
+ b[a>>24] ^ b[(a>>16)&0xFF] ^ b[(a>>8)&0xFF] ^ b[a&0xFF]
+ len(longVariableName) * 2
+
+ token(matchType + xlength<<lengthShift + xoffset)
+}
+
+
+func f(x int, args ...int) {
+ f(0, args...)
+ f(1, args)
+ f(2, args[0])
+
+ // make sure syntactically legal code remains syntactically legal
+ f(3, 42 ...) // a blank must remain between 42 and ...
+ f(4, 42....)
+ f(5, 42....)
+ f(6, 42.0...)
+ f(7, 42.0...)
+ f(8, .42...)
+ f(9, .42...)
+ f(10, 42e0...)
+ f(11, 42e0...)
+
+ _ = 42 .x // a blank must remain between 42 and .x
+ _ = 42..x
+ _ = 42..x
+ _ = 42.0.x
+ _ = 42.0.x
+ _ = .42.x
+ _ = .42.x
+ _ = 42e0.x
+ _ = 42e0.x
+
+ // a blank must remain between the binary operator and the 2nd operand
+ _ = x / *y
+ _ = x < -1
+ _ = x < <-1
+ _ = x + +1
+ _ = x - -1
+ _ = x & &x
+ _ = x & ^x
+
+ _ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
+}
+
+
+func _() {
+ _ = T{}
+ _ = struct{}{}
+ _ = [10]T{}
+ _ = [...]T{}
+ _ = []T{}
+ _ = map[int]T{}
+}
+
+
+// one-line structs/interfaces in composite literals (up to a threshold)
+func _() {
+ _ = struct{}{}
+ _ = struct{ x int }{0}
+ _ = struct{ x, y, z int }{0, 1, 2}
+ _ = struct{ int }{0}
+ _ = struct {
+ s struct {
+ int
+ }
+ }{struct{ int }{0}} // compositeLit context not propagated => multiLine result
+}
+
+
+func _() {
+ // do not modify literals
+ _ = "tab1 tab2 tab3 end" // string contains 3 tabs
+ _ = "tab1 tab2 tab3 end" // same string with 3 blanks - may be unaligned because editors see tabs in strings
+ _ = "" // this comment should be aligned with the one on the previous line
+ _ = ``
+ _ = `
+`
+ _ = `foo
+ bar`
+ _ = `three spaces before the end of the line starting here:
+they must not be removed`
+}
+
+
+func _() {
+ // one-line function literals (body is on a single line)
+ _ = func() {}
+ _ = func() int { return 0 }
+ _ = func(x, y int) bool { m := (x + y) / 2; return m < 0 }
+
+ // multi-line function literals (body is not on one line)
+ _ = func() {
+ }
+ _ = func() int {
+ return 0
+ }
+ _ = func(x, y int) bool {
+ m := (x + y) / 2
+ return x < y
+ }
+
+ f(func() {
+ })
+ f(func() int {
+ return 0
+ })
+ f(func(x, y int) bool {
+ m := (x + y) / 2
+ return x < y
+ })
+}
+
+
+func _() {
+ _ = [][]int{
+ []int{1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ {1, 2},
+ {1, 2, 3},
+ }
+ _ = [][]int{{1}, {1, 2}, {1, 2, 3}}
+}
+
+
+// various multi-line expressions
+func _() {
+ // do not add extra indentation to multi-line string lists
+ _ = "foo" + "bar"
+ _ = "foo" +
+ "bar" +
+ "bah"
+ _ = []string{
+ "abc" +
+ "def",
+ "foo" +
+ "bar",
+ }
+}
+
+
+const _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+
+const _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+
+const _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+
+func _() {
+ _ = F1 +
+ `string = "%s";` +
+ `ptr = *;` +
+ `datafmt.T2 = s ["-" p "-"];`
+
+ _ =
+ `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+
+ _ = `datafmt "datafmt";` +
+ `default = "%v";` +
+ `array = *;` +
+ `datafmt.T3 = s {" " a a / ","};`
+}
+
+
+func _() {
+ // respect source lines in multi-line expressions
+ _ = a +
+ b +
+ c
+ _ = a < b ||
+ b < a
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+}
+
+
+// Alignment after overlong lines
+const (
+ _ = "991"
+ _ = "2432902008176640000" // 20!
+ _ = "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000" // 100!
+ _ = "170141183460469231731687303715884105727" // prime
+)
+
+
+// Correct placement of operators and comments in multi-line expressions
+func _() {
+ _ = a + // comment
+ b + // comment
+ c
+ _ = "a" +
+ "b" + // comment
+ "c"
+ _ = "ba0408" + "7265717569726564" // field 71, encoding 2, string "required"
+}
+
+
+// Correct placement of terminating comma/closing parentheses in multi-line calls.
+func _() {
+ f(1,
+ 2,
+ 3)
+ f(1,
+ 2,
+ 3,
+ )
+ f(1,
+ 2,
+ 3) // comment
+ f(1,
+ 2,
+ 3, // comment
+ )
+ f(1,
+ 2,
+ 3) // comment
+ f(1,
+ 2,
+ 3, // comment
+ )
+}
+
+
+// Align comments in multi-line lists of single-line expressions.
+var txpix = [NCOL]draw.Color{
+ draw.Yellow, // yellow
+ draw.Cyan, // cyan
+ draw.Green, // lime green
+ draw.GreyBlue, // slate
+ draw.Red, /* red */
+ draw.GreyGreen, /* olive green */
+ draw.Blue, /* blue */
+ draw.Color(0xFF55AAFF), /* pink */
+ draw.Color(0xFFAAFFFF), /* lavender */
+ draw.Color(0xBB005DFF), /* maroon */
+}
+
+
+func same(t, u *Time) bool {
+ // respect source lines in multi-line expressions
+ return t.Year == u.Year &&
+ t.Month == u.Month &&
+ t.Day == u.Day &&
+ t.Hour == u.Hour &&
+ t.Minute == u.Minute &&
+ t.Second == u.Second &&
+ t.Weekday == u.Weekday &&
+ t.ZoneOffset == u.ZoneOffset &&
+ t.Zone == u.Zone
+}
+
+
+func (p *parser) charClass() {
+ // respect source lines in multi-line expressions
+ if cc.negate && len(cc.ranges) == 2 &&
+ cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+ nl := new(_NotNl)
+ p.re.add(nl)
+ }
+}
+
+
+func addState(s []state, inst instr, match []int) {
+ // handle comments correctly in multi-line expressions
+ for i := 0; i < l; i++ {
+ if s[i].inst.index() == index && // same instruction
+ s[i].match[0] < pos { // earlier match already going; leftmost wins
+ return s
+ }
+ }
+}
+
+func (self *T) foo(x int) *T { return self }
+
+func _() { module.Func1().Func2() }
+
+func _() {
+ _ = new(T).
+ foo(1).
+ foo(2).
+ foo(3)
+
+ _ = new(T).
+ foo(1).
+ foo(2). // inline comments
+ foo(3)
+
+ _ = new(T).foo(1).foo(2).foo(3)
+
+ // handle multiline argument list correctly
+ _ = new(T).
+ foo(
+ 1).
+ foo(2)
+
+ _ = new(T).foo(
+ 1).foo(2)
+
+ _ = Array[3+
+ 4]
+
+ _ = Method(1, 2,
+ 3)
+
+ _ = new(T).
+ foo().
+ bar().(*Type)
+
+ _ = new(T).
+ foo().
+ bar().(*Type).
+ baz()
+
+ _ = new(T).
+ foo().
+ bar()["idx"]
+
+ _ = new(T).
+ foo().
+ bar()["idx"].
+ baz()
+
+ _ = new(T).
+ foo().
+ bar()[1:2]
+
+ _ = new(T).
+ foo().
+ bar()[1:2].
+ baz()
+
+ _ = new(T).
+ Field.
+ Array[3+
+ 4].
+ Table["foo"].
+ Blob.(*Type).
+ Slices[1:4].
+ Method(1, 2,
+ 3).
+ Thingy
+
+ _ = a.b.c
+ _ = a.
+ b.
+ c
+ _ = a.b().c
+ _ = a.
+ b().
+ c
+ _ = a.b[0].c
+ _ = a.
+ b[0].
+ c
+ _ = a.b[0:].c
+ _ = a.
+ b[0:].
+ c
+ _ = a.b.(T).c
+ _ = a.
+ b.(T).
+ c
+}
diff --git a/libgo/go/go/printer/testdata/linebreaks.golden b/libgo/go/go/printer/testdata/linebreaks.golden
new file mode 100644
index 000000000..be780da67
--- /dev/null
+++ b/libgo/go/go/printer/testdata/linebreaks.golden
@@ -0,0 +1,223 @@
+// 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 linebreaks
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type writerTestEntry struct {
+ header *Header
+ contents string
+}
+
+type writerTest struct {
+ file string // filename of expected output
+ entries []*writerTestEntry
+}
+
+var writerTests = []*writerTest{
+ &writerTest{
+ file: "testdata/writer.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1246508266,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Kilts",
+ },
+ &writerTestEntry{
+ header: &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1245217492,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Google.com\n",
+ },
+ },
+ },
+ // The truncated test file was produced using these commands:
+ // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+ // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+ &writerTest{
+ file: "testdata/writer-big.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "tmp/16gig.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 16 << 30,
+ Mtime: 1254699560,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ // no contents
+ },
+ },
+ },
+}
+
+type untarTest struct {
+ file string
+ headers []*Header
+}
+
+var untarTests = []*untarTest{
+ &untarTest{
+ file: "testdata/gnu.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244428340,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244436044,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ },
+ },
+ &untarTest{
+ file: "testdata/star.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ },
+ },
+ &untarTest{
+ file: "testdata/v7.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ },
+ },
+}
+
+var facts = map[int]string{
+ 0: "1",
+ 1: "1",
+ 2: "2",
+ 10: "3628800",
+ 20: "2432902008176640000",
+ 100: "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000",
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr,
+ // TODO(gri): the 2nd string of this string list should not be indented
+ "usage: godoc package [name ...]\n"+
+ " godoc -http=:6060\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+func TestReader(t *testing.T) {
+testLoop:
+ for i, test := range untarTests {
+ f, err := os.Open(test.file, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+ tr := NewReader(f)
+ for j, header := range test.headers {
+ hdr, err := tr.Next()
+ if err != nil || hdr == nil {
+ t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
+ f.Close()
+ continue testLoop
+ }
+ if !reflect.DeepEqual(hdr, header) {
+ t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
+ i, j, *hdr, *header)
+ }
+ }
+ hdr, err := tr.Next()
+ if hdr != nil || err != nil {
+ t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, err)
+ }
+ f.Close()
+ }
+}
+
+// There should be exactly one linebreak after this comment.
diff --git a/libgo/go/go/printer/testdata/linebreaks.input b/libgo/go/go/printer/testdata/linebreaks.input
new file mode 100644
index 000000000..457b491e6
--- /dev/null
+++ b/libgo/go/go/printer/testdata/linebreaks.input
@@ -0,0 +1,223 @@
+// 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 linebreaks
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type writerTestEntry struct {
+ header *Header
+ contents string
+}
+
+type writerTest struct {
+ file string // filename of expected output
+ entries []*writerTestEntry
+}
+
+var writerTests = []*writerTest{
+ &writerTest{
+ file: "testdata/writer.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1246508266,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Kilts",
+ },
+ &writerTestEntry{
+ header: &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1245217492,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Google.com\n",
+ },
+ },
+ },
+ // The truncated test file was produced using these commands:
+ // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+ // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+ &writerTest{
+ file: "testdata/writer-big.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "tmp/16gig.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 16 << 30,
+ Mtime: 1254699560,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ // no contents
+ },
+ },
+ },
+}
+
+type untarTest struct {
+ file string
+ headers []*Header
+}
+
+var untarTests = []*untarTest{
+ &untarTest{
+ file: "testdata/gnu.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244428340,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244436044,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ },
+ },
+ &untarTest{
+ file: "testdata/star.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ },
+ },
+ &untarTest{
+ file: "testdata/v7.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ },
+ },
+}
+
+var facts = map[int] string {
+ 0: "1",
+ 1: "1",
+ 2: "2",
+ 10: "3628800",
+ 20: "2432902008176640000",
+ 100: "933262154439441526816992388562667004907159682643816214685929" +
+ "638952175999932299156089414639761565182862536979208272237582" +
+ "51185210916864000000000000000000000000",
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr,
+ // TODO(gri): the 2nd string of this string list should not be indented
+ "usage: godoc package [name ...]\n" +
+ " godoc -http=:6060\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+func TestReader(t *testing.T) {
+testLoop:
+ for i, test := range untarTests {
+ f, err := os.Open(test.file, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+ tr := NewReader(f)
+ for j, header := range test.headers {
+ hdr, err := tr.Next()
+ if err != nil || hdr == nil {
+ t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
+ f.Close()
+ continue testLoop
+ }
+ if !reflect.DeepEqual(hdr, header) {
+ t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
+ i, j, *hdr, *header)
+ }
+ }
+ hdr, err := tr.Next()
+ if hdr != nil || err != nil {
+ t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, err)
+ }
+ f.Close()
+ }
+}
+
+// There should be exactly one linebreak after this comment.
diff --git a/libgo/go/go/printer/testdata/statements.golden b/libgo/go/go/printer/testdata/statements.golden
new file mode 100644
index 000000000..5eceb7dd5
--- /dev/null
+++ b/libgo/go/go/printer/testdata/statements.golden
@@ -0,0 +1,417 @@
+// 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 statements
+
+var expr bool
+
+func use(x interface{}) {}
+
+// Formatting of if-statement headers.
+func _() {
+ if {
+ }
+ if {
+ } // no semicolon printed
+ if expr {
+ }
+ if expr {
+ } // no semicolon printed
+ if expr {
+ } // no parens printed
+ if expr {
+ } // no semicolon and parens printed
+ if x := expr; {
+ use(x)
+ }
+ if x := expr; expr {
+ use(x)
+ }
+}
+
+
+// Formatting of switch-statement headers.
+func _() {
+ switch {
+ }
+ switch {
+ } // no semicolon printed
+ switch expr {
+ }
+ switch expr {
+ } // no semicolon printed
+ switch expr {
+ } // no parens printed
+ switch expr {
+ } // no semicolon and parens printed
+ switch x := expr; {
+ default:
+ use(
+ x)
+ }
+ switch x := expr; expr {
+ default:
+ use(x)
+ }
+}
+
+
+// Formatting of switch statement bodies.
+func _() {
+ switch {
+ }
+
+ switch x := 0; x {
+ case 1:
+ use(x)
+ use(x) // followed by an empty line
+
+ case 2: // followed by an empty line
+
+ use(x) // followed by an empty line
+
+ case 3: // no empty lines
+ use(x)
+ use(x)
+ }
+
+ switch x {
+ case 0:
+ use(x)
+ case 1: // this comment should have no effect on the previous or next line
+ use(x)
+ }
+
+ switch x := 0; x {
+ case 1:
+ x = 0
+ // this comment should be indented
+ case 2:
+ x = 0
+ // this comment should not be indented, it is aligned with the next case
+ case 3:
+ x = 0
+ /* indented comment
+ aligned
+ aligned
+ */
+ // bla
+ /* and more */
+ case 4:
+ x = 0
+ /* not indented comment
+ aligned
+ aligned
+ */
+ // bla
+ /* and more */
+ case 5:
+ }
+}
+
+
+// Formatting of for-statement headers.
+func _() {
+ for {
+ }
+ for expr {
+ }
+ for expr {
+ } // no parens printed
+ for {
+ } // no semicolons printed
+ for x := expr; ; {
+ use(x)
+ }
+ for expr {
+ } // no semicolons printed
+ for expr {
+ } // no semicolons and parens printed
+ for ; ; expr = false {
+ }
+ for x := expr; expr; {
+ use(x)
+ }
+ for x := expr; ; expr = false {
+ use(x)
+ }
+ for ; expr; expr = false {
+ }
+ for x := expr; expr; expr = false {
+ use(x)
+ }
+ for x := range []int{} {
+ use(x)
+ }
+ for x := range []int{} {
+ use(x)
+ } // no parens printed
+}
+
+
+// Don't remove mandatory parentheses around composite literals in control clauses.
+func _() {
+ // strip parentheses - no composite literals or composite literals don't start with a type name
+ if x {
+ }
+ if x {
+ }
+ if []T{} {
+ }
+ if []T{} {
+ }
+ if []T{} {
+ }
+
+ for x {
+ }
+ for x {
+ }
+ for []T{} {
+ }
+ for []T{} {
+ }
+ for []T{} {
+ }
+
+ switch x {
+ }
+ switch x {
+ }
+ switch []T{} {
+ }
+ switch []T{} {
+ }
+
+ for _ = range []T{T{42}} {
+ }
+
+ // leave parentheses - composite literals start with a type name
+ if (T{}) {
+ }
+ if (T{}) {
+ }
+ if (T{}) {
+ }
+
+ for (T{}) {
+ }
+ for (T{}) {
+ }
+ for (T{}) {
+ }
+
+ switch (T{}) {
+ }
+ switch (T{}) {
+ }
+
+ for _ = range (T1{T{42}}) {
+ }
+
+ if x == (T{42}[0]) {
+ }
+ if (x == T{42}[0]) {
+ }
+ if x == (T{42}[0]) {
+ }
+ if x == (T{42}[0]) {
+ }
+ if x == (T{42}[0]) {
+ }
+ if x == a+b*(T{42}[0]) {
+ }
+ if (x == a+b*T{42}[0]) {
+ }
+ if x == a+b*(T{42}[0]) {
+ }
+ if x == a+(b * (T{42}[0])) {
+ }
+ if x == a+b*(T{42}[0]) {
+ }
+ if (a + b*(T{42}[0])) == x {
+ }
+ if (a + b*(T{42}[0])) == x {
+ }
+
+ if struct{ x bool }{false}.x {
+ }
+ if (struct{ x bool }{false}.x) == false {
+ }
+ if struct{ x bool }{false}.x == false {
+ }
+}
+
+
+// Extra empty lines inside functions. Do respect source code line
+// breaks between statement boundaries but print at most one empty
+// line at a time.
+func _() {
+
+ const _ = 0
+
+ const _ = 1
+ type _ int
+ type _ float
+
+ var _ = 0
+ var x = 1
+
+ // Each use(x) call below should have at most one empty line before and after.
+ // Known bug: The first use call may have more than one empty line before
+ // (see go/printer/nodes.go, func linebreak).
+
+
+ use(x)
+
+ if x < x {
+
+ use(x)
+
+ } else {
+
+ use(x)
+
+ }
+}
+
+
+// Formatting around labels.
+func _() {
+L:
+}
+
+
+func _() {
+ // this comment should be indented
+L: // no semicolon needed
+}
+
+
+func _() {
+ switch 0 {
+ case 0:
+ L0:
+ ; // semicolon required
+ case 1:
+ L1:
+ ; // semicolon required
+ default:
+ L2: // no semicolon needed
+ }
+}
+
+
+func _() {
+ f()
+L1:
+ f()
+L2:
+ ;
+L3:
+}
+
+
+func _() {
+ // this comment should be indented
+L:
+}
+
+
+func _() {
+L:
+ _ = 0
+}
+
+
+func _() {
+ // this comment should be indented
+L:
+ _ = 0
+}
+
+
+func _() {
+ for {
+ L1:
+ _ = 0
+ L2:
+ _ = 0
+ }
+}
+
+
+func _() {
+ // this comment should be indented
+ for {
+ L1:
+ _ = 0
+ L2:
+ _ = 0
+ }
+}
+
+
+func _() {
+ if {
+ _ = 0
+ }
+ _ = 0 // the indentation here should not be affected by the long label name
+AnOverlongLabel:
+ _ = 0
+
+ if {
+ _ = 0
+ }
+ _ = 0
+
+L:
+ _ = 0
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L: // A comment on the same line as the label, followed by a single empty line.
+ // Known bug: There may be more than one empty line before MoreCode()
+ // (see go/printer/nodes.go, func linebreak).
+
+
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto AVeryLongLabelThatShouldNotAffectFormatting
+ }
+AVeryLongLabelThatShouldNotAffectFormatting:
+ // There should be a single empty line after this comment.
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
diff --git a/libgo/go/go/printer/testdata/statements.input b/libgo/go/go/printer/testdata/statements.input
new file mode 100644
index 000000000..7819820ed
--- /dev/null
+++ b/libgo/go/go/printer/testdata/statements.input
@@ -0,0 +1,338 @@
+// 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 statements
+
+var expr bool
+
+func use(x interface{}) {}
+
+// Formatting of if-statement headers.
+func _() {
+ if {}
+ if;{} // no semicolon printed
+ if expr{}
+ if;expr{} // no semicolon printed
+ if (expr){} // no parens printed
+ if;((expr)){} // no semicolon and parens printed
+ if x:=expr;{
+ use(x)}
+ if x:=expr; expr {use(x)}
+}
+
+
+// Formatting of switch-statement headers.
+func _() {
+ switch {}
+ switch;{} // no semicolon printed
+ switch expr {}
+ switch;expr{} // no semicolon printed
+ switch (expr) {} // no parens printed
+ switch;((expr)){} // no semicolon and parens printed
+ switch x := expr; { default:use(
+x)
+ }
+ switch x := expr; expr {default:use(x)}
+}
+
+
+// Formatting of switch statement bodies.
+func _() {
+ switch {
+ }
+
+ switch x := 0; x {
+ case 1:
+ use(x)
+ use(x) // followed by an empty line
+
+ case 2: // followed by an empty line
+
+ use(x) // followed by an empty line
+
+ case 3: // no empty lines
+ use(x)
+ use(x)
+ }
+
+ switch x {
+ case 0:
+ use(x)
+ case 1: // this comment should have no effect on the previous or next line
+ use(x)
+ }
+
+ switch x := 0; x {
+ case 1:
+ x = 0
+ // this comment should be indented
+ case 2:
+ x = 0
+ // this comment should not be indented, it is aligned with the next case
+ case 3:
+ x = 0
+ /* indented comment
+ aligned
+ aligned
+ */
+ // bla
+ /* and more */
+ case 4:
+ x = 0
+ /* not indented comment
+ aligned
+ aligned
+ */
+ // bla
+ /* and more */
+ case 5:
+ }
+}
+
+
+// Formatting of for-statement headers.
+func _() {
+ for{}
+ for expr {}
+ for (expr) {} // no parens printed
+ for;;{} // no semicolons printed
+ for x :=expr;; {use( x)}
+ for; expr;{} // no semicolons printed
+ for; ((expr));{} // no semicolons and parens printed
+ for; ; expr = false {}
+ for x :=expr; expr; {use(x)}
+ for x := expr;; expr=false {use(x)}
+ for;expr;expr =false {
+ }
+ for x := expr;expr;expr = false { use(x) }
+ for x := range []int{} { use(x) }
+ for x := range (([]int{})) { use(x) } // no parens printed
+}
+
+
+// Don't remove mandatory parentheses around composite literals in control clauses.
+func _() {
+ // strip parentheses - no composite literals or composite literals don't start with a type name
+ if (x) {}
+ if (((x))) {}
+ if ([]T{}) {}
+ if (([]T{})) {}
+ if ; (((([]T{})))) {}
+
+ for (x) {}
+ for (((x))) {}
+ for ([]T{}) {}
+ for (([]T{})) {}
+ for ; (((([]T{})))) ; {}
+
+ switch (x) {}
+ switch (((x))) {}
+ switch ([]T{}) {}
+ switch ; (((([]T{})))) {}
+
+ for _ = range ((([]T{T{42}}))) {}
+
+ // leave parentheses - composite literals start with a type name
+ if (T{}) {}
+ if ((T{})) {}
+ if ; ((((T{})))) {}
+
+ for (T{}) {}
+ for ((T{})) {}
+ for ; ((((T{})))) ; {}
+
+ switch (T{}) {}
+ switch ; ((((T{})))) {}
+
+ for _ = range (((T1{T{42}}))) {}
+
+ if x == (T{42}[0]) {}
+ if (x == T{42}[0]) {}
+ if (x == (T{42}[0])) {}
+ if (x == (((T{42}[0])))) {}
+ if (((x == (T{42}[0])))) {}
+ if x == a + b*(T{42}[0]) {}
+ if (x == a + b*T{42}[0]) {}
+ if (x == a + b*(T{42}[0])) {}
+ if (x == a + ((b * (T{42}[0])))) {}
+ if (((x == a + b * (T{42}[0])))) {}
+ if (((a + b * (T{42}[0])) == x)) {}
+ if (((a + b * (T{42}[0])))) == x {}
+
+ if (struct{x bool}{false}.x) {}
+ if (struct{x bool}{false}.x) == false {}
+ if (struct{x bool}{false}.x == false) {}
+}
+
+
+// Extra empty lines inside functions. Do respect source code line
+// breaks between statement boundaries but print at most one empty
+// line at a time.
+func _() {
+
+ const _ = 0
+
+ const _ = 1
+ type _ int
+ type _ float
+
+ var _ = 0
+ var x = 1
+
+ // Each use(x) call below should have at most one empty line before and after.
+ // Known bug: The first use call may have more than one empty line before
+ // (see go/printer/nodes.go, func linebreak).
+
+
+
+ use(x)
+
+ if x < x {
+
+ use(x)
+
+ } else {
+
+ use(x)
+
+ }
+}
+
+
+// Formatting around labels.
+func _() {
+ L:
+}
+
+
+func _() {
+ // this comment should be indented
+ L: ; // no semicolon needed
+}
+
+
+func _() {
+ switch 0 {
+ case 0:
+ L0: ; // semicolon required
+ case 1:
+ L1: ; // semicolon required
+ default:
+ L2: ; // no semicolon needed
+ }
+}
+
+
+func _() {
+ f()
+L1:
+ f()
+L2:
+ ;
+L3:
+}
+
+
+func _() {
+ // this comment should be indented
+ L:
+}
+
+
+func _() {
+ L: _ = 0
+}
+
+
+func _() {
+ // this comment should be indented
+ L: _ = 0
+}
+
+
+func _() {
+ for {
+ L1: _ = 0
+ L2:
+ _ = 0
+ }
+}
+
+
+func _() {
+ // this comment should be indented
+ for {
+ L1: _ = 0
+ L2:
+ _ = 0
+ }
+}
+
+
+func _() {
+ if {
+ _ = 0
+ }
+ _ = 0 // the indentation here should not be affected by the long label name
+AnOverlongLabel:
+ _ = 0
+
+ if {
+ _ = 0
+ }
+ _ = 0
+
+L: _ = 0
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L: // A comment on the same line as the label, followed by a single empty line.
+ // Known bug: There may be more than one empty line before MoreCode()
+ // (see go/printer/nodes.go, func linebreak).
+
+
+
+
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+
+
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto AVeryLongLabelThatShouldNotAffectFormatting
+ }
+AVeryLongLabelThatShouldNotAffectFormatting:
+ // There should be a single empty line after this comment.
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
diff --git a/libgo/go/go/scanner/errors.go b/libgo/go/go/scanner/errors.go
new file mode 100644
index 000000000..47e35a710
--- /dev/null
+++ b/libgo/go/go/scanner/errors.go
@@ -0,0 +1,186 @@
+// 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 scanner
+
+import (
+ "container/vector"
+ "fmt"
+ "go/token"
+ "io"
+ "os"
+ "sort"
+)
+
+
+// An implementation of an ErrorHandler may be provided to the Scanner.
+// If a syntax error is encountered and a handler was installed, Error
+// is called with a position and an error message. The position points
+// to the beginning of the offending token.
+//
+type ErrorHandler interface {
+ Error(pos token.Position, msg string)
+}
+
+
+// ErrorVector implements the ErrorHandler interface. It maintains a list
+// of errors which can be retrieved with GetErrorList and GetError. The
+// zero value for an ErrorVector is an empty ErrorVector ready to use.
+//
+// A common usage pattern is to embed an ErrorVector alongside a
+// scanner in a data structure that uses the scanner. By passing a
+// reference to an ErrorVector to the scanner's Init call, default
+// error handling is obtained.
+//
+type ErrorVector struct {
+ errors vector.Vector
+}
+
+
+// Reset resets an ErrorVector to no errors.
+func (h *ErrorVector) Reset() { h.errors.Resize(0, 0) }
+
+
+// ErrorCount returns the number of errors collected.
+func (h *ErrorVector) ErrorCount() int { return h.errors.Len() }
+
+
+// Within ErrorVector, an error is represented by an Error node. The
+// position Pos, if valid, points to the beginning of the offending
+// token, and the error condition is described by Msg.
+//
+type Error struct {
+ Pos token.Position
+ Msg string
+}
+
+
+func (e *Error) String() string {
+ if e.Pos.Filename != "" || e.Pos.IsValid() {
+ // don't print "<unknown position>"
+ // TODO(gri) reconsider the semantics of Position.IsValid
+ return e.Pos.String() + ": " + e.Msg
+ }
+ return e.Msg
+}
+
+
+// An ErrorList is a (possibly sorted) list of Errors.
+type ErrorList []*Error
+
+
+// ErrorList implements the sort Interface.
+func (p ErrorList) Len() int { return len(p) }
+func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
+
+func (p ErrorList) Less(i, j int) bool {
+ e := &p[i].Pos
+ f := &p[j].Pos
+ // Note that it is not sufficient to simply compare file offsets because
+ // the offsets do not reflect modified line information (through //line
+ // comments).
+ if e.Filename < f.Filename {
+ return true
+ }
+ if e.Filename == f.Filename {
+ if e.Line < f.Line {
+ return true
+ }
+ if e.Line == f.Line {
+ return e.Column < f.Column
+ }
+ }
+ return false
+}
+
+
+func (p ErrorList) String() string {
+ switch len(p) {
+ case 0:
+ return "unspecified error"
+ case 1:
+ return p[0].String()
+ }
+ return fmt.Sprintf("%s (and %d more errors)", p[0].String(), len(p)-1)
+}
+
+
+// These constants control the construction of the ErrorList
+// returned by GetErrors.
+//
+const (
+ Raw = iota // leave error list unchanged
+ Sorted // sort error list by file, line, and column number
+ NoMultiples // sort error list and leave only the first error per line
+)
+
+
+// GetErrorList returns the list of errors collected by an ErrorVector.
+// The construction of the ErrorList returned is controlled by the mode
+// parameter. If there are no errors, the result is nil.
+//
+func (h *ErrorVector) GetErrorList(mode int) ErrorList {
+ if h.errors.Len() == 0 {
+ return nil
+ }
+
+ list := make(ErrorList, h.errors.Len())
+ for i := 0; i < h.errors.Len(); i++ {
+ list[i] = h.errors.At(i).(*Error)
+ }
+
+ if mode >= Sorted {
+ sort.Sort(list)
+ }
+
+ if mode >= NoMultiples {
+ var last token.Position // initial last.Line is != any legal error line
+ i := 0
+ for _, e := range list {
+ if e.Pos.Filename != last.Filename || e.Pos.Line != last.Line {
+ last = e.Pos
+ list[i] = e
+ i++
+ }
+ }
+ list = list[0:i]
+ }
+
+ return list
+}
+
+
+// GetError is like GetErrorList, but it returns an os.Error instead
+// so that a nil result can be assigned to an os.Error variable and
+// remains nil.
+//
+func (h *ErrorVector) GetError(mode int) os.Error {
+ if h.errors.Len() == 0 {
+ return nil
+ }
+
+ return h.GetErrorList(mode)
+}
+
+
+// ErrorVector implements the ErrorHandler interface.
+func (h *ErrorVector) Error(pos token.Position, msg string) {
+ h.errors.Push(&Error{pos, msg})
+}
+
+
+// PrintError is a utility function that prints a list of errors to w,
+// one error per line, if the err parameter is an ErrorList. Otherwise
+// it prints the err string.
+//
+func PrintError(w io.Writer, err os.Error) {
+ if list, ok := err.(ErrorList); ok {
+ for _, e := range list {
+ fmt.Fprintf(w, "%s\n", e)
+ }
+ } else {
+ fmt.Fprintf(w, "%s\n", err)
+ }
+}
diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go
new file mode 100644
index 000000000..8c3205230
--- /dev/null
+++ b/libgo/go/go/scanner/scanner.go
@@ -0,0 +1,714 @@
+// 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 scanner for Go source text. Takes a []byte as source which can
+// then be tokenized through repeated calls to the Scan function.
+// Typical use:
+//
+// var s Scanner
+// fset := token.NewFileSet() // position information is relative to fset
+// s.Init(fset, filename, src, nil /* no error handler */, 0)
+// for {
+// pos, tok, lit := s.Scan()
+// if tok == token.EOF {
+// break
+// }
+// // do something here with pos, tok, and lit
+// }
+//
+package scanner
+
+import (
+ "bytes"
+ "go/token"
+ "path"
+ "strconv"
+ "unicode"
+ "utf8"
+)
+
+
+// A Scanner holds the scanner's internal state while processing
+// a given text. It can be allocated as part of another data
+// structure but must be initialized via Init before use.
+//
+type Scanner struct {
+ // immutable state
+ file *token.File // source file handle
+ dir string // directory portion of file.Name()
+ src []byte // source
+ err ErrorHandler // error reporting; or nil
+ mode uint // scanning mode
+
+ // scanning state
+ ch int // current character
+ offset int // character offset
+ rdOffset int // reading offset (position after current character)
+ lineOffset int // current line offset
+ insertSemi bool // insert a semicolon before next newline
+
+ // public state - ok to modify
+ ErrorCount int // number of errors encountered
+}
+
+
+// Read the next Unicode char into S.ch.
+// S.ch < 0 means end-of-file.
+//
+func (S *Scanner) next() {
+ if S.rdOffset < len(S.src) {
+ S.offset = S.rdOffset
+ if S.ch == '\n' {
+ S.lineOffset = S.offset
+ S.file.AddLine(S.offset)
+ }
+ r, w := int(S.src[S.rdOffset]), 1
+ switch {
+ case r == 0:
+ S.error(S.offset, "illegal character NUL")
+ case r >= 0x80:
+ // not ASCII
+ r, w = utf8.DecodeRune(S.src[S.rdOffset:])
+ if r == utf8.RuneError && w == 1 {
+ S.error(S.offset, "illegal UTF-8 encoding")
+ }
+ }
+ S.rdOffset += w
+ S.ch = r
+ } else {
+ S.offset = len(S.src)
+ if S.ch == '\n' {
+ S.lineOffset = S.offset
+ S.file.AddLine(S.offset)
+ }
+ S.ch = -1 // eof
+ }
+}
+
+
+// The mode parameter to the Init function is a set of flags (or 0).
+// They control scanner behavior.
+//
+const (
+ ScanComments = 1 << iota // return comments as COMMENT tokens
+ AllowIllegalChars // do not report an error for illegal chars
+ InsertSemis // automatically insert semicolons
+)
+
+// Init prepares the scanner S to tokenize the text src by setting the
+// scanner at the beginning of src. The scanner uses the file set file
+// for position information and it adds line information for each line.
+// It is ok to re-use the same file when re-scanning the same file as
+// line information which is already present is ignored. Init causes a
+// panic if the file size does not match the src size.
+//
+// Calls to Scan will use the error handler err if they encounter a
+// syntax error and err is not nil. Also, for each error encountered,
+// the Scanner field ErrorCount is incremented by one. The mode parameter
+// determines how comments, illegal characters, and semicolons are handled.
+//
+// Note that Init may call err if there is an error in the first character
+// of the file.
+//
+func (S *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode uint) {
+ // Explicitly initialize all fields since a scanner may be reused.
+ if file.Size() != len(src) {
+ panic("file size does not match src len")
+ }
+ S.file = file
+ S.dir, _ = path.Split(file.Name())
+ S.src = src
+ S.err = err
+ S.mode = mode
+
+ S.ch = ' '
+ S.offset = 0
+ S.rdOffset = 0
+ S.lineOffset = 0
+ S.insertSemi = false
+ S.ErrorCount = 0
+
+ S.next()
+}
+
+
+func charString(ch int) string {
+ var s string
+ switch ch {
+ case -1:
+ return `EOF`
+ case '\a':
+ s = `\a`
+ case '\b':
+ s = `\b`
+ case '\f':
+ s = `\f`
+ case '\n':
+ s = `\n`
+ case '\r':
+ s = `\r`
+ case '\t':
+ s = `\t`
+ case '\v':
+ s = `\v`
+ case '\\':
+ s = `\\`
+ case '\'':
+ s = `\'`
+ default:
+ s = string(ch)
+ }
+ return "'" + s + "' (U+" + strconv.Itob(ch, 16) + ")"
+}
+
+
+func (S *Scanner) error(offs int, msg string) {
+ if S.err != nil {
+ S.err.Error(S.file.Position(S.file.Pos(offs)), msg)
+ }
+ S.ErrorCount++
+}
+
+
+var prefix = []byte("//line ")
+
+func (S *Scanner) interpretLineComment(text []byte) {
+ if bytes.HasPrefix(text, prefix) {
+ // get filename and line number, if any
+ if i := bytes.Index(text, []byte{':'}); i > 0 {
+ if line, err := strconv.Atoi(string(text[i+1:])); err == nil && line > 0 {
+ // valid //line filename:line comment;
+ filename := path.Clean(string(text[len(prefix):i]))
+ if filename[0] != '/' {
+ // make filename relative to current directory
+ filename = path.Join(S.dir, filename)
+ }
+ // update scanner position
+ S.file.AddLineInfo(S.lineOffset, filename, line-1) // -1 since comment applies to next line
+ }
+ }
+ }
+}
+
+
+func (S *Scanner) scanComment() {
+ // initial '/' already consumed; S.ch == '/' || S.ch == '*'
+ offs := S.offset - 1 // position of initial '/'
+
+ if S.ch == '/' {
+ //-style comment
+ S.next()
+ for S.ch != '\n' && S.ch >= 0 {
+ S.next()
+ }
+ if offs == S.lineOffset {
+ // comment starts at the beginning of the current line
+ S.interpretLineComment(S.src[offs:S.offset])
+ }
+ return
+ }
+
+ /*-style comment */
+ S.next()
+ for S.ch >= 0 {
+ ch := S.ch
+ S.next()
+ if ch == '*' && S.ch == '/' {
+ S.next()
+ return
+ }
+ }
+
+ S.error(offs, "comment not terminated")
+}
+
+
+func (S *Scanner) findLineEnd() bool {
+ // initial '/' already consumed
+
+ defer func(offs int) {
+ // reset scanner state to where it was upon calling findLineEnd
+ S.ch = '/'
+ S.offset = offs
+ S.rdOffset = offs + 1
+ S.next() // consume initial '/' again
+ }(S.offset - 1)
+
+ // read ahead until a newline, EOF, or non-comment token is found
+ for S.ch == '/' || S.ch == '*' {
+ if S.ch == '/' {
+ //-style comment always contains a newline
+ return true
+ }
+ /*-style comment: look for newline */
+ S.next()
+ for S.ch >= 0 {
+ ch := S.ch
+ if ch == '\n' {
+ return true
+ }
+ S.next()
+ if ch == '*' && S.ch == '/' {
+ S.next()
+ break
+ }
+ }
+ S.skipWhitespace() // S.insertSemi is set
+ if S.ch < 0 || S.ch == '\n' {
+ return true
+ }
+ if S.ch != '/' {
+ // non-comment token
+ return false
+ }
+ S.next() // consume '/'
+ }
+
+ return false
+}
+
+
+func isLetter(ch int) bool {
+ return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
+}
+
+
+func isDigit(ch int) bool {
+ return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
+}
+
+
+func (S *Scanner) scanIdentifier() token.Token {
+ offs := S.offset
+ for isLetter(S.ch) || isDigit(S.ch) {
+ S.next()
+ }
+ return token.Lookup(S.src[offs:S.offset])
+}
+
+
+func digitVal(ch int) int {
+ switch {
+ case '0' <= ch && ch <= '9':
+ return ch - '0'
+ case 'a' <= ch && ch <= 'f':
+ return ch - 'a' + 10
+ case 'A' <= ch && ch <= 'F':
+ return ch - 'A' + 10
+ }
+ return 16 // larger than any legal digit val
+}
+
+
+func (S *Scanner) scanMantissa(base int) {
+ for digitVal(S.ch) < base {
+ S.next()
+ }
+}
+
+
+func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token {
+ // digitVal(S.ch) < 10
+ tok := token.INT
+
+ if seenDecimalPoint {
+ tok = token.FLOAT
+ S.scanMantissa(10)
+ goto exponent
+ }
+
+ if S.ch == '0' {
+ // int or float
+ offs := S.offset
+ S.next()
+ if S.ch == 'x' || S.ch == 'X' {
+ // hexadecimal int
+ S.next()
+ S.scanMantissa(16)
+ } else {
+ // octal int or float
+ seenDecimalDigit := false
+ S.scanMantissa(8)
+ if S.ch == '8' || S.ch == '9' {
+ // illegal octal int or float
+ seenDecimalDigit = true
+ S.scanMantissa(10)
+ }
+ if S.ch == '.' || S.ch == 'e' || S.ch == 'E' || S.ch == 'i' {
+ goto fraction
+ }
+ // octal int
+ if seenDecimalDigit {
+ S.error(offs, "illegal octal number")
+ }
+ }
+ goto exit
+ }
+
+ // decimal int or float
+ S.scanMantissa(10)
+
+fraction:
+ if S.ch == '.' {
+ tok = token.FLOAT
+ S.next()
+ S.scanMantissa(10)
+ }
+
+exponent:
+ if S.ch == 'e' || S.ch == 'E' {
+ tok = token.FLOAT
+ S.next()
+ if S.ch == '-' || S.ch == '+' {
+ S.next()
+ }
+ S.scanMantissa(10)
+ }
+
+ if S.ch == 'i' {
+ tok = token.IMAG
+ S.next()
+ }
+
+exit:
+ return tok
+}
+
+
+func (S *Scanner) scanEscape(quote int) {
+ offs := S.offset
+
+ var i, base, max uint32
+ switch S.ch {
+ case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
+ S.next()
+ return
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ i, base, max = 3, 8, 255
+ case 'x':
+ S.next()
+ i, base, max = 2, 16, 255
+ case 'u':
+ S.next()
+ i, base, max = 4, 16, unicode.MaxRune
+ case 'U':
+ S.next()
+ i, base, max = 8, 16, unicode.MaxRune
+ default:
+ S.next() // always make progress
+ S.error(offs, "unknown escape sequence")
+ return
+ }
+
+ var x uint32
+ for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
+ d := uint32(digitVal(S.ch))
+ if d >= base {
+ S.error(S.offset, "illegal character in escape sequence")
+ break
+ }
+ x = x*base + d
+ S.next()
+ }
+ // in case of an error, consume remaining chars
+ for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
+ S.next()
+ }
+ if x > max || 0xd800 <= x && x < 0xe000 {
+ S.error(offs, "escape sequence is invalid Unicode code point")
+ }
+}
+
+
+func (S *Scanner) scanChar() {
+ // '\'' opening already consumed
+ offs := S.offset - 1
+
+ n := 0
+ for S.ch != '\'' {
+ ch := S.ch
+ n++
+ S.next()
+ if ch == '\n' || ch < 0 {
+ S.error(offs, "character literal not terminated")
+ n = 1
+ break
+ }
+ if ch == '\\' {
+ S.scanEscape('\'')
+ }
+ }
+
+ S.next()
+
+ if n != 1 {
+ S.error(offs, "illegal character literal")
+ }
+}
+
+
+func (S *Scanner) scanString() {
+ // '"' opening already consumed
+ offs := S.offset - 1
+
+ for S.ch != '"' {
+ ch := S.ch
+ S.next()
+ if ch == '\n' || ch < 0 {
+ S.error(offs, "string not terminated")
+ break
+ }
+ if ch == '\\' {
+ S.scanEscape('"')
+ }
+ }
+
+ S.next()
+}
+
+
+func (S *Scanner) scanRawString() {
+ // '`' opening already consumed
+ offs := S.offset - 1
+
+ for S.ch != '`' {
+ ch := S.ch
+ S.next()
+ if ch < 0 {
+ S.error(offs, "string not terminated")
+ break
+ }
+ }
+
+ S.next()
+}
+
+
+func (S *Scanner) skipWhitespace() {
+ for S.ch == ' ' || S.ch == '\t' || S.ch == '\n' && !S.insertSemi || S.ch == '\r' {
+ S.next()
+ }
+}
+
+
+// Helper functions for scanning multi-byte tokens such as >> += >>= .
+// Different routines recognize different length tok_i based on matches
+// of ch_i. If a token ends in '=', the result is tok1 or tok3
+// respectively. Otherwise, the result is tok0 if there was no other
+// matching character, or tok2 if the matching character was ch2.
+
+func (S *Scanner) switch2(tok0, tok1 token.Token) token.Token {
+ if S.ch == '=' {
+ S.next()
+ return tok1
+ }
+ return tok0
+}
+
+
+func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) token.Token {
+ if S.ch == '=' {
+ S.next()
+ return tok1
+ }
+ if S.ch == ch2 {
+ S.next()
+ return tok2
+ }
+ return tok0
+}
+
+
+func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Token) token.Token {
+ if S.ch == '=' {
+ S.next()
+ return tok1
+ }
+ if S.ch == ch2 {
+ S.next()
+ if S.ch == '=' {
+ S.next()
+ return tok3
+ }
+ return tok2
+ }
+ return tok0
+}
+
+
+var newline = []byte{'\n'}
+
+// Scan scans the next token and returns the token position pos,
+// the token tok, and the literal text lit corresponding to the
+// token. The source end is indicated by token.EOF.
+//
+// If the returned token is token.SEMICOLON, the corresponding
+// literal value is ";" if the semicolon was present in the source,
+// and "\n" if the semicolon was inserted because of a newline or
+// at EOF.
+//
+// For more tolerant parsing, Scan will return a valid token if
+// possible even if a syntax error was encountered. Thus, even
+// if the resulting token sequence contains no illegal tokens,
+// a client may not assume that no error occurred. Instead it
+// must check the scanner's ErrorCount or the number of calls
+// of the error handler, if there was one installed.
+//
+// Scan adds line information to the file added to the file
+// set with Init. Token positions are relative to that file
+// and thus relative to the file set.
+//
+func (S *Scanner) Scan() (token.Pos, token.Token, []byte) {
+scanAgain:
+ S.skipWhitespace()
+
+ // current token start
+ insertSemi := false
+ offs := S.offset
+ tok := token.ILLEGAL
+
+ // determine token value
+ switch ch := S.ch; {
+ case isLetter(ch):
+ tok = S.scanIdentifier()
+ switch tok {
+ case token.IDENT, token.BREAK, token.CONTINUE, token.FALLTHROUGH, token.RETURN:
+ insertSemi = true
+ }
+ case digitVal(ch) < 10:
+ insertSemi = true
+ tok = S.scanNumber(false)
+ default:
+ S.next() // always make progress
+ switch ch {
+ case -1:
+ if S.insertSemi {
+ S.insertSemi = false // EOF consumed
+ return S.file.Pos(offs), token.SEMICOLON, newline
+ }
+ tok = token.EOF
+ case '\n':
+ // we only reach here if S.insertSemi was
+ // set in the first place and exited early
+ // from S.skipWhitespace()
+ S.insertSemi = false // newline consumed
+ return S.file.Pos(offs), token.SEMICOLON, newline
+ case '"':
+ insertSemi = true
+ tok = token.STRING
+ S.scanString()
+ case '\'':
+ insertSemi = true
+ tok = token.CHAR
+ S.scanChar()
+ case '`':
+ insertSemi = true
+ tok = token.STRING
+ S.scanRawString()
+ case ':':
+ tok = S.switch2(token.COLON, token.DEFINE)
+ case '.':
+ if digitVal(S.ch) < 10 {
+ insertSemi = true
+ tok = S.scanNumber(true)
+ } else if S.ch == '.' {
+ S.next()
+ if S.ch == '.' {
+ S.next()
+ tok = token.ELLIPSIS
+ }
+ } else {
+ tok = token.PERIOD
+ }
+ case ',':
+ tok = token.COMMA
+ case ';':
+ tok = token.SEMICOLON
+ case '(':
+ tok = token.LPAREN
+ case ')':
+ insertSemi = true
+ tok = token.RPAREN
+ case '[':
+ tok = token.LBRACK
+ case ']':
+ insertSemi = true
+ tok = token.RBRACK
+ case '{':
+ tok = token.LBRACE
+ case '}':
+ insertSemi = true
+ tok = token.RBRACE
+ case '+':
+ tok = S.switch3(token.ADD, token.ADD_ASSIGN, '+', token.INC)
+ if tok == token.INC {
+ insertSemi = true
+ }
+ case '-':
+ tok = S.switch3(token.SUB, token.SUB_ASSIGN, '-', token.DEC)
+ if tok == token.DEC {
+ insertSemi = true
+ }
+ case '*':
+ tok = S.switch2(token.MUL, token.MUL_ASSIGN)
+ case '/':
+ if S.ch == '/' || S.ch == '*' {
+ // comment
+ if S.insertSemi && S.findLineEnd() {
+ // reset position to the beginning of the comment
+ S.ch = '/'
+ S.offset = offs
+ S.rdOffset = offs + 1
+ S.insertSemi = false // newline consumed
+ return S.file.Pos(offs), token.SEMICOLON, newline
+ }
+ S.scanComment()
+ if S.mode&ScanComments == 0 {
+ // skip comment
+ S.insertSemi = false // newline consumed
+ goto scanAgain
+ }
+ tok = token.COMMENT
+ } else {
+ tok = S.switch2(token.QUO, token.QUO_ASSIGN)
+ }
+ case '%':
+ tok = S.switch2(token.REM, token.REM_ASSIGN)
+ case '^':
+ tok = S.switch2(token.XOR, token.XOR_ASSIGN)
+ case '<':
+ if S.ch == '-' {
+ S.next()
+ tok = token.ARROW
+ } else {
+ tok = S.switch4(token.LSS, token.LEQ, '<', token.SHL, token.SHL_ASSIGN)
+ }
+ case '>':
+ tok = S.switch4(token.GTR, token.GEQ, '>', token.SHR, token.SHR_ASSIGN)
+ case '=':
+ tok = S.switch2(token.ASSIGN, token.EQL)
+ case '!':
+ tok = S.switch2(token.NOT, token.NEQ)
+ case '&':
+ if S.ch == '^' {
+ S.next()
+ tok = S.switch2(token.AND_NOT, token.AND_NOT_ASSIGN)
+ } else {
+ tok = S.switch3(token.AND, token.AND_ASSIGN, '&', token.LAND)
+ }
+ case '|':
+ tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
+ default:
+ if S.mode&AllowIllegalChars == 0 {
+ S.error(offs, "illegal character "+charString(ch))
+ }
+ insertSemi = S.insertSemi // preserve insertSemi info
+ }
+ }
+
+ if S.mode&InsertSemis != 0 {
+ S.insertSemi = insertSemi
+ }
+ return S.file.Pos(offs), tok, S.src[offs:S.offset]
+}
diff --git a/libgo/go/go/scanner/scanner_test.go b/libgo/go/go/scanner/scanner_test.go
new file mode 100644
index 000000000..1c3b6728c
--- /dev/null
+++ b/libgo/go/go/scanner/scanner_test.go
@@ -0,0 +1,672 @@
+// 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 scanner
+
+import (
+ "go/token"
+ "os"
+ "testing"
+)
+
+
+var fset = token.NewFileSet()
+
+
+const /* class */ (
+ special = iota
+ literal
+ operator
+ keyword
+)
+
+
+func tokenclass(tok token.Token) int {
+ switch {
+ case tok.IsLiteral():
+ return literal
+ case tok.IsOperator():
+ return operator
+ case tok.IsKeyword():
+ return keyword
+ }
+ return special
+}
+
+
+type elt struct {
+ tok token.Token
+ lit string
+ class int
+}
+
+
+var tokens = [...]elt{
+ // Special tokens
+ {token.COMMENT, "/* a comment */", special},
+ {token.COMMENT, "// a comment \n", special},
+
+ // Identifiers and basic type literals
+ {token.IDENT, "foobar", literal},
+ {token.IDENT, "a۰۱۸", literal},
+ {token.IDENT, "foo६४", literal},
+ {token.IDENT, "bar9876", literal},
+ {token.INT, "0", literal},
+ {token.INT, "1", literal},
+ {token.INT, "123456789012345678890", literal},
+ {token.INT, "01234567", literal},
+ {token.INT, "0xcafebabe", literal},
+ {token.FLOAT, "0.", literal},
+ {token.FLOAT, ".0", literal},
+ {token.FLOAT, "3.14159265", literal},
+ {token.FLOAT, "1e0", literal},
+ {token.FLOAT, "1e+100", literal},
+ {token.FLOAT, "1e-100", literal},
+ {token.FLOAT, "2.71828e-1000", literal},
+ {token.IMAG, "0i", literal},
+ {token.IMAG, "1i", literal},
+ {token.IMAG, "012345678901234567889i", literal},
+ {token.IMAG, "123456789012345678890i", literal},
+ {token.IMAG, "0.i", literal},
+ {token.IMAG, ".0i", literal},
+ {token.IMAG, "3.14159265i", literal},
+ {token.IMAG, "1e0i", literal},
+ {token.IMAG, "1e+100i", literal},
+ {token.IMAG, "1e-100i", literal},
+ {token.IMAG, "2.71828e-1000i", literal},
+ {token.CHAR, "'a'", literal},
+ {token.CHAR, "'\\000'", literal},
+ {token.CHAR, "'\\xFF'", literal},
+ {token.CHAR, "'\\uff16'", literal},
+ {token.CHAR, "'\\U0000ff16'", literal},
+ {token.STRING, "`foobar`", literal},
+ {token.STRING, "`" + `foo
+ bar` +
+ "`",
+ literal,
+ },
+
+ // Operators and delimitors
+ {token.ADD, "+", operator},
+ {token.SUB, "-", operator},
+ {token.MUL, "*", operator},
+ {token.QUO, "/", operator},
+ {token.REM, "%", operator},
+
+ {token.AND, "&", operator},
+ {token.OR, "|", operator},
+ {token.XOR, "^", operator},
+ {token.SHL, "<<", operator},
+ {token.SHR, ">>", operator},
+ {token.AND_NOT, "&^", operator},
+
+ {token.ADD_ASSIGN, "+=", operator},
+ {token.SUB_ASSIGN, "-=", operator},
+ {token.MUL_ASSIGN, "*=", operator},
+ {token.QUO_ASSIGN, "/=", operator},
+ {token.REM_ASSIGN, "%=", operator},
+
+ {token.AND_ASSIGN, "&=", operator},
+ {token.OR_ASSIGN, "|=", operator},
+ {token.XOR_ASSIGN, "^=", operator},
+ {token.SHL_ASSIGN, "<<=", operator},
+ {token.SHR_ASSIGN, ">>=", operator},
+ {token.AND_NOT_ASSIGN, "&^=", operator},
+
+ {token.LAND, "&&", operator},
+ {token.LOR, "||", operator},
+ {token.ARROW, "<-", operator},
+ {token.INC, "++", operator},
+ {token.DEC, "--", operator},
+
+ {token.EQL, "==", operator},
+ {token.LSS, "<", operator},
+ {token.GTR, ">", operator},
+ {token.ASSIGN, "=", operator},
+ {token.NOT, "!", operator},
+
+ {token.NEQ, "!=", operator},
+ {token.LEQ, "<=", operator},
+ {token.GEQ, ">=", operator},
+ {token.DEFINE, ":=", operator},
+ {token.ELLIPSIS, "...", operator},
+
+ {token.LPAREN, "(", operator},
+ {token.LBRACK, "[", operator},
+ {token.LBRACE, "{", operator},
+ {token.COMMA, ",", operator},
+ {token.PERIOD, ".", operator},
+
+ {token.RPAREN, ")", operator},
+ {token.RBRACK, "]", operator},
+ {token.RBRACE, "}", operator},
+ {token.SEMICOLON, ";", operator},
+ {token.COLON, ":", operator},
+
+ // Keywords
+ {token.BREAK, "break", keyword},
+ {token.CASE, "case", keyword},
+ {token.CHAN, "chan", keyword},
+ {token.CONST, "const", keyword},
+ {token.CONTINUE, "continue", keyword},
+
+ {token.DEFAULT, "default", keyword},
+ {token.DEFER, "defer", keyword},
+ {token.ELSE, "else", keyword},
+ {token.FALLTHROUGH, "fallthrough", keyword},
+ {token.FOR, "for", keyword},
+
+ {token.FUNC, "func", keyword},
+ {token.GO, "go", keyword},
+ {token.GOTO, "goto", keyword},
+ {token.IF, "if", keyword},
+ {token.IMPORT, "import", keyword},
+
+ {token.INTERFACE, "interface", keyword},
+ {token.MAP, "map", keyword},
+ {token.PACKAGE, "package", keyword},
+ {token.RANGE, "range", keyword},
+ {token.RETURN, "return", keyword},
+
+ {token.SELECT, "select", keyword},
+ {token.STRUCT, "struct", keyword},
+ {token.SWITCH, "switch", keyword},
+ {token.TYPE, "type", keyword},
+ {token.VAR, "var", keyword},
+}
+
+
+const whitespace = " \t \n\n\n" // to separate tokens
+
+type testErrorHandler struct {
+ t *testing.T
+}
+
+func (h *testErrorHandler) Error(pos token.Position, msg string) {
+ h.t.Errorf("Error() called (msg = %s)", msg)
+}
+
+
+func newlineCount(s string) int {
+ n := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == '\n' {
+ n++
+ }
+ }
+ return n
+}
+
+
+func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) {
+ pos := fset.Position(p)
+ if pos.Filename != expected.Filename {
+ t.Errorf("bad filename for %q: got %s, expected %s", lit, pos.Filename, expected.Filename)
+ }
+ if pos.Offset != expected.Offset {
+ t.Errorf("bad position for %q: got %d, expected %d", lit, pos.Offset, expected.Offset)
+ }
+ if pos.Line != expected.Line {
+ t.Errorf("bad line for %q: got %d, expected %d", lit, pos.Line, expected.Line)
+ }
+ if pos.Column != expected.Column {
+ t.Errorf("bad column for %q: got %d, expected %d", lit, pos.Column, expected.Column)
+ }
+}
+
+
+// Verify that calling Scan() provides the correct results.
+func TestScan(t *testing.T) {
+ // make source
+ var src string
+ for _, e := range tokens {
+ src += e.lit + whitespace
+ }
+ src_linecount := newlineCount(src) + 1
+ whitespace_linecount := newlineCount(whitespace)
+
+ // verify scan
+ var s Scanner
+ s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), &testErrorHandler{t}, ScanComments)
+ index := 0
+ epos := token.Position{"", 0, 1, 1} // expected position
+ for {
+ pos, tok, litb := s.Scan()
+ e := elt{token.EOF, "", special}
+ if index < len(tokens) {
+ e = tokens[index]
+ }
+ lit := string(litb)
+ if tok == token.EOF {
+ lit = "<EOF>"
+ epos.Line = src_linecount
+ epos.Column = 1
+ }
+ checkPos(t, lit, pos, epos)
+ if tok != e.tok {
+ t.Errorf("bad token for %q: got %s, expected %s", lit, tok.String(), e.tok.String())
+ }
+ if e.tok.IsLiteral() && lit != e.lit {
+ t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, e.lit)
+ }
+ if tokenclass(tok) != e.class {
+ t.Errorf("bad class for %q: got %d, expected %d", lit, tokenclass(tok), e.class)
+ }
+ epos.Offset += len(lit) + len(whitespace)
+ epos.Line += newlineCount(lit) + whitespace_linecount
+ if tok == token.COMMENT && litb[1] == '/' {
+ // correct for unaccounted '/n' in //-style comment
+ epos.Offset++
+ epos.Line++
+ }
+ index++
+ if tok == token.EOF {
+ break
+ }
+ }
+ if s.ErrorCount != 0 {
+ t.Errorf("found %d errors", s.ErrorCount)
+ }
+}
+
+
+func checkSemi(t *testing.T, line string, mode uint) {
+ var S Scanner
+ file := fset.AddFile("TestSemis", fset.Base(), len(line))
+ S.Init(file, []byte(line), nil, mode)
+ pos, tok, lit := S.Scan()
+ for tok != token.EOF {
+ if tok == token.ILLEGAL {
+ // the illegal token literal indicates what
+ // kind of semicolon literal to expect
+ semiLit := "\n"
+ if lit[0] == '#' {
+ semiLit = ";"
+ }
+ // next token must be a semicolon
+ semiPos := file.Position(pos)
+ semiPos.Offset++
+ semiPos.Column++
+ pos, tok, lit = S.Scan()
+ if tok == token.SEMICOLON {
+ if string(lit) != semiLit {
+ t.Errorf(`bad literal for %q: got %q, expected %q`, line, lit, semiLit)
+ }
+ checkPos(t, line, pos, semiPos)
+ } else {
+ t.Errorf("bad token for %q: got %s, expected ;", line, tok.String())
+ }
+ } else if tok == token.SEMICOLON {
+ t.Errorf("bad token for %q: got ;, expected no ;", line)
+ }
+ pos, tok, lit = S.Scan()
+ }
+}
+
+
+var lines = []string{
+ // # indicates a semicolon present in the source
+ // $ indicates an automatically inserted semicolon
+ "",
+ "#;",
+ "foo$\n",
+ "123$\n",
+ "1.2$\n",
+ "'x'$\n",
+ `"x"` + "$\n",
+ "`x`$\n",
+
+ "+\n",
+ "-\n",
+ "*\n",
+ "/\n",
+ "%\n",
+
+ "&\n",
+ "|\n",
+ "^\n",
+ "<<\n",
+ ">>\n",
+ "&^\n",
+
+ "+=\n",
+ "-=\n",
+ "*=\n",
+ "/=\n",
+ "%=\n",
+
+ "&=\n",
+ "|=\n",
+ "^=\n",
+ "<<=\n",
+ ">>=\n",
+ "&^=\n",
+
+ "&&\n",
+ "||\n",
+ "<-\n",
+ "++$\n",
+ "--$\n",
+
+ "==\n",
+ "<\n",
+ ">\n",
+ "=\n",
+ "!\n",
+
+ "!=\n",
+ "<=\n",
+ ">=\n",
+ ":=\n",
+ "...\n",
+
+ "(\n",
+ "[\n",
+ "{\n",
+ ",\n",
+ ".\n",
+
+ ")$\n",
+ "]$\n",
+ "}$\n",
+ "#;\n",
+ ":\n",
+
+ "break$\n",
+ "case\n",
+ "chan\n",
+ "const\n",
+ "continue$\n",
+
+ "default\n",
+ "defer\n",
+ "else\n",
+ "fallthrough$\n",
+ "for\n",
+
+ "func\n",
+ "go\n",
+ "goto\n",
+ "if\n",
+ "import\n",
+
+ "interface\n",
+ "map\n",
+ "package\n",
+ "range\n",
+ "return$\n",
+
+ "select\n",
+ "struct\n",
+ "switch\n",
+ "type\n",
+ "var\n",
+
+ "foo$//comment\n",
+ "foo$//comment",
+ "foo$/*comment*/\n",
+ "foo$/*\n*/",
+ "foo$/*comment*/ \n",
+ "foo$/*\n*/ ",
+
+ "foo $// comment\n",
+ "foo $// comment",
+ "foo $/*comment*/\n",
+ "foo $/*\n*/",
+ "foo $/* */ /* \n */ bar$/**/\n",
+ "foo $/*0*/ /*1*/ /*2*/\n",
+
+ "foo $/*comment*/ \n",
+ "foo $/*0*/ /*1*/ /*2*/ \n",
+ "foo $/**/ /*-------------*/ /*----\n*/bar $/* \n*/baa$\n",
+ "foo $/* an EOF terminates a line */",
+ "foo $/* an EOF terminates a line */ /*",
+ "foo $/* an EOF terminates a line */ //",
+
+ "package main$\n\nfunc main() {\n\tif {\n\t\treturn /* */ }$\n}$\n",
+ "package main$",
+}
+
+
+func TestSemis(t *testing.T) {
+ for _, line := range lines {
+ checkSemi(t, line, AllowIllegalChars|InsertSemis)
+ checkSemi(t, line, AllowIllegalChars|InsertSemis|ScanComments)
+
+ // if the input ended in newlines, the input must tokenize the
+ // same with or without those newlines
+ for i := len(line) - 1; i >= 0 && line[i] == '\n'; i-- {
+ checkSemi(t, line[0:i], AllowIllegalChars|InsertSemis)
+ checkSemi(t, line[0:i], AllowIllegalChars|InsertSemis|ScanComments)
+ }
+ }
+}
+
+
+var segments = []struct {
+ srcline string // a line of source text
+ filename string // filename for current token
+ line int // line number for current token
+}{
+ // exactly one token per line since the test consumes one token per segment
+ {" line1", "dir/TestLineComments", 1},
+ {"\nline2", "dir/TestLineComments", 2},
+ {"\nline3 //line File1.go:100", "dir/TestLineComments", 3}, // bad line comment, ignored
+ {"\nline4", "dir/TestLineComments", 4},
+ {"\n//line File1.go:100\n line100", "dir/File1.go", 100},
+ {"\n//line File2.go:200\n line200", "dir/File2.go", 200},
+ {"\n//line :1\n line1", "dir", 1},
+ {"\n//line foo:42\n line42", "dir/foo", 42},
+ {"\n //line foo:42\n line44", "dir/foo", 44}, // bad line comment, ignored
+ {"\n//line foo 42\n line46", "dir/foo", 46}, // bad line comment, ignored
+ {"\n//line foo:42 extra text\n line48", "dir/foo", 48}, // bad line comment, ignored
+ {"\n//line /bar:42\n line42", "/bar", 42},
+ {"\n//line ./foo:42\n line42", "dir/foo", 42},
+ {"\n//line a/b/c/File1.go:100\n line100", "dir/a/b/c/File1.go", 100},
+}
+
+
+// Verify that comments of the form "//line filename:line" are interpreted correctly.
+func TestLineComments(t *testing.T) {
+ // make source
+ var src string
+ for _, e := range segments {
+ src += e.srcline
+ }
+
+ // verify scan
+ var S Scanner
+ file := fset.AddFile("dir/TestLineComments", fset.Base(), len(src))
+ S.Init(file, []byte(src), nil, 0)
+ for _, s := range segments {
+ p, _, lit := S.Scan()
+ pos := file.Position(p)
+ checkPos(t, string(lit), p, token.Position{s.filename, pos.Offset, s.line, pos.Column})
+ }
+
+ if S.ErrorCount != 0 {
+ t.Errorf("found %d errors", S.ErrorCount)
+ }
+}
+
+
+// Verify that initializing the same scanner more then once works correctly.
+func TestInit(t *testing.T) {
+ var s Scanner
+
+ // 1st init
+ src1 := "if true { }"
+ f1 := fset.AddFile("src1", fset.Base(), len(src1))
+ s.Init(f1, []byte(src1), nil, 0)
+ if f1.Size() != len(src1) {
+ t.Errorf("bad file size: got %d, expected %d", f1.Size(), len(src1))
+ }
+ s.Scan() // if
+ s.Scan() // true
+ _, tok, _ := s.Scan() // {
+ if tok != token.LBRACE {
+ t.Errorf("bad token: got %s, expected %s", tok.String(), token.LBRACE)
+ }
+
+ // 2nd init
+ src2 := "go true { ]"
+ f2 := fset.AddFile("src2", fset.Base(), len(src2))
+ s.Init(f2, []byte(src2), nil, 0)
+ if f2.Size() != len(src2) {
+ t.Errorf("bad file size: got %d, expected %d", f2.Size(), len(src2))
+ }
+ _, tok, _ = s.Scan() // go
+ if tok != token.GO {
+ t.Errorf("bad token: got %s, expected %s", tok.String(), token.GO)
+ }
+
+ if s.ErrorCount != 0 {
+ t.Errorf("found %d errors", s.ErrorCount)
+ }
+}
+
+
+func TestIllegalChars(t *testing.T) {
+ var s Scanner
+
+ const src = "*?*$*@*"
+ file := fset.AddFile("", fset.Base(), len(src))
+ s.Init(file, []byte(src), &testErrorHandler{t}, AllowIllegalChars)
+ for offs, ch := range src {
+ pos, tok, lit := s.Scan()
+ if poffs := file.Offset(pos); poffs != offs {
+ t.Errorf("bad position for %s: got %d, expected %d", string(lit), poffs, offs)
+ }
+ if tok == token.ILLEGAL && string(lit) != string(ch) {
+ t.Errorf("bad token: got %s, expected %s", string(lit), string(ch))
+ }
+ }
+
+ if s.ErrorCount != 0 {
+ t.Errorf("found %d errors", s.ErrorCount)
+ }
+}
+
+
+func TestStdErrorHander(t *testing.T) {
+ const src = "@\n" + // illegal character, cause an error
+ "@ @\n" + // two errors on the same line
+ "//line File2:20\n" +
+ "@\n" + // different file, but same line
+ "//line File2:1\n" +
+ "@ @\n" + // same file, decreasing line number
+ "//line File1:1\n" +
+ "@ @ @" // original file, line 1 again
+
+ v := new(ErrorVector)
+ var s Scanner
+ s.Init(fset.AddFile("File1", fset.Base(), len(src)), []byte(src), v, 0)
+ for {
+ if _, tok, _ := s.Scan(); tok == token.EOF {
+ break
+ }
+ }
+
+ list := v.GetErrorList(Raw)
+ if len(list) != 9 {
+ t.Errorf("found %d raw errors, expected 9", len(list))
+ PrintError(os.Stderr, list)
+ }
+
+ list = v.GetErrorList(Sorted)
+ if len(list) != 9 {
+ t.Errorf("found %d sorted errors, expected 9", len(list))
+ PrintError(os.Stderr, list)
+ }
+
+ list = v.GetErrorList(NoMultiples)
+ if len(list) != 4 {
+ t.Errorf("found %d one-per-line errors, expected 4", len(list))
+ PrintError(os.Stderr, list)
+ }
+
+ if v.ErrorCount() != s.ErrorCount {
+ t.Errorf("found %d errors, expected %d", v.ErrorCount(), s.ErrorCount)
+ }
+}
+
+
+type errorCollector struct {
+ cnt int // number of errors encountered
+ msg string // last error message encountered
+ pos token.Position // last error position encountered
+}
+
+
+func (h *errorCollector) Error(pos token.Position, msg string) {
+ h.cnt++
+ h.msg = msg
+ h.pos = pos
+}
+
+
+func checkError(t *testing.T, src string, tok token.Token, pos int, err string) {
+ var s Scanner
+ var h errorCollector
+ s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), &h, ScanComments)
+ _, tok0, _ := s.Scan()
+ _, tok1, _ := s.Scan()
+ if tok0 != tok {
+ t.Errorf("%q: got %s, expected %s", src, tok0, tok)
+ }
+ if tok1 != token.EOF {
+ t.Errorf("%q: got %s, expected EOF", src, tok1)
+ }
+ cnt := 0
+ if err != "" {
+ cnt = 1
+ }
+ if h.cnt != cnt {
+ t.Errorf("%q: got cnt %d, expected %d", src, h.cnt, cnt)
+ }
+ if h.msg != err {
+ t.Errorf("%q: got msg %q, expected %q", src, h.msg, err)
+ }
+ if h.pos.Offset != pos {
+ t.Errorf("%q: got offset %d, expected %d", src, h.pos.Offset, pos)
+ }
+}
+
+
+var errors = []struct {
+ src string
+ tok token.Token
+ pos int
+ err string
+}{
+ {`#`, token.ILLEGAL, 0, "illegal character '#' (U+23)"},
+ {`' '`, token.CHAR, 0, ""},
+ {`''`, token.CHAR, 0, "illegal character literal"},
+ {`'\8'`, token.CHAR, 2, "unknown escape sequence"},
+ {`'\08'`, token.CHAR, 3, "illegal character in escape sequence"},
+ {`'\x0g'`, token.CHAR, 4, "illegal character in escape sequence"},
+ {`'\Uffffffff'`, token.CHAR, 2, "escape sequence is invalid Unicode code point"},
+ {`'`, token.CHAR, 0, "character literal not terminated"},
+ {`""`, token.STRING, 0, ""},
+ {`"`, token.STRING, 0, "string not terminated"},
+ {"``", token.STRING, 0, ""},
+ {"`", token.STRING, 0, "string not terminated"},
+ {"/**/", token.COMMENT, 0, ""},
+ {"/*", token.COMMENT, 0, "comment not terminated"},
+ {"077", token.INT, 0, ""},
+ {"078.", token.FLOAT, 0, ""},
+ {"07801234567.", token.FLOAT, 0, ""},
+ {"078e0", token.FLOAT, 0, ""},
+ {"078", token.INT, 0, "illegal octal number"},
+ {"07800000009", token.INT, 0, "illegal octal number"},
+ {"\"abc\x00def\"", token.STRING, 4, "illegal character NUL"},
+ {"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"},
+}
+
+
+func TestScanErrors(t *testing.T) {
+ for _, e := range errors {
+ checkError(t, e.src, e.tok, e.pos, e.err)
+ }
+}
diff --git a/libgo/go/go/token/position.go b/libgo/go/go/token/position.go
new file mode 100644
index 000000000..0044a0ed7
--- /dev/null
+++ b/libgo/go/go/token/position.go
@@ -0,0 +1,409 @@
+// 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.
+
+// TODO(gri) consider making this a separate package outside the go directory.
+
+package token
+
+import (
+ "fmt"
+ "sort"
+ "sync"
+)
+
+
+// Position describes an arbitrary source position
+// including the file, line, and column location.
+// A Position is valid if the line number is > 0.
+//
+type Position struct {
+ Filename string // filename, if any
+ Offset int // offset, starting at 0
+ Line int // line number, starting at 1
+ Column int // column number, starting at 1 (character count)
+}
+
+
+// IsValid returns true if the position is valid.
+func (pos *Position) IsValid() bool { return pos.Line > 0 }
+
+
+// String returns a string in one of several forms:
+//
+// file:line:column valid position with file name
+// line:column valid position without file name
+// file invalid position with file name
+// - invalid position without file name
+//
+func (pos Position) String() string {
+ s := pos.Filename
+ if pos.IsValid() {
+ if s != "" {
+ s += ":"
+ }
+ s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
+ }
+ if s == "" {
+ s = "-"
+ }
+ return s
+}
+
+
+// Pos is a compact encoding of a source position within a file set.
+// It can be converted into a Position for a more convenient, but much
+// larger, representation.
+//
+// The Pos value for a given file is a number in the range [base, base+size],
+// where base and size are specified when adding the file to the file set via
+// AddFile.
+//
+// To create the Pos value for a specific source offset, first add
+// the respective file to the current file set (via FileSet.AddFile)
+// and then call File.Pos(offset) for that file. Given a Pos value p
+// for a specific file set fset, the corresponding Position value is
+// obtained by calling fset.Position(p).
+//
+// Pos values can be compared directly with the usual comparison operators:
+// If two Pos values p and q are in the same file, comparing p and q is
+// equivalent to comparing the respective source file offsets. If p and q
+// are in different files, p < q is true if the file implied by p was added
+// to the respective file set before the file implied by q.
+//
+type Pos int
+
+
+// The zero value for Pos is NoPos; there is no file and line information
+// associated with it, and NoPos().IsValid() is false. NoPos is always
+// smaller than any other Pos value. The corresponding Position value
+// for NoPos is the zero value for Position.
+//
+const NoPos Pos = 0
+
+
+// IsValid returns true if the position is valid.
+func (p Pos) IsValid() bool {
+ return p != NoPos
+}
+
+
+func searchFiles(a []*File, x int) int {
+ return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1
+}
+
+
+func (s *FileSet) file(p Pos) *File {
+ if i := searchFiles(s.files, int(p)); i >= 0 {
+ f := s.files[i]
+ // f.base <= int(p) by definition of searchFiles
+ if int(p) <= f.base+f.size {
+ return f
+ }
+ }
+ return nil
+}
+
+
+// File returns the file which contains the position p.
+// If no such file is found (for instance for p == NoPos),
+// the result is nil.
+//
+func (s *FileSet) File(p Pos) (f *File) {
+ if p != NoPos {
+ s.mutex.RLock()
+ f = s.file(p)
+ s.mutex.RUnlock()
+ }
+ return
+}
+
+
+func (f *File) position(p Pos) (pos Position) {
+ offset := int(p) - f.base
+ pos.Offset = offset
+ pos.Filename, pos.Line, pos.Column = f.info(offset)
+ return
+}
+
+
+// Position converts a Pos in the fileset into a general Position.
+func (s *FileSet) Position(p Pos) (pos Position) {
+ if p != NoPos {
+ // TODO(gri) consider optimizing the case where p
+ // is in the last file addded, or perhaps
+ // looked at - will eliminate one level
+ // of search
+ s.mutex.RLock()
+ if f := s.file(p); f != nil {
+ pos = f.position(p)
+ }
+ s.mutex.RUnlock()
+ }
+ return
+}
+
+
+type lineInfo struct {
+ offset int
+ filename string
+ line int
+}
+
+
+// AddLineInfo adds alternative file and line number information for
+// a given file offset. The offset must be larger than the offset for
+// the previously added alternative line info and not larger than the
+// file size; otherwise the information is ignored.
+//
+// AddLineInfo is typically used to register alternative position
+// information for //line filename:line comments in source files.
+//
+func (f *File) AddLineInfo(offset int, filename string, line int) {
+ f.set.mutex.Lock()
+ if i := len(f.infos); i == 0 || f.infos[i-1].offset < offset && offset <= f.size {
+ f.infos = append(f.infos, lineInfo{offset, filename, line})
+ }
+ f.set.mutex.Unlock()
+}
+
+
+// A File is a handle for a file belonging to a FileSet.
+// A File has a name, size, and line offset table.
+//
+type File struct {
+ set *FileSet
+ name string // file name as provided to AddFile
+ base int // Pos value range for this file is [base...base+size]
+ size int // file size as provided to AddFile
+
+ // lines and infos are protected by set.mutex
+ lines []int
+ infos []lineInfo
+}
+
+
+// Name returns the file name of file f as registered with AddFile.
+func (f *File) Name() string {
+ return f.name
+}
+
+
+// Base returns the base offset of file f as registered with AddFile.
+func (f *File) Base() int {
+ return f.base
+}
+
+
+// Size returns the size of file f as registered with AddFile.
+func (f *File) Size() int {
+ return f.size
+}
+
+
+// LineCount returns the number of lines in file f.
+func (f *File) LineCount() int {
+ f.set.mutex.RLock()
+ n := len(f.lines)
+ f.set.mutex.RUnlock()
+ return n
+}
+
+
+// AddLine adds the line offset for a new line.
+// The line offset must be larger than the offset for the previous line
+// and not larger than the file size; otherwise the line offset is ignored.
+//
+func (f *File) AddLine(offset int) {
+ f.set.mutex.Lock()
+ if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset <= f.size {
+ f.lines = append(f.lines, offset)
+ }
+ f.set.mutex.Unlock()
+}
+
+
+// SetLines sets all line offsets for a file and returns true if successful.
+// Each line offset must be larger than the offset for the previous line
+// and not larger than the file size; otherwise the SetLines fails and returns
+// false.
+//
+func (f *File) SetLines(lines []int) bool {
+ // verify validity of lines table
+ size := f.size
+ for i, offset := range lines {
+ if i > 0 && offset <= lines[i-1] || size < offset {
+ return false
+ }
+ }
+
+ // set lines table
+ f.set.mutex.Lock()
+ f.lines = lines
+ f.set.mutex.Unlock()
+ return true
+}
+
+
+// Pos returns the Pos value for the given file offset;
+// the offset must be <= f.Size().
+// f.Pos(f.Offset(p)) == p.
+//
+func (f *File) Pos(offset int) Pos {
+ if offset > f.size {
+ panic("illegal file offset")
+ }
+ return Pos(f.base + offset)
+}
+
+
+// Offset returns the offset for the given file position p;
+// p must be a valid Pos value in that file.
+// f.Offset(f.Pos(offset)) == offset.
+//
+func (f *File) Offset(p Pos) int {
+ if int(p) < f.base || int(p) > f.base+f.size {
+ panic("illegal Pos value")
+ }
+ return int(p) - f.base
+}
+
+
+// Line returns the line number for the given file position p;
+// p must be a Pos value in that file or NoPos.
+//
+func (f *File) Line(p Pos) int {
+ // TODO(gri) this can be implemented much more efficiently
+ return f.Position(p).Line
+}
+
+
+// Position returns the Position value for the given file position p;
+// p must be a Pos value in that file or NoPos.
+//
+func (f *File) Position(p Pos) (pos Position) {
+ if p != NoPos {
+ if int(p) < f.base || int(p) > f.base+f.size {
+ panic("illegal Pos value")
+ }
+ pos = f.position(p)
+ }
+ return
+}
+
+
+func searchUints(a []int, x int) int {
+ return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1
+}
+
+
+func searchLineInfos(a []lineInfo, x int) int {
+ return sort.Search(len(a), func(i int) bool { return a[i].offset > x }) - 1
+}
+
+
+// info returns the file name, line, and column number for a file offset.
+func (f *File) info(offset int) (filename string, line, column int) {
+ filename = f.name
+ if i := searchUints(f.lines, offset); i >= 0 {
+ line, column = i+1, offset-f.lines[i]+1
+ }
+ if i := searchLineInfos(f.infos, offset); i >= 0 {
+ alt := &f.infos[i]
+ filename = alt.filename
+ if i := searchUints(f.lines, alt.offset); i >= 0 {
+ line += alt.line - i - 1
+ }
+ }
+ return
+}
+
+
+// A FileSet represents a set of source files.
+// Methods of file sets are synchronized; multiple goroutines
+// may invoke them concurrently.
+//
+type FileSet struct {
+ mutex sync.RWMutex // protects the file set
+ base int // base offset for the next file
+ files []*File // list of files in the order added to the set
+ index map[*File]int // file -> files index for quick lookup
+}
+
+
+// NewFileSet creates a new file set.
+func NewFileSet() *FileSet {
+ s := new(FileSet)
+ s.base = 1 // 0 == NoPos
+ s.index = make(map[*File]int)
+ return s
+}
+
+
+// Base returns the minimum base offset that must be provided to
+// AddFile when adding the next file.
+//
+func (s *FileSet) Base() int {
+ s.mutex.RLock()
+ b := s.base
+ s.mutex.RUnlock()
+ return b
+
+}
+
+
+// AddFile adds a new file with a given filename, base offset, and file size
+// to the file set s and returns the file. Multiple files may have the same
+// name. The base offset must not be smaller than the FileSet's Base(), and
+// size must not be negative.
+//
+// Adding the file will set the file set's Base() value to base + size + 1
+// as the minimum base value for the next file. The following relationship
+// exists between a Pos value p for a given file offset offs:
+//
+// int(p) = base + offs
+//
+// with offs in the range [0, size] and thus p in the range [base, base+size].
+// For convenience, File.Pos may be used to create file-specific position
+// values from a file offset.
+//
+func (s *FileSet) AddFile(filename string, base, size int) *File {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+ if base < s.base || size < 0 {
+ panic("illegal base or size")
+ }
+ // base >= s.base && size >= 0
+ f := &File{s, filename, base, size, []int{0}, nil}
+ base += size + 1 // +1 because EOF also has a position
+ if base < 0 {
+ panic("token.Pos offset overflow (> 2G of source code in file set)")
+ }
+ // add the file to the file set
+ s.base = base
+ s.index[f] = len(s.files)
+ s.files = append(s.files, f)
+ return f
+}
+
+
+// Files returns the files added to the file set.
+func (s *FileSet) Files() <-chan *File {
+ ch := make(chan *File)
+ go func() {
+ for i := 0; ; i++ {
+ var f *File
+ s.mutex.RLock()
+ if i < len(s.files) {
+ f = s.files[i]
+ }
+ s.mutex.RUnlock()
+ if f == nil {
+ break
+ }
+ ch <- f
+ }
+ close(ch)
+ }()
+ return ch
+}
diff --git a/libgo/go/go/token/position_test.go b/libgo/go/go/token/position_test.go
new file mode 100644
index 000000000..1cffcc3c2
--- /dev/null
+++ b/libgo/go/go/token/position_test.go
@@ -0,0 +1,158 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package token
+
+import (
+ "fmt"
+ "testing"
+)
+
+
+func checkPos(t *testing.T, msg string, p, q Position) {
+ if p.Filename != q.Filename {
+ t.Errorf("%s: expected filename = %q; got %q", msg, q.Filename, p.Filename)
+ }
+ if p.Offset != q.Offset {
+ t.Errorf("%s: expected offset = %d; got %d", msg, q.Offset, p.Offset)
+ }
+ if p.Line != q.Line {
+ t.Errorf("%s: expected line = %d; got %d", msg, q.Line, p.Line)
+ }
+ if p.Column != q.Column {
+ t.Errorf("%s: expected column = %d; got %d", msg, q.Column, p.Column)
+ }
+}
+
+
+func TestNoPos(t *testing.T) {
+ if NoPos.IsValid() {
+ t.Errorf("NoPos should not be valid")
+ }
+ var fset *FileSet
+ checkPos(t, "nil NoPos", fset.Position(NoPos), Position{})
+ fset = NewFileSet()
+ checkPos(t, "fset NoPos", fset.Position(NoPos), Position{})
+}
+
+
+var tests = []struct {
+ filename string
+ size int
+ lines []int
+}{
+ {"a", 0, []int{}},
+ {"b", 5, []int{0}},
+ {"c", 10, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}},
+ {"d", 100, []int{0, 5, 10, 20, 30, 70, 71, 72, 80, 85, 90, 99}},
+ {"e", 777, []int{0, 80, 100, 120, 130, 180, 267, 455, 500, 567, 620}},
+}
+
+
+func linecol(lines []int, offs int) (int, int) {
+ prevLineOffs := 0
+ for line, lineOffs := range lines {
+ if offs < lineOffs {
+ return line, offs - prevLineOffs + 1
+ }
+ prevLineOffs = lineOffs
+ }
+ return len(lines), offs - prevLineOffs + 1
+}
+
+
+func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
+ for offs := 0; offs < f.Size(); offs++ {
+ p := f.Pos(offs)
+ offs2 := f.Offset(p)
+ if offs2 != offs {
+ t.Errorf("%s, Offset: expected offset %d; got %d", f.Name(), offs, offs2)
+ }
+ line, col := linecol(lines, offs)
+ msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
+ checkPos(t, msg, f.Position(f.Pos(offs)), Position{f.Name(), offs, line, col})
+ checkPos(t, msg, fset.Position(p), Position{f.Name(), offs, line, col})
+ }
+}
+
+
+func TestPositions(t *testing.T) {
+ const delta = 7 // a non-zero base offset increment
+ fset := NewFileSet()
+ for _, test := range tests {
+ // add file and verify name and size
+ f := fset.AddFile(test.filename, fset.Base()+delta, test.size)
+ if f.Name() != test.filename {
+ t.Errorf("expected filename %q; got %q", test.filename, f.Name())
+ }
+ if f.Size() != test.size {
+ t.Errorf("%s: expected file size %d; got %d", f.Name(), test.size, f.Size())
+ }
+ if fset.File(f.Pos(0)) != f {
+ t.Errorf("%s: f.Pos(0) was not found in f", f.Name())
+ }
+
+ // add lines individually and verify all positions
+ for i, offset := range test.lines {
+ f.AddLine(offset)
+ if f.LineCount() != i+1 {
+ t.Errorf("%s, AddLine: expected line count %d; got %d", f.Name(), i+1, f.LineCount())
+ }
+ // adding the same offset again should be ignored
+ f.AddLine(offset)
+ if f.LineCount() != i+1 {
+ t.Errorf("%s, AddLine: expected unchanged line count %d; got %d", f.Name(), i+1, f.LineCount())
+ }
+ verifyPositions(t, fset, f, test.lines[0:i+1])
+ }
+
+ // add lines at once and verify all positions
+ ok := f.SetLines(test.lines)
+ if !ok {
+ t.Errorf("%s: SetLines failed", f.Name())
+ }
+ if f.LineCount() != len(test.lines) {
+ t.Errorf("%s, SetLines: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount())
+ }
+ verifyPositions(t, fset, f, test.lines)
+ }
+}
+
+
+func TestLineInfo(t *testing.T) {
+ fset := NewFileSet()
+ f := fset.AddFile("foo", fset.Base(), 500)
+ lines := []int{0, 42, 77, 100, 210, 220, 277, 300, 333, 401}
+ // add lines individually and provide alternative line information
+ for _, offs := range lines {
+ f.AddLine(offs)
+ f.AddLineInfo(offs, "bar", 42)
+ }
+ // verify positions for all offsets
+ for offs := 0; offs <= f.Size(); offs++ {
+ p := f.Pos(offs)
+ _, col := linecol(lines, offs)
+ msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
+ checkPos(t, msg, f.Position(f.Pos(offs)), Position{"bar", offs, 42, col})
+ checkPos(t, msg, fset.Position(p), Position{"bar", offs, 42, col})
+ }
+}
+
+
+func TestFiles(t *testing.T) {
+ fset := NewFileSet()
+ for i, test := range tests {
+ fset.AddFile(test.filename, fset.Base(), test.size)
+ j := 0
+ for g := range fset.Files() {
+ if g.Name() != tests[j].filename {
+ t.Errorf("expected filename = %s; got %s", tests[j].filename, g.Name())
+ }
+ j++
+ }
+ if j != i+1 {
+ t.Errorf("expected %d files; got %d", i+1, j)
+ }
+ }
+}
diff --git a/libgo/go/go/token/token.go b/libgo/go/go/token/token.go
new file mode 100644
index 000000000..1bd81c1b1
--- /dev/null
+++ b/libgo/go/go/token/token.go
@@ -0,0 +1,320 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package defines constants representing the lexical
+// tokens of the Go programming language and basic operations
+// on tokens (printing, predicates).
+//
+package token
+
+import "strconv"
+
+
+// Token is the set of lexical tokens of the Go programming language.
+type Token int
+
+// The list of tokens.
+const (
+ // Special tokens
+ ILLEGAL Token = iota
+ EOF
+ COMMENT
+
+ literal_beg
+ // Identifiers and basic type literals
+ // (these tokens stand for classes of literals)
+ IDENT // main
+ INT // 12345
+ FLOAT // 123.45
+ IMAG // 123.45i
+ CHAR // 'a'
+ STRING // "abc"
+ literal_end
+
+ operator_beg
+ // Operators and delimiters
+ ADD // +
+ SUB // -
+ MUL // *
+ QUO // /
+ REM // %
+
+ AND // &
+ OR // |
+ XOR // ^
+ SHL // <<
+ SHR // >>
+ AND_NOT // &^
+
+ ADD_ASSIGN // +=
+ SUB_ASSIGN // -=
+ MUL_ASSIGN // *=
+ QUO_ASSIGN // /=
+ REM_ASSIGN // %=
+
+ AND_ASSIGN // &=
+ OR_ASSIGN // |=
+ XOR_ASSIGN // ^=
+ SHL_ASSIGN // <<=
+ SHR_ASSIGN // >>=
+ AND_NOT_ASSIGN // &^=
+
+ LAND // &&
+ LOR // ||
+ ARROW // <-
+ INC // ++
+ DEC // --
+
+ EQL // ==
+ LSS // <
+ GTR // >
+ ASSIGN // =
+ NOT // !
+
+ NEQ // !=
+ LEQ // <=
+ GEQ // >=
+ DEFINE // :=
+ ELLIPSIS // ...
+
+ LPAREN // (
+ LBRACK // [
+ LBRACE // {
+ COMMA // ,
+ PERIOD // .
+
+ RPAREN // )
+ RBRACK // ]
+ RBRACE // }
+ SEMICOLON // ;
+ COLON // :
+ operator_end
+
+ keyword_beg
+ // Keywords
+ BREAK
+ CASE
+ CHAN
+ CONST
+ CONTINUE
+
+ DEFAULT
+ DEFER
+ ELSE
+ FALLTHROUGH
+ FOR
+
+ FUNC
+ GO
+ GOTO
+ IF
+ IMPORT
+
+ INTERFACE
+ MAP
+ PACKAGE
+ RANGE
+ RETURN
+
+ SELECT
+ STRUCT
+ SWITCH
+ TYPE
+ VAR
+ keyword_end
+)
+
+
+// At the moment we have no array literal syntax that lets us describe
+// the index for each element - use a map for now to make sure they are
+// in sync.
+var tokens = map[Token]string{
+ ILLEGAL: "ILLEGAL",
+
+ EOF: "EOF",
+ COMMENT: "COMMENT",
+
+ IDENT: "IDENT",
+ INT: "INT",
+ FLOAT: "FLOAT",
+ IMAG: "IMAG",
+ CHAR: "CHAR",
+ STRING: "STRING",
+
+ ADD: "+",
+ SUB: "-",
+ MUL: "*",
+ QUO: "/",
+ REM: "%",
+
+ AND: "&",
+ OR: "|",
+ XOR: "^",
+ SHL: "<<",
+ SHR: ">>",
+ AND_NOT: "&^",
+
+ ADD_ASSIGN: "+=",
+ SUB_ASSIGN: "-=",
+ MUL_ASSIGN: "*=",
+ QUO_ASSIGN: "/=",
+ REM_ASSIGN: "%=",
+
+ AND_ASSIGN: "&=",
+ OR_ASSIGN: "|=",
+ XOR_ASSIGN: "^=",
+ SHL_ASSIGN: "<<=",
+ SHR_ASSIGN: ">>=",
+ AND_NOT_ASSIGN: "&^=",
+
+ LAND: "&&",
+ LOR: "||",
+ ARROW: "<-",
+ INC: "++",
+ DEC: "--",
+
+ EQL: "==",
+ LSS: "<",
+ GTR: ">",
+ ASSIGN: "=",
+ NOT: "!",
+
+ NEQ: "!=",
+ LEQ: "<=",
+ GEQ: ">=",
+ DEFINE: ":=",
+ ELLIPSIS: "...",
+
+ LPAREN: "(",
+ LBRACK: "[",
+ LBRACE: "{",
+ COMMA: ",",
+ PERIOD: ".",
+
+ RPAREN: ")",
+ RBRACK: "]",
+ RBRACE: "}",
+ SEMICOLON: ";",
+ COLON: ":",
+
+ BREAK: "break",
+ CASE: "case",
+ CHAN: "chan",
+ CONST: "const",
+ CONTINUE: "continue",
+
+ DEFAULT: "default",
+ DEFER: "defer",
+ ELSE: "else",
+ FALLTHROUGH: "fallthrough",
+ FOR: "for",
+
+ FUNC: "func",
+ GO: "go",
+ GOTO: "goto",
+ IF: "if",
+ IMPORT: "import",
+
+ INTERFACE: "interface",
+ MAP: "map",
+ PACKAGE: "package",
+ RANGE: "range",
+ RETURN: "return",
+
+ SELECT: "select",
+ STRUCT: "struct",
+ SWITCH: "switch",
+ TYPE: "type",
+ VAR: "var",
+}
+
+
+// String returns the string corresponding to the token tok.
+// For operators, delimiters, and keywords the string is the actual
+// token character sequence (e.g., for the token ADD, the string is
+// "+"). For all other tokens the string corresponds to the token
+// constant name (e.g. for the token IDENT, the string is "IDENT").
+//
+func (tok Token) String() string {
+ if str, exists := tokens[tok]; exists {
+ return str
+ }
+ return "token(" + strconv.Itoa(int(tok)) + ")"
+}
+
+
+// A set of constants for precedence-based expression parsing.
+// Non-operators have lowest precedence, followed by operators
+// starting with precedence 1 up to unary operators. The highest
+// precedence corresponds serves as "catch-all" precedence for
+// selector, indexing, and other operator and delimiter tokens.
+//
+const (
+ LowestPrec = 0 // non-operators
+ UnaryPrec = 7
+ HighestPrec = 8
+)
+
+
+// Precedence returns the operator precedence of the binary
+// operator op. If op is not a binary operator, the result
+// is LowestPrecedence.
+//
+func (op Token) Precedence() int {
+ switch op {
+ case LOR:
+ return 1
+ case LAND:
+ return 2
+ case ARROW:
+ return 3
+ case EQL, NEQ, LSS, LEQ, GTR, GEQ:
+ return 4
+ case ADD, SUB, OR, XOR:
+ return 5
+ case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
+ return 6
+ }
+ return LowestPrec
+}
+
+
+var keywords map[string]Token
+
+func init() {
+ keywords = make(map[string]Token)
+ for i := keyword_beg + 1; i < keyword_end; i++ {
+ keywords[tokens[i]] = i
+ }
+}
+
+
+// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
+//
+func Lookup(ident []byte) Token {
+ // TODO Maps with []byte key are illegal because []byte does not
+ // support == . Should find a more efficient solution eventually.
+ if tok, is_keyword := keywords[string(ident)]; is_keyword {
+ return tok
+ }
+ return IDENT
+}
+
+
+// Predicates
+
+// IsLiteral returns true for tokens corresponding to identifiers
+// and basic type literals; returns false otherwise.
+//
+func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end }
+
+// IsOperator returns true for tokens corresponding to operators and
+// delimiters; returns false otherwise.
+//
+func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end }
+
+// IsKeyword returns true for tokens corresponding to keywords;
+// returns false otherwise.
+//
+func (tok Token) IsKeyword() bool { return keyword_beg < tok && tok < keyword_end }
diff --git a/libgo/go/go/typechecker/scope.go b/libgo/go/go/typechecker/scope.go
new file mode 100644
index 000000000..114c93ea8
--- /dev/null
+++ b/libgo/go/go/typechecker/scope.go
@@ -0,0 +1,119 @@
+// 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.
+
+// This file implements scope support functions.
+
+package typechecker
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+)
+
+
+func (tc *typechecker) openScope() *ast.Scope {
+ tc.topScope = ast.NewScope(tc.topScope)
+ return tc.topScope
+}
+
+
+func (tc *typechecker) closeScope() {
+ tc.topScope = tc.topScope.Outer
+}
+
+
+// objPos computes the source position of the declaration of an object name.
+// Only required for error reporting, so doesn't have to be fast.
+func objPos(obj *ast.Object) (pos token.Pos) {
+ switch d := obj.Decl.(type) {
+ case *ast.Field:
+ for _, n := range d.Names {
+ if n.Name == obj.Name {
+ return n.Pos()
+ }
+ }
+ case *ast.ValueSpec:
+ for _, n := range d.Names {
+ if n.Name == obj.Name {
+ return n.Pos()
+ }
+ }
+ case *ast.TypeSpec:
+ return d.Name.Pos()
+ case *ast.FuncDecl:
+ return d.Name.Pos()
+ }
+ if debug {
+ fmt.Printf("decl = %T\n", obj.Decl)
+ }
+ panic("unreachable")
+}
+
+
+// declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
+// It returns the newly allocated object. If an object with the same name already exists in scope, an error
+// is reported and the object is not inserted.
+// (Objects with _ name are always inserted into a scope without errors, but they cannot be found.)
+func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+ obj := ast.NewObj(kind, name.Name)
+ obj.Decl = decl
+ obj.N = n
+ name.Obj = obj
+ if alt := scope.Insert(obj); alt != obj {
+ tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, objPos(alt))
+ }
+ return obj
+}
+
+
+// decl is the same as declInScope(tc.topScope, ...)
+func (tc *typechecker) decl(kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+ return tc.declInScope(tc.topScope, kind, name, decl, n)
+}
+
+
+// find returns the object with the given name if visible in the current scope hierarchy.
+// If no such object is found, an error is reported and a bad object is returned instead.
+func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
+ for s := tc.topScope; s != nil && obj == nil; s = s.Outer {
+ obj = s.Lookup(name.Name)
+ }
+ if obj == nil {
+ tc.Errorf(name.Pos(), "%s not declared", name.Name)
+ obj = ast.NewObj(ast.Bad, name.Name)
+ }
+ name.Obj = obj
+ return
+}
+
+
+// findField returns the object with the given name if visible in the type's scope.
+// If no such object is found, an error is reported and a bad object is returned instead.
+func (tc *typechecker) findField(typ *ast.Type, name *ast.Ident) (obj *ast.Object) {
+ // TODO(gri) This is simplistic at the moment and ignores anonymous fields.
+ obj = typ.Scope.Lookup(name.Name)
+ if obj == nil {
+ tc.Errorf(name.Pos(), "%s not declared", name.Name)
+ obj = ast.NewObj(ast.Bad, name.Name)
+ }
+ return
+}
+
+
+// printScope prints the objects in a scope.
+func printScope(scope *ast.Scope) {
+ fmt.Printf("scope %p {", scope)
+ if scope != nil && len(scope.Objects) > 0 {
+ fmt.Println()
+ for _, obj := range scope.Objects {
+ form := "void"
+ if obj.Type != nil {
+ form = obj.Type.Form.String()
+ }
+ fmt.Printf("\t%s\t%s\n", obj.Name, form)
+ }
+ }
+ fmt.Printf("}\n")
+}
diff --git a/libgo/go/go/typechecker/testdata/test0.go b/libgo/go/go/typechecker/testdata/test0.go
new file mode 100644
index 000000000..4e317f214
--- /dev/null
+++ b/libgo/go/go/typechecker/testdata/test0.go
@@ -0,0 +1,94 @@
+// 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.
+
+// type declarations
+
+package P0
+
+type (
+ B bool
+ I int32
+ A [10]P
+ T struct {
+ x, y P
+ }
+ P *T
+ R *R
+ F func(A) I
+ Y interface {
+ f(A) I
+ }
+ S []P
+ M map[I]F
+ C chan<- I
+)
+
+type (
+ a/* ERROR "illegal cycle" */ a
+ a/* ERROR "already declared" */ int
+
+ b/* ERROR "illegal cycle" */ c
+ c d
+ d e
+ e b /* ERROR "not a type" */
+
+ t *t
+
+ U V
+ V W
+ W *U
+
+ P1 *S2
+ P2 P1
+
+ S1 struct {
+ a, b, c int
+ u, v, a/* ERROR "already declared" */ float
+ }
+ S2/* ERROR "illegal cycle" */ struct {
+ x S2
+ }
+
+ L1 []L1
+ L2 []int
+
+ A1 [10]int
+ A2/* ERROR "illegal cycle" */ [10]A2
+ A3/* ERROR "illegal cycle" */ [10]struct {
+ x A4
+ }
+ A4 [10]A3
+
+ F1 func()
+ F2 func(x, y, z float)
+ F3 func(x, y, x /* ERROR "already declared" */ float)
+ F4 func() (x, y, x /* ERROR "already declared" */ float)
+ F5 func(x int) (x /* ERROR "already declared" */ float)
+
+ I1 interface{}
+ I2 interface {
+ m1()
+ }
+ I3 interface {
+ m1()
+ m1 /* ERROR "already declared" */ ()
+ }
+ I4 interface {
+ m1(x, y, x /* ERROR "already declared" */ float)
+ m2() (x, y, x /* ERROR "already declared" */ float)
+ m3(x int) (x /* ERROR "already declared" */ float)
+ }
+ I5 interface {
+ m1(I5)
+ }
+
+ C1 chan int
+ C2 <-chan int
+ C3 chan<- C3
+
+ M1 map[Last]string
+ M2 map[string]M2
+
+ Last int
+)
diff --git a/libgo/go/go/typechecker/testdata/test1.go b/libgo/go/go/typechecker/testdata/test1.go
new file mode 100644
index 000000000..b0808ee7a
--- /dev/null
+++ b/libgo/go/go/typechecker/testdata/test1.go
@@ -0,0 +1,13 @@
+// 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.
+
+// const and var declarations
+
+package P1
+
+const (
+ c1 /* ERROR "missing initializer" */
+ c2 int = 0
+ c3, c4 = 0
+)
diff --git a/libgo/go/go/typechecker/testdata/test3.go b/libgo/go/go/typechecker/testdata/test3.go
new file mode 100644
index 000000000..ea35808a0
--- /dev/null
+++ b/libgo/go/go/typechecker/testdata/test3.go
@@ -0,0 +1,38 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package P3
+
+// function and method signatures
+
+func _() {}
+func _() {}
+func _(x, x /* ERROR "already declared" */ int) {}
+
+func f() {}
+func f /* ERROR "already declared" */ () {}
+
+func (*foo /* ERROR "invalid receiver" */ ) m() {}
+func (bar /* ERROR "not a type" */ ) m() {}
+
+func f1(x, _, _ int) (_, _ float) {}
+func f2(x, y, x /* ERROR "already declared" */ int) {}
+func f3(x, y int) (a, b, x /* ERROR "already declared" */ int) {}
+
+func (x *T) m1() {}
+func (x *T) m1 /* ERROR "already declared" */ () {}
+func (x T) m1 /* ERROR "already declared" */ () {}
+func (T) m1 /* ERROR "already declared" */ () {}
+
+func (x *T) m2(u, x /* ERROR "already declared" */ int) {}
+func (x *T) m3(a, b, c int) (u, x /* ERROR "already declared" */ int) {}
+func (T) _(x, x /* ERROR "already declared" */ int) {}
+func (T) _() (x, x /* ERROR "already declared" */ int) {}
+
+//func (PT) _() {}
+
+var bar int
+
+type T struct{}
+type PT (T)
diff --git a/libgo/go/go/typechecker/testdata/test4.go b/libgo/go/go/typechecker/testdata/test4.go
new file mode 100644
index 000000000..bb9aee3ad
--- /dev/null
+++ b/libgo/go/go/typechecker/testdata/test4.go
@@ -0,0 +1,11 @@
+// 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.
+
+// Constant declarations
+
+package P4
+
+const (
+ c0 /* ERROR "missing initializer" */
+)
diff --git a/libgo/go/go/typechecker/typechecker.go b/libgo/go/go/typechecker/typechecker.go
new file mode 100644
index 000000000..e9aefa240
--- /dev/null
+++ b/libgo/go/go/typechecker/typechecker.go
@@ -0,0 +1,484 @@
+// 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.
+
+// INCOMPLETE PACKAGE.
+// This package implements typechecking of a Go AST.
+// The result of the typecheck is an augmented AST
+// with object and type information for each identifier.
+//
+package typechecker
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "go/scanner"
+ "os"
+)
+
+
+// TODO(gri) don't report errors for objects/types that are marked as bad.
+
+
+const debug = true // set for debugging output
+
+
+// An importer takes an import path and returns the data describing the
+// respective package's exported interface. The data format is TBD.
+//
+type Importer func(path string) ([]byte, os.Error)
+
+
+// CheckPackage typechecks a package and augments the AST by setting
+// *ast.Object, *ast.Type, and *ast.Scope fields accordingly. If an
+// importer is provided, it is used to handle imports, otherwise they
+// are ignored (likely leading to typechecking errors).
+//
+// If errors are reported, the AST may be incompletely augmented (fields
+// may be nil) or contain incomplete object, type, or scope information.
+//
+func CheckPackage(fset *token.FileSet, pkg *ast.Package, importer Importer) os.Error {
+ var tc typechecker
+ tc.fset = fset
+ tc.importer = importer
+ tc.checkPackage(pkg)
+ return tc.GetError(scanner.Sorted)
+}
+
+
+// CheckFile typechecks a single file, but otherwise behaves like
+// CheckPackage. If the complete package consists of more than just
+// one file, the file may not typecheck without errors.
+//
+func CheckFile(fset *token.FileSet, file *ast.File, importer Importer) os.Error {
+ // create a single-file dummy package
+ pkg := &ast.Package{file.Name.Name, nil, map[string]*ast.File{fset.Position(file.Name.NamePos).Filename: file}}
+ return CheckPackage(fset, pkg, importer)
+}
+
+
+// ----------------------------------------------------------------------------
+// Typechecker state
+
+type typechecker struct {
+ fset *token.FileSet
+ scanner.ErrorVector
+ importer Importer
+ topScope *ast.Scope // current top-most scope
+ cyclemap map[*ast.Object]bool // for cycle detection
+ iota int // current value of iota
+}
+
+
+func (tc *typechecker) Errorf(pos token.Pos, format string, args ...interface{}) {
+ tc.Error(tc.fset.Position(pos), fmt.Sprintf(format, args...))
+}
+
+
+func assert(pred bool) {
+ if !pred {
+ panic("internal error")
+ }
+}
+
+
+/*
+Typechecking is done in several phases:
+
+phase 1: declare all global objects; also collect all function and method declarations
+ - all objects have kind, name, decl fields; the decl field permits
+ quick lookup of an object's declaration
+ - constant objects have an iota value
+ - type objects have unresolved types with empty scopes, all others have nil types
+ - report global double declarations
+
+phase 2: bind methods to their receiver base types
+ - received base types must be declared in the package, thus for
+ each method a corresponding (unresolved) type must exist
+ - report method double declarations and errors with base types
+
+phase 3: resolve all global objects
+ - sequentially iterate through all objects in the global scope
+ - resolve types for all unresolved types and assign types to
+ all attached methods
+ - assign types to all other objects, possibly by evaluating
+ constant and initializer expressions
+ - resolution may recurse; a cyclemap is used to detect cycles
+ - report global typing errors
+
+phase 4: sequentially typecheck function and method bodies
+ - all global objects are declared and have types and values;
+ all methods have types
+ - sequentially process statements in each body; any object
+ referred to must be fully defined at this point
+ - report local typing errors
+*/
+
+func (tc *typechecker) checkPackage(pkg *ast.Package) {
+ // setup package scope
+ tc.topScope = Universe
+ tc.openScope()
+ defer tc.closeScope()
+
+ // TODO(gri) there's no file scope at the moment since we ignore imports
+
+ // phase 1: declare all global objects; also collect all function and method declarations
+ var funcs []*ast.FuncDecl
+ for _, file := range pkg.Files {
+ for _, decl := range file.Decls {
+ tc.declGlobal(decl)
+ if f, isFunc := decl.(*ast.FuncDecl); isFunc {
+ funcs = append(funcs, f)
+ }
+ }
+ }
+
+ // phase 2: bind methods to their receiver base types
+ for _, m := range funcs {
+ if m.Recv != nil {
+ tc.bindMethod(m)
+ }
+ }
+
+ // phase 3: resolve all global objects
+ // (note that objects with _ name are also in the scope)
+ tc.cyclemap = make(map[*ast.Object]bool)
+ for _, obj := range tc.topScope.Objects {
+ tc.resolve(obj)
+ }
+ assert(len(tc.cyclemap) == 0)
+
+ // 4: sequentially typecheck function and method bodies
+ for _, f := range funcs {
+ tc.checkBlock(f.Body.List, f.Name.Obj.Type)
+ }
+
+ pkg.Scope = tc.topScope
+}
+
+
+func (tc *typechecker) declGlobal(global ast.Decl) {
+ switch d := global.(type) {
+ case *ast.BadDecl:
+ // ignore
+
+ case *ast.GenDecl:
+ iota := 0
+ var prev *ast.ValueSpec
+ for _, spec := range d.Specs {
+ switch s := spec.(type) {
+ case *ast.ImportSpec:
+ // TODO(gri) imports go into file scope
+ case *ast.ValueSpec:
+ switch d.Tok {
+ case token.CONST:
+ if s.Values == nil {
+ // create a new spec with type and values from the previous one
+ if prev != nil {
+ s = &ast.ValueSpec{s.Doc, s.Names, prev.Type, prev.Values, s.Comment}
+ } else {
+ // TODO(gri) this should probably go into the const decl code
+ tc.Errorf(s.Pos(), "missing initializer for const %s", s.Names[0].Name)
+ }
+ }
+ for _, name := range s.Names {
+ tc.decl(ast.Con, name, s, iota)
+ }
+ case token.VAR:
+ for _, name := range s.Names {
+ tc.decl(ast.Var, name, s, 0)
+ }
+ default:
+ panic("unreachable")
+ }
+ prev = s
+ iota++
+ case *ast.TypeSpec:
+ obj := tc.decl(ast.Typ, s.Name, s, 0)
+ // give all type objects an unresolved type so
+ // that we can collect methods in the type scope
+ typ := ast.NewType(ast.Unresolved)
+ obj.Type = typ
+ typ.Obj = obj
+ default:
+ panic("unreachable")
+ }
+ }
+
+ case *ast.FuncDecl:
+ if d.Recv == nil {
+ tc.decl(ast.Fun, d.Name, d, 0)
+ }
+
+ default:
+ panic("unreachable")
+ }
+}
+
+
+// If x is of the form *T, deref returns T, otherwise it returns x.
+func deref(x ast.Expr) ast.Expr {
+ if p, isPtr := x.(*ast.StarExpr); isPtr {
+ x = p.X
+ }
+ return x
+}
+
+
+func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
+ // a method is declared in the receiver base type's scope
+ var scope *ast.Scope
+ base := deref(method.Recv.List[0].Type)
+ if name, isIdent := base.(*ast.Ident); isIdent {
+ // if base is not an *ast.Ident, we had a syntax
+ // error and the parser reported an error already
+ obj := tc.topScope.Lookup(name.Name)
+ if obj == nil {
+ tc.Errorf(name.Pos(), "invalid receiver: %s is not declared in this package", name.Name)
+ } else if obj.Kind != ast.Typ {
+ tc.Errorf(name.Pos(), "invalid receiver: %s is not a type", name.Name)
+ } else {
+ typ := obj.Type
+ assert(typ.Form == ast.Unresolved)
+ scope = typ.Scope
+ }
+ }
+ if scope == nil {
+ // no receiver type found; use a dummy scope
+ // (we still want to type-check the method
+ // body, so make sure there is a name object
+ // and type)
+ // TODO(gri) should we record the scope so
+ // that we don't lose the receiver for type-
+ // checking of the method body?
+ scope = ast.NewScope(nil)
+ }
+ tc.declInScope(scope, ast.Fun, method.Name, method, 0)
+}
+
+
+func (tc *typechecker) resolve(obj *ast.Object) {
+ // check for declaration cycles
+ if tc.cyclemap[obj] {
+ tc.Errorf(objPos(obj), "illegal cycle in declaration of %s", obj.Name)
+ obj.Kind = ast.Bad
+ return
+ }
+ tc.cyclemap[obj] = true
+ defer func() {
+ tc.cyclemap[obj] = false, false
+ }()
+
+ // resolve non-type objects
+ typ := obj.Type
+ if typ == nil {
+ switch obj.Kind {
+ case ast.Bad:
+ // ignore
+
+ case ast.Con:
+ tc.declConst(obj)
+
+ case ast.Var:
+ tc.declVar(obj)
+ //obj.Type = tc.typeFor(nil, obj.Decl.(*ast.ValueSpec).Type, false)
+
+ case ast.Fun:
+ obj.Type = ast.NewType(ast.Function)
+ t := obj.Decl.(*ast.FuncDecl).Type
+ tc.declSignature(obj.Type, nil, t.Params, t.Results)
+
+ default:
+ // type objects have non-nil types when resolve is called
+ if debug {
+ fmt.Printf("kind = %s\n", obj.Kind)
+ }
+ panic("unreachable")
+ }
+ return
+ }
+
+ // resolve type objects
+ if typ.Form == ast.Unresolved {
+ tc.typeFor(typ, typ.Obj.Decl.(*ast.TypeSpec).Type, false)
+
+ // provide types for all methods
+ for _, obj := range typ.Scope.Objects {
+ if obj.Kind == ast.Fun {
+ assert(obj.Type == nil)
+ obj.Type = ast.NewType(ast.Method)
+ f := obj.Decl.(*ast.FuncDecl)
+ t := f.Type
+ tc.declSignature(obj.Type, f.Recv, t.Params, t.Results)
+ }
+ }
+ }
+}
+
+
+func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *ast.Type) {
+ tc.openScope()
+ defer tc.closeScope()
+
+ // inject function/method parameters into block scope, if any
+ if ftype != nil {
+ for _, par := range ftype.Params.Objects {
+ obj := tc.topScope.Insert(par)
+ assert(obj == par) // ftype has no double declarations
+ }
+ }
+
+ for _, stmt := range body {
+ tc.checkStmt(stmt)
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// Types
+
+// unparen removes parentheses around x, if any.
+func unparen(x ast.Expr) ast.Expr {
+ if ux, hasParens := x.(*ast.ParenExpr); hasParens {
+ return unparen(ux.X)
+ }
+ return x
+}
+
+
+func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref bool) (n uint) {
+ if fields != nil {
+ for _, f := range fields.List {
+ typ := tc.typeFor(nil, f.Type, ref)
+ for _, name := range f.Names {
+ fld := tc.declInScope(scope, ast.Var, name, f, 0)
+ fld.Type = typ
+ n++
+ }
+ }
+ }
+ return n
+}
+
+
+func (tc *typechecker) declSignature(typ *ast.Type, recv, params, results *ast.FieldList) {
+ assert((typ.Form == ast.Method) == (recv != nil))
+ typ.Params = ast.NewScope(nil)
+ tc.declFields(typ.Params, recv, true)
+ tc.declFields(typ.Params, params, true)
+ typ.N = tc.declFields(typ.Params, results, true)
+}
+
+
+func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Type) {
+ x = unparen(x)
+
+ // type name
+ if t, isIdent := x.(*ast.Ident); isIdent {
+ obj := tc.find(t)
+
+ if obj.Kind != ast.Typ {
+ tc.Errorf(t.Pos(), "%s is not a type", t.Name)
+ if def == nil {
+ typ = ast.NewType(ast.BadType)
+ } else {
+ typ = def
+ typ.Form = ast.BadType
+ }
+ typ.Expr = x
+ return
+ }
+
+ if !ref {
+ tc.resolve(obj) // check for cycles even if type resolved
+ }
+ typ = obj.Type
+
+ if def != nil {
+ // new type declaration: copy type structure
+ def.Form = typ.Form
+ def.N = typ.N
+ def.Key, def.Elt = typ.Key, typ.Elt
+ def.Params = typ.Params
+ def.Expr = x
+ typ = def
+ }
+ return
+ }
+
+ // type literal
+ typ = def
+ if typ == nil {
+ typ = ast.NewType(ast.BadType)
+ }
+ typ.Expr = x
+
+ switch t := x.(type) {
+ case *ast.SelectorExpr:
+ if debug {
+ fmt.Println("qualified identifier unimplemented")
+ }
+ typ.Form = ast.BadType
+
+ case *ast.StarExpr:
+ typ.Form = ast.Pointer
+ typ.Elt = tc.typeFor(nil, t.X, true)
+
+ case *ast.ArrayType:
+ if t.Len != nil {
+ typ.Form = ast.Array
+ // TODO(gri) compute the real length
+ // (this may call resolve recursively)
+ (*typ).N = 42
+ } else {
+ typ.Form = ast.Slice
+ }
+ typ.Elt = tc.typeFor(nil, t.Elt, t.Len == nil)
+
+ case *ast.StructType:
+ typ.Form = ast.Struct
+ tc.declFields(typ.Scope, t.Fields, false)
+
+ case *ast.FuncType:
+ typ.Form = ast.Function
+ tc.declSignature(typ, nil, t.Params, t.Results)
+
+ case *ast.InterfaceType:
+ typ.Form = ast.Interface
+ tc.declFields(typ.Scope, t.Methods, true)
+
+ case *ast.MapType:
+ typ.Form = ast.Map
+ typ.Key = tc.typeFor(nil, t.Key, true)
+ typ.Elt = tc.typeFor(nil, t.Value, true)
+
+ case *ast.ChanType:
+ typ.Form = ast.Channel
+ typ.N = uint(t.Dir)
+ typ.Elt = tc.typeFor(nil, t.Value, true)
+
+ default:
+ if debug {
+ fmt.Printf("x is %T\n", x)
+ }
+ panic("unreachable")
+ }
+
+ return
+}
+
+
+// ----------------------------------------------------------------------------
+// TODO(gri) implement these place holders
+
+func (tc *typechecker) declConst(*ast.Object) {
+}
+
+
+func (tc *typechecker) declVar(*ast.Object) {
+}
+
+
+func (tc *typechecker) checkStmt(ast.Stmt) {
+}
diff --git a/libgo/go/go/typechecker/typechecker_test.go b/libgo/go/go/typechecker/typechecker_test.go
new file mode 100644
index 000000000..33f4a6223
--- /dev/null
+++ b/libgo/go/go/typechecker/typechecker_test.go
@@ -0,0 +1,168 @@
+// 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.
+
+// This file implements a simple typechecker test harness. Packages found
+// in the testDir directory are typechecked. Error messages reported by
+// the typechecker are compared against the error messages expected for
+// the test files.
+//
+// Expected errors are indicated in the test files by putting a comment
+// of the form /* ERROR "rx" */ immediately following an offending token.
+// The harness will verify that an error matching the regular expression
+// rx is reported at that source position. Consecutive comments may be
+// used to indicate multiple errors for the same token position.
+//
+// For instance, the following test file indicates that a "not declared"
+// error should be reported for the undeclared variable x:
+//
+// package P0
+// func f() {
+// _ = x /* ERROR "not declared" */ + 1
+// }
+//
+// If the -pkg flag is set, only packages with package names matching
+// the regular expression provided via the flag value are tested.
+
+package typechecker
+
+import (
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "regexp"
+ "sort"
+ "strings"
+ "testing"
+)
+
+
+const testDir = "./testdata" // location of test packages
+
+var fset = token.NewFileSet()
+
+var (
+ pkgPat = flag.String("pkg", ".*", "regular expression to select test packages by package name")
+ trace = flag.Bool("trace", false, "print package names")
+)
+
+
+// ERROR comments must be of the form /* ERROR "rx" */ and rx is
+// a regular expression that matches the expected error message.
+var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
+
+// expectedErrors collects the regular expressions of ERROR comments
+// found in the package files of pkg and returns them in sorted order
+// (by filename and position).
+func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
+ // scan all package files
+ for filename := range pkg.Files {
+ src, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Fatalf("expectedErrors(%s): %v", pkg.Name, err)
+ }
+
+ var s scanner.Scanner
+ file := fset.AddFile(filename, fset.Base(), len(src))
+ s.Init(file, src, nil, scanner.ScanComments)
+ var prev token.Pos // position of last non-comment token
+ loop:
+ for {
+ pos, tok, lit := s.Scan()
+ switch tok {
+ case token.EOF:
+ break loop
+ case token.COMMENT:
+ s := errRx.FindSubmatch(lit)
+ if len(s) == 2 {
+ list = append(list, &scanner.Error{fset.Position(prev), string(s[1])})
+ }
+ default:
+ prev = pos
+ }
+ }
+ }
+ sort.Sort(list) // multiple files may not be sorted
+ return
+}
+
+
+func testFilter(f *os.FileInfo) bool {
+ return strings.HasSuffix(f.Name, ".go") && f.Name[0] != '.'
+}
+
+
+func checkError(t *testing.T, expected, found *scanner.Error) {
+ rx, err := regexp.Compile(expected.Msg)
+ if err != nil {
+ t.Errorf("%s: %v", expected.Pos, err)
+ return
+ }
+
+ match := rx.MatchString(found.Msg)
+
+ if expected.Pos.Offset != found.Pos.Offset {
+ if match {
+ t.Errorf("%s: expected error should have been at %s", expected.Pos, found.Pos)
+ } else {
+ t.Errorf("%s: error matching %q expected", expected.Pos, expected.Msg)
+ return
+ }
+ }
+
+ if !match {
+ t.Errorf("%s: %q does not match %q", expected.Pos, expected.Msg, found.Msg)
+ }
+}
+
+
+func TestTypeCheck(t *testing.T) {
+ flag.Parse()
+ pkgRx, err := regexp.Compile(*pkgPat)
+ if err != nil {
+ t.Fatalf("illegal flag value %q: %s", *pkgPat, err)
+ }
+
+ pkgs, err := parser.ParseDir(fset, testDir, testFilter, 0)
+ if err != nil {
+ scanner.PrintError(os.Stderr, err)
+ t.Fatalf("packages in %s contain syntax errors", testDir)
+ }
+
+ for _, pkg := range pkgs {
+ if !pkgRx.MatchString(pkg.Name) {
+ continue // only test selected packages
+ }
+
+ if *trace {
+ fmt.Println(pkg.Name)
+ }
+
+ xlist := expectedErrors(t, pkg)
+ err := CheckPackage(fset, pkg, nil)
+ if err != nil {
+ if elist, ok := err.(scanner.ErrorList); ok {
+ // verify that errors match
+ for i := 0; i < len(xlist) && i < len(elist); i++ {
+ checkError(t, xlist[i], elist[i])
+ }
+ // the correct number or errors must have been found
+ if len(xlist) != len(elist) {
+ fmt.Fprintf(os.Stderr, "%s\n", pkg.Name)
+ scanner.PrintError(os.Stderr, elist)
+ fmt.Fprintln(os.Stderr)
+ t.Errorf("TypeCheck(%s): %d errors expected but %d reported", pkg.Name, len(xlist), len(elist))
+ }
+ } else {
+ t.Errorf("TypeCheck(%s): %v", pkg.Name, err)
+ }
+ } else if len(xlist) > 0 {
+ t.Errorf("TypeCheck(%s): %d errors expected but 0 reported", pkg.Name, len(xlist))
+ }
+ }
+}
diff --git a/libgo/go/go/typechecker/universe.go b/libgo/go/go/typechecker/universe.go
new file mode 100644
index 000000000..db950737f
--- /dev/null
+++ b/libgo/go/go/typechecker/universe.go
@@ -0,0 +1,38 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typechecker
+
+import "go/ast"
+
+// TODO(gri) should this be in package ast?
+
+// The Universe scope contains all predeclared identifiers.
+var Universe *ast.Scope
+
+
+func def(obj *ast.Object) {
+ alt := Universe.Insert(obj)
+ if alt != obj {
+ panic("object declared twice")
+ }
+}
+
+
+func init() {
+ Universe = ast.NewScope(nil)
+
+ // basic types
+ for n, name := range ast.BasicTypes {
+ typ := ast.NewType(ast.Basic)
+ typ.N = n
+ obj := ast.NewObj(ast.Typ, name)
+ obj.Type = typ
+ typ.Obj = obj
+ def(obj)
+ }
+
+ // built-in functions
+ // TODO(gri) implement this
+}
diff --git a/libgo/go/gob/codec_test.go b/libgo/go/gob/codec_test.go
new file mode 100644
index 000000000..af941c629
--- /dev/null
+++ b/libgo/go/gob/codec_test.go
@@ -0,0 +1,1355 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "math"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+ "unsafe"
+)
+
+// Guarantee encoding format by comparing some encodings to hand-written values
+type EncodeT struct {
+ x uint64
+ b []byte
+}
+
+var encodeT = []EncodeT{
+ {0x00, []byte{0x00}},
+ {0x0F, []byte{0x0F}},
+ {0xFF, []byte{0xFF, 0xFF}},
+ {0xFFFF, []byte{0xFE, 0xFF, 0xFF}},
+ {0xFFFFFF, []byte{0xFD, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFF, []byte{0xFC, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFF, []byte{0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFF, []byte{0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFFFF, []byte{0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFFFFFF, []byte{0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0x1111, []byte{0xFE, 0x11, 0x11}},
+ {0x1111111111111111, []byte{0xF8, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
+ {0x8888888888888888, []byte{0xF8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}},
+ {1 << 63, []byte{0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+}
+
+// testError is meant to be used as a deferred function to turn a panic(gobError) into a
+// plain test.Error call.
+func testError(t *testing.T) {
+ if e := recover(); e != nil {
+ t.Error(e.(gobError).Error) // Will re-panic if not one of our errors, such as a runtime error.
+ }
+ return
+}
+
+// Test basic encode/decode routines for unsigned integers
+func TestUintCodec(t *testing.T) {
+ defer testError(t)
+ b := new(bytes.Buffer)
+ encState := newEncoderState(nil, b)
+ for _, tt := range encodeT {
+ b.Reset()
+ encState.encodeUint(tt.x)
+ if !bytes.Equal(tt.b, b.Bytes()) {
+ t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes())
+ }
+ }
+ decState := newDecodeState(nil, &b)
+ for u := uint64(0); ; u = (u + 1) * 7 {
+ b.Reset()
+ encState.encodeUint(u)
+ v := decState.decodeUint()
+ if u != v {
+ t.Errorf("Encode/Decode: sent %#x received %#x", u, v)
+ }
+ if u&(1<<63) != 0 {
+ break
+ }
+ }
+}
+
+func verifyInt(i int64, t *testing.T) {
+ defer testError(t)
+ var b = new(bytes.Buffer)
+ encState := newEncoderState(nil, b)
+ encState.encodeInt(i)
+ decState := newDecodeState(nil, &b)
+ decState.buf = make([]byte, 8)
+ j := decState.decodeInt()
+ if i != j {
+ t.Errorf("Encode/Decode: sent %#x received %#x", uint64(i), uint64(j))
+ }
+}
+
+// Test basic encode/decode routines for signed integers
+func TestIntCodec(t *testing.T) {
+ for u := uint64(0); ; u = (u + 1) * 7 {
+ // Do positive and negative values
+ i := int64(u)
+ verifyInt(i, t)
+ verifyInt(-i, t)
+ verifyInt(^i, t)
+ if u&(1<<63) != 0 {
+ break
+ }
+ }
+ verifyInt(-1<<63, t) // a tricky case
+}
+
+// The result of encoding a true boolean with field number 7
+var boolResult = []byte{0x07, 0x01}
+// The result of encoding a number 17 with field number 7
+var signedResult = []byte{0x07, 2 * 17}
+var unsignedResult = []byte{0x07, 17}
+var floatResult = []byte{0x07, 0xFE, 0x31, 0x40}
+// The result of encoding a number 17+19i with field number 7
+var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40}
+// The result of encoding "hello" with field number 7
+var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
+
+func newencoderState(b *bytes.Buffer) *encoderState {
+ b.Reset()
+ state := newEncoderState(nil, b)
+ state.fieldnum = -1
+ return state
+}
+
+// Test instruction execution for encoding.
+// Do not run the machine yet; instead do individual instructions crafted by hand.
+func TestScalarEncInstructions(t *testing.T) {
+ var b = new(bytes.Buffer)
+
+ // bool
+ {
+ data := struct{ a bool }{true}
+ instr := &encInstr{encBool, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(boolResult, b.Bytes()) {
+ t.Errorf("bool enc instructions: expected % x got % x", boolResult, b.Bytes())
+ }
+ }
+
+ // int
+ {
+ b.Reset()
+ data := struct{ a int }{17}
+ instr := &encInstr{encInt, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(signedResult, b.Bytes()) {
+ t.Errorf("int enc instructions: expected % x got % x", signedResult, b.Bytes())
+ }
+ }
+
+ // uint
+ {
+ b.Reset()
+ data := struct{ a uint }{17}
+ instr := &encInstr{encUint, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(unsignedResult, b.Bytes()) {
+ t.Errorf("uint enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+ }
+ }
+
+ // int8
+ {
+ b.Reset()
+ data := struct{ a int8 }{17}
+ instr := &encInstr{encInt8, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(signedResult, b.Bytes()) {
+ t.Errorf("int8 enc instructions: expected % x got % x", signedResult, b.Bytes())
+ }
+ }
+
+ // uint8
+ {
+ b.Reset()
+ data := struct{ a uint8 }{17}
+ instr := &encInstr{encUint8, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(unsignedResult, b.Bytes()) {
+ t.Errorf("uint8 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+ }
+ }
+
+ // int16
+ {
+ b.Reset()
+ data := struct{ a int16 }{17}
+ instr := &encInstr{encInt16, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(signedResult, b.Bytes()) {
+ t.Errorf("int16 enc instructions: expected % x got % x", signedResult, b.Bytes())
+ }
+ }
+
+ // uint16
+ {
+ b.Reset()
+ data := struct{ a uint16 }{17}
+ instr := &encInstr{encUint16, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(unsignedResult, b.Bytes()) {
+ t.Errorf("uint16 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+ }
+ }
+
+ // int32
+ {
+ b.Reset()
+ data := struct{ a int32 }{17}
+ instr := &encInstr{encInt32, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(signedResult, b.Bytes()) {
+ t.Errorf("int32 enc instructions: expected % x got % x", signedResult, b.Bytes())
+ }
+ }
+
+ // uint32
+ {
+ b.Reset()
+ data := struct{ a uint32 }{17}
+ instr := &encInstr{encUint32, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(unsignedResult, b.Bytes()) {
+ t.Errorf("uint32 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+ }
+ }
+
+ // int64
+ {
+ b.Reset()
+ data := struct{ a int64 }{17}
+ instr := &encInstr{encInt64, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(signedResult, b.Bytes()) {
+ t.Errorf("int64 enc instructions: expected % x got % x", signedResult, b.Bytes())
+ }
+ }
+
+ // uint64
+ {
+ b.Reset()
+ data := struct{ a uint64 }{17}
+ instr := &encInstr{encUint64, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(unsignedResult, b.Bytes()) {
+ t.Errorf("uint64 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
+ }
+ }
+
+ // float32
+ {
+ b.Reset()
+ data := struct{ a float32 }{17}
+ instr := &encInstr{encFloat32, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(floatResult, b.Bytes()) {
+ t.Errorf("float32 enc instructions: expected % x got % x", floatResult, b.Bytes())
+ }
+ }
+
+ // float64
+ {
+ b.Reset()
+ data := struct{ a float64 }{17}
+ instr := &encInstr{encFloat64, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(floatResult, b.Bytes()) {
+ t.Errorf("float64 enc instructions: expected % x got % x", floatResult, b.Bytes())
+ }
+ }
+
+ // bytes == []uint8
+ {
+ b.Reset()
+ data := struct{ a []byte }{[]byte("hello")}
+ instr := &encInstr{encUint8Array, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(bytesResult, b.Bytes()) {
+ t.Errorf("bytes enc instructions: expected % x got % x", bytesResult, b.Bytes())
+ }
+ }
+
+ // string
+ {
+ b.Reset()
+ data := struct{ a string }{"hello"}
+ instr := &encInstr{encString, 6, 0, 0}
+ state := newencoderState(b)
+ instr.op(instr, state, unsafe.Pointer(&data))
+ if !bytes.Equal(bytesResult, b.Bytes()) {
+ t.Errorf("string enc instructions: expected % x got % x", bytesResult, b.Bytes())
+ }
+ }
+}
+
+func execDec(typ string, instr *decInstr, state *decodeState, t *testing.T, p unsafe.Pointer) {
+ defer testError(t)
+ v := int(state.decodeUint())
+ if v+state.fieldnum != 6 {
+ t.Fatalf("decoding field number %d, got %d", 6, v+state.fieldnum)
+ }
+ instr.op(instr, state, decIndirect(p, instr.indir))
+ state.fieldnum = 6
+}
+
+func newDecodeStateFromData(data []byte) *decodeState {
+ b := bytes.NewBuffer(data)
+ state := newDecodeState(nil, &b)
+ state.fieldnum = -1
+ return state
+}
+
+// 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")
+
+ // bool
+ {
+ var data struct {
+ a bool
+ }
+ instr := &decInstr{decBool, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(boolResult)
+ execDec("bool", instr, state, t, unsafe.Pointer(&data))
+ if data.a != true {
+ t.Errorf("bool a = %v not true", data.a)
+ }
+ }
+ // int
+ {
+ var data struct {
+ a int
+ }
+ instr := &decInstr{decOpMap[reflect.Int], 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(signedResult)
+ execDec("int", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("int a = %v not 17", data.a)
+ }
+ }
+
+ // uint
+ {
+ var data struct {
+ a uint
+ }
+ instr := &decInstr{decOpMap[reflect.Uint], 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uint", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uint a = %v not 17", data.a)
+ }
+ }
+
+ // int8
+ {
+ var data struct {
+ a int8
+ }
+ instr := &decInstr{decInt8, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(signedResult)
+ execDec("int8", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("int8 a = %v not 17", data.a)
+ }
+ }
+
+ // uint8
+ {
+ var data struct {
+ a uint8
+ }
+ instr := &decInstr{decUint8, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uint8", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uint8 a = %v not 17", data.a)
+ }
+ }
+
+ // int16
+ {
+ var data struct {
+ a int16
+ }
+ instr := &decInstr{decInt16, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(signedResult)
+ execDec("int16", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("int16 a = %v not 17", data.a)
+ }
+ }
+
+ // uint16
+ {
+ var data struct {
+ a uint16
+ }
+ instr := &decInstr{decUint16, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uint16", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uint16 a = %v not 17", data.a)
+ }
+ }
+
+ // int32
+ {
+ var data struct {
+ a int32
+ }
+ instr := &decInstr{decInt32, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(signedResult)
+ execDec("int32", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("int32 a = %v not 17", data.a)
+ }
+ }
+
+ // uint32
+ {
+ var data struct {
+ a uint32
+ }
+ instr := &decInstr{decUint32, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uint32", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uint32 a = %v not 17", data.a)
+ }
+ }
+
+ // uintptr
+ {
+ var data struct {
+ a uintptr
+ }
+ instr := &decInstr{decOpMap[reflect.Uintptr], 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uintptr", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uintptr a = %v not 17", data.a)
+ }
+ }
+
+ // int64
+ {
+ var data struct {
+ a int64
+ }
+ instr := &decInstr{decInt64, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(signedResult)
+ execDec("int64", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("int64 a = %v not 17", data.a)
+ }
+ }
+
+ // uint64
+ {
+ var data struct {
+ a uint64
+ }
+ instr := &decInstr{decUint64, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(unsignedResult)
+ execDec("uint64", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("uint64 a = %v not 17", data.a)
+ }
+ }
+
+ // float32
+ {
+ var data struct {
+ a float32
+ }
+ instr := &decInstr{decFloat32, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(floatResult)
+ execDec("float32", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("float32 a = %v not 17", data.a)
+ }
+ }
+
+ // float64
+ {
+ var data struct {
+ a float64
+ }
+ instr := &decInstr{decFloat64, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(floatResult)
+ execDec("float64", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17 {
+ t.Errorf("float64 a = %v not 17", data.a)
+ }
+ }
+
+ // complex64
+ {
+ var data struct {
+ a complex64
+ }
+ instr := &decInstr{decOpMap[reflect.Complex64], 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(complexResult)
+ execDec("complex", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17+19i {
+ t.Errorf("complex a = %v not 17+19i", data.a)
+ }
+ }
+
+ // complex128
+ {
+ var data struct {
+ a complex128
+ }
+ instr := &decInstr{decOpMap[reflect.Complex128], 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(complexResult)
+ execDec("complex", instr, state, t, unsafe.Pointer(&data))
+ if data.a != 17+19i {
+ t.Errorf("complex a = %v not 17+19i", data.a)
+ }
+ }
+
+ // bytes == []uint8
+ {
+ var data struct {
+ a []byte
+ }
+ instr := &decInstr{decUint8Array, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(bytesResult)
+ execDec("bytes", instr, state, t, unsafe.Pointer(&data))
+ if string(data.a) != "hello" {
+ t.Errorf(`bytes a = %q not "hello"`, string(data.a))
+ }
+ }
+
+ // string
+ {
+ var data struct {
+ a string
+ }
+ instr := &decInstr{decString, 6, 0, 0, ovfl}
+ state := newDecodeStateFromData(bytesResult)
+ execDec("bytes", instr, state, t, unsafe.Pointer(&data))
+ if data.a != "hello" {
+ t.Errorf(`bytes a = %q not "hello"`, data.a)
+ }
+ }
+}
+
+func TestEndToEnd(t *testing.T) {
+ type T2 struct {
+ T string
+ }
+ s1 := "string1"
+ s2 := "string2"
+ type T1 struct {
+ A, B, C int
+ M map[string]*float64
+ N *[3]float64
+ Strs *[2]string
+ Int64s *[]int64
+ RI complex64
+ S string
+ Y []byte
+ T *T2
+ }
+ pi := 3.14159
+ e := 2.71828
+ t1 := &T1{
+ A: 17,
+ B: 18,
+ C: -5,
+ M: map[string]*float64{"pi": &pi, "e": &e},
+ N: &[3]float64{1.5, 2.5, 3.5},
+ Strs: &[2]string{s1, s2},
+ Int64s: &[]int64{77, 89, 123412342134},
+ RI: 17 - 23i,
+ S: "Now is the time",
+ Y: []byte("hello, sailor"),
+ T: &T2{"this is T2"},
+ }
+ b := new(bytes.Buffer)
+ err := NewEncoder(b).Encode(t1)
+ if err != nil {
+ t.Error("encode:", err)
+ }
+ var _t1 T1
+ err = NewDecoder(b).Decode(&_t1)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(t1, &_t1) {
+ t.Errorf("encode expected %v got %v", *t1, _t1)
+ }
+}
+
+func TestOverflow(t *testing.T) {
+ type inputT struct {
+ Maxi int64
+ Mini int64
+ Maxu uint64
+ Maxf float64
+ Minf float64
+ Maxc complex128
+ Minc complex128
+ }
+ var it inputT
+ var err os.Error
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ dec := NewDecoder(b)
+
+ // int8
+ b.Reset()
+ it = inputT{
+ Maxi: math.MaxInt8 + 1,
+ }
+ type outi8 struct {
+ Maxi int8
+ Mini int8
+ }
+ var o1 outi8
+ enc.Encode(it)
+ err = dec.Decode(&o1)
+ if err == nil || err.String() != `value for "Maxi" out of range` {
+ t.Error("wrong overflow error for int8:", err)
+ }
+ it = inputT{
+ Mini: math.MinInt8 - 1,
+ }
+ b.Reset()
+ enc.Encode(it)
+ err = dec.Decode(&o1)
+ if err == nil || err.String() != `value for "Mini" out of range` {
+ t.Error("wrong underflow error for int8:", err)
+ }
+
+ // int16
+ b.Reset()
+ it = inputT{
+ Maxi: math.MaxInt16 + 1,
+ }
+ type outi16 struct {
+ Maxi int16
+ Mini int16
+ }
+ var o2 outi16
+ enc.Encode(it)
+ err = dec.Decode(&o2)
+ if err == nil || err.String() != `value for "Maxi" out of range` {
+ t.Error("wrong overflow error for int16:", err)
+ }
+ it = inputT{
+ Mini: math.MinInt16 - 1,
+ }
+ b.Reset()
+ enc.Encode(it)
+ err = dec.Decode(&o2)
+ if err == nil || err.String() != `value for "Mini" out of range` {
+ t.Error("wrong underflow error for int16:", err)
+ }
+
+ // int32
+ b.Reset()
+ it = inputT{
+ Maxi: math.MaxInt32 + 1,
+ }
+ type outi32 struct {
+ Maxi int32
+ Mini int32
+ }
+ var o3 outi32
+ enc.Encode(it)
+ err = dec.Decode(&o3)
+ if err == nil || err.String() != `value for "Maxi" out of range` {
+ t.Error("wrong overflow error for int32:", err)
+ }
+ it = inputT{
+ Mini: math.MinInt32 - 1,
+ }
+ b.Reset()
+ enc.Encode(it)
+ err = dec.Decode(&o3)
+ if err == nil || err.String() != `value for "Mini" out of range` {
+ t.Error("wrong underflow error for int32:", err)
+ }
+
+ // uint8
+ b.Reset()
+ it = inputT{
+ Maxu: math.MaxUint8 + 1,
+ }
+ type outu8 struct {
+ Maxu uint8
+ }
+ var o4 outu8
+ enc.Encode(it)
+ err = dec.Decode(&o4)
+ if err == nil || err.String() != `value for "Maxu" out of range` {
+ t.Error("wrong overflow error for uint8:", err)
+ }
+
+ // uint16
+ b.Reset()
+ it = inputT{
+ Maxu: math.MaxUint16 + 1,
+ }
+ type outu16 struct {
+ Maxu uint16
+ }
+ var o5 outu16
+ enc.Encode(it)
+ err = dec.Decode(&o5)
+ if err == nil || err.String() != `value for "Maxu" out of range` {
+ t.Error("wrong overflow error for uint16:", err)
+ }
+
+ // uint32
+ b.Reset()
+ it = inputT{
+ Maxu: math.MaxUint32 + 1,
+ }
+ type outu32 struct {
+ Maxu uint32
+ }
+ var o6 outu32
+ enc.Encode(it)
+ err = dec.Decode(&o6)
+ if err == nil || err.String() != `value for "Maxu" out of range` {
+ t.Error("wrong overflow error for uint32:", err)
+ }
+
+ // float32
+ b.Reset()
+ it = inputT{
+ Maxf: math.MaxFloat32 * 2,
+ }
+ type outf32 struct {
+ Maxf float32
+ Minf float32
+ }
+ var o7 outf32
+ enc.Encode(it)
+ err = dec.Decode(&o7)
+ if err == nil || err.String() != `value for "Maxf" out of range` {
+ t.Error("wrong overflow error for float32:", err)
+ }
+
+ // complex64
+ b.Reset()
+ it = inputT{
+ Maxc: complex(math.MaxFloat32*2, math.MaxFloat32*2),
+ }
+ type outc64 struct {
+ Maxc complex64
+ Minc complex64
+ }
+ var o8 outc64
+ enc.Encode(it)
+ err = dec.Decode(&o8)
+ if err == nil || err.String() != `value for "Maxc" out of range` {
+ t.Error("wrong overflow error for complex64:", err)
+ }
+}
+
+
+func TestNesting(t *testing.T) {
+ type RT struct {
+ A string
+ Next *RT
+ }
+ rt := new(RT)
+ rt.A = "level1"
+ rt.Next = new(RT)
+ rt.Next.A = "level2"
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(rt)
+ var drt RT
+ dec := NewDecoder(b)
+ err := dec.Decode(&drt)
+ if err != nil {
+ t.Fatal("decoder error:", err)
+ }
+ if drt.A != rt.A {
+ t.Errorf("nesting: encode expected %v got %v", *rt, drt)
+ }
+ if drt.Next == nil {
+ t.Errorf("nesting: recursion failed")
+ }
+ if drt.Next.A != rt.Next.A {
+ t.Errorf("nesting: encode expected %v got %v", *rt.Next, *drt.Next)
+ }
+}
+
+// These three structures have the same data with different indirections
+type T0 struct {
+ A int
+ B int
+ C int
+ D int
+}
+type T1 struct {
+ A int
+ B *int
+ C **int
+ D ***int
+}
+type T2 struct {
+ A ***int
+ B **int
+ C *int
+ D int
+}
+
+func TestAutoIndirection(t *testing.T) {
+ // First transfer t1 into t0
+ var t1 T1
+ t1.A = 17
+ t1.B = new(int)
+ *t1.B = 177
+ t1.C = new(*int)
+ *t1.C = new(int)
+ **t1.C = 1777
+ t1.D = new(**int)
+ *t1.D = new(*int)
+ **t1.D = new(int)
+ ***t1.D = 17777
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ enc.Encode(t1)
+ dec := NewDecoder(b)
+ var t0 T0
+ dec.Decode(&t0)
+ if t0.A != 17 || t0.B != 177 || t0.C != 1777 || t0.D != 17777 {
+ t.Errorf("t1->t0: expected {17 177 1777 17777}; got %v", t0)
+ }
+
+ // Now transfer t2 into t0
+ var t2 T2
+ t2.D = 17777
+ t2.C = new(int)
+ *t2.C = 1777
+ t2.B = new(*int)
+ *t2.B = new(int)
+ **t2.B = 177
+ t2.A = new(**int)
+ *t2.A = new(*int)
+ **t2.A = new(int)
+ ***t2.A = 17
+ b.Reset()
+ enc.Encode(t2)
+ t0 = T0{}
+ dec.Decode(&t0)
+ if t0.A != 17 || t0.B != 177 || t0.C != 1777 || t0.D != 17777 {
+ t.Errorf("t2->t0 expected {17 177 1777 17777}; got %v", t0)
+ }
+
+ // Now transfer t0 into t1
+ t0 = T0{17, 177, 1777, 17777}
+ b.Reset()
+ enc.Encode(t0)
+ t1 = T1{}
+ dec.Decode(&t1)
+ if t1.A != 17 || *t1.B != 177 || **t1.C != 1777 || ***t1.D != 17777 {
+ t.Errorf("t0->t1 expected {17 177 1777 17777}; got {%d %d %d %d}", t1.A, *t1.B, **t1.C, ***t1.D)
+ }
+
+ // Now transfer t0 into t2
+ b.Reset()
+ enc.Encode(t0)
+ t2 = T2{}
+ dec.Decode(&t2)
+ if ***t2.A != 17 || **t2.B != 177 || *t2.C != 1777 || t2.D != 17777 {
+ t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.A, **t2.B, *t2.C, t2.D)
+ }
+
+ // Now do t2 again but without pre-allocated pointers.
+ b.Reset()
+ enc.Encode(t0)
+ ***t2.A = 0
+ **t2.B = 0
+ *t2.C = 0
+ t2.D = 0
+ dec.Decode(&t2)
+ if ***t2.A != 17 || **t2.B != 177 || *t2.C != 1777 || t2.D != 17777 {
+ t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.A, **t2.B, *t2.C, t2.D)
+ }
+}
+
+type RT0 struct {
+ A int
+ B string
+ C float64
+}
+type RT1 struct {
+ C float64
+ B string
+ A int
+ NotSet string
+}
+
+func TestReorderedFields(t *testing.T) {
+ var rt0 RT0
+ rt0.A = 17
+ rt0.B = "hello"
+ rt0.C = 3.14159
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(rt0)
+ dec := NewDecoder(b)
+ var rt1 RT1
+ // Wire type is RT0, local type is RT1.
+ err := dec.Decode(&rt1)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if rt0.A != rt1.A || rt0.B != rt1.B || rt0.C != rt1.C {
+ t.Errorf("rt1->rt0: expected %v; got %v", rt0, rt1)
+ }
+}
+
+// Like an RT0 but with fields we'll ignore on the decode side.
+type IT0 struct {
+ A int64
+ B string
+ Ignore_d []int
+ Ignore_e [3]float64
+ Ignore_f bool
+ Ignore_g string
+ Ignore_h []byte
+ Ignore_i *RT1
+ Ignore_m map[string]int
+ C float64
+}
+
+func TestIgnoredFields(t *testing.T) {
+ var it0 IT0
+ it0.A = 17
+ it0.B = "hello"
+ it0.C = 3.14159
+ it0.Ignore_d = []int{1, 2, 3}
+ it0.Ignore_e[0] = 1.0
+ it0.Ignore_e[1] = 2.0
+ it0.Ignore_e[2] = 3.0
+ it0.Ignore_f = true
+ it0.Ignore_g = "pay no attention"
+ it0.Ignore_h = []byte("to the curtain")
+ it0.Ignore_i = &RT1{3.1, "hi", 7, "hello"}
+ it0.Ignore_m = map[string]int{"one": 1, "two": 2}
+
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(it0)
+ dec := NewDecoder(b)
+ var rt1 RT1
+ // Wire type is IT0, local type is RT1.
+ err := dec.Decode(&rt1)
+ if err != nil {
+ t.Error("error: ", err)
+ }
+ if int(it0.A) != rt1.A || it0.B != rt1.B || it0.C != rt1.C {
+ t.Errorf("rt0->rt1: expected %v; got %v", it0, rt1)
+ }
+}
+
+type Bad0 struct {
+ ch chan int
+ c float64
+}
+
+var nilEncoder *Encoder
+
+func TestInvalidField(t *testing.T) {
+ var bad0 Bad0
+ bad0.ch = make(chan int)
+ b := new(bytes.Buffer)
+ err := nilEncoder.encode(b, reflect.NewValue(&bad0))
+ if err == nil {
+ t.Error("expected error; got none")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("expected type error; got", err)
+ }
+}
+
+type Indirect struct {
+ A ***[3]int
+ S ***[]int
+ M ****map[string]int
+}
+
+type Direct struct {
+ A [3]int
+ S []int
+ M map[string]int
+}
+
+func TestIndirectSliceMapArray(t *testing.T) {
+ // Marshal indirect, unmarshal to direct.
+ i := new(Indirect)
+ i.A = new(**[3]int)
+ *i.A = new(*[3]int)
+ **i.A = new([3]int)
+ ***i.A = [3]int{1, 2, 3}
+ i.S = new(**[]int)
+ *i.S = new(*[]int)
+ **i.S = new([]int)
+ ***i.S = []int{4, 5, 6}
+ i.M = new(***map[string]int)
+ *i.M = new(**map[string]int)
+ **i.M = new(*map[string]int)
+ ***i.M = new(map[string]int)
+ ****i.M = map[string]int{"one": 1, "two": 2, "three": 3}
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(i)
+ dec := NewDecoder(b)
+ var d Direct
+ err := dec.Decode(&d)
+ if err != nil {
+ t.Error("error: ", err)
+ }
+ if len(d.A) != 3 || d.A[0] != 1 || d.A[1] != 2 || d.A[2] != 3 {
+ t.Errorf("indirect to direct: d.A is %v not %v", d.A, ***i.A)
+ }
+ if len(d.S) != 3 || d.S[0] != 4 || d.S[1] != 5 || d.S[2] != 6 {
+ t.Errorf("indirect to direct: d.S is %v not %v", d.S, ***i.S)
+ }
+ if len(d.M) != 3 || d.M["one"] != 1 || d.M["two"] != 2 || d.M["three"] != 3 {
+ t.Errorf("indirect to direct: d.M is %v not %v", d.M, ***i.M)
+ }
+ // Marshal direct, unmarshal to indirect.
+ d.A = [3]int{11, 22, 33}
+ d.S = []int{44, 55, 66}
+ d.M = map[string]int{"four": 4, "five": 5, "six": 6}
+ i = new(Indirect)
+ b.Reset()
+ NewEncoder(b).Encode(d)
+ dec = NewDecoder(b)
+ err = dec.Decode(&i)
+ if err != nil {
+ t.Fatal("error: ", err)
+ }
+ if len(***i.A) != 3 || (***i.A)[0] != 11 || (***i.A)[1] != 22 || (***i.A)[2] != 33 {
+ t.Errorf("direct to indirect: ***i.A is %v not %v", ***i.A, d.A)
+ }
+ if len(***i.S) != 3 || (***i.S)[0] != 44 || (***i.S)[1] != 55 || (***i.S)[2] != 66 {
+ t.Errorf("direct to indirect: ***i.S is %v not %v", ***i.S, ***i.S)
+ }
+ if len(****i.M) != 3 || (****i.M)["four"] != 4 || (****i.M)["five"] != 5 || (****i.M)["six"] != 6 {
+ t.Errorf("direct to indirect: ****i.M is %v not %v", ****i.M, d.M)
+ }
+}
+
+// An interface with several implementations
+type Squarer interface {
+ Square() int
+}
+
+type Int int
+
+func (i Int) Square() int {
+ return int(i * i)
+}
+
+type Float float64
+
+func (f Float) Square() int {
+ return int(f * f)
+}
+
+type Vector []int
+
+func (v Vector) Square() int {
+ sum := 0
+ for _, x := range v {
+ sum += x * x
+ }
+ return sum
+}
+
+type Point struct {
+ a, b int
+}
+
+func (p Point) Square() int {
+ return p.a*p.a + p.b*p.b
+}
+
+// A struct with interfaces in it.
+type InterfaceItem struct {
+ I int
+ Sq1, Sq2, Sq3 Squarer
+ F float64
+ Sq []Squarer
+}
+
+// The same struct without interfaces
+type NoInterfaceItem struct {
+ I int
+ F float64
+}
+
+func TestInterface(t *testing.T) {
+ iVal := Int(3)
+ fVal := Float(5)
+ // Sending a Vector will require that the receiver define a type in the middle of
+ // receiving the value for item2.
+ vVal := Vector{1, 2, 3}
+ b := new(bytes.Buffer)
+ item1 := &InterfaceItem{1, iVal, fVal, vVal, 11.5, []Squarer{iVal, fVal, nil, vVal}}
+ // Register the types.
+ Register(Int(0))
+ Register(Float(0))
+ Register(Vector{})
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := InterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if item2.I != item1.I {
+ t.Error("normal int did not decode correctly")
+ }
+ if item2.Sq1 == nil || item2.Sq1.Square() != iVal.Square() {
+ t.Error("Int did not decode correctly")
+ }
+ if item2.Sq2 == nil || item2.Sq2.Square() != fVal.Square() {
+ t.Error("Float did not decode correctly")
+ }
+ if item2.Sq3 == nil || item2.Sq3.Square() != vVal.Square() {
+ t.Error("Vector did not decode correctly")
+ }
+ if item2.F != item1.F {
+ t.Error("normal float did not decode correctly")
+ }
+ // Now check that we received a slice of Squarers correctly, including a nil element
+ if len(item1.Sq) != len(item2.Sq) {
+ t.Fatalf("[]Squarer length wrong: got %d; expected %d", len(item2.Sq), len(item1.Sq))
+ }
+ for i, v1 := range item1.Sq {
+ v2 := item2.Sq[i]
+ if v1 == nil || v2 == nil {
+ if v1 != nil || v2 != nil {
+ t.Errorf("item %d inconsistent nils", i)
+ }
+ continue
+ if v1.Square() != v2.Square() {
+ t.Errorf("item %d inconsistent values: %v %v", i, v1, v2)
+ }
+ }
+ }
+
+}
+
+// A struct with all basic types, stored in interfaces.
+type BasicInterfaceItem struct {
+ Int, Int8, Int16, Int32, Int64 interface{}
+ Uint, Uint8, Uint16, Uint32, Uint64 interface{}
+ Float32, Float64 interface{}
+ Complex64, Complex128 interface{}
+ Bool interface{}
+ String interface{}
+ Bytes interface{}
+}
+
+func TestInterfaceBasic(t *testing.T) {
+ b := new(bytes.Buffer)
+ item1 := &BasicInterfaceItem{
+ int(1), int8(1), int16(1), int32(1), int64(1),
+ uint(1), uint8(1), uint16(1), uint32(1), uint64(1),
+ float32(1), 1.0,
+ complex64(0i), complex128(0i),
+ true,
+ "hello",
+ []byte("sailor"),
+ }
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := &BasicInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(item1, item2) {
+ t.Errorf("encode expected %v got %v", item1, item2)
+ }
+ // Hand check a couple for correct types.
+ if v, ok := item2.Bool.(bool); !ok || !v {
+ t.Error("boolean should be true")
+ }
+ if v, ok := item2.String.(string); !ok || v != item1.String.(string) {
+ t.Errorf("string should be %v is %v", item1.String, v)
+ }
+}
+
+type String string
+
+type PtrInterfaceItem struct {
+ Str1 interface{} // basic
+ Str2 interface{} // derived
+}
+
+// We'll send pointers; should receive values.
+// Also check that we can register T but send *T.
+func TestInterfacePointer(t *testing.T) {
+ b := new(bytes.Buffer)
+ str1 := "howdy"
+ str2 := String("kiddo")
+ item1 := &PtrInterfaceItem{
+ &str1,
+ &str2,
+ }
+ // Register the type.
+ Register(str2)
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := &PtrInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ // Hand test for correct types and values.
+ if v, ok := item2.Str1.(string); !ok || v != str1 {
+ t.Errorf("basic string failed: %q should be %q", v, str1)
+ }
+ if v, ok := item2.Str2.(String); !ok || v != str2 {
+ t.Errorf("derived type String failed: %q should be %q", v, str2)
+ }
+}
+
+func TestIgnoreInterface(t *testing.T) {
+ iVal := Int(3)
+ fVal := Float(5)
+ // Sending a Point will require that the receiver define a type in the middle of
+ // receiving the value for item2.
+ pVal := Point{2, 3}
+ b := new(bytes.Buffer)
+ item1 := &InterfaceItem{1, iVal, fVal, pVal, 11.5, nil}
+ // Register the types.
+ Register(Int(0))
+ Register(Float(0))
+ Register(Point{})
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := NoInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if item2.I != item1.I {
+ t.Error("normal int did not decode correctly")
+ }
+ if item2.F != item2.F {
+ t.Error("normal float did not decode correctly")
+ }
+}
+
+type U struct {
+ A int
+ B string
+ c float64
+ D uint
+}
+
+func TestUnexportedFields(t *testing.T) {
+ var u0 U
+ u0.A = 17
+ u0.B = "hello"
+ u0.c = 3.14159
+ u0.D = 23
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(u0)
+ dec := NewDecoder(b)
+ var u1 U
+ u1.c = 1234.
+ err := dec.Decode(&u1)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if u0.A != u0.A || u0.B != u1.B || u0.D != u1.D {
+ t.Errorf("u1->u0: expected %v; got %v", u0, u1)
+ }
+ if u1.c != 1234. {
+ t.Error("u1.c modified")
+ }
+}
+
+// A type that won't be defined in the gob until we send it in an interface value.
+type OnTheFly struct {
+ A int
+}
+
+type DT struct {
+ // X OnTheFly
+ A int
+ B string
+ C float64
+ I interface{}
+ J interface{}
+ I_nil interface{}
+ M map[string]int
+ T [3]int
+ S []string
+}
+
+func TestDebug(t *testing.T) {
+ if debugFunc == nil {
+ return
+ }
+ Register(OnTheFly{})
+ var dt DT
+ dt.A = 17
+ dt.B = "hello"
+ dt.C = 3.14159
+ dt.I = 271828
+ dt.J = OnTheFly{3}
+ dt.I_nil = nil
+ dt.M = map[string]int{"one": 1, "two": 2}
+ dt.T = [3]int{11, 22, 33}
+ dt.S = []string{"hi", "joe"}
+ b := new(bytes.Buffer)
+ err := NewEncoder(b).Encode(dt)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ debugBuffer := bytes.NewBuffer(b.Bytes())
+ dt2 := &DT{}
+ err = NewDecoder(b).Decode(&dt2)
+ if err != nil {
+ t.Error("decode:", err)
+ }
+ debugFunc(debugBuffer)
+}
diff --git a/libgo/go/gob/decode.go b/libgo/go/gob/decode.go
new file mode 100644
index 000000000..2db75215c
--- /dev/null
+++ b/libgo/go/gob/decode.go
@@ -0,0 +1,1020 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+// TODO(rsc): When garbage collector changes, revisit
+// the allocations in this file that use unsafe.Pointer.
+
+import (
+ "bytes"
+ "io"
+ "math"
+ "os"
+ "reflect"
+ "unicode"
+ "unsafe"
+ "utf8"
+)
+
+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: internal error: field numbers out of bounds")
+)
+
+// The execution state of an instance of the decoder. A new state
+// is created for nested objects.
+type decodeState struct {
+ dec *Decoder
+ // The buffer is stored with an extra indirection because it may be replaced
+ // if we load a type during decode (when reading an interface value).
+ b **bytes.Buffer
+ fieldnum int // the last field number read.
+ buf []byte
+}
+
+func newDecodeState(dec *Decoder, b **bytes.Buffer) *decodeState {
+ d := new(decodeState)
+ d.dec = dec
+ d.b = b
+ d.buf = make([]byte, uint64Size)
+ return d
+}
+
+func overflow(name string) os.ErrorString {
+ return os.ErrorString(`value for "` + name + `" out of range`)
+}
+
+// decodeUintReader reads an encoded unsigned integer from an io.Reader.
+// Used only by the Decoder to read the message length.
+func decodeUintReader(r io.Reader, buf []byte) (x uint64, err os.Error) {
+ _, err = r.Read(buf[0:1])
+ if err != nil {
+ return
+ }
+ b := buf[0]
+ if b <= 0x7f {
+ return uint64(b), nil
+ }
+ nb := -int(int8(b))
+ if nb > uint64Size {
+ err = errBadUint
+ return
+ }
+ var n int
+ n, err = io.ReadFull(r, buf[0:nb])
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+ }
+ // Could check that the high byte is zero but it's not worth it.
+ for i := 0; i < n; i++ {
+ x <<= 8
+ x |= uint64(buf[i])
+ }
+ return
+}
+
+// decodeUint reads an encoded unsigned integer from state.r.
+// Does not check for overflow.
+func (state *decodeState) decodeUint() (x uint64) {
+ b, err := state.b.ReadByte()
+ if err != nil {
+ error(err)
+ }
+ if b <= 0x7f {
+ return uint64(b)
+ }
+ nb := -int(int8(b))
+ if nb > uint64Size {
+ error(errBadUint)
+ }
+ n, err := state.b.Read(state.buf[0:nb])
+ if err != nil {
+ error(err)
+ }
+ // Don't need to check error; it's safe to loop regardless.
+ // Could check that the high byte is zero but it's not worth it.
+ for i := 0; i < n; i++ {
+ x <<= 8
+ x |= uint64(state.buf[i])
+ }
+ return x
+}
+
+// decodeInt reads an encoded signed integer from state.r.
+// Does not check for overflow.
+func (state *decodeState) decodeInt() int64 {
+ x := state.decodeUint()
+ if x&1 != 0 {
+ return ^int64(x >> 1)
+ }
+ return int64(x >> 1)
+}
+
+type decOp func(i *decInstr, state *decodeState, 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)
+}
+
+// Since the encoder writes no zeros, if we arrive at a decoder we have
+// a value to extract and store. The field number has already been read
+// (it's how we knew to call this decoder).
+// Each decoder is responsible for handling any indirections associated
+// with the data structure. If any pointer so reached is nil, allocation must
+// be done.
+
+// Walk the pointer hierarchy, allocating if we find a nil. Stop one before the end.
+func decIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
+ for ; indir > 1; indir-- {
+ if *(*unsafe.Pointer)(p) == nil {
+ // Allocation required
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(unsafe.Pointer))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ return p
+}
+
+func ignoreUint(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ state.decodeUint()
+}
+
+func ignoreTwoUints(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ state.decodeUint()
+ state.decodeUint()
+}
+
+func decBool(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(bool))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ *(*bool)(p) = state.decodeInt() != 0
+}
+
+func decInt8(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int8))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeInt()
+ if v < math.MinInt8 || math.MaxInt8 < v {
+ error(i.ovfl)
+ } else {
+ *(*int8)(p) = int8(v)
+ }
+}
+
+func decUint8(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint8))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeUint()
+ if math.MaxUint8 < v {
+ error(i.ovfl)
+ } else {
+ *(*uint8)(p) = uint8(v)
+ }
+}
+
+func decInt16(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int16))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeInt()
+ if v < math.MinInt16 || math.MaxInt16 < v {
+ error(i.ovfl)
+ } else {
+ *(*int16)(p) = int16(v)
+ }
+}
+
+func decUint16(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint16))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeUint()
+ if math.MaxUint16 < v {
+ error(i.ovfl)
+ } else {
+ *(*uint16)(p) = uint16(v)
+ }
+}
+
+func decInt32(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int32))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeInt()
+ if v < math.MinInt32 || math.MaxInt32 < v {
+ error(i.ovfl)
+ } else {
+ *(*int32)(p) = int32(v)
+ }
+}
+
+func decUint32(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint32))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ v := state.decodeUint()
+ if math.MaxUint32 < v {
+ error(i.ovfl)
+ } else {
+ *(*uint32)(p) = uint32(v)
+ }
+}
+
+func decInt64(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(int64))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ *(*int64)(p) = int64(state.decodeInt())
+}
+
+func decUint64(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint64))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ *(*uint64)(p) = uint64(state.decodeUint())
+}
+
+// Floating-point numbers are transmitted as uint64s holding the bits
+// of the underlying representation. They are sent byte-reversed, with
+// the exponent end coming out first, so integer floating point numbers
+// (for example) transmit more compactly. This routine does the
+// unswizzling.
+func floatFromBits(u uint64) float64 {
+ var v uint64
+ for i := 0; i < 8; i++ {
+ v <<= 8
+ v |= u & 0xFF
+ u >>= 8
+ }
+ return math.Float64frombits(v)
+}
+
+func storeFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ v := floatFromBits(state.decodeUint())
+ av := v
+ if av < 0 {
+ av = -av
+ }
+ // +Inf is OK in both 32- and 64-bit floats. Underflow is always OK.
+ if math.MaxFloat32 < av && av <= math.MaxFloat64 {
+ error(i.ovfl)
+ } else {
+ *(*float32)(p) = float32(v)
+ }
+}
+
+func decFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(float32))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ storeFloat32(i, state, p)
+}
+
+func decFloat64(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(float64))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ *(*float64)(p) = floatFromBits(uint64(state.decodeUint()))
+}
+
+// Complex numbers are just a pair of floating-point numbers, real part first.
+func decComplex64(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex64))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ storeFloat32(i, state, p)
+ storeFloat32(i, state, unsafe.Pointer(uintptr(p)+uintptr(unsafe.Sizeof(float32(0)))))
+}
+
+func decComplex128(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex128))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ real := floatFromBits(uint64(state.decodeUint()))
+ imag := floatFromBits(uint64(state.decodeUint()))
+ *(*complex128)(p) = complex(real, imag)
+}
+
+// uint8 arrays are encoded as an unsigned count followed by the raw bytes.
+func decUint8Array(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new([]uint8))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ b := make([]uint8, state.decodeUint())
+ state.b.Read(b)
+ *(*[]uint8)(p) = b
+}
+
+// Strings are encoded as an unsigned count followed by the raw bytes.
+func decString(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ if i.indir > 0 {
+ if *(*unsafe.Pointer)(p) == nil {
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(new([]byte))
+ }
+ p = *(*unsafe.Pointer)(p)
+ }
+ b := make([]byte, state.decodeUint())
+ state.b.Read(b)
+ *(*string)(p) = string(b)
+}
+
+func ignoreUint8Array(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ b := make([]byte, state.decodeUint())
+ state.b.Read(b)
+}
+
+// Execution engine
+
+// The encoder engine is an array of instructions indexed by field number of the incoming
+// decoder. It is executed with random access according to field number.
+type decEngine struct {
+ instr []decInstr
+ numInstr int // the number of active instructions
+}
+
+// allocate makes sure storage is available for an object of underlying type rtyp
+// that is indir levels of indirection through p.
+func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr {
+ if indir == 0 {
+ return p
+ }
+ up := unsafe.Pointer(p)
+ if indir > 1 {
+ up = decIndirect(up, indir)
+ }
+ if *(*unsafe.Pointer)(up) == nil {
+ // Allocate object.
+ *(*unsafe.Pointer)(up) = unsafe.New(rtyp)
+ }
+ return *(*uintptr)(up)
+}
+
+func (dec *Decoder) decodeSingle(engine *decEngine, rtyp reflect.Type, b **bytes.Buffer, p uintptr, indir int) (err os.Error) {
+ defer catchError(&err)
+ p = allocate(rtyp, p, indir)
+ state := newDecodeState(dec, b)
+ state.fieldnum = singletonField
+ basep := p
+ delta := int(state.decodeUint())
+ if delta != 0 {
+ errorf("gob decode: corrupted data: non-zero delta for singleton")
+ }
+ instr := &engine.instr[singletonField]
+ ptr := unsafe.Pointer(basep) // offset will be zero
+ if instr.indir > 1 {
+ ptr = decIndirect(ptr, instr.indir)
+ }
+ instr.op(instr, state, ptr)
+ return nil
+}
+
+func (dec *Decoder) decodeStruct(engine *decEngine, rtyp *reflect.StructType, b **bytes.Buffer, p uintptr, indir int) (err os.Error) {
+ defer catchError(&err)
+ p = allocate(rtyp, p, indir)
+ state := newDecodeState(dec, b)
+ state.fieldnum = -1
+ basep := p
+ for state.b.Len() > 0 {
+ delta := int(state.decodeUint())
+ if delta < 0 {
+ errorf("gob decode: corrupted data: negative delta")
+ }
+ if delta == 0 { // struct terminator is zero delta fieldnum
+ break
+ }
+ fieldnum := state.fieldnum + delta
+ if fieldnum >= len(engine.instr) {
+ error(errRange)
+ break
+ }
+ instr := &engine.instr[fieldnum]
+ p := unsafe.Pointer(basep + instr.offset)
+ if instr.indir > 1 {
+ p = decIndirect(p, instr.indir)
+ }
+ instr.op(instr, state, p)
+ state.fieldnum = fieldnum
+ }
+ return nil
+}
+
+func (dec *Decoder) ignoreStruct(engine *decEngine, b **bytes.Buffer) (err os.Error) {
+ defer catchError(&err)
+ state := newDecodeState(dec, b)
+ state.fieldnum = -1
+ for state.b.Len() > 0 {
+ delta := int(state.decodeUint())
+ if delta < 0 {
+ errorf("gob ignore decode: corrupted data: negative delta")
+ }
+ if delta == 0 { // struct terminator is zero delta fieldnum
+ break
+ }
+ fieldnum := state.fieldnum + delta
+ if fieldnum >= len(engine.instr) {
+ error(errRange)
+ }
+ instr := &engine.instr[fieldnum]
+ instr.op(instr, state, unsafe.Pointer(nil))
+ state.fieldnum = fieldnum
+ }
+ return nil
+}
+
+func (dec *Decoder) decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) {
+ instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl}
+ for i := 0; i < length; i++ {
+ up := unsafe.Pointer(p)
+ if elemIndir > 1 {
+ up = decIndirect(up, elemIndir)
+ }
+ elemOp(instr, state, up)
+ p += uintptr(elemWid)
+ }
+}
+
+func (dec *Decoder) decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.ErrorString) {
+ if indir > 0 {
+ p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect
+ }
+ if n := state.decodeUint(); n != uint64(length) {
+ errorf("gob: length mismatch in decodeArray")
+ }
+ dec.decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir, ovfl)
+}
+
+func decodeIntoValue(state *decodeState, op decOp, indir int, v reflect.Value, ovfl os.ErrorString) reflect.Value {
+ instr := &decInstr{op, 0, indir, 0, ovfl}
+ up := unsafe.Pointer(v.Addr())
+ if indir > 1 {
+ up = decIndirect(up, indir)
+ }
+ op(instr, state, up)
+ return v
+}
+
+func (dec *Decoder) decodeMap(mtyp *reflect.MapType, state *decodeState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.ErrorString) {
+ if indir > 0 {
+ p = allocate(mtyp, p, 1) // All but the last level has been allocated by dec.Indirect
+ }
+ up := unsafe.Pointer(p)
+ if *(*unsafe.Pointer)(up) == nil { // maps are represented as a pointer in the runtime
+ // Allocate map.
+ *(*unsafe.Pointer)(up) = unsafe.Pointer(reflect.MakeMap(mtyp).Get())
+ }
+ // Maps cannot be accessed by moving addresses around the way
+ // that slices etc. can. We must recover a full reflection value for
+ // the iteration.
+ v := reflect.NewValue(unsafe.Unreflect(mtyp, unsafe.Pointer((p)))).(*reflect.MapValue)
+ n := int(state.decodeUint())
+ for i := 0; i < n; i++ {
+ key := decodeIntoValue(state, keyOp, keyIndir, reflect.MakeZero(mtyp.Key()), ovfl)
+ elem := decodeIntoValue(state, elemOp, elemIndir, reflect.MakeZero(mtyp.Elem()), ovfl)
+ v.SetElem(key, elem)
+ }
+}
+
+func (dec *Decoder) ignoreArrayHelper(state *decodeState, elemOp decOp, length int) {
+ instr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")}
+ for i := 0; i < length; i++ {
+ elemOp(instr, state, nil)
+ }
+}
+
+func (dec *Decoder) ignoreArray(state *decodeState, elemOp decOp, length int) {
+ if n := state.decodeUint(); n != uint64(length) {
+ errorf("gob: length mismatch in ignoreArray")
+ }
+ dec.ignoreArrayHelper(state, elemOp, length)
+}
+
+func (dec *Decoder) ignoreMap(state *decodeState, 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")}
+ for i := 0; i < n; i++ {
+ keyOp(keyInstr, state, nil)
+ elemOp(elemInstr, state, nil)
+ }
+}
+
+func (dec *Decoder) decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) {
+ n := int(uintptr(state.decodeUint()))
+ if indir > 0 {
+ up := unsafe.Pointer(p)
+ if *(*unsafe.Pointer)(up) == nil {
+ // Allocate the slice header.
+ *(*unsafe.Pointer)(up) = unsafe.Pointer(new([]unsafe.Pointer))
+ }
+ p = *(*uintptr)(up)
+ }
+ // Allocate storage for the slice elements, that is, the underlying array.
+ // Always write a header at p.
+ hdrp := (*reflect.SliceHeader)(unsafe.Pointer(p))
+ hdrp.Data = uintptr(unsafe.NewArray(atyp.Elem(), n))
+ hdrp.Len = n
+ hdrp.Cap = n
+ dec.decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, n, elemIndir, ovfl)
+}
+
+func (dec *Decoder) ignoreSlice(state *decodeState, elemOp decOp) {
+ dec.ignoreArrayHelper(state, elemOp, int(state.decodeUint()))
+}
+
+// setInterfaceValue sets an interface value to a concrete value through
+// reflection. If the concrete value does not implement the interface, the
+// setting will panic. This routine turns the panic into an error return.
+// This dance avoids manually checking that the value satisfies the
+// interface.
+// TODO(rsc): avoid panic+recover after fixing issue 327.
+func setInterfaceValue(ivalue *reflect.InterfaceValue, value reflect.Value) {
+ defer func() {
+ if e := recover(); e != nil {
+ error(e.(os.Error))
+ }
+ }()
+ ivalue.Set(value)
+}
+
+// decodeInterface receives the name of a concrete type followed by its value.
+// If the name is empty, the value is nil and no value is sent.
+func (dec *Decoder) decodeInterface(ityp *reflect.InterfaceType, state *decodeState, p uintptr, indir int) {
+ // Create an interface reflect.Value. We need one even for the nil case.
+ ivalue := reflect.MakeZero(ityp).(*reflect.InterfaceValue)
+ // Read the name of the concrete type.
+ b := make([]byte, state.decodeUint())
+ state.b.Read(b)
+ name := string(b)
+ if name == "" {
+ // Copy the representation of the nil interface value to the target.
+ // This is horribly unsafe and special.
+ *(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.Get()
+ return
+ }
+ // The concrete type must be registered.
+ typ, ok := nameToConcreteType[name]
+ if !ok {
+ errorf("gob: name not registered for interface: %q", name)
+ }
+ // Read the concrete value.
+ value := reflect.MakeZero(typ)
+ dec.decodeValueFromBuffer(value, false, true)
+ if dec.err != nil {
+ error(dec.err)
+ }
+ // Allocate the destination interface value.
+ if indir > 0 {
+ p = allocate(ityp, p, 1) // All but the last level has been allocated by dec.Indirect
+ }
+ // Assign the concrete value to the interface.
+ // Tread carefully; it might not satisfy the interface.
+ setInterfaceValue(ivalue, value)
+ // Copy the representation of the interface value to the target.
+ // This is horribly unsafe and special.
+ *(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.Get()
+}
+
+func (dec *Decoder) ignoreInterface(state *decodeState) {
+ // Read the name of the concrete type.
+ b := make([]byte, state.decodeUint())
+ _, err := state.b.Read(b)
+ if err != nil {
+ error(err)
+ }
+ dec.decodeValueFromBuffer(nil, true, true)
+ if dec.err != nil {
+ error(err)
+ }
+}
+
+// Index by Go types.
+var decOpMap = []decOp{
+ reflect.Bool: decBool,
+ reflect.Int8: decInt8,
+ reflect.Int16: decInt16,
+ reflect.Int32: decInt32,
+ reflect.Int64: decInt64,
+ reflect.Uint8: decUint8,
+ reflect.Uint16: decUint16,
+ reflect.Uint32: decUint32,
+ reflect.Uint64: decUint64,
+ reflect.Float32: decFloat32,
+ reflect.Float64: decFloat64,
+ reflect.Complex64: decComplex64,
+ reflect.Complex128: decComplex128,
+ reflect.String: decString,
+}
+
+// Indexed by gob types. tComplex will be added during type.init().
+var decIgnoreOpMap = map[typeId]decOp{
+ tBool: ignoreUint,
+ tInt: ignoreUint,
+ tUint: ignoreUint,
+ tFloat: ignoreUint,
+ tBytes: ignoreUint8Array,
+ tString: ignoreUint8Array,
+ tComplex: ignoreTwoUints,
+}
+
+// Return the decoding op for the base type under rt and
+// the indirection count to reach it.
+func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp, int) {
+ typ, indir := indirect(rt)
+ var op decOp
+ k := typ.Kind()
+ if int(k) < len(decOpMap) {
+ op = decOpMap[k]
+ }
+ if op == nil {
+ // Special cases
+ switch t := typ.(type) {
+ case *reflect.ArrayType:
+ name = "element of " + name
+ elemId := dec.wireType[wireId].ArrayT.Elem
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
+ ovfl := overflow(name)
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ state.dec.decodeArray(t, state, uintptr(p), elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir, ovfl)
+ }
+
+ case *reflect.MapType:
+ name = "element of " + name
+ keyId := dec.wireType[wireId].MapT.Key
+ elemId := dec.wireType[wireId].MapT.Elem
+ keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), name)
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
+ ovfl := overflow(name)
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ up := unsafe.Pointer(p)
+ state.dec.decodeMap(t, state, uintptr(up), keyOp, elemOp, i.indir, keyIndir, elemIndir, ovfl)
+ }
+
+ case *reflect.SliceType:
+ name = "element of " + name
+ if t.Elem().Kind() == reflect.Uint8 {
+ op = decUint8Array
+ break
+ }
+ var elemId typeId
+ if tt, ok := builtinIdToType[wireId]; ok {
+ elemId = tt.(*sliceType).Elem
+ } else {
+ elemId = dec.wireType[wireId].SliceT.Elem
+ }
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
+ ovfl := overflow(name)
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ state.dec.decodeSlice(t, state, uintptr(p), elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
+ }
+
+ case *reflect.StructType:
+ // Generate a closure that calls out to the engine for the nested type.
+ enginePtr, err := dec.getDecEnginePtr(wireId, typ)
+ if err != nil {
+ error(err)
+ }
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ // indirect through enginePtr to delay evaluation for recursive structs
+ err = dec.decodeStruct(*enginePtr, t, state.b, uintptr(p), i.indir)
+ if err != nil {
+ error(err)
+ }
+ }
+ case *reflect.InterfaceType:
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ dec.decodeInterface(t, state, uintptr(p), i.indir)
+ }
+ }
+ }
+ if op == nil {
+ errorf("gob: decode can't handle type %s", rt.String())
+ }
+ return op, indir
+}
+
+// Return the decoding op for a field that has no destination.
+func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
+ op, ok := decIgnoreOpMap[wireId]
+ if !ok {
+ if wireId == tInterface {
+ // Special case because it's a method: the ignored item might
+ // define types and we need to record their state in the decoder.
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ dec.ignoreInterface(state)
+ }
+ return op
+ }
+ // Special cases
+ wire := dec.wireType[wireId]
+ switch {
+ case wire == nil:
+ panic("internal error: can't find ignore op for type " + wireId.string())
+ case wire.ArrayT != nil:
+ elemId := wire.ArrayT.Elem
+ elemOp := dec.decIgnoreOpFor(elemId)
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ state.dec.ignoreArray(state, elemOp, wire.ArrayT.Len)
+ }
+
+ case wire.MapT != nil:
+ keyId := dec.wireType[wireId].MapT.Key
+ elemId := dec.wireType[wireId].MapT.Elem
+ keyOp := dec.decIgnoreOpFor(keyId)
+ elemOp := dec.decIgnoreOpFor(elemId)
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ state.dec.ignoreMap(state, keyOp, elemOp)
+ }
+
+ case wire.SliceT != nil:
+ elemId := wire.SliceT.Elem
+ elemOp := dec.decIgnoreOpFor(elemId)
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ state.dec.ignoreSlice(state, elemOp)
+ }
+
+ case wire.StructT != nil:
+ // Generate a closure that calls out to the engine for the nested type.
+ enginePtr, err := dec.getIgnoreEnginePtr(wireId)
+ if err != nil {
+ error(err)
+ }
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ // indirect through enginePtr to delay evaluation for recursive structs
+ state.dec.ignoreStruct(*enginePtr, state.b)
+ }
+ }
+ }
+ if op == nil {
+ errorf("ignore can't handle type %s", wireId.string())
+ }
+ return op
+}
+
+// Are these two gob Types compatible?
+// Answers the question for basic types, arrays, and slices.
+// Structs are considered ok; fields will be checked later.
+func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
+ fr, _ = indirect(fr)
+ switch t := fr.(type) {
+ default:
+ // map, chan, etc: cannot handle.
+ return false
+ case *reflect.BoolType:
+ return fw == tBool
+ case *reflect.IntType:
+ return fw == tInt
+ case *reflect.UintType:
+ return fw == tUint
+ case *reflect.FloatType:
+ return fw == tFloat
+ case *reflect.ComplexType:
+ return fw == tComplex
+ case *reflect.StringType:
+ return fw == tString
+ case *reflect.InterfaceType:
+ return fw == tInterface
+ case *reflect.ArrayType:
+ wire, ok := dec.wireType[fw]
+ if !ok || wire.ArrayT == nil {
+ return false
+ }
+ array := wire.ArrayT
+ return t.Len() == array.Len && dec.compatibleType(t.Elem(), array.Elem)
+ case *reflect.MapType:
+ wire, ok := dec.wireType[fw]
+ if !ok || wire.MapT == nil {
+ return false
+ }
+ MapType := wire.MapT
+ return dec.compatibleType(t.Key(), MapType.Key) && dec.compatibleType(t.Elem(), MapType.Elem)
+ case *reflect.SliceType:
+ // Is it an array of bytes?
+ if t.Elem().Kind() == reflect.Uint8 {
+ return fw == tBytes
+ }
+ // Extract and compare element types.
+ var sw *sliceType
+ if tt, ok := builtinIdToType[fw]; ok {
+ sw = tt.(*sliceType)
+ } else {
+ sw = dec.wireType[fw].SliceT
+ }
+ elem, _ := indirect(t.Elem())
+ return sw != nil && dec.compatibleType(elem, sw.Elem)
+ case *reflect.StructType:
+ return true
+ }
+ return true
+}
+
+// typeString returns a human-readable description of the type identified by remoteId.
+func (dec *Decoder) typeString(remoteId typeId) string {
+ if t := idToType[remoteId]; t != nil {
+ // globally known type.
+ return t.string()
+ }
+ return dec.wireType[remoteId].string()
+}
+
+
+func (dec *Decoder) compileSingle(remoteId typeId, rt reflect.Type) (engine *decEngine, err os.Error) {
+ engine = new(decEngine)
+ engine.instr = make([]decInstr, 1) // one item
+ name := rt.String() // best we can do
+ if !dec.compatibleType(rt, remoteId) {
+ return nil, os.ErrorString("gob: wrong type received for local value " + name + ": " + dec.typeString(remoteId))
+ }
+ op, indir := dec.decOpFor(remoteId, rt, name)
+ ovfl := os.ErrorString(`value for "` + name + `" out of range`)
+ engine.instr[singletonField] = decInstr{op, singletonField, indir, 0, ovfl}
+ engine.numInstr = 1
+ return
+}
+
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
+func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEngine, err os.Error) {
+ defer catchError(&err)
+ srt, ok := rt.(*reflect.StructType)
+ if !ok {
+ return dec.compileSingle(remoteId, rt)
+ }
+ var wireStruct *structType
+ // Builtin types can come from global pool; the rest must be defined by the decoder.
+ // Also we know we're decoding a struct now, so the client must have sent one.
+ if t, ok := builtinIdToType[remoteId]; ok {
+ wireStruct, _ = t.(*structType)
+ } else {
+ wireStruct = dec.wireType[remoteId].StructT
+ }
+ if wireStruct == nil {
+ errorf("gob: type mismatch in decoder: want struct type %s; got non-struct", rt.String())
+ }
+ engine = new(decEngine)
+ engine.instr = make([]decInstr, len(wireStruct.Field))
+ // Loop over the fields of the wire type.
+ for fieldnum := 0; fieldnum < len(wireStruct.Field); fieldnum++ {
+ wireField := wireStruct.Field[fieldnum]
+ if wireField.Name == "" {
+ errorf("gob: empty name for remote field of type %s", wireStruct.Name)
+ }
+ ovfl := overflow(wireField.Name)
+ // Find the field of the local type with the same name.
+ localField, present := srt.FieldByName(wireField.Name)
+ // TODO(r): anonymous names
+ if !present || !isExported(wireField.Name) {
+ op := dec.decIgnoreOpFor(wireField.Id)
+ engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl}
+ continue
+ }
+ if !dec.compatibleType(localField.Type, wireField.Id) {
+ errorf("gob: wrong type (%s) for received field %s.%s", localField.Type, wireStruct.Name, wireField.Name)
+ }
+ op, indir := dec.decOpFor(wireField.Id, localField.Type, localField.Name)
+ engine.instr[fieldnum] = decInstr{op, fieldnum, indir, uintptr(localField.Offset), ovfl}
+ engine.numInstr++
+ }
+ return
+}
+
+func (dec *Decoder) getDecEnginePtr(remoteId typeId, rt reflect.Type) (enginePtr **decEngine, err os.Error) {
+ decoderMap, ok := dec.decoderCache[rt]
+ if !ok {
+ decoderMap = make(map[typeId]**decEngine)
+ dec.decoderCache[rt] = decoderMap
+ }
+ if enginePtr, ok = decoderMap[remoteId]; !ok {
+ // To handle recursive types, mark this engine as underway before compiling.
+ enginePtr = new(*decEngine)
+ decoderMap[remoteId] = enginePtr
+ *enginePtr, err = dec.compileDec(remoteId, rt)
+ if err != nil {
+ decoderMap[remoteId] = nil, false
+ }
+ }
+ return
+}
+
+// When ignoring struct data, in effect we compile it into this type
+type emptyStruct struct{}
+
+var emptyStructType = reflect.Typeof(emptyStruct{})
+
+func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err os.Error) {
+ var ok bool
+ if enginePtr, ok = dec.ignorerCache[wireId]; !ok {
+ // To handle recursive types, mark this engine as underway before compiling.
+ enginePtr = new(*decEngine)
+ dec.ignorerCache[wireId] = enginePtr
+ *enginePtr, err = dec.compileDec(wireId, emptyStructType)
+ if err != nil {
+ dec.ignorerCache[wireId] = nil, false
+ }
+ }
+ return
+}
+
+func (dec *Decoder) decode(wireId typeId, val reflect.Value) os.Error {
+ // Dereference down to the underlying struct type.
+ rt, indir := indirect(val.Type())
+ enginePtr, err := dec.getDecEnginePtr(wireId, rt)
+ if err != nil {
+ return err
+ }
+ engine := *enginePtr
+ if st, ok := rt.(*reflect.StructType); ok {
+ if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
+ name := rt.Name()
+ return os.ErrorString("gob: type mismatch: no fields matched compiling decoder for " + name)
+ }
+ return dec.decodeStruct(engine, st, dec.state.b, uintptr(val.Addr()), indir)
+ }
+ return dec.decodeSingle(engine, rt, dec.state.b, uintptr(val.Addr()), indir)
+}
+
+func init() {
+ var iop, uop decOp
+ switch reflect.Typeof(int(0)).Bits() {
+ case 32:
+ iop = decInt32
+ uop = decUint32
+ case 64:
+ iop = decInt64
+ uop = decUint64
+ default:
+ panic("gob: unknown size of int/uint")
+ }
+ decOpMap[reflect.Int] = iop
+ decOpMap[reflect.Uint] = uop
+
+ // Finally uintptr
+ switch reflect.Typeof(uintptr(0)).Bits() {
+ case 32:
+ uop = decUint32
+ case 64:
+ uop = decUint64
+ default:
+ panic("gob: unknown size of uintptr")
+ }
+ decOpMap[reflect.Uintptr] = uop
+}
diff --git a/libgo/go/gob/decoder.go b/libgo/go/gob/decoder.go
new file mode 100644
index 000000000..664001a4b
--- /dev/null
+++ b/libgo/go/gob/decoder.go
@@ -0,0 +1,164 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "sync"
+)
+
+// A Decoder manages the receipt of type and data information read from the
+// remote side of a connection.
+type Decoder struct {
+ mutex sync.Mutex // each item must be received atomically
+ r io.Reader // source of the data
+ wireType map[typeId]*wireType // map from remote ID to local description
+ decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
+ ignorerCache map[typeId]**decEngine // ditto for ignored objects
+ state *decodeState // reads data from in-memory buffer
+ countState *decodeState // reads counts from wire
+ buf []byte
+ countBuf [9]byte // counts may be uint64s (unlikely!), require 9 bytes
+ byteBuffer *bytes.Buffer
+ err os.Error
+}
+
+// NewDecoder returns a new decoder that reads from the io.Reader.
+func NewDecoder(r io.Reader) *Decoder {
+ dec := new(Decoder)
+ dec.r = r
+ dec.wireType = make(map[typeId]*wireType)
+ dec.state = newDecodeState(dec, &dec.byteBuffer) // buffer set in Decode()
+ dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
+ dec.ignorerCache = make(map[typeId]**decEngine)
+
+ return dec
+}
+
+// recvType loads the definition of a type and reloads the Decoder's buffer.
+func (dec *Decoder) recvType(id typeId) {
+ // Have we already seen this type? That's an error
+ if dec.wireType[id] != nil {
+ dec.err = os.ErrorString("gob: duplicate type received")
+ return
+ }
+
+ // Type:
+ wire := new(wireType)
+ dec.err = dec.decode(tWireType, reflect.NewValue(wire))
+ if dec.err != nil {
+ return
+ }
+ // Remember we've seen this type.
+ dec.wireType[id] = wire
+
+ // Load the next parcel.
+ dec.recv()
+}
+
+// Decode reads the next value from the connection and stores
+// it in the data represented by the empty interface value.
+// The value underlying e must be the correct type for the next
+// data item received, and must be a pointer.
+func (dec *Decoder) Decode(e interface{}) os.Error {
+ value := reflect.NewValue(e)
+ // 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")
+ return dec.err
+ }
+ return dec.DecodeValue(value)
+}
+
+// recv reads the next count-delimited item from the input. It is the converse
+// of Encoder.send.
+func (dec *Decoder) recv() {
+ // Read a count.
+ var nbytes uint64
+ nbytes, dec.err = decodeUintReader(dec.r, dec.countBuf[0:])
+ if dec.err != nil {
+ return
+ }
+ // Allocate the buffer.
+ if nbytes > uint64(len(dec.buf)) {
+ dec.buf = make([]byte, nbytes+1000)
+ }
+ dec.byteBuffer = bytes.NewBuffer(dec.buf[0:nbytes])
+
+ // Read the data
+ _, dec.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
+ if dec.err != nil {
+ if dec.err == os.EOF {
+ dec.err = io.ErrUnexpectedEOF
+ }
+ return
+ }
+}
+
+// decodeValueFromBuffer grabs the next value from the input. The Decoder's
+// buffer already contains data. If the next item in the buffer is a type
+// descriptor, it may be necessary to reload the buffer, but recvType does that.
+func (dec *Decoder) decodeValueFromBuffer(value reflect.Value, ignoreInterfaceValue, countPresent bool) {
+ for dec.state.b.Len() > 0 {
+ // Receive a type id.
+ id := typeId(dec.state.decodeInt())
+
+ // Is it a new type?
+ if id < 0 { // 0 is the error state, handled above
+ // If the id is negative, we have a type.
+ dec.recvType(-id)
+ if dec.err != nil {
+ break
+ }
+ continue
+ }
+
+ // Make sure the type has been defined already or is a builtin type (for
+ // top-level singleton values).
+ if dec.wireType[id] == nil && builtinIdToType[id] == nil {
+ dec.err = errBadType
+ break
+ }
+ // An interface value is preceded by a byte count.
+ if countPresent {
+ count := int(dec.state.decodeUint())
+ if ignoreInterfaceValue {
+ // An interface value is preceded by a byte count. Just skip that many bytes.
+ dec.state.b.Next(int(count))
+ break
+ }
+ // Otherwise fall through and decode it.
+ }
+ dec.err = dec.decode(id, value)
+ break
+ }
+}
+
+// DecodeValue reads the next value from the connection and stores
+// it in the data represented by the reflection value.
+// The value must be the correct type for the next
+// data item received.
+func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
+ // Make sure we're single-threaded through here.
+ dec.mutex.Lock()
+ defer dec.mutex.Unlock()
+
+ dec.err = nil
+ dec.recv()
+ if dec.err != nil {
+ return dec.err
+ }
+ dec.decodeValueFromBuffer(value, false, false)
+ return dec.err
+}
+
+// If debug.go is compiled into the program , debugFunc prints a human-readable
+// representation of the gob data read from r by calling that file's Debug function.
+// Otherwise it is nil.
+var debugFunc func(io.Reader)
diff --git a/libgo/go/gob/doc.go b/libgo/go/gob/doc.go
new file mode 100644
index 000000000..31253f16d
--- /dev/null
+++ b/libgo/go/gob/doc.go
@@ -0,0 +1,307 @@
+// 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.
+
+/*
+The gob package manages streams of gobs - binary values exchanged between an
+Encoder (transmitter) and a Decoder (receiver). A typical use is transporting
+arguments and results of remote procedure calls (RPCs) such as those provided by
+package "rpc".
+
+A stream of gobs is self-describing. Each data item in the stream is preceded by
+a specification of its type, expressed in terms of a small set of predefined
+types. Pointers are not transmitted, but the things they point to are
+transmitted; that is, the values are flattened. Recursive types work fine, but
+recursive values (data with cycles) are problematic. This may change.
+
+To use gobs, create an Encoder and present it with a series of data items as
+values or addresses that can be dereferenced to values. The Encoder makes sure
+all type information is sent before it is needed. At the receive side, a
+Decoder retrieves values from the encoded stream and unpacks them into local
+variables.
+
+The source and destination values/types need not correspond exactly. For structs,
+fields (identified by name) that are in the source but absent from the receiving
+variable will be ignored. Fields that are in the receiving variable but missing
+from the transmitted type or value will be ignored in the destination. If a field
+with the same name is present in both, their types must be compatible. Both the
+receiver and transmitter will do all necessary indirection and dereferencing to
+convert between gobs and actual Go values. For instance, a gob type that is
+schematically,
+
+ struct { a, b int }
+
+can be sent from or received into any of these Go types:
+
+ struct { a, b int } // the same
+ *struct { a, b int } // extra indirection of the struct
+ struct { *a, **b int } // extra indirection of the fields
+ struct { a, b int64 } // different concrete value type; see below
+
+It may also be received into any of these:
+
+ struct { a, b int } // the same
+ struct { b, a int } // ordering doesn't matter; matching is by name
+ struct { a, b, c int } // extra field (c) ignored
+ struct { b int } // missing field (a) ignored; data will be dropped
+ struct { b, c int } // missing field (a) ignored; extra field (c) ignored.
+
+Attempting to receive into these types will draw a decode error:
+
+ struct { a int; b uint } // change of signedness for b
+ struct { a int; b float } // change of type for b
+ struct { } // no field names in common
+ struct { c, d int } // no field names in common
+
+Integers are transmitted two ways: arbitrary precision signed integers or
+arbitrary precision unsigned integers. There is no int8, int16 etc.
+discrimination in the gob format; there are only signed and unsigned integers. As
+described below, the transmitter sends the value in a variable-length encoding;
+the receiver accepts the value and stores it in the destination variable.
+Floating-point numbers are always sent using IEEE-754 64-bit precision (see
+below).
+
+Signed integers may be received into any signed integer variable: int, int16, etc.;
+unsigned integers may be received into any unsigned integer variable; and floating
+point values may be received into any floating point variable. However,
+the destination variable must be able to represent the value or the decode
+operation will fail.
+
+Structs, arrays and slices are also supported. Strings and arrays of bytes are
+supported with a special, efficient representation (see below).
+
+Functions and channels cannot be sent in a gob. Attempting
+to encode a value that contains one will fail.
+
+The rest of this comment documents the encoding, details that are not important
+for most users. Details are presented bottom-up.
+
+An unsigned integer is sent one of two ways. If it is less than 128, it is sent
+as a byte with that value. Otherwise it is sent as a minimal-length big-endian
+(high byte first) byte stream holding the value, preceded by one byte holding the
+byte count, negated. Thus 0 is transmitted as (00), 7 is transmitted as (07) and
+256 is transmitted as (FE 01 00).
+
+A boolean is encoded within an unsigned integer: 0 for false, 1 for true.
+
+A signed integer, i, is encoded within an unsigned integer, u. Within u, bits 1
+upward contain the value; bit 0 says whether they should be complemented upon
+receipt. The encode algorithm looks like this:
+
+ uint u;
+ if i < 0 {
+ u = (^i << 1) | 1 // complement i, bit 0 is 1
+ } else {
+ u = (i << 1) // do not complement i, bit 0 is 0
+ }
+ encodeUnsigned(u)
+
+The low bit is therefore analogous to a sign bit, but making it the complement bit
+instead guarantees that the largest negative integer is not a special case. For
+example, -129=^128=(^256>>1) encodes as (FE 01 01).
+
+Floating-point numbers are always sent as a representation of a float64 value.
+That value is converted to a uint64 using math.Float64bits. The uint64 is then
+byte-reversed and sent as a regular unsigned integer. The byte-reversal means the
+exponent and high-precision part of the mantissa go first. Since the low bits are
+often zero, this can save encoding bytes. For instance, 17.0 is encoded in only
+three bytes (FE 31 40).
+
+Strings and slices of bytes are sent as an unsigned count followed by that many
+uninterpreted bytes of the value.
+
+All other slices and arrays are sent as an unsigned count followed by that many
+elements using the standard gob encoding for their type, recursively.
+
+Structs are sent as a sequence of (field number, field value) pairs. The field
+value is sent using the standard gob encoding for its type, recursively. If a
+field has the zero value for its type, it is omitted from the transmission. The
+field number is defined by the type of the encoded struct: the first field of the
+encoded type is field 0, the second is field 1, etc. When encoding a value, the
+field numbers are delta encoded for efficiency and the fields are always sent in
+order of increasing field number; the deltas are therefore unsigned. The
+initialization for the delta encoding sets the field number to -1, so an unsigned
+integer field 0 with value 7 is transmitted as unsigned delta = 1, unsigned value
+= 7 or (01 07). Finally, after all the fields have been sent a terminating mark
+denotes the end of the struct. That mark is a delta=0 value, which has
+representation (00).
+
+Interface types are not checked for compatibility; all interface types are
+treated, for transmission, as members of a single "interface" type, analogous to
+int or []byte - in effect they're all treated as interface{}. Interface values
+are transmitted as a string identifying the concrete type being sent (a name
+that must be pre-defined by calling Register), followed by a byte count of the
+length of the following data (so the value can be skipped if it cannot be
+stored), followed by the usual encoding of concrete (dynamic) value stored in
+the interface value. (A nil interface value is identified by the empty string
+and transmits no value.) Upon receipt, the decoder verifies that the unpacked
+concrete item satisfies the interface of the receiving variable.
+
+The representation of types is described below. When a type is defined on a given
+connection between an Encoder and Decoder, it is assigned a signed integer type
+id. When Encoder.Encode(v) is called, it makes sure there is an id assigned for
+the type of v and all its elements and then it sends the pair (typeid, encoded-v)
+where typeid is the type id of the encoded type of v and encoded-v is the gob
+encoding of the value v.
+
+To define a type, the encoder chooses an unused, positive type id and sends the
+pair (-type id, encoded-type) where encoded-type is the gob encoding of a wireType
+description, constructed from these types:
+
+ type wireType struct {
+ ArrayT *ArrayType
+ SliceT *SliceType
+ StructT *StructType
+ MapT *MapType
+ }
+ type ArrayType struct {
+ CommonType
+ Elem typeId
+ Len int
+ }
+ type CommonType {
+ Name string // the name of the struct type
+ Id int // the id of the type, repeated so it's inside the type
+ }
+ type SliceType struct {
+ CommonType
+ Elem typeId
+ }
+ type StructType struct {
+ CommonType
+ Field []*fieldType // the fields of the struct.
+ }
+ type FieldType struct {
+ Name string // the name of the field.
+ Id int // the type id of the field, which must be already defined
+ }
+ type MapType struct {
+ CommonType
+ Key typeId
+ Elem typeId
+ }
+
+If there are nested type ids, the types for all inner type ids must be defined
+before the top-level type id is used to describe an encoded-v.
+
+For simplicity in setup, the connection is defined to understand these types a
+priori, as well as the basic gob types int, uint, etc. Their ids are:
+
+ bool 1
+ int 2
+ uint 3
+ float 4
+ []byte 5
+ string 6
+ complex 7
+ interface 8
+ // gap for reserved ids.
+ WireType 16
+ ArrayType 17
+ CommonType 18
+ SliceType 19
+ StructType 20
+ FieldType 21
+ // 22 is slice of fieldType.
+ MapType 23
+
+Finally, each message created by a call to Encode is preceded by an encoded
+unsigned integer count of the number of bytes remaining in the message. After
+the initial type name, interface values are wrapped the same way; in effect, the
+interface value acts like a recursive invocation of Encode.
+
+In summary, a gob stream looks like
+
+ (byteCount (-type id, encoding of a wireType)* (type id, encoding of a value))*
+
+where * signifies zero or more repetitions and the type id of a value must
+be predefined or be defined before the value in the stream.
+*/
+package gob
+
+/*
+For implementers and the curious, here is an encoded example. Given
+ type Point struct {x, y int}
+and the value
+ p := Point{22, 33}
+the bytes transmitted that encode p will be:
+ 1f ff 81 03 01 01 05 50 6f 69 6e 74 01 ff 82 00
+ 01 02 01 01 78 01 04 00 01 01 79 01 04 00 00 00
+ 07 ff 82 01 2c 01 42 00
+They are determined as follows.
+
+Since this is the first transmission of type Point, the type descriptor
+for Point itself must be sent before the value. This is the first type
+we've sent on this Encoder, so it has type id 65 (0 through 64 are
+reserved).
+
+ 1f // This item (a type descriptor) is 31 bytes long.
+ ff 81 // The negative of the id for the type we're defining, -65.
+ // This is one byte (indicated by FF = -1) followed by
+ // ^-65<<1 | 1. The low 1 bit signals to complement the
+ // rest upon receipt.
+
+ // Now we send a type descriptor, which is itself a struct (wireType).
+ // The type of wireType itself is known (it's built in, as is the type of
+ // all its components), so we just need to send a *value* of type wireType
+ // that represents type "Point".
+ // Here starts the encoding of that value.
+ // Set the field number implicitly to -1; this is done at the beginning
+ // of every struct, including nested structs.
+ 03 // Add 3 to field number; now 2 (wireType.structType; this is a struct).
+ // structType starts with an embedded commonType, which appears
+ // as a regular structure here too.
+ 01 // add 1 to field number (now 0); start of embedded commonType.
+ 01 // add 1 to field number (now 0, the name of the type)
+ 05 // string is (unsigned) 5 bytes long
+ 50 6f 69 6e 74 // wireType.structType.commonType.name = "Point"
+ 01 // add 1 to field number (now 1, the id of the type)
+ ff 82 // wireType.structType.commonType._id = 65
+ 00 // end of embedded wiretype.structType.commonType struct
+ 01 // add 1 to field number (now 1, the field array in wireType.structType)
+ 02 // There are two fields in the type (len(structType.field))
+ 01 // Start of first field structure; add 1 to get field number 0: field[0].name
+ 01 // 1 byte
+ 78 // structType.field[0].name = "x"
+ 01 // Add 1 to get field number 1: field[0].id
+ 04 // structType.field[0].typeId is 2 (signed int).
+ 00 // End of structType.field[0]; start structType.field[1]; set field number to -1.
+ 01 // Add 1 to get field number 0: field[1].name
+ 01 // 1 byte
+ 79 // structType.field[1].name = "y"
+ 01 // Add 1 to get field number 1: field[0].id
+ 04 // struct.Type.field[1].typeId is 2 (signed int).
+ 00 // End of structType.field[1]; end of structType.field.
+ 00 // end of wireType.structType structure
+ 00 // end of wireType structure
+
+Now we can send the Point value. Again the field number resets to -1:
+
+ 07 // this value is 7 bytes long
+ ff 82 // the type number, 65 (1 byte (-FF) followed by 65<<1)
+ 01 // add one to field number, yielding field 0
+ 2c // encoding of signed "22" (0x22 = 44 = 22<<1); Point.x = 22
+ 01 // add one to field number, yielding field 1
+ 42 // encoding of signed "33" (0x42 = 66 = 33<<1); Point.y = 33
+ 00 // end of structure
+
+The type encoding is long and fairly intricate but we send it only once.
+If p is transmitted a second time, the type is already known so the
+output will be just:
+
+ 07 ff 82 01 2c 01 42 00
+
+A single non-struct value at top level is transmitted like a field with
+delta tag 0. For instance, a signed integer with value 3 presented as
+the argument to Encode will emit:
+
+ 03 04 00 06
+
+Which represents:
+
+ 03 // this value is 3 bytes long
+ 04 // the type number, 2, represents an integer
+ 00 // tag delta 0
+ 06 // value 3
+
+*/
diff --git a/libgo/go/gob/encode.go b/libgo/go/gob/encode.go
new file mode 100644
index 000000000..d286a7e00
--- /dev/null
+++ b/libgo/go/gob/encode.go
@@ -0,0 +1,573 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "io"
+ "math"
+ "os"
+ "reflect"
+ "unsafe"
+)
+
+const uint64Size = unsafe.Sizeof(uint64(0))
+
+// The global execution state of an instance of the encoder.
+// Field numbers are delta encoded and always increase. The field
+// number is initialized to -1 so 0 comes out as delta(1). A delta of
+// 0 terminates the structure.
+type encoderState struct {
+ enc *Encoder
+ b *bytes.Buffer
+ sendZero bool // encoding an array element or map key/value pair; send zero values
+ fieldnum int // the last field number written.
+ buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation.
+}
+
+func newEncoderState(enc *Encoder, b *bytes.Buffer) *encoderState {
+ return &encoderState{enc: enc, b: b}
+}
+
+// Unsigned integers have a two-state encoding. If the number is less
+// than 128 (0 through 0x7F), its value is written directly.
+// Otherwise the value is written in big-endian byte order preceded
+// by the byte length, negated.
+
+// encodeUint writes an encoded unsigned integer to state.b.
+func (state *encoderState) encodeUint(x uint64) {
+ if x <= 0x7F {
+ err := state.b.WriteByte(uint8(x))
+ if err != nil {
+ error(err)
+ }
+ return
+ }
+ var n, m int
+ m = uint64Size
+ for n = 1; x > 0; n++ {
+ state.buf[m] = uint8(x & 0xFF)
+ x >>= 8
+ m--
+ }
+ state.buf[m] = uint8(-(n - 1))
+ n, err := state.b.Write(state.buf[m : uint64Size+1])
+ if err != nil {
+ error(err)
+ }
+}
+
+// encodeInt writes an encoded signed integer to state.w.
+// The low bit of the encoding says whether to bit complement the (other bits of the)
+// uint to recover the int.
+func (state *encoderState) encodeInt(i int64) {
+ var x uint64
+ if i < 0 {
+ x = uint64(^i<<1) | 1
+ } else {
+ x = uint64(i << 1)
+ }
+ state.encodeUint(uint64(x))
+}
+
+type encOp func(i *encInstr, state *encoderState, p unsafe.Pointer)
+
+// The 'instructions' of the encoding machine
+type encInstr struct {
+ op encOp
+ field int // field number
+ indir int // how many pointer indirections to reach the value in the struct
+ offset uintptr // offset in the structure of the field to encode
+}
+
+// Emit a field number and update the state to record its value for delta encoding.
+// If the instruction pointer is nil, do nothing
+func (state *encoderState) update(instr *encInstr) {
+ if instr != nil {
+ state.encodeUint(uint64(instr.field - state.fieldnum))
+ state.fieldnum = instr.field
+ }
+}
+
+// Each encoder is responsible for handling any indirections associated
+// with the data structure. If any pointer so reached is nil, no bytes are written.
+// If the data item is zero, no bytes are written.
+// Otherwise, the output (for a scalar) is the field number, as an encoded integer,
+// followed by the field data in its appropriate format.
+
+func encIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
+ for ; indir > 0; indir-- {
+ p = *(*unsafe.Pointer)(p)
+ if p == nil {
+ return unsafe.Pointer(nil)
+ }
+ }
+ return p
+}
+
+func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ b := *(*bool)(p)
+ if b || state.sendZero {
+ state.update(i)
+ if b {
+ state.encodeUint(1)
+ } else {
+ state.encodeUint(0)
+ }
+ }
+}
+
+func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := int64(*(*int)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeInt(v)
+ }
+}
+
+func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := uint64(*(*uint)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := int64(*(*int8)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeInt(v)
+ }
+}
+
+func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := uint64(*(*uint8)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := int64(*(*int16)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeInt(v)
+ }
+}
+
+func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := uint64(*(*uint16)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := int64(*(*int32)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeInt(v)
+ }
+}
+
+func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := uint64(*(*uint32)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := *(*int64)(p)
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeInt(v)
+ }
+}
+
+func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := *(*uint64)(p)
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+func encUintptr(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ v := uint64(*(*uintptr)(p))
+ if v != 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+// Floating-point numbers are transmitted as uint64s holding the bits
+// of the underlying representation. They are sent byte-reversed, with
+// the exponent end coming out first, so integer floating point numbers
+// (for example) transmit more compactly. This routine does the
+// swizzling.
+func floatBits(f float64) uint64 {
+ u := math.Float64bits(f)
+ var v uint64
+ for i := 0; i < 8; i++ {
+ v <<= 8
+ v |= u & 0xFF
+ u >>= 8
+ }
+ return v
+}
+
+func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ f := *(*float32)(p)
+ if f != 0 || state.sendZero {
+ v := floatBits(float64(f))
+ state.update(i)
+ state.encodeUint(v)
+ }
+}
+
+func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ f := *(*float64)(p)
+ if f != 0 || state.sendZero {
+ state.update(i)
+ v := floatBits(f)
+ state.encodeUint(v)
+ }
+}
+
+// Complex numbers are just a pair of floating-point numbers, real part first.
+func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ c := *(*complex64)(p)
+ if c != 0+0i || state.sendZero {
+ rpart := floatBits(float64(real(c)))
+ ipart := floatBits(float64(imag(c)))
+ state.update(i)
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
+ }
+}
+
+func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ c := *(*complex128)(p)
+ if c != 0+0i || state.sendZero {
+ rpart := floatBits(real(c))
+ ipart := floatBits(imag(c))
+ state.update(i)
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
+ }
+}
+
+func encNoOp(i *encInstr, state *encoderState, p unsafe.Pointer) {
+}
+
+// Byte arrays are encoded as an unsigned count followed by the raw bytes.
+func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ b := *(*[]byte)(p)
+ if len(b) > 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(uint64(len(b)))
+ state.b.Write(b)
+ }
+}
+
+// Strings are encoded as an unsigned count followed by the raw bytes.
+func encString(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ s := *(*string)(p)
+ if len(s) > 0 || state.sendZero {
+ state.update(i)
+ state.encodeUint(uint64(len(s)))
+ io.WriteString(state.b, s)
+ }
+}
+
+// The end of a struct is marked by a delta field number of 0.
+func encStructTerminator(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ state.encodeUint(0)
+}
+
+// Execution engine
+
+// The encoder engine is an array of instructions indexed by field number of the encoding
+// data, typically a struct. It is executed top to bottom, walking the struct.
+type encEngine struct {
+ instr []encInstr
+}
+
+const singletonField = 0
+
+func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep uintptr) {
+ state := newEncoderState(enc, b)
+ state.fieldnum = singletonField
+ // There is no surrounding struct to frame the transmission, so we must
+ // generate data even if the item is zero. To do this, set sendZero.
+ state.sendZero = true
+ instr := &engine.instr[singletonField]
+ p := unsafe.Pointer(basep) // offset will be zero
+ if instr.indir > 0 {
+ if p = encIndirect(p, instr.indir); p == nil {
+ return
+ }
+ }
+ instr.op(instr, state, p)
+}
+
+func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep uintptr) {
+ state := newEncoderState(enc, b)
+ state.fieldnum = -1
+ for i := 0; i < len(engine.instr); i++ {
+ instr := &engine.instr[i]
+ p := unsafe.Pointer(basep + instr.offset)
+ if instr.indir > 0 {
+ if p = encIndirect(p, instr.indir); p == nil {
+ continue
+ }
+ }
+ instr.op(instr, state, p)
+ }
+}
+
+func (enc *Encoder) encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) {
+ state := newEncoderState(enc, b)
+ state.fieldnum = -1
+ state.sendZero = true
+ state.encodeUint(uint64(length))
+ for i := 0; i < length; i++ {
+ elemp := p
+ up := unsafe.Pointer(elemp)
+ if elemIndir > 0 {
+ if up = encIndirect(up, elemIndir); up == nil {
+ errorf("gob: encodeArray: nil element")
+ }
+ elemp = uintptr(up)
+ }
+ op(nil, state, unsafe.Pointer(elemp))
+ p += uintptr(elemWid)
+ }
+}
+
+func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir int) {
+ for i := 0; i < indir && v != nil; i++ {
+ v = reflect.Indirect(v)
+ }
+ if v == nil {
+ errorf("gob: encodeReflectValue: nil element")
+ }
+ op(nil, state, unsafe.Pointer(v.Addr()))
+}
+
+func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elemOp encOp, keyIndir, elemIndir int) {
+ state := newEncoderState(enc, b)
+ state.fieldnum = -1
+ state.sendZero = true
+ keys := mv.Keys()
+ state.encodeUint(uint64(len(keys)))
+ for _, key := range keys {
+ encodeReflectValue(state, key, keyOp, keyIndir)
+ encodeReflectValue(state, mv.Elem(key), elemOp, elemIndir)
+ }
+}
+
+// To send an interface, we send a string identifying the concrete type, followed
+// by the type identifier (which might require defining that type right now), followed
+// by the concrete value. A nil value gets sent as the empty string for the name,
+// followed by no value.
+func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue) {
+ state := newEncoderState(enc, b)
+ state.fieldnum = -1
+ state.sendZero = true
+ if iv.IsNil() {
+ state.encodeUint(0)
+ return
+ }
+
+ typ, _ := indirect(iv.Elem().Type())
+ name, ok := concreteTypeToName[typ]
+ if !ok {
+ errorf("gob: type not registered for interface: %s", typ)
+ }
+ // Send the name.
+ state.encodeUint(uint64(len(name)))
+ _, err := io.WriteString(state.b, name)
+ if err != nil {
+ error(err)
+ }
+ // Send (and maybe first define) the type id.
+ enc.sendTypeDescriptor(typ)
+ // Encode the value into a new buffer.
+ data := new(bytes.Buffer)
+ err = enc.encode(data, iv.Elem())
+ if err != nil {
+ error(err)
+ }
+ state.encodeUint(uint64(data.Len()))
+ _, err = state.b.Write(data.Bytes())
+ if err != nil {
+ error(err)
+ }
+}
+
+var encOpMap = []encOp{
+ reflect.Bool: encBool,
+ reflect.Int: encInt,
+ reflect.Int8: encInt8,
+ reflect.Int16: encInt16,
+ reflect.Int32: encInt32,
+ reflect.Int64: encInt64,
+ reflect.Uint: encUint,
+ reflect.Uint8: encUint8,
+ reflect.Uint16: encUint16,
+ reflect.Uint32: encUint32,
+ reflect.Uint64: encUint64,
+ reflect.Uintptr: encUintptr,
+ reflect.Float32: encFloat32,
+ reflect.Float64: encFloat64,
+ reflect.Complex64: encComplex64,
+ reflect.Complex128: encComplex128,
+ reflect.String: encString,
+}
+
+// Return the encoding op for the base type under rt and
+// the indirection count to reach it.
+func (enc *Encoder) encOpFor(rt reflect.Type) (encOp, int) {
+ typ, indir := indirect(rt)
+ var op encOp
+ k := typ.Kind()
+ if int(k) < len(encOpMap) {
+ op = encOpMap[k]
+ }
+ if op == nil {
+ // Special cases
+ switch t := typ.(type) {
+ case *reflect.SliceType:
+ if t.Elem().Kind() == reflect.Uint8 {
+ op = encUint8Array
+ break
+ }
+ // Slices have a header; we decode it to find the underlying array.
+ elemOp, indir := enc.encOpFor(t.Elem())
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ slice := (*reflect.SliceHeader)(p)
+ if !state.sendZero && slice.Len == 0 {
+ return
+ }
+ state.update(i)
+ state.enc.encodeArray(state.b, slice.Data, elemOp, t.Elem().Size(), indir, int(slice.Len))
+ }
+ case *reflect.ArrayType:
+ // True arrays have size in the type.
+ elemOp, indir := enc.encOpFor(t.Elem())
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ state.update(i)
+ state.enc.encodeArray(state.b, uintptr(p), elemOp, t.Elem().Size(), indir, t.Len())
+ }
+ case *reflect.MapType:
+ keyOp, keyIndir := enc.encOpFor(t.Key())
+ elemOp, elemIndir := enc.encOpFor(t.Elem())
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ // Maps cannot be accessed by moving addresses around the way
+ // that slices etc. can. We must recover a full reflection value for
+ // the iteration.
+ v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer((p))))
+ mv := reflect.Indirect(v).(*reflect.MapValue)
+ if !state.sendZero && mv.Len() == 0 {
+ return
+ }
+ state.update(i)
+ state.enc.encodeMap(state.b, mv, keyOp, elemOp, keyIndir, elemIndir)
+ }
+ case *reflect.StructType:
+ // Generate a closure that calls out to the engine for the nested type.
+ enc.getEncEngine(typ)
+ info := mustGetTypeInfo(typ)
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ state.update(i)
+ // indirect through info to delay evaluation for recursive structs
+ state.enc.encodeStruct(state.b, info.encoder, uintptr(p))
+ }
+ case *reflect.InterfaceType:
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ // Interfaces transmit the name and contents of the concrete
+ // value they contain.
+ v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer((p))))
+ iv := reflect.Indirect(v).(*reflect.InterfaceValue)
+ if !state.sendZero && (iv == nil || iv.IsNil()) {
+ return
+ }
+ state.update(i)
+ state.enc.encodeInterface(state.b, iv)
+ }
+ }
+ }
+ if op == nil {
+ errorf("gob enc: can't happen: encode type %s", rt.String())
+ }
+ return op, indir
+}
+
+// The local Type was compiled from the actual value, so we know it's compatible.
+func (enc *Encoder) compileEnc(rt reflect.Type) *encEngine {
+ srt, isStruct := rt.(*reflect.StructType)
+ engine := new(encEngine)
+ if isStruct {
+ engine.instr = make([]encInstr, srt.NumField()+1) // +1 for terminator
+ for fieldnum := 0; fieldnum < srt.NumField(); fieldnum++ {
+ f := srt.Field(fieldnum)
+ op, indir := enc.encOpFor(f.Type)
+ if !isExported(f.Name) {
+ op = encNoOp
+ }
+ engine.instr[fieldnum] = encInstr{op, fieldnum, indir, uintptr(f.Offset)}
+ }
+ engine.instr[srt.NumField()] = encInstr{encStructTerminator, 0, 0, 0}
+ } else {
+ engine.instr = make([]encInstr, 1)
+ op, indir := enc.encOpFor(rt)
+ engine.instr[0] = encInstr{op, singletonField, indir, 0} // offset is zero
+ }
+ return engine
+}
+
+// typeLock must be held (or we're in initialization and guaranteed single-threaded).
+// The reflection type must have all its indirections processed out.
+func (enc *Encoder) getEncEngine(rt reflect.Type) *encEngine {
+ info, err1 := getTypeInfo(rt)
+ if err1 != nil {
+ error(err1)
+ }
+ if info.encoder == nil {
+ // mark this engine as underway before compiling to handle recursive types.
+ info.encoder = new(encEngine)
+ info.encoder = enc.compileEnc(rt)
+ }
+ return info.encoder
+}
+
+// Put this in a function so we can hold the lock only while compiling, not when encoding.
+func (enc *Encoder) lockAndGetEncEngine(rt reflect.Type) *encEngine {
+ typeLock.Lock()
+ defer typeLock.Unlock()
+ return enc.getEncEngine(rt)
+}
+
+func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value) (err os.Error) {
+ defer catchError(&err)
+ // Dereference down to the underlying object.
+ rt, indir := indirect(value.Type())
+ for i := 0; i < indir; i++ {
+ value = reflect.Indirect(value)
+ }
+ engine := enc.lockAndGetEncEngine(rt)
+ if value.Type().Kind() == reflect.Struct {
+ enc.encodeStruct(b, engine, value.Addr())
+ } else {
+ enc.encodeSingle(b, engine, value.Addr())
+ }
+ return nil
+}
diff --git a/libgo/go/gob/encoder.go b/libgo/go/gob/encoder.go
new file mode 100644
index 000000000..8869b2629
--- /dev/null
+++ b/libgo/go/gob/encoder.go
@@ -0,0 +1,207 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "sync"
+)
+
+// An Encoder manages the transmission of type and data information to the
+// other side of a connection.
+type Encoder struct {
+ mutex sync.Mutex // each item must be sent atomically
+ w io.Writer // where to send the data
+ sent map[reflect.Type]typeId // which types we've already sent
+ state *encoderState // so we can encode integers, strings directly
+ countState *encoderState // stage for writing counts
+ buf []byte // for collecting the output.
+ err os.Error
+}
+
+// NewEncoder returns a new encoder that will transmit on the io.Writer.
+func NewEncoder(w io.Writer) *Encoder {
+ enc := new(Encoder)
+ enc.w = w
+ enc.sent = make(map[reflect.Type]typeId)
+ enc.state = newEncoderState(enc, new(bytes.Buffer))
+ enc.countState = newEncoderState(enc, new(bytes.Buffer))
+ return enc
+}
+
+func (enc *Encoder) badType(rt reflect.Type) {
+ enc.setError(os.ErrorString("gob: can't encode type " + rt.String()))
+}
+
+func (enc *Encoder) setError(err os.Error) {
+ if enc.err == nil { // remember the first.
+ enc.err = err
+ }
+ enc.state.b.Reset()
+}
+
+// Send the data item preceded by a unsigned count of its length.
+func (enc *Encoder) send() {
+ // Encode the length.
+ enc.countState.encodeUint(uint64(enc.state.b.Len()))
+ // Build the buffer.
+ countLen := enc.countState.b.Len()
+ total := countLen + enc.state.b.Len()
+ if total > len(enc.buf) {
+ enc.buf = make([]byte, total+1000) // extra for growth
+ }
+ // Place the length before the data.
+ // TODO(r): avoid the extra copy here.
+ enc.countState.b.Read(enc.buf[0:countLen])
+ // Now the data.
+ enc.state.b.Read(enc.buf[countLen:total])
+ // Write the data.
+ _, err := enc.w.Write(enc.buf[0:total])
+ if err != nil {
+ enc.setError(err)
+ }
+}
+
+func (enc *Encoder) sendType(origt reflect.Type) (sent bool) {
+ // Drill down to the base type.
+ rt, _ := indirect(origt)
+
+ switch rt := rt.(type) {
+ default:
+ // Basic types and interfaces do not need to be described.
+ return
+ case *reflect.SliceType:
+ // If it's []uint8, don't send; it's considered basic.
+ if rt.Elem().Kind() == reflect.Uint8 {
+ return
+ }
+ // Otherwise we do send.
+ break
+ case *reflect.ArrayType:
+ // arrays must be sent so we know their lengths and element types.
+ break
+ case *reflect.MapType:
+ // maps must be sent so we know their lengths and key/value types.
+ break
+ case *reflect.StructType:
+ // structs must be sent so we know their fields.
+ break
+ case *reflect.ChanType, *reflect.FuncType:
+ // Probably a bad field in a struct.
+ enc.badType(rt)
+ return
+ }
+
+ // Have we already sent this type? This time we ask about the base type.
+ if _, alreadySent := enc.sent[rt]; alreadySent {
+ return
+ }
+
+ // Need to send it.
+ typeLock.Lock()
+ info, err := getTypeInfo(rt)
+ typeLock.Unlock()
+ if err != nil {
+ enc.setError(err)
+ return
+ }
+ // Send the pair (-id, type)
+ // Id:
+ enc.state.encodeInt(-int64(info.id))
+ // Type:
+ enc.encode(enc.state.b, reflect.NewValue(info.wire))
+ enc.send()
+ if enc.err != nil {
+ return
+ }
+
+ // Remember we've sent this type.
+ enc.sent[rt] = info.id
+ // Remember we've sent the top-level, possibly indirect type too.
+ enc.sent[origt] = info.id
+ // Now send the inner types
+ switch st := rt.(type) {
+ case *reflect.StructType:
+ for i := 0; i < st.NumField(); i++ {
+ enc.sendType(st.Field(i).Type)
+ }
+ case reflect.ArrayOrSliceType:
+ enc.sendType(st.Elem())
+ }
+ return true
+}
+
+// Encode transmits the data item represented by the empty interface value,
+// guaranteeing that all necessary type information has been transmitted first.
+func (enc *Encoder) Encode(e interface{}) os.Error {
+ return enc.EncodeValue(reflect.NewValue(e))
+}
+
+// sendTypeId makes sure the remote side knows about this type.
+// It will send a descriptor if this is the first time the type has been
+// sent. Regardless, it sends the id.
+func (enc *Encoder) sendTypeDescriptor(rt reflect.Type) {
+ // Make sure the type is known to the other side.
+ // First, have we already sent this type?
+ if _, alreadySent := enc.sent[rt]; !alreadySent {
+ // No, so send it.
+ sent := enc.sendType(rt)
+ if enc.err != nil {
+ return
+ }
+ // If the type info has still not been transmitted, it means we have
+ // a singleton basic type (int, []byte etc.) at top level. We don't
+ // need to send the type info but we do need to update enc.sent.
+ if !sent {
+ typeLock.Lock()
+ info, err := getTypeInfo(rt)
+ typeLock.Unlock()
+ if err != nil {
+ enc.setError(err)
+ return
+ }
+ enc.sent[rt] = info.id
+ }
+ }
+
+ // Identify the type of this top-level value.
+ enc.state.encodeInt(int64(enc.sent[rt]))
+}
+
+// EncodeValue transmits the data item represented by the reflection value,
+// guaranteeing that all necessary type information has been transmitted first.
+func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
+ // Make sure we're single-threaded through here, so multiple
+ // goroutines can share an encoder.
+ enc.mutex.Lock()
+ defer enc.mutex.Unlock()
+
+ enc.err = nil
+ rt, _ := indirect(value.Type())
+
+ // Sanity check only: encoder should never come in with data present.
+ if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 {
+ enc.err = os.ErrorString("encoder: buffer not empty")
+ return enc.err
+ }
+
+ enc.sendTypeDescriptor(rt)
+ if enc.err != nil {
+ return enc.err
+ }
+
+ // Encode the object.
+ err := enc.encode(enc.state.b, value)
+ if err != nil {
+ enc.setError(err)
+ } else {
+ enc.send()
+ }
+
+ return enc.err
+}
diff --git a/libgo/go/gob/encoder_test.go b/libgo/go/gob/encoder_test.go
new file mode 100644
index 000000000..c2309352a
--- /dev/null
+++ b/libgo/go/gob/encoder_test.go
@@ -0,0 +1,385 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type ET2 struct {
+ X string
+}
+
+type ET1 struct {
+ A int
+ Et2 *ET2
+ Next *ET1
+}
+
+// Like ET1 but with a different name for a field
+type ET3 struct {
+ A int
+ Et2 *ET2
+ DifferentNext *ET1
+}
+
+// Like ET1 but with a different type for a field
+type ET4 struct {
+ A int
+ Et2 float64
+ Next int
+}
+
+func TestEncoderDecoder(t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ et1 := new(ET1)
+ et1.A = 7
+ et1.Et2 = new(ET2)
+ err := enc.Encode(et1)
+ if err != nil {
+ t.Error("encoder fail:", err)
+ }
+ dec := NewDecoder(b)
+ newEt1 := new(ET1)
+ err = dec.Decode(newEt1)
+ if err != nil {
+ t.Fatal("error decoding ET1:", err)
+ }
+
+ if !reflect.DeepEqual(et1, newEt1) {
+ t.Fatalf("invalid data for et1: expected %+v; got %+v", *et1, *newEt1)
+ }
+ if b.Len() != 0 {
+ t.Error("not at eof;", b.Len(), "bytes left")
+ }
+
+ enc.Encode(et1)
+ newEt1 = new(ET1)
+ err = dec.Decode(newEt1)
+ if err != nil {
+ t.Fatal("round 2: error decoding ET1:", err)
+ }
+ if !reflect.DeepEqual(et1, newEt1) {
+ t.Fatalf("round 2: invalid data for et1: expected %+v; got %+v", *et1, *newEt1)
+ }
+ if b.Len() != 0 {
+ t.Error("round 2: not at eof;", b.Len(), "bytes left")
+ }
+
+ // Now test with a running encoder/decoder pair that we recognize a type mismatch.
+ err = enc.Encode(et1)
+ if err != nil {
+ t.Error("round 3: encoder fail:", err)
+ }
+ newEt2 := new(ET2)
+ err = dec.Decode(newEt2)
+ if err == nil {
+ t.Fatal("round 3: expected `bad type' error decoding ET2")
+ }
+}
+
+// Run one value through the encoder/decoder, but use the wrong type.
+// Input is always an ET1; we compare it to whatever is under 'e'.
+func badTypeCheck(e interface{}, shouldFail bool, msg string, t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ et1 := new(ET1)
+ et1.A = 7
+ et1.Et2 = new(ET2)
+ err := enc.Encode(et1)
+ if err != nil {
+ t.Error("encoder fail:", err)
+ }
+ dec := NewDecoder(b)
+ err = dec.Decode(e)
+ if shouldFail && err == nil {
+ t.Error("expected error for", msg)
+ }
+ if !shouldFail && err != nil {
+ t.Error("unexpected error for", msg, err)
+ }
+}
+
+// Test that we recognize a bad type the first time.
+func TestWrongTypeDecoder(t *testing.T) {
+ badTypeCheck(new(ET2), true, "no fields in common", t)
+ badTypeCheck(new(ET3), false, "different name of field", t)
+ badTypeCheck(new(ET4), true, "different type of field", t)
+}
+
+func corruptDataCheck(s string, err os.Error, t *testing.T) {
+ b := bytes.NewBufferString(s)
+ dec := NewDecoder(b)
+ err1 := dec.Decode(new(ET2))
+ if err1 != err {
+ t.Error("expected error", err, "got", err1)
+ }
+}
+
+// Check that we survive bad data.
+func TestBadData(t *testing.T) {
+ corruptDataCheck("", os.EOF, t)
+ corruptDataCheck("\x7Fhi", io.ErrUnexpectedEOF, t)
+ corruptDataCheck("\x03now is the time for all good men", errBadType, t)
+}
+
+// Types not supported by the Encoder.
+var unsupportedValues = []interface{}{
+ make(chan int),
+ func(a int) bool { return true },
+}
+
+func TestUnsupported(t *testing.T) {
+ var b bytes.Buffer
+ enc := NewEncoder(&b)
+ for _, v := range unsupportedValues {
+ err := enc.Encode(v)
+ if err == nil {
+ t.Errorf("expected error for %T; got none", v)
+ }
+ }
+}
+
+func encAndDec(in, out interface{}) os.Error {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(in)
+ if err != nil {
+ return err
+ }
+ dec := NewDecoder(b)
+ err = dec.Decode(out)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func TestTypeToPtrType(t *testing.T) {
+ // Encode a T, decode a *T
+ type Type0 struct {
+ A int
+ }
+ t0 := Type0{7}
+ t0p := (*Type0)(nil)
+ if err := encAndDec(t0, t0p); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestPtrTypeToType(t *testing.T) {
+ // Encode a *T, decode a T
+ type Type1 struct {
+ A uint
+ }
+ t1p := &Type1{17}
+ var t1 Type1
+ if err := encAndDec(t1, t1p); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestTypeToPtrPtrPtrPtrType(t *testing.T) {
+ type Type2 struct {
+ A ****float64
+ }
+ t2 := Type2{}
+ t2.A = new(***float64)
+ *t2.A = new(**float64)
+ **t2.A = new(*float64)
+ ***t2.A = new(float64)
+ ****t2.A = 27.4
+ t2pppp := new(***Type2)
+ if err := encAndDec(t2, t2pppp); err != nil {
+ t.Fatal(err)
+ }
+ if ****(****t2pppp).A != ****t2.A {
+ t.Errorf("wrong value after decode: %g not %g", ****(****t2pppp).A, ****t2.A)
+ }
+}
+
+func TestSlice(t *testing.T) {
+ type Type3 struct {
+ A []string
+ }
+ t3p := &Type3{[]string{"hello", "world"}}
+ var t3 Type3
+ if err := encAndDec(t3, t3p); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestValueError(t *testing.T) {
+ // Encode a *T, decode a T
+ type Type4 struct {
+ a int
+ }
+ t4p := &Type4{3}
+ var t4 Type4 // note: not a pointer.
+ if err := encAndDec(t4p, t4); err == nil || strings.Index(err.String(), "pointer") < 0 {
+ t.Error("expected error about pointer; got", err)
+ }
+}
+
+func TestArray(t *testing.T) {
+ type Type5 struct {
+ A [3]string
+ B [3]byte
+ }
+ type Type6 struct {
+ A [2]string // can't hold t5.a
+ }
+ t5 := Type5{[3]string{"hello", ",", "world"}, [3]byte{1, 2, 3}}
+ var t5p Type5
+ if err := encAndDec(t5, &t5p); err != nil {
+ t.Error(err)
+ }
+ var t6 Type6
+ if err := encAndDec(t5, &t6); err == nil {
+ t.Error("should fail with mismatched array sizes")
+ }
+}
+
+// Regression test for bug: must send zero values inside arrays
+func TestDefaultsInArray(t *testing.T) {
+ type Type7 struct {
+ B []bool
+ I []int
+ S []string
+ F []float64
+ }
+ t7 := Type7{
+ []bool{false, false, true},
+ []int{0, 0, 1},
+ []string{"hi", "", "there"},
+ []float64{0, 0, 1},
+ }
+ var t7p Type7
+ if err := encAndDec(t7, &t7p); err != nil {
+ t.Error(err)
+ }
+}
+
+var testInt int
+var testFloat32 float32
+var testString string
+var testSlice []string
+var testMap map[string]int
+var testArray [7]int
+
+type SingleTest struct {
+ in interface{}
+ out interface{}
+ err string
+}
+
+var singleTests = []SingleTest{
+ {17, &testInt, ""},
+ {float32(17.5), &testFloat32, ""},
+ {"bike shed", &testString, ""},
+ {[]string{"bike", "shed", "paint", "color"}, &testSlice, ""},
+ {map[string]int{"seven": 7, "twelve": 12}, &testMap, ""},
+ {[7]int{4, 55, 0, 0, 0, 0, 0}, &testArray, ""}, // case that once triggered a bug
+ {[7]int{4, 55, 1, 44, 22, 66, 1234}, &testArray, ""},
+
+ // Decode errors
+ {172, &testFloat32, "wrong type"},
+}
+
+func TestSingletons(t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ dec := NewDecoder(b)
+ for _, test := range singleTests {
+ b.Reset()
+ err := enc.Encode(test.in)
+ if err != nil {
+ t.Errorf("error encoding %v: %s", test.in, err)
+ continue
+ }
+ err = dec.Decode(test.out)
+ switch {
+ case err != nil && test.err == "":
+ t.Errorf("error decoding %v: %s", test.in, err)
+ continue
+ case err == nil && test.err != "":
+ t.Errorf("expected error decoding %v: %s", test.in, test.err)
+ continue
+ case err != nil && test.err != "":
+ if strings.Index(err.String(), test.err) < 0 {
+ t.Errorf("wrong error decoding %v: wanted %s, got %v", test.in, test.err, err)
+ }
+ continue
+ }
+ // Get rid of the pointer in the rhs
+ val := reflect.NewValue(test.out).(*reflect.PtrValue).Elem().Interface()
+ if !reflect.DeepEqual(test.in, val) {
+ t.Errorf("decoding singleton: expected %v got %v", test.in, val)
+ }
+ }
+}
+
+func TestStructNonStruct(t *testing.T) {
+ type Struct struct {
+ A string
+ }
+ type NonStruct string
+ s := Struct{"hello"}
+ var sp Struct
+ if err := encAndDec(s, &sp); err != nil {
+ t.Error(err)
+ }
+ var ns NonStruct
+ if err := encAndDec(s, &ns); err == nil {
+ t.Error("should get error for struct/non-struct")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("for struct/non-struct expected type error; got", err)
+ }
+ // Now try the other way
+ var nsp NonStruct
+ if err := encAndDec(ns, &nsp); err != nil {
+ t.Error(err)
+ }
+ if err := encAndDec(ns, &s); err == nil {
+ t.Error("should get error for non-struct/struct")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("for non-struct/struct expected type error; got", err)
+ }
+}
+
+type interfaceIndirectTestI interface {
+ F() bool
+}
+
+type interfaceIndirectTestT struct{}
+
+func (this *interfaceIndirectTestT) F() bool {
+ return true
+}
+
+// A version of a bug reported on golang-nuts. Also tests top-level
+// slice of interfaces. The issue was registering *T caused T to be
+// stored as the concrete type.
+func TestInterfaceIndirect(t *testing.T) {
+ Register(&interfaceIndirectTestT{})
+ b := new(bytes.Buffer)
+ w := []interfaceIndirectTestI{&interfaceIndirectTestT{}}
+ err := NewEncoder(b).Encode(w)
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+
+ var r []interfaceIndirectTestI
+ err = NewDecoder(b).Decode(&r)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+}
diff --git a/libgo/go/gob/error.go b/libgo/go/gob/error.go
new file mode 100644
index 000000000..b053761fb
--- /dev/null
+++ b/libgo/go/gob/error.go
@@ -0,0 +1,41 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "fmt"
+ "os"
+)
+
+// Errors in decoding and encoding are handled using panic and recover.
+// Panics caused by user error (that is, everything except run-time panics
+// such as "index out of bounds" errors) do not leave the file that caused
+// them, but are instead turned into plain os.Error returns. Encoding and
+// decoding functions and methods that do not return an os.Error either use
+// panic to report an error or are guaranteed error-free.
+
+// A gobError wraps an os.Error and is used to distinguish errors (panics) generated in this package.
+type gobError struct {
+ os.Error
+}
+
+// errorf is like error but takes Printf-style arguments to construct an os.Error.
+func errorf(format string, args ...interface{}) {
+ error(fmt.Errorf(format, args...))
+}
+
+// error wraps the argument error and uses it as the argument to panic.
+func error(err os.Error) {
+ panic(gobError{Error: err})
+}
+
+// catchError is meant to be used as a deferred function to turn a panic(gobError) into a
+// plain os.Error. It overwrites the error return of the function that deferred its call.
+func catchError(err *os.Error) {
+ if e := recover(); e != nil {
+ *err = e.(gobError).Error // Will re-panic if not one of our errors, such as a runtime error.
+ }
+ return
+}
diff --git a/libgo/go/gob/type.go b/libgo/go/gob/type.go
new file mode 100644
index 000000000..22502a6e6
--- /dev/null
+++ b/libgo/go/gob/type.go
@@ -0,0 +1,539 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "sync"
+)
+
+// Reflection types are themselves interface values holding structs
+// describing the type. Each type has a different struct so that struct can
+// be the kind. For example, if typ is the reflect type for an int8, typ is
+// a pointer to a reflect.Int8Type struct; if typ is the reflect type for a
+// function, typ is a pointer to a reflect.FuncType struct; we use the type
+// of that pointer as the kind.
+
+// A typeId represents a gob Type as an integer that can be passed on the wire.
+// Internally, typeIds are used as keys to a map to recover the underlying type info.
+type typeId int32
+
+var nextId typeId // incremented for each new type we build
+var typeLock sync.Mutex // set while building a type
+const firstUserId = 64 // lowest id number granted to user
+
+type gobType interface {
+ id() typeId
+ setId(id typeId)
+ name() string
+ string() string // not public; only for debugging
+ safeString(seen map[typeId]bool) string
+}
+
+var types = make(map[reflect.Type]gobType)
+var idToType = make(map[typeId]gobType)
+var builtinIdToType map[typeId]gobType // set in init() after builtins are established
+
+func setTypeId(typ gobType) {
+ nextId++
+ typ.setId(nextId)
+ idToType[nextId] = typ
+}
+
+func (t typeId) gobType() gobType {
+ if t == 0 {
+ return nil
+ }
+ return idToType[t]
+}
+
+// string returns the string representation of the type associated with the typeId.
+func (t typeId) string() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().string()
+}
+
+// Name returns the name of the type associated with the typeId.
+func (t typeId) name() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().name()
+}
+
+// Common elements of all types.
+type CommonType struct {
+ Name string
+ Id typeId
+}
+
+func (t *CommonType) id() typeId { return t.Id }
+
+func (t *CommonType) setId(id typeId) { t.Id = id }
+
+func (t *CommonType) string() string { return t.Name }
+
+func (t *CommonType) safeString(seen map[typeId]bool) string {
+ return t.Name
+}
+
+func (t *CommonType) name() string { return t.Name }
+
+// Create and check predefined types
+// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
+
+var (
+ // Primordial types, needed during initialization.
+ tBool = bootstrapType("bool", false, 1)
+ tInt = bootstrapType("int", int(0), 2)
+ tUint = bootstrapType("uint", uint(0), 3)
+ tFloat = bootstrapType("float", 0.0, 4)
+ tBytes = bootstrapType("bytes", make([]byte, 0), 5)
+ tString = bootstrapType("string", "", 6)
+ tComplex = bootstrapType("complex", 0+0i, 7)
+ tInterface = bootstrapType("interface", interface{}(nil), 8)
+ // Reserve some Ids for compatible expansion
+ tReserved7 = bootstrapType("_reserved1", struct{ r7 int }{}, 9)
+ tReserved6 = bootstrapType("_reserved1", struct{ r6 int }{}, 10)
+ tReserved5 = bootstrapType("_reserved1", struct{ r5 int }{}, 11)
+ tReserved4 = bootstrapType("_reserved1", struct{ r4 int }{}, 12)
+ tReserved3 = bootstrapType("_reserved1", struct{ r3 int }{}, 13)
+ tReserved2 = bootstrapType("_reserved1", struct{ r2 int }{}, 14)
+ tReserved1 = bootstrapType("_reserved1", struct{ r1 int }{}, 15)
+)
+
+// Predefined because it's needed by the Decoder
+var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id
+
+func init() {
+ // Some magic numbers to make sure there are no surprises.
+ checkId(16, tWireType)
+ checkId(17, mustGetTypeInfo(reflect.Typeof(arrayType{})).id)
+ checkId(18, mustGetTypeInfo(reflect.Typeof(CommonType{})).id)
+ checkId(19, mustGetTypeInfo(reflect.Typeof(sliceType{})).id)
+ checkId(20, mustGetTypeInfo(reflect.Typeof(structType{})).id)
+ checkId(21, mustGetTypeInfo(reflect.Typeof(fieldType{})).id)
+ checkId(23, mustGetTypeInfo(reflect.Typeof(mapType{})).id)
+
+ builtinIdToType = make(map[typeId]gobType)
+ for k, v := range idToType {
+ builtinIdToType[k] = v
+ }
+
+ // Move the id space upwards to allow for growth in the predefined world
+ // without breaking existing files.
+ if nextId > firstUserId {
+ panic(fmt.Sprintln("nextId too large:", nextId))
+ }
+ nextId = firstUserId
+ registerBasics()
+}
+
+// Array type
+type arrayType struct {
+ CommonType
+ Elem typeId
+ Len int
+}
+
+func newArrayType(name string, elem gobType, length int) *arrayType {
+ a := &arrayType{CommonType{Name: name}, elem.id(), length}
+ setTypeId(a)
+ return a
+}
+
+func (a *arrayType) safeString(seen map[typeId]bool) string {
+ if seen[a.Id] {
+ return a.Name
+ }
+ seen[a.Id] = true
+ return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen))
+}
+
+func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool)) }
+
+// Map type
+type mapType struct {
+ CommonType
+ Key typeId
+ Elem typeId
+}
+
+func newMapType(name string, key, elem gobType) *mapType {
+ m := &mapType{CommonType{Name: name}, key.id(), elem.id()}
+ setTypeId(m)
+ return m
+}
+
+func (m *mapType) safeString(seen map[typeId]bool) string {
+ if seen[m.Id] {
+ return m.Name
+ }
+ seen[m.Id] = true
+ key := m.Key.gobType().safeString(seen)
+ elem := m.Elem.gobType().safeString(seen)
+ return fmt.Sprintf("map[%s]%s", key, elem)
+}
+
+func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) }
+
+// Slice type
+type sliceType struct {
+ CommonType
+ Elem typeId
+}
+
+func newSliceType(name string, elem gobType) *sliceType {
+ s := &sliceType{CommonType{Name: name}, elem.id()}
+ setTypeId(s)
+ return s
+}
+
+func (s *sliceType) safeString(seen map[typeId]bool) string {
+ if seen[s.Id] {
+ return s.Name
+ }
+ seen[s.Id] = true
+ return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen))
+}
+
+func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool)) }
+
+// Struct type
+type fieldType struct {
+ Name string
+ Id typeId
+}
+
+type structType struct {
+ CommonType
+ Field []*fieldType
+}
+
+func (s *structType) safeString(seen map[typeId]bool) string {
+ if s == nil {
+ return "<nil>"
+ }
+ if _, ok := seen[s.Id]; ok {
+ return s.Name
+ }
+ seen[s.Id] = true
+ str := s.Name + " = struct { "
+ for _, f := range s.Field {
+ str += fmt.Sprintf("%s %s; ", f.Name, f.Id.gobType().safeString(seen))
+ }
+ str += "}"
+ return str
+}
+
+func (s *structType) string() string { return s.safeString(make(map[typeId]bool)) }
+
+func newStructType(name string) *structType {
+ s := &structType{CommonType{Name: name}, nil}
+ setTypeId(s)
+ return s
+}
+
+// Step through the indirections on a type to discover the base type.
+// Return the base type and the number of indirections.
+func indirect(t reflect.Type) (rt reflect.Type, count int) {
+ rt = t
+ for {
+ pt, ok := rt.(*reflect.PtrType)
+ if !ok {
+ break
+ }
+ rt = pt.Elem()
+ count++
+ }
+ return
+}
+
+func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
+ switch t := rt.(type) {
+ // All basic types are easy: they are predefined.
+ case *reflect.BoolType:
+ return tBool.gobType(), nil
+
+ case *reflect.IntType:
+ return tInt.gobType(), nil
+
+ case *reflect.UintType:
+ return tUint.gobType(), nil
+
+ case *reflect.FloatType:
+ return tFloat.gobType(), nil
+
+ case *reflect.ComplexType:
+ return tComplex.gobType(), nil
+
+ case *reflect.StringType:
+ return tString.gobType(), nil
+
+ case *reflect.InterfaceType:
+ return tInterface.gobType(), nil
+
+ case *reflect.ArrayType:
+ gt, err := getType("", t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ return newArrayType(name, gt, t.Len()), nil
+
+ case *reflect.MapType:
+ kt, err := getType("", t.Key())
+ if err != nil {
+ return nil, err
+ }
+ vt, err := getType("", t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ return newMapType(name, kt, vt), nil
+
+ case *reflect.SliceType:
+ // []byte == []uint8 is a special case
+ if t.Elem().Kind() == reflect.Uint8 {
+ return tBytes.gobType(), nil
+ }
+ gt, err := getType(t.Elem().Name(), t.Elem())
+ if err != nil {
+ return nil, err
+ }
+ return newSliceType(name, gt), nil
+
+ case *reflect.StructType:
+ // Install the struct type itself before the fields so recursive
+ // structures can be constructed safely.
+ strType := newStructType(name)
+ types[rt] = strType
+ idToType[strType.id()] = strType
+ field := make([]*fieldType, t.NumField())
+ for i := 0; i < t.NumField(); i++ {
+ f := t.Field(i)
+ typ, _ := indirect(f.Type)
+ tname := typ.Name()
+ if tname == "" {
+ t, _ := indirect(f.Type)
+ tname = t.String()
+ }
+ gt, err := getType(tname, f.Type)
+ if err != nil {
+ return nil, err
+ }
+ field[i] = &fieldType{f.Name, gt.id()}
+ }
+ strType.Field = field
+ return strType, nil
+
+ default:
+ return nil, os.ErrorString("gob NewTypeObject can't handle type: " + rt.String())
+ }
+ return nil, nil
+}
+
+// getType returns the Gob type describing the given reflect.Type.
+// typeLock must be held.
+func getType(name string, rt reflect.Type) (gobType, os.Error) {
+ rt, _ = indirect(rt)
+ typ, present := types[rt]
+ if present {
+ return typ, nil
+ }
+ typ, err := newTypeObject(name, rt)
+ if err == nil {
+ types[rt] = typ
+ }
+ return typ, err
+}
+
+func checkId(want, got typeId) {
+ if want != got {
+ fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(want), int(got))
+ panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string())
+ }
+}
+
+// used for building the basic types; called only from init()
+func bootstrapType(name string, e interface{}, expect typeId) typeId {
+ rt := reflect.Typeof(e)
+ _, present := types[rt]
+ if present {
+ panic("bootstrap type already present: " + name + ", " + rt.String())
+ }
+ typ := &CommonType{Name: name}
+ types[rt] = typ
+ setTypeId(typ)
+ checkId(expect, nextId)
+ return nextId
+}
+
+// Representation of the information we send and receive about this type.
+// Each value we send is preceded by its type definition: an encoded int.
+// However, the very first time we send the value, we first send the pair
+// (-id, wireType).
+// For bootstrapping purposes, we assume that the recipient knows how
+// to decode a wireType; it is exactly the wireType struct here, interpreted
+// using the gob rules for sending a structure, except that we assume the
+// ids for wireType and structType are known. The relevant pieces
+// are built in encode.go's init() function.
+// To maintain binary compatibility, if you extend this type, always put
+// the new fields last.
+type wireType struct {
+ ArrayT *arrayType
+ SliceT *sliceType
+ StructT *structType
+ MapT *mapType
+}
+
+func (w *wireType) string() string {
+ const unknown = "unknown type"
+ if w == nil {
+ return unknown
+ }
+ switch {
+ case w.ArrayT != nil:
+ return w.ArrayT.Name
+ case w.SliceT != nil:
+ return w.SliceT.Name
+ case w.StructT != nil:
+ return w.StructT.Name
+ case w.MapT != nil:
+ return w.MapT.Name
+ }
+ return unknown
+}
+
+type typeInfo struct {
+ id typeId
+ encoder *encEngine
+ wire *wireType
+}
+
+var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock
+
+// The reflection type must have all its indirections processed out.
+// typeLock must be held.
+func getTypeInfo(rt reflect.Type) (*typeInfo, os.Error) {
+ if rt.Kind() == reflect.Ptr {
+ panic("pointer type in getTypeInfo: " + rt.String())
+ }
+ info, ok := typeInfoMap[rt]
+ if !ok {
+ info = new(typeInfo)
+ name := rt.Name()
+ gt, err := getType(name, rt)
+ if err != nil {
+ return nil, err
+ }
+ info.id = gt.id()
+ t := info.id.gobType()
+ switch typ := rt.(type) {
+ case *reflect.ArrayType:
+ info.wire = &wireType{ArrayT: t.(*arrayType)}
+ case *reflect.MapType:
+ info.wire = &wireType{MapT: t.(*mapType)}
+ case *reflect.SliceType:
+ // []byte == []uint8 is a special case handled separately
+ if typ.Elem().Kind() != reflect.Uint8 {
+ info.wire = &wireType{SliceT: t.(*sliceType)}
+ }
+ case *reflect.StructType:
+ info.wire = &wireType{StructT: t.(*structType)}
+ }
+ typeInfoMap[rt] = info
+ }
+ return info, nil
+}
+
+// Called only when a panic is acceptable and unexpected.
+func mustGetTypeInfo(rt reflect.Type) *typeInfo {
+ t, err := getTypeInfo(rt)
+ if err != nil {
+ panic("getTypeInfo: " + err.String())
+ }
+ return t
+}
+
+var (
+ nameToConcreteType = make(map[string]reflect.Type)
+ concreteTypeToName = make(map[reflect.Type]string)
+)
+
+// RegisterName is like Register but uses the provided name rather than the
+// type's default.
+func RegisterName(name string, value interface{}) {
+ if name == "" {
+ // reserved for nil
+ panic("attempt to register empty name")
+ }
+ rt, _ := indirect(reflect.Typeof(value))
+ // Check for incompatible duplicates.
+ if t, ok := nameToConcreteType[name]; ok && t != rt {
+ panic("gob: registering duplicate types for " + name)
+ }
+ if n, ok := concreteTypeToName[rt]; ok && n != name {
+ panic("gob: registering duplicate names for " + rt.String())
+ }
+ // Store the name and type provided by the user....
+ nameToConcreteType[name] = reflect.Typeof(value)
+ // but the flattened type in the type table, since that's what decode needs.
+ concreteTypeToName[rt] = name
+}
+
+// Register records a type, identified by a value for that type, under its
+// internal type name. That name will identify the concrete type of a value
+// sent or received as an interface variable. Only types that will be
+// transferred as implementations of interface values need to be registered.
+// Expecting to be used only during initialization, it panics if the mapping
+// between types and names is not a bijection.
+func Register(value interface{}) {
+ // Default to printed representation for unnamed types
+ rt := reflect.Typeof(value)
+ name := rt.String()
+
+ // But for named types (or pointers to them), qualify with import path.
+ // Dereference one pointer looking for a named type.
+ star := ""
+ if rt.Name() == "" {
+ if pt, ok := rt.(*reflect.PtrType); ok {
+ star = "*"
+ rt = pt
+ }
+ }
+ if rt.Name() != "" {
+ if rt.PkgPath() == "" {
+ name = star + rt.Name()
+ } else {
+ name = star + rt.PkgPath() + "." + rt.Name()
+ }
+ }
+
+ RegisterName(name, value)
+}
+
+func registerBasics() {
+ Register(int(0))
+ Register(int8(0))
+ Register(int16(0))
+ Register(int32(0))
+ Register(int64(0))
+ Register(uint(0))
+ Register(uint8(0))
+ Register(uint16(0))
+ Register(uint32(0))
+ Register(uint64(0))
+ Register(float32(0))
+ Register(0.0)
+ Register(complex64(0i))
+ Register(complex128(0i))
+ Register(false)
+ Register("")
+ Register([]byte(nil))
+}
diff --git a/libgo/go/gob/type_test.go b/libgo/go/gob/type_test.go
new file mode 100644
index 000000000..5aecde103
--- /dev/null
+++ b/libgo/go/gob/type_test.go
@@ -0,0 +1,153 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "reflect"
+ "testing"
+)
+
+type typeT struct {
+ id typeId
+ str string
+}
+
+var basicTypes = []typeT{
+ {tBool, "bool"},
+ {tInt, "int"},
+ {tUint, "uint"},
+ {tFloat, "float"},
+ {tBytes, "bytes"},
+ {tString, "string"},
+}
+
+func getTypeUnlocked(name string, rt reflect.Type) gobType {
+ typeLock.Lock()
+ defer typeLock.Unlock()
+ t, err := getType(name, rt)
+ if err != nil {
+ panic("getTypeUnlocked: " + err.String())
+ }
+ return t
+}
+
+// Sanity checks
+func TestBasic(t *testing.T) {
+ for _, tt := range basicTypes {
+ if tt.id.string() != tt.str {
+ t.Errorf("checkType: expected %q got %s", tt.str, tt.id.string())
+ }
+ if tt.id == 0 {
+ t.Errorf("id for %q is zero", tt.str)
+ }
+ }
+}
+
+// Reregister some basic types to check registration is idempotent.
+func TestReregistration(t *testing.T) {
+ newtyp := getTypeUnlocked("int", reflect.Typeof(int(0)))
+ if newtyp != tInt.gobType() {
+ t.Errorf("reregistration of %s got new type", newtyp.string())
+ }
+ newtyp = getTypeUnlocked("uint", reflect.Typeof(uint(0)))
+ if newtyp != tUint.gobType() {
+ t.Errorf("reregistration of %s got new type", newtyp.string())
+ }
+ newtyp = getTypeUnlocked("string", reflect.Typeof("hello"))
+ if newtyp != tString.gobType() {
+ t.Errorf("reregistration of %s got new type", newtyp.string())
+ }
+}
+
+func TestArrayType(t *testing.T) {
+ var a3 [3]int
+ a3int := getTypeUnlocked("foo", reflect.Typeof(a3))
+ newa3int := getTypeUnlocked("bar", reflect.Typeof(a3))
+ if a3int != newa3int {
+ t.Errorf("second registration of [3]int creates new type")
+ }
+ var a4 [4]int
+ a4int := getTypeUnlocked("goo", reflect.Typeof(a4))
+ if a3int == a4int {
+ t.Errorf("registration of [3]int creates same type as [4]int")
+ }
+ var b3 [3]bool
+ a3bool := getTypeUnlocked("", reflect.Typeof(b3))
+ if a3int == a3bool {
+ t.Errorf("registration of [3]bool creates same type as [3]int")
+ }
+ str := a3bool.string()
+ expected := "[3]bool"
+ if str != expected {
+ t.Errorf("array printed as %q; expected %q", str, expected)
+ }
+}
+
+func TestSliceType(t *testing.T) {
+ var s []int
+ sint := getTypeUnlocked("slice", reflect.Typeof(s))
+ var news []int
+ newsint := getTypeUnlocked("slice1", reflect.Typeof(news))
+ if sint != newsint {
+ t.Errorf("second registration of []int creates new type")
+ }
+ var b []bool
+ sbool := getTypeUnlocked("", reflect.Typeof(b))
+ if sbool == sint {
+ t.Errorf("registration of []bool creates same type as []int")
+ }
+ str := sbool.string()
+ expected := "[]bool"
+ if str != expected {
+ t.Errorf("slice printed as %q; expected %q", str, expected)
+ }
+}
+
+func TestMapType(t *testing.T) {
+ var m map[string]int
+ mapStringInt := getTypeUnlocked("map", reflect.Typeof(m))
+ var newm map[string]int
+ newMapStringInt := getTypeUnlocked("map1", reflect.Typeof(newm))
+ if mapStringInt != newMapStringInt {
+ t.Errorf("second registration of map[string]int creates new type")
+ }
+ var b map[string]bool
+ mapStringBool := getTypeUnlocked("", reflect.Typeof(b))
+ if mapStringBool == mapStringInt {
+ t.Errorf("registration of map[string]bool creates same type as map[string]int")
+ }
+ str := mapStringBool.string()
+ expected := "map[string]bool"
+ if str != expected {
+ t.Errorf("map printed as %q; expected %q", str, expected)
+ }
+}
+
+type Bar struct {
+ x string
+}
+
+// This structure has pointers and refers to itself, making it a good test case.
+type Foo struct {
+ a int
+ b int32 // will become int
+ c string
+ d []byte
+ e *float64 // will become float64
+ f ****float64 // will become float64
+ g *Bar
+ h *Bar // should not interpolate the definition of Bar again
+ i *Foo // will not explode
+}
+
+func TestStructType(t *testing.T) {
+ sstruct := getTypeUnlocked("Foo", reflect.Typeof(Foo{}))
+ str := sstruct.string()
+ // If we can print it correctly, we built it correctly.
+ expected := "Foo = struct { a int; b int; c string; d bytes; e float; f float; g Bar = struct { x string; }; h Bar; i Foo; }"
+ if str != expected {
+ t.Errorf("struct printed as %q; expected %q", str, expected)
+ }
+}
diff --git a/libgo/go/hash/adler32/adler32.go b/libgo/go/hash/adler32/adler32.go
new file mode 100644
index 000000000..cd0c2599a
--- /dev/null
+++ b/libgo/go/hash/adler32/adler32.go
@@ -0,0 +1,88 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the Adler-32 checksum.
+// Defined in RFC 1950:
+// Adler-32 is composed of two sums accumulated per byte: s1 is
+// the sum of all bytes, s2 is the sum of all s1 values. Both sums
+// are done modulo 65521. s1 is initialized to 1, s2 to zero. The
+// Adler-32 checksum is stored as s2*65536 + s1 in most-
+// significant-byte first (network) order.
+package adler32
+
+import (
+ "hash"
+ "os"
+)
+
+const (
+ mod = 65521
+)
+
+// The size of an Adler-32 checksum in bytes.
+const Size = 4
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ // invariant: (a < mod && b < mod) || a <= b
+ // invariant: a + b + 255 <= 0xffffffff
+ a, b uint32
+}
+
+func (d *digest) Reset() { d.a, d.b = 1, 0 }
+
+// New returns a new hash.Hash32 computing the Adler-32 checksum.
+func New() hash.Hash32 {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int { return Size }
+
+// Add p to the running checksum a, b.
+func update(a, b uint32, p []byte) (aa, bb uint32) {
+ for i := 0; i < len(p); i++ {
+ a += uint32(p[i])
+ b += a
+ // invariant: a <= b
+ if b > (0xffffffff-255)/2 {
+ a %= mod
+ b %= mod
+ // invariant: a < mod && b < mod
+ } else {
+ // invariant: a + b + 255 <= 2 * b + 255 <= 0xffffffff
+ }
+ }
+ return a, b
+}
+
+// Return the 32-bit checksum corresponding to a, b.
+func finish(a, b uint32) uint32 {
+ if b >= mod {
+ a %= mod
+ b %= mod
+ }
+ return b<<16 | a
+}
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+ d.a, d.b = update(d.a, d.b, p)
+ return len(p), nil
+}
+
+func (d *digest) Sum32() uint32 { return finish(d.a, d.b) }
+
+func (d *digest) Sum() []byte {
+ p := make([]byte, 4)
+ s := d.Sum32()
+ p[0] = byte(s >> 24)
+ p[1] = byte(s >> 16)
+ p[2] = byte(s >> 8)
+ p[3] = byte(s)
+ return p
+}
+
+// Checksum returns the Adler-32 checksum of data.
+func Checksum(data []byte) uint32 { return finish(update(1, 0, data)) }
diff --git a/libgo/go/hash/adler32/adler32_test.go b/libgo/go/hash/adler32/adler32_test.go
new file mode 100644
index 000000000..ffa5569bc
--- /dev/null
+++ b/libgo/go/hash/adler32/adler32_test.go
@@ -0,0 +1,63 @@
+// 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 adler32
+
+import (
+ "io"
+ "testing"
+)
+
+type _Adler32Test struct {
+ out uint32
+ in string
+}
+
+var golden = []_Adler32Test{
+ {0x1, ""},
+ {0x620062, "a"},
+ {0x12600c4, "ab"},
+ {0x24d0127, "abc"},
+ {0x3d8018b, "abcd"},
+ {0x5c801f0, "abcde"},
+ {0x81e0256, "abcdef"},
+ {0xadb02bd, "abcdefg"},
+ {0xe000325, "abcdefgh"},
+ {0x118e038e, "abcdefghi"},
+ {0x158603f8, "abcdefghij"},
+ {0x3f090f02, "Discard medicine more than two years old."},
+ {0x46d81477, "He who has a shady past knows that nice guys finish last."},
+ {0x40ee0ee1, "I wouldn't marry him with a ten foot pole."},
+ {0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x5b2e1480, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x8c3c09ea, "Nepal premier won't resign."},
+ {0x45ac18fd, "For every action there is an equal and opposite government program."},
+ {0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0x61b507df, "size: a.out: bad magic"},
+ {0xb8631171, "The major problem is with sendmail. -Mark Horton"},
+ {0x8b5e1904, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x7cc6102b, "If the enemy is within range, then so are you."},
+ {0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0xb55b0b09, "C is as portable as Stonehedge!!"},
+ {0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0x2e5d1316, "How can you write a big system without C++? -Paul Glick"},
+ {0xd0201df6, "'Invariant assertions' is the most elegant programming technique! -Tom Szymanski"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ io.WriteString(c, g.in)
+ s := c.Sum32()
+ if s != g.out {
+ t.Errorf("adler32(%s) = 0x%x want 0x%x", g.in, s, g.out)
+ t.FailNow()
+ }
+ }
+}
diff --git a/libgo/go/hash/crc32/crc32.go b/libgo/go/hash/crc32/crc32.go
new file mode 100644
index 000000000..2ab0c5491
--- /dev/null
+++ b/libgo/go/hash/crc32/crc32.go
@@ -0,0 +1,111 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the 32-bit cyclic redundancy check, or CRC-32, checksum.
+// See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for information.
+package crc32
+
+import (
+ "hash"
+ "os"
+)
+
+// The size of a CRC-32 checksum in bytes.
+const Size = 4
+
+// Predefined polynomials.
+const (
+ // Far and away the most common CRC-32 polynomial.
+ // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, mpeg-2, ...
+ IEEE = 0xedb88320
+
+ // Castagnoli's polynomial, used in iSCSI.
+ // Has better error detection characteristics than IEEE.
+ // http://dx.doi.org/10.1109/26.231911
+ Castagnoli = 0x82f63b78
+
+ // Koopman's polynomial.
+ // Also has better error detection characteristics than IEEE.
+ // http://dx.doi.org/10.1109/DSN.2002.1028931
+ Koopman = 0xeb31d82e
+)
+
+// Table is a 256-word table representing the polynomial for efficient processing.
+type Table [256]uint32
+
+// MakeTable returns the Table constructed from the specified polynomial.
+func MakeTable(poly uint32) *Table {
+ t := new(Table)
+ for i := 0; i < 256; i++ {
+ crc := uint32(i)
+ for j := 0; j < 8; j++ {
+ if crc&1 == 1 {
+ crc = (crc >> 1) ^ poly
+ } else {
+ crc >>= 1
+ }
+ }
+ t[i] = crc
+ }
+ return t
+}
+
+// IEEETable is the table for the IEEE polynomial.
+var IEEETable = MakeTable(IEEE)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ crc uint32
+ tab *Table
+}
+
+// New creates a new hash.Hash32 computing the CRC-32 checksum
+// using the polynomial represented by the Table.
+func New(tab *Table) hash.Hash32 { return &digest{0, tab} }
+
+// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum
+// using the IEEE polynomial.
+func NewIEEE() hash.Hash32 { return New(IEEETable) }
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Reset() { d.crc = 0 }
+
+func update(crc uint32, tab *Table, p []byte) uint32 {
+ crc = ^crc
+ for _, v := range p {
+ crc = tab[byte(crc)^v] ^ (crc >> 8)
+ }
+ return ^crc
+}
+
+// Update returns the result of adding the bytes in p to the crc.
+func Update(crc uint32, tab *Table, p []byte) uint32 {
+ return update(crc, tab, p)
+}
+
+func (d *digest) Write(p []byte) (n int, err os.Error) {
+ d.crc = update(d.crc, d.tab, p)
+ return len(p), nil
+}
+
+func (d *digest) Sum32() uint32 { return d.crc }
+
+func (d *digest) Sum() []byte {
+ p := make([]byte, 4)
+ s := d.Sum32()
+ p[0] = byte(s >> 24)
+ p[1] = byte(s >> 16)
+ p[2] = byte(s >> 8)
+ p[3] = byte(s)
+ return p
+}
+
+// Checksum returns the CRC-32 checksum of data
+// using the polynomial represented by the Table.
+func Checksum(data []byte, tab *Table) uint32 { return update(0, tab, data) }
+
+// ChecksumIEEE returns the CRC-32 checksum of data
+// using the IEEE polynomial.
+func ChecksumIEEE(data []byte) uint32 { return update(0, IEEETable, data) }
diff --git a/libgo/go/hash/crc32/crc32_test.go b/libgo/go/hash/crc32/crc32_test.go
new file mode 100644
index 000000000..cf5743c99
--- /dev/null
+++ b/libgo/go/hash/crc32/crc32_test.go
@@ -0,0 +1,76 @@
+// 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 crc32
+
+import (
+ "io"
+ "testing"
+)
+
+type test struct {
+ out uint32
+ in string
+}
+
+var golden = []test{
+ {0x0, ""},
+ {0xe8b7be43, "a"},
+ {0x9e83486d, "ab"},
+ {0x352441c2, "abc"},
+ {0xed82cd11, "abcd"},
+ {0x8587d865, "abcde"},
+ {0x4b8e39ef, "abcdef"},
+ {0x312a6aa6, "abcdefg"},
+ {0xaeef2a50, "abcdefgh"},
+ {0x8da988af, "abcdefghi"},
+ {0x3981703a, "abcdefghij"},
+ {0x6b9cdfe7, "Discard medicine more than two years old."},
+ {0xc90ef73f, "He who has a shady past knows that nice guys finish last."},
+ {0xb902341f, "I wouldn't marry him with a ten foot pole."},
+ {0x42080e8, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x154c6d11, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x4c418325, "Nepal premier won't resign."},
+ {0x33955150, "For every action there is an equal and opposite government program."},
+ {0x26216a4b, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0x1abbe45e, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xc89a94f7, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0xab3abe14, "size: a.out: bad magic"},
+ {0xbab102b6, "The major problem is with sendmail. -Mark Horton"},
+ {0x999149d7, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x6d52a33c, "If the enemy is within range, then so are you."},
+ {0x90631e8d, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x78309130, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0x7d0a377f, "C is as portable as Stonehedge!!"},
+ {0x8c79fd79, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0xa20b7167, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0x8e0bb443, "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := NewIEEE()
+ io.WriteString(c, g.in)
+ s := c.Sum32()
+ if s != g.out {
+ t.Errorf("crc32(%s) = 0x%x want 0x%x", g.in, s, g.out)
+ t.FailNow()
+ }
+ }
+}
+
+func BenchmarkCrc32KB(b *testing.B) {
+ b.StopTimer()
+ data := make([]uint8, 1024)
+ for i := 0; i < 1024; i++ {
+ data[i] = uint8(i)
+ }
+ c := NewIEEE()
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ c.Write(data)
+ }
+}
diff --git a/libgo/go/hash/crc64/crc64.go b/libgo/go/hash/crc64/crc64.go
new file mode 100644
index 000000000..844386564
--- /dev/null
+++ b/libgo/go/hash/crc64/crc64.go
@@ -0,0 +1,96 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the 64-bit cyclic redundancy check, or CRC-64, checksum.
+// See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for information.
+package crc64
+
+import (
+ "hash"
+ "os"
+)
+
+// The size of a CRC-64 checksum in bytes.
+const Size = 8
+
+// Predefined polynomials.
+const (
+ // The ISO polynomial, defined in ISO 3309 and used in HDLC.
+ ISO = 0xD800000000000000
+
+ // The ECMA polynomial, defined in ECMA 182.
+ ECMA = 0xC96C5795D7870F42
+)
+
+// Table is a 256-word table representing the polynomial for efficient processing.
+type Table [256]uint64
+
+// MakeTable returns the Table constructed from the specified polynomial.
+func MakeTable(poly uint64) *Table {
+ t := new(Table)
+ for i := 0; i < 256; i++ {
+ crc := uint64(i)
+ for j := 0; j < 8; j++ {
+ if crc&1 == 1 {
+ crc = (crc >> 1) ^ poly
+ } else {
+ crc >>= 1
+ }
+ }
+ t[i] = crc
+ }
+ return t
+}
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ crc uint64
+ tab *Table
+}
+
+// New creates a new hash.Hash64 computing the CRC-64 checksum
+// using the polynomial represented by the Table.
+func New(tab *Table) hash.Hash64 { return &digest{0, tab} }
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) Reset() { d.crc = 0 }
+
+func update(crc uint64, tab *Table, p []byte) uint64 {
+ crc = ^crc
+ for _, v := range p {
+ crc = tab[byte(crc)^v] ^ (crc >> 8)
+ }
+ return ^crc
+}
+
+// Update returns the result of adding the bytes in p to the crc.
+func Update(crc uint64, tab *Table, p []byte) uint64 {
+ return update(crc, tab, p)
+}
+
+func (d *digest) Write(p []byte) (n int, err os.Error) {
+ d.crc = update(d.crc, d.tab, p)
+ return len(p), nil
+}
+
+func (d *digest) Sum64() uint64 { return d.crc }
+
+func (d *digest) Sum() []byte {
+ p := make([]byte, 8)
+ s := d.Sum64()
+ p[0] = byte(s >> 56)
+ p[1] = byte(s >> 48)
+ p[2] = byte(s >> 40)
+ p[3] = byte(s >> 32)
+ p[4] = byte(s >> 24)
+ p[5] = byte(s >> 16)
+ p[6] = byte(s >> 8)
+ p[7] = byte(s)
+ return p
+}
+
+// Checksum returns the CRC-64 checksum of data
+// using the polynomial represented by the Table.
+func Checksum(data []byte, tab *Table) uint64 { return update(0, tab, data) }
diff --git a/libgo/go/hash/crc64/crc64_test.go b/libgo/go/hash/crc64/crc64_test.go
new file mode 100644
index 000000000..e932524e0
--- /dev/null
+++ b/libgo/go/hash/crc64/crc64_test.go
@@ -0,0 +1,78 @@
+// 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 crc64
+
+import (
+ "io"
+ "testing"
+)
+
+type test struct {
+ out uint64
+ in string
+}
+
+var golden = []test{
+ {0x0, ""},
+ {0x3420000000000000, "a"},
+ {0x36c4200000000000, "ab"},
+ {0x3776c42000000000, "abc"},
+ {0x336776c420000000, "abcd"},
+ {0x32d36776c4200000, "abcde"},
+ {0x3002d36776c42000, "abcdef"},
+ {0x31b002d36776c420, "abcdefg"},
+ {0xe21b002d36776c4, "abcdefgh"},
+ {0x8b6e21b002d36776, "abcdefghi"},
+ {0x7f5b6e21b002d367, "abcdefghij"},
+ {0x8ec0e7c835bf9cdf, "Discard medicine more than two years old."},
+ {0xc7db1759e2be5ab4, "He who has a shady past knows that nice guys finish last."},
+ {0xfbf9d9603a6fa020, "I wouldn't marry him with a ten foot pole."},
+ {0xeafc4211a6daa0ef, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x3e05b21c7a4dc4da, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x5255866ad6ef28a6, "Nepal premier won't resign."},
+ {0x8a79895be1e9c361, "For every action there is an equal and opposite government program."},
+ {0x8878963a649d4916, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0xa7b9d53ea87eb82f, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xdb6805c0966a2f9c, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0xf3553c65dacdadd2, "size: a.out: bad magic"},
+ {0x9d5e034087a676b9, "The major problem is with sendmail. -Mark Horton"},
+ {0xa6db2d7f8da96417, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x325e00cd2fe819f9, "If the enemy is within range, then so are you."},
+ {0x88c6600ce58ae4c6, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x28c4a3f3b769e078, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0xa698a34c9d9f1dca, "C is as portable as Stonehedge!!"},
+ {0xf6c1e2a8c26c5cfc, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0xd402559dfe9b70c, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0xdb6efff26aa94946, "How can you write a big system without C++? -Paul Glick"},
+}
+
+var tab = MakeTable(ISO)
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New(tab)
+ io.WriteString(c, g.in)
+ s := c.Sum64()
+ if s != g.out {
+ t.Errorf("crc64(%s) = 0x%x want 0x%x", g.in, s, g.out)
+ t.FailNow()
+ }
+ }
+}
+
+func BenchmarkCrc64KB(b *testing.B) {
+ b.StopTimer()
+ data := make([]uint8, 1024)
+ for i := 0; i < 1024; i++ {
+ data[i] = uint8(i)
+ }
+ c := New(tab)
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ c.Write(data)
+ }
+}
diff --git a/libgo/go/hash/hash.go b/libgo/go/hash/hash.go
new file mode 100644
index 000000000..56ac259db
--- /dev/null
+++ b/libgo/go/hash/hash.go
@@ -0,0 +1,36 @@
+// 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 hash
+
+import "io"
+
+// Hash is the common interface implemented by all hash functions.
+type Hash interface {
+ // Write adds more data to the running hash.
+ // It never returns an error.
+ io.Writer
+
+ // Sum returns the current hash, without changing the
+ // underlying hash state.
+ Sum() []byte
+
+ // Reset resets the hash to one with zero bytes written.
+ Reset()
+
+ // Size returns the number of bytes Sum will return.
+ Size() int
+}
+
+// Hash32 is the common interface implemented by all 32-bit hash functions.
+type Hash32 interface {
+ Hash
+ Sum32() uint32
+}
+
+// Hash64 is the common interface implemented by all 64-bit hash functions.
+type Hash64 interface {
+ Hash
+ Sum64() uint64
+}
diff --git a/libgo/go/html/doc.go b/libgo/go/html/doc.go
new file mode 100644
index 000000000..c5338d078
--- /dev/null
+++ b/libgo/go/html/doc.go
@@ -0,0 +1,106 @@
+// 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.
+
+/*
+The html package implements an HTML5-compliant tokenizer and parser.
+
+Tokenization is done by creating a Tokenizer for an io.Reader r. It is the
+caller's responsibility to ensure that r provides UTF-8 encoded HTML.
+
+ z := html.NewTokenizer(r)
+
+Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(),
+which parses the next token and returns its type, or an error:
+
+ for {
+ tt := z.Next()
+ if tt == html.ErrorToken {
+ // ...
+ return ...
+ }
+ // Process the current token.
+ }
+
+There are two APIs for retrieving the current token. The high-level API is to
+call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs
+allow optionally calling Raw after Next but before Token, Text, TagName, or
+TagAttr. In EBNF notation, the valid call sequence per token is:
+
+ Next {Raw} [ Token | Text | TagName {TagAttr} ]
+
+Token returns an independent data structure that completely describes a token.
+Entities (such as "&lt;") are unescaped, tag names and attribute keys are
+lower-cased, and attributes are collected into a []Attribute. For example:
+
+ for {
+ if z.Next() == html.ErrorToken {
+ // Returning os.EOF indicates success.
+ return z.Error()
+ }
+ emitToken(z.Token())
+ }
+
+The low-level API performs fewer allocations and copies, but the contents of
+the []byte values returned by Text, TagName and TagAttr may change on the next
+call to Next. For example, to extract an HTML page's anchor text:
+
+ depth := 0
+ for {
+ tt := z.Next()
+ switch tt {
+ case ErrorToken:
+ return z.Error()
+ case TextToken:
+ if depth > 0 {
+ // emitBytes should copy the []byte it receives,
+ // if it doesn't process it immediately.
+ emitBytes(z.Text())
+ }
+ case StartTagToken, EndTagToken:
+ tn, _ := z.TagName()
+ if len(tn) == 1 && tn[0] == 'a' {
+ if tt == StartTag {
+ depth++
+ } else {
+ depth--
+ }
+ }
+ }
+ }
+
+Parsing is done by calling Parse with an io.Reader, which returns the root of
+the parse tree (the document element) as a *Node. It is the caller's
+responsibility to ensure that the Reader provides UTF-8 encoded HTML. For
+example, to process each anchor node in depth-first order:
+
+ doc, err := html.Parse(r)
+ if err != nil {
+ // ...
+ }
+ var f func(*html.Node)
+ f = func(n *html.Node) {
+ if n.Type == html.ElementNode && n.Data == "a" {
+ // Do something with n...
+ }
+ for _, c := range n.Child {
+ f(c)
+ }
+ }
+ f(doc)
+
+The relevant specifications include:
+http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html and
+http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html
+*/
+package html
+
+// The tokenization algorithm implemented by this package is not a line-by-line
+// transliteration of the relatively verbose state-machine in the WHATWG
+// specification. A more direct approach is used instead, where the program
+// counter implies the state, such as whether it is tokenizing a tag or a text
+// node. Specification compliance is verified by checking expected and actual
+// outputs over a test suite rather than aiming for algorithmic fidelity.
+
+// TODO(nigeltao): Does a DOM API belong in this package or a separate one?
+// TODO(nigeltao): How does parsing interact with a JavaScript engine?
diff --git a/libgo/go/html/entity.go b/libgo/go/html/entity.go
new file mode 100644
index 000000000..1530290cb
--- /dev/null
+++ b/libgo/go/html/entity.go
@@ -0,0 +1,2250 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+// entity is a map from HTML entity names to their values. The semicolon matters:
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html
+// lists both "amp" and "amp;" as two separate entries.
+//
+// Note that the HTML5 list is larger than the HTML4 list at
+// http://www.w3.org/TR/html4/sgml/entities.html
+var entity = map[string]int{
+ "AElig;": '\U000000C6',
+ "AMP;": '\U00000026',
+ "Aacute;": '\U000000C1',
+ "Abreve;": '\U00000102',
+ "Acirc;": '\U000000C2',
+ "Acy;": '\U00000410',
+ "Afr;": '\U0001D504',
+ "Agrave;": '\U000000C0',
+ "Alpha;": '\U00000391',
+ "Amacr;": '\U00000100',
+ "And;": '\U00002A53',
+ "Aogon;": '\U00000104',
+ "Aopf;": '\U0001D538',
+ "ApplyFunction;": '\U00002061',
+ "Aring;": '\U000000C5',
+ "Ascr;": '\U0001D49C',
+ "Assign;": '\U00002254',
+ "Atilde;": '\U000000C3',
+ "Auml;": '\U000000C4',
+ "Backslash;": '\U00002216',
+ "Barv;": '\U00002AE7',
+ "Barwed;": '\U00002306',
+ "Bcy;": '\U00000411',
+ "Because;": '\U00002235',
+ "Bernoullis;": '\U0000212C',
+ "Beta;": '\U00000392',
+ "Bfr;": '\U0001D505',
+ "Bopf;": '\U0001D539',
+ "Breve;": '\U000002D8',
+ "Bscr;": '\U0000212C',
+ "Bumpeq;": '\U0000224E',
+ "CHcy;": '\U00000427',
+ "COPY;": '\U000000A9',
+ "Cacute;": '\U00000106',
+ "Cap;": '\U000022D2',
+ "CapitalDifferentialD;": '\U00002145',
+ "Cayleys;": '\U0000212D',
+ "Ccaron;": '\U0000010C',
+ "Ccedil;": '\U000000C7',
+ "Ccirc;": '\U00000108',
+ "Cconint;": '\U00002230',
+ "Cdot;": '\U0000010A',
+ "Cedilla;": '\U000000B8',
+ "CenterDot;": '\U000000B7',
+ "Cfr;": '\U0000212D',
+ "Chi;": '\U000003A7',
+ "CircleDot;": '\U00002299',
+ "CircleMinus;": '\U00002296',
+ "CirclePlus;": '\U00002295',
+ "CircleTimes;": '\U00002297',
+ "ClockwiseContourIntegral;": '\U00002232',
+ "CloseCurlyDoubleQuote;": '\U0000201D',
+ "CloseCurlyQuote;": '\U00002019',
+ "Colon;": '\U00002237',
+ "Colone;": '\U00002A74',
+ "Congruent;": '\U00002261',
+ "Conint;": '\U0000222F',
+ "ContourIntegral;": '\U0000222E',
+ "Copf;": '\U00002102',
+ "Coproduct;": '\U00002210',
+ "CounterClockwiseContourIntegral;": '\U00002233',
+ "Cross;": '\U00002A2F',
+ "Cscr;": '\U0001D49E',
+ "Cup;": '\U000022D3',
+ "CupCap;": '\U0000224D',
+ "DD;": '\U00002145',
+ "DDotrahd;": '\U00002911',
+ "DJcy;": '\U00000402',
+ "DScy;": '\U00000405',
+ "DZcy;": '\U0000040F',
+ "Dagger;": '\U00002021',
+ "Darr;": '\U000021A1',
+ "Dashv;": '\U00002AE4',
+ "Dcaron;": '\U0000010E',
+ "Dcy;": '\U00000414',
+ "Del;": '\U00002207',
+ "Delta;": '\U00000394',
+ "Dfr;": '\U0001D507',
+ "DiacriticalAcute;": '\U000000B4',
+ "DiacriticalDot;": '\U000002D9',
+ "DiacriticalDoubleAcute;": '\U000002DD',
+ "DiacriticalGrave;": '\U00000060',
+ "DiacriticalTilde;": '\U000002DC',
+ "Diamond;": '\U000022C4',
+ "DifferentialD;": '\U00002146',
+ "Dopf;": '\U0001D53B',
+ "Dot;": '\U000000A8',
+ "DotDot;": '\U000020DC',
+ "DotEqual;": '\U00002250',
+ "DoubleContourIntegral;": '\U0000222F',
+ "DoubleDot;": '\U000000A8',
+ "DoubleDownArrow;": '\U000021D3',
+ "DoubleLeftArrow;": '\U000021D0',
+ "DoubleLeftRightArrow;": '\U000021D4',
+ "DoubleLeftTee;": '\U00002AE4',
+ "DoubleLongLeftArrow;": '\U000027F8',
+ "DoubleLongLeftRightArrow;": '\U000027FA',
+ "DoubleLongRightArrow;": '\U000027F9',
+ "DoubleRightArrow;": '\U000021D2',
+ "DoubleRightTee;": '\U000022A8',
+ "DoubleUpArrow;": '\U000021D1',
+ "DoubleUpDownArrow;": '\U000021D5',
+ "DoubleVerticalBar;": '\U00002225',
+ "DownArrow;": '\U00002193',
+ "DownArrowBar;": '\U00002913',
+ "DownArrowUpArrow;": '\U000021F5',
+ "DownBreve;": '\U00000311',
+ "DownLeftRightVector;": '\U00002950',
+ "DownLeftTeeVector;": '\U0000295E',
+ "DownLeftVector;": '\U000021BD',
+ "DownLeftVectorBar;": '\U00002956',
+ "DownRightTeeVector;": '\U0000295F',
+ "DownRightVector;": '\U000021C1',
+ "DownRightVectorBar;": '\U00002957',
+ "DownTee;": '\U000022A4',
+ "DownTeeArrow;": '\U000021A7',
+ "Downarrow;": '\U000021D3',
+ "Dscr;": '\U0001D49F',
+ "Dstrok;": '\U00000110',
+ "ENG;": '\U0000014A',
+ "ETH;": '\U000000D0',
+ "Eacute;": '\U000000C9',
+ "Ecaron;": '\U0000011A',
+ "Ecirc;": '\U000000CA',
+ "Ecy;": '\U0000042D',
+ "Edot;": '\U00000116',
+ "Efr;": '\U0001D508',
+ "Egrave;": '\U000000C8',
+ "Element;": '\U00002208',
+ "Emacr;": '\U00000112',
+ "EmptySmallSquare;": '\U000025FB',
+ "EmptyVerySmallSquare;": '\U000025AB',
+ "Eogon;": '\U00000118',
+ "Eopf;": '\U0001D53C',
+ "Epsilon;": '\U00000395',
+ "Equal;": '\U00002A75',
+ "EqualTilde;": '\U00002242',
+ "Equilibrium;": '\U000021CC',
+ "Escr;": '\U00002130',
+ "Esim;": '\U00002A73',
+ "Eta;": '\U00000397',
+ "Euml;": '\U000000CB',
+ "Exists;": '\U00002203',
+ "ExponentialE;": '\U00002147',
+ "Fcy;": '\U00000424',
+ "Ffr;": '\U0001D509',
+ "FilledSmallSquare;": '\U000025FC',
+ "FilledVerySmallSquare;": '\U000025AA',
+ "Fopf;": '\U0001D53D',
+ "ForAll;": '\U00002200',
+ "Fouriertrf;": '\U00002131',
+ "Fscr;": '\U00002131',
+ "GJcy;": '\U00000403',
+ "GT;": '\U0000003E',
+ "Gamma;": '\U00000393',
+ "Gammad;": '\U000003DC',
+ "Gbreve;": '\U0000011E',
+ "Gcedil;": '\U00000122',
+ "Gcirc;": '\U0000011C',
+ "Gcy;": '\U00000413',
+ "Gdot;": '\U00000120',
+ "Gfr;": '\U0001D50A',
+ "Gg;": '\U000022D9',
+ "Gopf;": '\U0001D53E',
+ "GreaterEqual;": '\U00002265',
+ "GreaterEqualLess;": '\U000022DB',
+ "GreaterFullEqual;": '\U00002267',
+ "GreaterGreater;": '\U00002AA2',
+ "GreaterLess;": '\U00002277',
+ "GreaterSlantEqual;": '\U00002A7E',
+ "GreaterTilde;": '\U00002273',
+ "Gscr;": '\U0001D4A2',
+ "Gt;": '\U0000226B',
+ "HARDcy;": '\U0000042A',
+ "Hacek;": '\U000002C7',
+ "Hat;": '\U0000005E',
+ "Hcirc;": '\U00000124',
+ "Hfr;": '\U0000210C',
+ "HilbertSpace;": '\U0000210B',
+ "Hopf;": '\U0000210D',
+ "HorizontalLine;": '\U00002500',
+ "Hscr;": '\U0000210B',
+ "Hstrok;": '\U00000126',
+ "HumpDownHump;": '\U0000224E',
+ "HumpEqual;": '\U0000224F',
+ "IEcy;": '\U00000415',
+ "IJlig;": '\U00000132',
+ "IOcy;": '\U00000401',
+ "Iacute;": '\U000000CD',
+ "Icirc;": '\U000000CE',
+ "Icy;": '\U00000418',
+ "Idot;": '\U00000130',
+ "Ifr;": '\U00002111',
+ "Igrave;": '\U000000CC',
+ "Im;": '\U00002111',
+ "Imacr;": '\U0000012A',
+ "ImaginaryI;": '\U00002148',
+ "Implies;": '\U000021D2',
+ "Int;": '\U0000222C',
+ "Integral;": '\U0000222B',
+ "Intersection;": '\U000022C2',
+ "InvisibleComma;": '\U00002063',
+ "InvisibleTimes;": '\U00002062',
+ "Iogon;": '\U0000012E',
+ "Iopf;": '\U0001D540',
+ "Iota;": '\U00000399',
+ "Iscr;": '\U00002110',
+ "Itilde;": '\U00000128',
+ "Iukcy;": '\U00000406',
+ "Iuml;": '\U000000CF',
+ "Jcirc;": '\U00000134',
+ "Jcy;": '\U00000419',
+ "Jfr;": '\U0001D50D',
+ "Jopf;": '\U0001D541',
+ "Jscr;": '\U0001D4A5',
+ "Jsercy;": '\U00000408',
+ "Jukcy;": '\U00000404',
+ "KHcy;": '\U00000425',
+ "KJcy;": '\U0000040C',
+ "Kappa;": '\U0000039A',
+ "Kcedil;": '\U00000136',
+ "Kcy;": '\U0000041A',
+ "Kfr;": '\U0001D50E',
+ "Kopf;": '\U0001D542',
+ "Kscr;": '\U0001D4A6',
+ "LJcy;": '\U00000409',
+ "LT;": '\U0000003C',
+ "Lacute;": '\U00000139',
+ "Lambda;": '\U0000039B',
+ "Lang;": '\U000027EA',
+ "Laplacetrf;": '\U00002112',
+ "Larr;": '\U0000219E',
+ "Lcaron;": '\U0000013D',
+ "Lcedil;": '\U0000013B',
+ "Lcy;": '\U0000041B',
+ "LeftAngleBracket;": '\U000027E8',
+ "LeftArrow;": '\U00002190',
+ "LeftArrowBar;": '\U000021E4',
+ "LeftArrowRightArrow;": '\U000021C6',
+ "LeftCeiling;": '\U00002308',
+ "LeftDoubleBracket;": '\U000027E6',
+ "LeftDownTeeVector;": '\U00002961',
+ "LeftDownVector;": '\U000021C3',
+ "LeftDownVectorBar;": '\U00002959',
+ "LeftFloor;": '\U0000230A',
+ "LeftRightArrow;": '\U00002194',
+ "LeftRightVector;": '\U0000294E',
+ "LeftTee;": '\U000022A3',
+ "LeftTeeArrow;": '\U000021A4',
+ "LeftTeeVector;": '\U0000295A',
+ "LeftTriangle;": '\U000022B2',
+ "LeftTriangleBar;": '\U000029CF',
+ "LeftTriangleEqual;": '\U000022B4',
+ "LeftUpDownVector;": '\U00002951',
+ "LeftUpTeeVector;": '\U00002960',
+ "LeftUpVector;": '\U000021BF',
+ "LeftUpVectorBar;": '\U00002958',
+ "LeftVector;": '\U000021BC',
+ "LeftVectorBar;": '\U00002952',
+ "Leftarrow;": '\U000021D0',
+ "Leftrightarrow;": '\U000021D4',
+ "LessEqualGreater;": '\U000022DA',
+ "LessFullEqual;": '\U00002266',
+ "LessGreater;": '\U00002276',
+ "LessLess;": '\U00002AA1',
+ "LessSlantEqual;": '\U00002A7D',
+ "LessTilde;": '\U00002272',
+ "Lfr;": '\U0001D50F',
+ "Ll;": '\U000022D8',
+ "Lleftarrow;": '\U000021DA',
+ "Lmidot;": '\U0000013F',
+ "LongLeftArrow;": '\U000027F5',
+ "LongLeftRightArrow;": '\U000027F7',
+ "LongRightArrow;": '\U000027F6',
+ "Longleftarrow;": '\U000027F8',
+ "Longleftrightarrow;": '\U000027FA',
+ "Longrightarrow;": '\U000027F9',
+ "Lopf;": '\U0001D543',
+ "LowerLeftArrow;": '\U00002199',
+ "LowerRightArrow;": '\U00002198',
+ "Lscr;": '\U00002112',
+ "Lsh;": '\U000021B0',
+ "Lstrok;": '\U00000141',
+ "Lt;": '\U0000226A',
+ "Map;": '\U00002905',
+ "Mcy;": '\U0000041C',
+ "MediumSpace;": '\U0000205F',
+ "Mellintrf;": '\U00002133',
+ "Mfr;": '\U0001D510',
+ "MinusPlus;": '\U00002213',
+ "Mopf;": '\U0001D544',
+ "Mscr;": '\U00002133',
+ "Mu;": '\U0000039C',
+ "NJcy;": '\U0000040A',
+ "Nacute;": '\U00000143',
+ "Ncaron;": '\U00000147',
+ "Ncedil;": '\U00000145',
+ "Ncy;": '\U0000041D',
+ "NegativeMediumSpace;": '\U0000200B',
+ "NegativeThickSpace;": '\U0000200B',
+ "NegativeThinSpace;": '\U0000200B',
+ "NegativeVeryThinSpace;": '\U0000200B',
+ "NestedGreaterGreater;": '\U0000226B',
+ "NestedLessLess;": '\U0000226A',
+ "NewLine;": '\U0000000A',
+ "Nfr;": '\U0001D511',
+ "NoBreak;": '\U00002060',
+ "NonBreakingSpace;": '\U000000A0',
+ "Nopf;": '\U00002115',
+ "Not;": '\U00002AEC',
+ "NotCongruent;": '\U00002262',
+ "NotCupCap;": '\U0000226D',
+ "NotDoubleVerticalBar;": '\U00002226',
+ "NotElement;": '\U00002209',
+ "NotEqual;": '\U00002260',
+ "NotExists;": '\U00002204',
+ "NotGreater;": '\U0000226F',
+ "NotGreaterEqual;": '\U00002271',
+ "NotGreaterLess;": '\U00002279',
+ "NotGreaterTilde;": '\U00002275',
+ "NotLeftTriangle;": '\U000022EA',
+ "NotLeftTriangleEqual;": '\U000022EC',
+ "NotLess;": '\U0000226E',
+ "NotLessEqual;": '\U00002270',
+ "NotLessGreater;": '\U00002278',
+ "NotLessTilde;": '\U00002274',
+ "NotPrecedes;": '\U00002280',
+ "NotPrecedesSlantEqual;": '\U000022E0',
+ "NotReverseElement;": '\U0000220C',
+ "NotRightTriangle;": '\U000022EB',
+ "NotRightTriangleEqual;": '\U000022ED',
+ "NotSquareSubsetEqual;": '\U000022E2',
+ "NotSquareSupersetEqual;": '\U000022E3',
+ "NotSubsetEqual;": '\U00002288',
+ "NotSucceeds;": '\U00002281',
+ "NotSucceedsSlantEqual;": '\U000022E1',
+ "NotSupersetEqual;": '\U00002289',
+ "NotTilde;": '\U00002241',
+ "NotTildeEqual;": '\U00002244',
+ "NotTildeFullEqual;": '\U00002247',
+ "NotTildeTilde;": '\U00002249',
+ "NotVerticalBar;": '\U00002224',
+ "Nscr;": '\U0001D4A9',
+ "Ntilde;": '\U000000D1',
+ "Nu;": '\U0000039D',
+ "OElig;": '\U00000152',
+ "Oacute;": '\U000000D3',
+ "Ocirc;": '\U000000D4',
+ "Ocy;": '\U0000041E',
+ "Odblac;": '\U00000150',
+ "Ofr;": '\U0001D512',
+ "Ograve;": '\U000000D2',
+ "Omacr;": '\U0000014C',
+ "Omega;": '\U000003A9',
+ "Omicron;": '\U0000039F',
+ "Oopf;": '\U0001D546',
+ "OpenCurlyDoubleQuote;": '\U0000201C',
+ "OpenCurlyQuote;": '\U00002018',
+ "Or;": '\U00002A54',
+ "Oscr;": '\U0001D4AA',
+ "Oslash;": '\U000000D8',
+ "Otilde;": '\U000000D5',
+ "Otimes;": '\U00002A37',
+ "Ouml;": '\U000000D6',
+ "OverBar;": '\U0000203E',
+ "OverBrace;": '\U000023DE',
+ "OverBracket;": '\U000023B4',
+ "OverParenthesis;": '\U000023DC',
+ "PartialD;": '\U00002202',
+ "Pcy;": '\U0000041F',
+ "Pfr;": '\U0001D513',
+ "Phi;": '\U000003A6',
+ "Pi;": '\U000003A0',
+ "PlusMinus;": '\U000000B1',
+ "Poincareplane;": '\U0000210C',
+ "Popf;": '\U00002119',
+ "Pr;": '\U00002ABB',
+ "Precedes;": '\U0000227A',
+ "PrecedesEqual;": '\U00002AAF',
+ "PrecedesSlantEqual;": '\U0000227C',
+ "PrecedesTilde;": '\U0000227E',
+ "Prime;": '\U00002033',
+ "Product;": '\U0000220F',
+ "Proportion;": '\U00002237',
+ "Proportional;": '\U0000221D',
+ "Pscr;": '\U0001D4AB',
+ "Psi;": '\U000003A8',
+ "QUOT;": '\U00000022',
+ "Qfr;": '\U0001D514',
+ "Qopf;": '\U0000211A',
+ "Qscr;": '\U0001D4AC',
+ "RBarr;": '\U00002910',
+ "REG;": '\U000000AE',
+ "Racute;": '\U00000154',
+ "Rang;": '\U000027EB',
+ "Rarr;": '\U000021A0',
+ "Rarrtl;": '\U00002916',
+ "Rcaron;": '\U00000158',
+ "Rcedil;": '\U00000156',
+ "Rcy;": '\U00000420',
+ "Re;": '\U0000211C',
+ "ReverseElement;": '\U0000220B',
+ "ReverseEquilibrium;": '\U000021CB',
+ "ReverseUpEquilibrium;": '\U0000296F',
+ "Rfr;": '\U0000211C',
+ "Rho;": '\U000003A1',
+ "RightAngleBracket;": '\U000027E9',
+ "RightArrow;": '\U00002192',
+ "RightArrowBar;": '\U000021E5',
+ "RightArrowLeftArrow;": '\U000021C4',
+ "RightCeiling;": '\U00002309',
+ "RightDoubleBracket;": '\U000027E7',
+ "RightDownTeeVector;": '\U0000295D',
+ "RightDownVector;": '\U000021C2',
+ "RightDownVectorBar;": '\U00002955',
+ "RightFloor;": '\U0000230B',
+ "RightTee;": '\U000022A2',
+ "RightTeeArrow;": '\U000021A6',
+ "RightTeeVector;": '\U0000295B',
+ "RightTriangle;": '\U000022B3',
+ "RightTriangleBar;": '\U000029D0',
+ "RightTriangleEqual;": '\U000022B5',
+ "RightUpDownVector;": '\U0000294F',
+ "RightUpTeeVector;": '\U0000295C',
+ "RightUpVector;": '\U000021BE',
+ "RightUpVectorBar;": '\U00002954',
+ "RightVector;": '\U000021C0',
+ "RightVectorBar;": '\U00002953',
+ "Rightarrow;": '\U000021D2',
+ "Ropf;": '\U0000211D',
+ "RoundImplies;": '\U00002970',
+ "Rrightarrow;": '\U000021DB',
+ "Rscr;": '\U0000211B',
+ "Rsh;": '\U000021B1',
+ "RuleDelayed;": '\U000029F4',
+ "SHCHcy;": '\U00000429',
+ "SHcy;": '\U00000428',
+ "SOFTcy;": '\U0000042C',
+ "Sacute;": '\U0000015A',
+ "Sc;": '\U00002ABC',
+ "Scaron;": '\U00000160',
+ "Scedil;": '\U0000015E',
+ "Scirc;": '\U0000015C',
+ "Scy;": '\U00000421',
+ "Sfr;": '\U0001D516',
+ "ShortDownArrow;": '\U00002193',
+ "ShortLeftArrow;": '\U00002190',
+ "ShortRightArrow;": '\U00002192',
+ "ShortUpArrow;": '\U00002191',
+ "Sigma;": '\U000003A3',
+ "SmallCircle;": '\U00002218',
+ "Sopf;": '\U0001D54A',
+ "Sqrt;": '\U0000221A',
+ "Square;": '\U000025A1',
+ "SquareIntersection;": '\U00002293',
+ "SquareSubset;": '\U0000228F',
+ "SquareSubsetEqual;": '\U00002291',
+ "SquareSuperset;": '\U00002290',
+ "SquareSupersetEqual;": '\U00002292',
+ "SquareUnion;": '\U00002294',
+ "Sscr;": '\U0001D4AE',
+ "Star;": '\U000022C6',
+ "Sub;": '\U000022D0',
+ "Subset;": '\U000022D0',
+ "SubsetEqual;": '\U00002286',
+ "Succeeds;": '\U0000227B',
+ "SucceedsEqual;": '\U00002AB0',
+ "SucceedsSlantEqual;": '\U0000227D',
+ "SucceedsTilde;": '\U0000227F',
+ "SuchThat;": '\U0000220B',
+ "Sum;": '\U00002211',
+ "Sup;": '\U000022D1',
+ "Superset;": '\U00002283',
+ "SupersetEqual;": '\U00002287',
+ "Supset;": '\U000022D1',
+ "THORN;": '\U000000DE',
+ "TRADE;": '\U00002122',
+ "TSHcy;": '\U0000040B',
+ "TScy;": '\U00000426',
+ "Tab;": '\U00000009',
+ "Tau;": '\U000003A4',
+ "Tcaron;": '\U00000164',
+ "Tcedil;": '\U00000162',
+ "Tcy;": '\U00000422',
+ "Tfr;": '\U0001D517',
+ "Therefore;": '\U00002234',
+ "Theta;": '\U00000398',
+ "ThinSpace;": '\U00002009',
+ "Tilde;": '\U0000223C',
+ "TildeEqual;": '\U00002243',
+ "TildeFullEqual;": '\U00002245',
+ "TildeTilde;": '\U00002248',
+ "Topf;": '\U0001D54B',
+ "TripleDot;": '\U000020DB',
+ "Tscr;": '\U0001D4AF',
+ "Tstrok;": '\U00000166',
+ "Uacute;": '\U000000DA',
+ "Uarr;": '\U0000219F',
+ "Uarrocir;": '\U00002949',
+ "Ubrcy;": '\U0000040E',
+ "Ubreve;": '\U0000016C',
+ "Ucirc;": '\U000000DB',
+ "Ucy;": '\U00000423',
+ "Udblac;": '\U00000170',
+ "Ufr;": '\U0001D518',
+ "Ugrave;": '\U000000D9',
+ "Umacr;": '\U0000016A',
+ "UnderBar;": '\U0000005F',
+ "UnderBrace;": '\U000023DF',
+ "UnderBracket;": '\U000023B5',
+ "UnderParenthesis;": '\U000023DD',
+ "Union;": '\U000022C3',
+ "UnionPlus;": '\U0000228E',
+ "Uogon;": '\U00000172',
+ "Uopf;": '\U0001D54C',
+ "UpArrow;": '\U00002191',
+ "UpArrowBar;": '\U00002912',
+ "UpArrowDownArrow;": '\U000021C5',
+ "UpDownArrow;": '\U00002195',
+ "UpEquilibrium;": '\U0000296E',
+ "UpTee;": '\U000022A5',
+ "UpTeeArrow;": '\U000021A5',
+ "Uparrow;": '\U000021D1',
+ "Updownarrow;": '\U000021D5',
+ "UpperLeftArrow;": '\U00002196',
+ "UpperRightArrow;": '\U00002197',
+ "Upsi;": '\U000003D2',
+ "Upsilon;": '\U000003A5',
+ "Uring;": '\U0000016E',
+ "Uscr;": '\U0001D4B0',
+ "Utilde;": '\U00000168',
+ "Uuml;": '\U000000DC',
+ "VDash;": '\U000022AB',
+ "Vbar;": '\U00002AEB',
+ "Vcy;": '\U00000412',
+ "Vdash;": '\U000022A9',
+ "Vdashl;": '\U00002AE6',
+ "Vee;": '\U000022C1',
+ "Verbar;": '\U00002016',
+ "Vert;": '\U00002016',
+ "VerticalBar;": '\U00002223',
+ "VerticalLine;": '\U0000007C',
+ "VerticalSeparator;": '\U00002758',
+ "VerticalTilde;": '\U00002240',
+ "VeryThinSpace;": '\U0000200A',
+ "Vfr;": '\U0001D519',
+ "Vopf;": '\U0001D54D',
+ "Vscr;": '\U0001D4B1',
+ "Vvdash;": '\U000022AA',
+ "Wcirc;": '\U00000174',
+ "Wedge;": '\U000022C0',
+ "Wfr;": '\U0001D51A',
+ "Wopf;": '\U0001D54E',
+ "Wscr;": '\U0001D4B2',
+ "Xfr;": '\U0001D51B',
+ "Xi;": '\U0000039E',
+ "Xopf;": '\U0001D54F',
+ "Xscr;": '\U0001D4B3',
+ "YAcy;": '\U0000042F',
+ "YIcy;": '\U00000407',
+ "YUcy;": '\U0000042E',
+ "Yacute;": '\U000000DD',
+ "Ycirc;": '\U00000176',
+ "Ycy;": '\U0000042B',
+ "Yfr;": '\U0001D51C',
+ "Yopf;": '\U0001D550',
+ "Yscr;": '\U0001D4B4',
+ "Yuml;": '\U00000178',
+ "ZHcy;": '\U00000416',
+ "Zacute;": '\U00000179',
+ "Zcaron;": '\U0000017D',
+ "Zcy;": '\U00000417',
+ "Zdot;": '\U0000017B',
+ "ZeroWidthSpace;": '\U0000200B',
+ "Zeta;": '\U00000396',
+ "Zfr;": '\U00002128',
+ "Zopf;": '\U00002124',
+ "Zscr;": '\U0001D4B5',
+ "aacute;": '\U000000E1',
+ "abreve;": '\U00000103',
+ "ac;": '\U0000223E',
+ "acd;": '\U0000223F',
+ "acirc;": '\U000000E2',
+ "acute;": '\U000000B4',
+ "acy;": '\U00000430',
+ "aelig;": '\U000000E6',
+ "af;": '\U00002061',
+ "afr;": '\U0001D51E',
+ "agrave;": '\U000000E0',
+ "alefsym;": '\U00002135',
+ "aleph;": '\U00002135',
+ "alpha;": '\U000003B1',
+ "amacr;": '\U00000101',
+ "amalg;": '\U00002A3F',
+ "amp;": '\U00000026',
+ "and;": '\U00002227',
+ "andand;": '\U00002A55',
+ "andd;": '\U00002A5C',
+ "andslope;": '\U00002A58',
+ "andv;": '\U00002A5A',
+ "ang;": '\U00002220',
+ "ange;": '\U000029A4',
+ "angle;": '\U00002220',
+ "angmsd;": '\U00002221',
+ "angmsdaa;": '\U000029A8',
+ "angmsdab;": '\U000029A9',
+ "angmsdac;": '\U000029AA',
+ "angmsdad;": '\U000029AB',
+ "angmsdae;": '\U000029AC',
+ "angmsdaf;": '\U000029AD',
+ "angmsdag;": '\U000029AE',
+ "angmsdah;": '\U000029AF',
+ "angrt;": '\U0000221F',
+ "angrtvb;": '\U000022BE',
+ "angrtvbd;": '\U0000299D',
+ "angsph;": '\U00002222',
+ "angst;": '\U000000C5',
+ "angzarr;": '\U0000237C',
+ "aogon;": '\U00000105',
+ "aopf;": '\U0001D552',
+ "ap;": '\U00002248',
+ "apE;": '\U00002A70',
+ "apacir;": '\U00002A6F',
+ "ape;": '\U0000224A',
+ "apid;": '\U0000224B',
+ "apos;": '\U00000027',
+ "approx;": '\U00002248',
+ "approxeq;": '\U0000224A',
+ "aring;": '\U000000E5',
+ "ascr;": '\U0001D4B6',
+ "ast;": '\U0000002A',
+ "asymp;": '\U00002248',
+ "asympeq;": '\U0000224D',
+ "atilde;": '\U000000E3',
+ "auml;": '\U000000E4',
+ "awconint;": '\U00002233',
+ "awint;": '\U00002A11',
+ "bNot;": '\U00002AED',
+ "backcong;": '\U0000224C',
+ "backepsilon;": '\U000003F6',
+ "backprime;": '\U00002035',
+ "backsim;": '\U0000223D',
+ "backsimeq;": '\U000022CD',
+ "barvee;": '\U000022BD',
+ "barwed;": '\U00002305',
+ "barwedge;": '\U00002305',
+ "bbrk;": '\U000023B5',
+ "bbrktbrk;": '\U000023B6',
+ "bcong;": '\U0000224C',
+ "bcy;": '\U00000431',
+ "bdquo;": '\U0000201E',
+ "becaus;": '\U00002235',
+ "because;": '\U00002235',
+ "bemptyv;": '\U000029B0',
+ "bepsi;": '\U000003F6',
+ "bernou;": '\U0000212C',
+ "beta;": '\U000003B2',
+ "beth;": '\U00002136',
+ "between;": '\U0000226C',
+ "bfr;": '\U0001D51F',
+ "bigcap;": '\U000022C2',
+ "bigcirc;": '\U000025EF',
+ "bigcup;": '\U000022C3',
+ "bigodot;": '\U00002A00',
+ "bigoplus;": '\U00002A01',
+ "bigotimes;": '\U00002A02',
+ "bigsqcup;": '\U00002A06',
+ "bigstar;": '\U00002605',
+ "bigtriangledown;": '\U000025BD',
+ "bigtriangleup;": '\U000025B3',
+ "biguplus;": '\U00002A04',
+ "bigvee;": '\U000022C1',
+ "bigwedge;": '\U000022C0',
+ "bkarow;": '\U0000290D',
+ "blacklozenge;": '\U000029EB',
+ "blacksquare;": '\U000025AA',
+ "blacktriangle;": '\U000025B4',
+ "blacktriangledown;": '\U000025BE',
+ "blacktriangleleft;": '\U000025C2',
+ "blacktriangleright;": '\U000025B8',
+ "blank;": '\U00002423',
+ "blk12;": '\U00002592',
+ "blk14;": '\U00002591',
+ "blk34;": '\U00002593',
+ "block;": '\U00002588',
+ "bnot;": '\U00002310',
+ "bopf;": '\U0001D553',
+ "bot;": '\U000022A5',
+ "bottom;": '\U000022A5',
+ "bowtie;": '\U000022C8',
+ "boxDL;": '\U00002557',
+ "boxDR;": '\U00002554',
+ "boxDl;": '\U00002556',
+ "boxDr;": '\U00002553',
+ "boxH;": '\U00002550',
+ "boxHD;": '\U00002566',
+ "boxHU;": '\U00002569',
+ "boxHd;": '\U00002564',
+ "boxHu;": '\U00002567',
+ "boxUL;": '\U0000255D',
+ "boxUR;": '\U0000255A',
+ "boxUl;": '\U0000255C',
+ "boxUr;": '\U00002559',
+ "boxV;": '\U00002551',
+ "boxVH;": '\U0000256C',
+ "boxVL;": '\U00002563',
+ "boxVR;": '\U00002560',
+ "boxVh;": '\U0000256B',
+ "boxVl;": '\U00002562',
+ "boxVr;": '\U0000255F',
+ "boxbox;": '\U000029C9',
+ "boxdL;": '\U00002555',
+ "boxdR;": '\U00002552',
+ "boxdl;": '\U00002510',
+ "boxdr;": '\U0000250C',
+ "boxh;": '\U00002500',
+ "boxhD;": '\U00002565',
+ "boxhU;": '\U00002568',
+ "boxhd;": '\U0000252C',
+ "boxhu;": '\U00002534',
+ "boxminus;": '\U0000229F',
+ "boxplus;": '\U0000229E',
+ "boxtimes;": '\U000022A0',
+ "boxuL;": '\U0000255B',
+ "boxuR;": '\U00002558',
+ "boxul;": '\U00002518',
+ "boxur;": '\U00002514',
+ "boxv;": '\U00002502',
+ "boxvH;": '\U0000256A',
+ "boxvL;": '\U00002561',
+ "boxvR;": '\U0000255E',
+ "boxvh;": '\U0000253C',
+ "boxvl;": '\U00002524',
+ "boxvr;": '\U0000251C',
+ "bprime;": '\U00002035',
+ "breve;": '\U000002D8',
+ "brvbar;": '\U000000A6',
+ "bscr;": '\U0001D4B7',
+ "bsemi;": '\U0000204F',
+ "bsim;": '\U0000223D',
+ "bsime;": '\U000022CD',
+ "bsol;": '\U0000005C',
+ "bsolb;": '\U000029C5',
+ "bsolhsub;": '\U000027C8',
+ "bull;": '\U00002022',
+ "bullet;": '\U00002022',
+ "bump;": '\U0000224E',
+ "bumpE;": '\U00002AAE',
+ "bumpe;": '\U0000224F',
+ "bumpeq;": '\U0000224F',
+ "cacute;": '\U00000107',
+ "cap;": '\U00002229',
+ "capand;": '\U00002A44',
+ "capbrcup;": '\U00002A49',
+ "capcap;": '\U00002A4B',
+ "capcup;": '\U00002A47',
+ "capdot;": '\U00002A40',
+ "caret;": '\U00002041',
+ "caron;": '\U000002C7',
+ "ccaps;": '\U00002A4D',
+ "ccaron;": '\U0000010D',
+ "ccedil;": '\U000000E7',
+ "ccirc;": '\U00000109',
+ "ccups;": '\U00002A4C',
+ "ccupssm;": '\U00002A50',
+ "cdot;": '\U0000010B',
+ "cedil;": '\U000000B8',
+ "cemptyv;": '\U000029B2',
+ "cent;": '\U000000A2',
+ "centerdot;": '\U000000B7',
+ "cfr;": '\U0001D520',
+ "chcy;": '\U00000447',
+ "check;": '\U00002713',
+ "checkmark;": '\U00002713',
+ "chi;": '\U000003C7',
+ "cir;": '\U000025CB',
+ "cirE;": '\U000029C3',
+ "circ;": '\U000002C6',
+ "circeq;": '\U00002257',
+ "circlearrowleft;": '\U000021BA',
+ "circlearrowright;": '\U000021BB',
+ "circledR;": '\U000000AE',
+ "circledS;": '\U000024C8',
+ "circledast;": '\U0000229B',
+ "circledcirc;": '\U0000229A',
+ "circleddash;": '\U0000229D',
+ "cire;": '\U00002257',
+ "cirfnint;": '\U00002A10',
+ "cirmid;": '\U00002AEF',
+ "cirscir;": '\U000029C2',
+ "clubs;": '\U00002663',
+ "clubsuit;": '\U00002663',
+ "colon;": '\U0000003A',
+ "colone;": '\U00002254',
+ "coloneq;": '\U00002254',
+ "comma;": '\U0000002C',
+ "commat;": '\U00000040',
+ "comp;": '\U00002201',
+ "compfn;": '\U00002218',
+ "complement;": '\U00002201',
+ "complexes;": '\U00002102',
+ "cong;": '\U00002245',
+ "congdot;": '\U00002A6D',
+ "conint;": '\U0000222E',
+ "copf;": '\U0001D554',
+ "coprod;": '\U00002210',
+ "copy;": '\U000000A9',
+ "copysr;": '\U00002117',
+ "crarr;": '\U000021B5',
+ "cross;": '\U00002717',
+ "cscr;": '\U0001D4B8',
+ "csub;": '\U00002ACF',
+ "csube;": '\U00002AD1',
+ "csup;": '\U00002AD0',
+ "csupe;": '\U00002AD2',
+ "ctdot;": '\U000022EF',
+ "cudarrl;": '\U00002938',
+ "cudarrr;": '\U00002935',
+ "cuepr;": '\U000022DE',
+ "cuesc;": '\U000022DF',
+ "cularr;": '\U000021B6',
+ "cularrp;": '\U0000293D',
+ "cup;": '\U0000222A',
+ "cupbrcap;": '\U00002A48',
+ "cupcap;": '\U00002A46',
+ "cupcup;": '\U00002A4A',
+ "cupdot;": '\U0000228D',
+ "cupor;": '\U00002A45',
+ "curarr;": '\U000021B7',
+ "curarrm;": '\U0000293C',
+ "curlyeqprec;": '\U000022DE',
+ "curlyeqsucc;": '\U000022DF',
+ "curlyvee;": '\U000022CE',
+ "curlywedge;": '\U000022CF',
+ "curren;": '\U000000A4',
+ "curvearrowleft;": '\U000021B6',
+ "curvearrowright;": '\U000021B7',
+ "cuvee;": '\U000022CE',
+ "cuwed;": '\U000022CF',
+ "cwconint;": '\U00002232',
+ "cwint;": '\U00002231',
+ "cylcty;": '\U0000232D',
+ "dArr;": '\U000021D3',
+ "dHar;": '\U00002965',
+ "dagger;": '\U00002020',
+ "daleth;": '\U00002138',
+ "darr;": '\U00002193',
+ "dash;": '\U00002010',
+ "dashv;": '\U000022A3',
+ "dbkarow;": '\U0000290F',
+ "dblac;": '\U000002DD',
+ "dcaron;": '\U0000010F',
+ "dcy;": '\U00000434',
+ "dd;": '\U00002146',
+ "ddagger;": '\U00002021',
+ "ddarr;": '\U000021CA',
+ "ddotseq;": '\U00002A77',
+ "deg;": '\U000000B0',
+ "delta;": '\U000003B4',
+ "demptyv;": '\U000029B1',
+ "dfisht;": '\U0000297F',
+ "dfr;": '\U0001D521',
+ "dharl;": '\U000021C3',
+ "dharr;": '\U000021C2',
+ "diam;": '\U000022C4',
+ "diamond;": '\U000022C4',
+ "diamondsuit;": '\U00002666',
+ "diams;": '\U00002666',
+ "die;": '\U000000A8',
+ "digamma;": '\U000003DD',
+ "disin;": '\U000022F2',
+ "div;": '\U000000F7',
+ "divide;": '\U000000F7',
+ "divideontimes;": '\U000022C7',
+ "divonx;": '\U000022C7',
+ "djcy;": '\U00000452',
+ "dlcorn;": '\U0000231E',
+ "dlcrop;": '\U0000230D',
+ "dollar;": '\U00000024',
+ "dopf;": '\U0001D555',
+ "dot;": '\U000002D9',
+ "doteq;": '\U00002250',
+ "doteqdot;": '\U00002251',
+ "dotminus;": '\U00002238',
+ "dotplus;": '\U00002214',
+ "dotsquare;": '\U000022A1',
+ "doublebarwedge;": '\U00002306',
+ "downarrow;": '\U00002193',
+ "downdownarrows;": '\U000021CA',
+ "downharpoonleft;": '\U000021C3',
+ "downharpoonright;": '\U000021C2',
+ "drbkarow;": '\U00002910',
+ "drcorn;": '\U0000231F',
+ "drcrop;": '\U0000230C',
+ "dscr;": '\U0001D4B9',
+ "dscy;": '\U00000455',
+ "dsol;": '\U000029F6',
+ "dstrok;": '\U00000111',
+ "dtdot;": '\U000022F1',
+ "dtri;": '\U000025BF',
+ "dtrif;": '\U000025BE',
+ "duarr;": '\U000021F5',
+ "duhar;": '\U0000296F',
+ "dwangle;": '\U000029A6',
+ "dzcy;": '\U0000045F',
+ "dzigrarr;": '\U000027FF',
+ "eDDot;": '\U00002A77',
+ "eDot;": '\U00002251',
+ "eacute;": '\U000000E9',
+ "easter;": '\U00002A6E',
+ "ecaron;": '\U0000011B',
+ "ecir;": '\U00002256',
+ "ecirc;": '\U000000EA',
+ "ecolon;": '\U00002255',
+ "ecy;": '\U0000044D',
+ "edot;": '\U00000117',
+ "ee;": '\U00002147',
+ "efDot;": '\U00002252',
+ "efr;": '\U0001D522',
+ "eg;": '\U00002A9A',
+ "egrave;": '\U000000E8',
+ "egs;": '\U00002A96',
+ "egsdot;": '\U00002A98',
+ "el;": '\U00002A99',
+ "elinters;": '\U000023E7',
+ "ell;": '\U00002113',
+ "els;": '\U00002A95',
+ "elsdot;": '\U00002A97',
+ "emacr;": '\U00000113',
+ "empty;": '\U00002205',
+ "emptyset;": '\U00002205',
+ "emptyv;": '\U00002205',
+ "emsp;": '\U00002003',
+ "emsp13;": '\U00002004',
+ "emsp14;": '\U00002005',
+ "eng;": '\U0000014B',
+ "ensp;": '\U00002002',
+ "eogon;": '\U00000119',
+ "eopf;": '\U0001D556',
+ "epar;": '\U000022D5',
+ "eparsl;": '\U000029E3',
+ "eplus;": '\U00002A71',
+ "epsi;": '\U000003B5',
+ "epsilon;": '\U000003B5',
+ "epsiv;": '\U000003F5',
+ "eqcirc;": '\U00002256',
+ "eqcolon;": '\U00002255',
+ "eqsim;": '\U00002242',
+ "eqslantgtr;": '\U00002A96',
+ "eqslantless;": '\U00002A95',
+ "equals;": '\U0000003D',
+ "equest;": '\U0000225F',
+ "equiv;": '\U00002261',
+ "equivDD;": '\U00002A78',
+ "eqvparsl;": '\U000029E5',
+ "erDot;": '\U00002253',
+ "erarr;": '\U00002971',
+ "escr;": '\U0000212F',
+ "esdot;": '\U00002250',
+ "esim;": '\U00002242',
+ "eta;": '\U000003B7',
+ "eth;": '\U000000F0',
+ "euml;": '\U000000EB',
+ "euro;": '\U000020AC',
+ "excl;": '\U00000021',
+ "exist;": '\U00002203',
+ "expectation;": '\U00002130',
+ "exponentiale;": '\U00002147',
+ "fallingdotseq;": '\U00002252',
+ "fcy;": '\U00000444',
+ "female;": '\U00002640',
+ "ffilig;": '\U0000FB03',
+ "fflig;": '\U0000FB00',
+ "ffllig;": '\U0000FB04',
+ "ffr;": '\U0001D523',
+ "filig;": '\U0000FB01',
+ "flat;": '\U0000266D',
+ "fllig;": '\U0000FB02',
+ "fltns;": '\U000025B1',
+ "fnof;": '\U00000192',
+ "fopf;": '\U0001D557',
+ "forall;": '\U00002200',
+ "fork;": '\U000022D4',
+ "forkv;": '\U00002AD9',
+ "fpartint;": '\U00002A0D',
+ "frac12;": '\U000000BD',
+ "frac13;": '\U00002153',
+ "frac14;": '\U000000BC',
+ "frac15;": '\U00002155',
+ "frac16;": '\U00002159',
+ "frac18;": '\U0000215B',
+ "frac23;": '\U00002154',
+ "frac25;": '\U00002156',
+ "frac34;": '\U000000BE',
+ "frac35;": '\U00002157',
+ "frac38;": '\U0000215C',
+ "frac45;": '\U00002158',
+ "frac56;": '\U0000215A',
+ "frac58;": '\U0000215D',
+ "frac78;": '\U0000215E',
+ "frasl;": '\U00002044',
+ "frown;": '\U00002322',
+ "fscr;": '\U0001D4BB',
+ "gE;": '\U00002267',
+ "gEl;": '\U00002A8C',
+ "gacute;": '\U000001F5',
+ "gamma;": '\U000003B3',
+ "gammad;": '\U000003DD',
+ "gap;": '\U00002A86',
+ "gbreve;": '\U0000011F',
+ "gcirc;": '\U0000011D',
+ "gcy;": '\U00000433',
+ "gdot;": '\U00000121',
+ "ge;": '\U00002265',
+ "gel;": '\U000022DB',
+ "geq;": '\U00002265',
+ "geqq;": '\U00002267',
+ "geqslant;": '\U00002A7E',
+ "ges;": '\U00002A7E',
+ "gescc;": '\U00002AA9',
+ "gesdot;": '\U00002A80',
+ "gesdoto;": '\U00002A82',
+ "gesdotol;": '\U00002A84',
+ "gesles;": '\U00002A94',
+ "gfr;": '\U0001D524',
+ "gg;": '\U0000226B',
+ "ggg;": '\U000022D9',
+ "gimel;": '\U00002137',
+ "gjcy;": '\U00000453',
+ "gl;": '\U00002277',
+ "glE;": '\U00002A92',
+ "gla;": '\U00002AA5',
+ "glj;": '\U00002AA4',
+ "gnE;": '\U00002269',
+ "gnap;": '\U00002A8A',
+ "gnapprox;": '\U00002A8A',
+ "gne;": '\U00002A88',
+ "gneq;": '\U00002A88',
+ "gneqq;": '\U00002269',
+ "gnsim;": '\U000022E7',
+ "gopf;": '\U0001D558',
+ "grave;": '\U00000060',
+ "gscr;": '\U0000210A',
+ "gsim;": '\U00002273',
+ "gsime;": '\U00002A8E',
+ "gsiml;": '\U00002A90',
+ "gt;": '\U0000003E',
+ "gtcc;": '\U00002AA7',
+ "gtcir;": '\U00002A7A',
+ "gtdot;": '\U000022D7',
+ "gtlPar;": '\U00002995',
+ "gtquest;": '\U00002A7C',
+ "gtrapprox;": '\U00002A86',
+ "gtrarr;": '\U00002978',
+ "gtrdot;": '\U000022D7',
+ "gtreqless;": '\U000022DB',
+ "gtreqqless;": '\U00002A8C',
+ "gtrless;": '\U00002277',
+ "gtrsim;": '\U00002273',
+ "hArr;": '\U000021D4',
+ "hairsp;": '\U0000200A',
+ "half;": '\U000000BD',
+ "hamilt;": '\U0000210B',
+ "hardcy;": '\U0000044A',
+ "harr;": '\U00002194',
+ "harrcir;": '\U00002948',
+ "harrw;": '\U000021AD',
+ "hbar;": '\U0000210F',
+ "hcirc;": '\U00000125',
+ "hearts;": '\U00002665',
+ "heartsuit;": '\U00002665',
+ "hellip;": '\U00002026',
+ "hercon;": '\U000022B9',
+ "hfr;": '\U0001D525',
+ "hksearow;": '\U00002925',
+ "hkswarow;": '\U00002926',
+ "hoarr;": '\U000021FF',
+ "homtht;": '\U0000223B',
+ "hookleftarrow;": '\U000021A9',
+ "hookrightarrow;": '\U000021AA',
+ "hopf;": '\U0001D559',
+ "horbar;": '\U00002015',
+ "hscr;": '\U0001D4BD',
+ "hslash;": '\U0000210F',
+ "hstrok;": '\U00000127',
+ "hybull;": '\U00002043',
+ "hyphen;": '\U00002010',
+ "iacute;": '\U000000ED',
+ "ic;": '\U00002063',
+ "icirc;": '\U000000EE',
+ "icy;": '\U00000438',
+ "iecy;": '\U00000435',
+ "iexcl;": '\U000000A1',
+ "iff;": '\U000021D4',
+ "ifr;": '\U0001D526',
+ "igrave;": '\U000000EC',
+ "ii;": '\U00002148',
+ "iiiint;": '\U00002A0C',
+ "iiint;": '\U0000222D',
+ "iinfin;": '\U000029DC',
+ "iiota;": '\U00002129',
+ "ijlig;": '\U00000133',
+ "imacr;": '\U0000012B',
+ "image;": '\U00002111',
+ "imagline;": '\U00002110',
+ "imagpart;": '\U00002111',
+ "imath;": '\U00000131',
+ "imof;": '\U000022B7',
+ "imped;": '\U000001B5',
+ "in;": '\U00002208',
+ "incare;": '\U00002105',
+ "infin;": '\U0000221E',
+ "infintie;": '\U000029DD',
+ "inodot;": '\U00000131',
+ "int;": '\U0000222B',
+ "intcal;": '\U000022BA',
+ "integers;": '\U00002124',
+ "intercal;": '\U000022BA',
+ "intlarhk;": '\U00002A17',
+ "intprod;": '\U00002A3C',
+ "iocy;": '\U00000451',
+ "iogon;": '\U0000012F',
+ "iopf;": '\U0001D55A',
+ "iota;": '\U000003B9',
+ "iprod;": '\U00002A3C',
+ "iquest;": '\U000000BF',
+ "iscr;": '\U0001D4BE',
+ "isin;": '\U00002208',
+ "isinE;": '\U000022F9',
+ "isindot;": '\U000022F5',
+ "isins;": '\U000022F4',
+ "isinsv;": '\U000022F3',
+ "isinv;": '\U00002208',
+ "it;": '\U00002062',
+ "itilde;": '\U00000129',
+ "iukcy;": '\U00000456',
+ "iuml;": '\U000000EF',
+ "jcirc;": '\U00000135',
+ "jcy;": '\U00000439',
+ "jfr;": '\U0001D527',
+ "jmath;": '\U00000237',
+ "jopf;": '\U0001D55B',
+ "jscr;": '\U0001D4BF',
+ "jsercy;": '\U00000458',
+ "jukcy;": '\U00000454',
+ "kappa;": '\U000003BA',
+ "kappav;": '\U000003F0',
+ "kcedil;": '\U00000137',
+ "kcy;": '\U0000043A',
+ "kfr;": '\U0001D528',
+ "kgreen;": '\U00000138',
+ "khcy;": '\U00000445',
+ "kjcy;": '\U0000045C',
+ "kopf;": '\U0001D55C',
+ "kscr;": '\U0001D4C0',
+ "lAarr;": '\U000021DA',
+ "lArr;": '\U000021D0',
+ "lAtail;": '\U0000291B',
+ "lBarr;": '\U0000290E',
+ "lE;": '\U00002266',
+ "lEg;": '\U00002A8B',
+ "lHar;": '\U00002962',
+ "lacute;": '\U0000013A',
+ "laemptyv;": '\U000029B4',
+ "lagran;": '\U00002112',
+ "lambda;": '\U000003BB',
+ "lang;": '\U000027E8',
+ "langd;": '\U00002991',
+ "langle;": '\U000027E8',
+ "lap;": '\U00002A85',
+ "laquo;": '\U000000AB',
+ "larr;": '\U00002190',
+ "larrb;": '\U000021E4',
+ "larrbfs;": '\U0000291F',
+ "larrfs;": '\U0000291D',
+ "larrhk;": '\U000021A9',
+ "larrlp;": '\U000021AB',
+ "larrpl;": '\U00002939',
+ "larrsim;": '\U00002973',
+ "larrtl;": '\U000021A2',
+ "lat;": '\U00002AAB',
+ "latail;": '\U00002919',
+ "late;": '\U00002AAD',
+ "lbarr;": '\U0000290C',
+ "lbbrk;": '\U00002772',
+ "lbrace;": '\U0000007B',
+ "lbrack;": '\U0000005B',
+ "lbrke;": '\U0000298B',
+ "lbrksld;": '\U0000298F',
+ "lbrkslu;": '\U0000298D',
+ "lcaron;": '\U0000013E',
+ "lcedil;": '\U0000013C',
+ "lceil;": '\U00002308',
+ "lcub;": '\U0000007B',
+ "lcy;": '\U0000043B',
+ "ldca;": '\U00002936',
+ "ldquo;": '\U0000201C',
+ "ldquor;": '\U0000201E',
+ "ldrdhar;": '\U00002967',
+ "ldrushar;": '\U0000294B',
+ "ldsh;": '\U000021B2',
+ "le;": '\U00002264',
+ "leftarrow;": '\U00002190',
+ "leftarrowtail;": '\U000021A2',
+ "leftharpoondown;": '\U000021BD',
+ "leftharpoonup;": '\U000021BC',
+ "leftleftarrows;": '\U000021C7',
+ "leftrightarrow;": '\U00002194',
+ "leftrightarrows;": '\U000021C6',
+ "leftrightharpoons;": '\U000021CB',
+ "leftrightsquigarrow;": '\U000021AD',
+ "leftthreetimes;": '\U000022CB',
+ "leg;": '\U000022DA',
+ "leq;": '\U00002264',
+ "leqq;": '\U00002266',
+ "leqslant;": '\U00002A7D',
+ "les;": '\U00002A7D',
+ "lescc;": '\U00002AA8',
+ "lesdot;": '\U00002A7F',
+ "lesdoto;": '\U00002A81',
+ "lesdotor;": '\U00002A83',
+ "lesges;": '\U00002A93',
+ "lessapprox;": '\U00002A85',
+ "lessdot;": '\U000022D6',
+ "lesseqgtr;": '\U000022DA',
+ "lesseqqgtr;": '\U00002A8B',
+ "lessgtr;": '\U00002276',
+ "lesssim;": '\U00002272',
+ "lfisht;": '\U0000297C',
+ "lfloor;": '\U0000230A',
+ "lfr;": '\U0001D529',
+ "lg;": '\U00002276',
+ "lgE;": '\U00002A91',
+ "lhard;": '\U000021BD',
+ "lharu;": '\U000021BC',
+ "lharul;": '\U0000296A',
+ "lhblk;": '\U00002584',
+ "ljcy;": '\U00000459',
+ "ll;": '\U0000226A',
+ "llarr;": '\U000021C7',
+ "llcorner;": '\U0000231E',
+ "llhard;": '\U0000296B',
+ "lltri;": '\U000025FA',
+ "lmidot;": '\U00000140',
+ "lmoust;": '\U000023B0',
+ "lmoustache;": '\U000023B0',
+ "lnE;": '\U00002268',
+ "lnap;": '\U00002A89',
+ "lnapprox;": '\U00002A89',
+ "lne;": '\U00002A87',
+ "lneq;": '\U00002A87',
+ "lneqq;": '\U00002268',
+ "lnsim;": '\U000022E6',
+ "loang;": '\U000027EC',
+ "loarr;": '\U000021FD',
+ "lobrk;": '\U000027E6',
+ "longleftarrow;": '\U000027F5',
+ "longleftrightarrow;": '\U000027F7',
+ "longmapsto;": '\U000027FC',
+ "longrightarrow;": '\U000027F6',
+ "looparrowleft;": '\U000021AB',
+ "looparrowright;": '\U000021AC',
+ "lopar;": '\U00002985',
+ "lopf;": '\U0001D55D',
+ "loplus;": '\U00002A2D',
+ "lotimes;": '\U00002A34',
+ "lowast;": '\U00002217',
+ "lowbar;": '\U0000005F',
+ "loz;": '\U000025CA',
+ "lozenge;": '\U000025CA',
+ "lozf;": '\U000029EB',
+ "lpar;": '\U00000028',
+ "lparlt;": '\U00002993',
+ "lrarr;": '\U000021C6',
+ "lrcorner;": '\U0000231F',
+ "lrhar;": '\U000021CB',
+ "lrhard;": '\U0000296D',
+ "lrm;": '\U0000200E',
+ "lrtri;": '\U000022BF',
+ "lsaquo;": '\U00002039',
+ "lscr;": '\U0001D4C1',
+ "lsh;": '\U000021B0',
+ "lsim;": '\U00002272',
+ "lsime;": '\U00002A8D',
+ "lsimg;": '\U00002A8F',
+ "lsqb;": '\U0000005B',
+ "lsquo;": '\U00002018',
+ "lsquor;": '\U0000201A',
+ "lstrok;": '\U00000142',
+ "lt;": '\U0000003C',
+ "ltcc;": '\U00002AA6',
+ "ltcir;": '\U00002A79',
+ "ltdot;": '\U000022D6',
+ "lthree;": '\U000022CB',
+ "ltimes;": '\U000022C9',
+ "ltlarr;": '\U00002976',
+ "ltquest;": '\U00002A7B',
+ "ltrPar;": '\U00002996',
+ "ltri;": '\U000025C3',
+ "ltrie;": '\U000022B4',
+ "ltrif;": '\U000025C2',
+ "lurdshar;": '\U0000294A',
+ "luruhar;": '\U00002966',
+ "mDDot;": '\U0000223A',
+ "macr;": '\U000000AF',
+ "male;": '\U00002642',
+ "malt;": '\U00002720',
+ "maltese;": '\U00002720',
+ "map;": '\U000021A6',
+ "mapsto;": '\U000021A6',
+ "mapstodown;": '\U000021A7',
+ "mapstoleft;": '\U000021A4',
+ "mapstoup;": '\U000021A5',
+ "marker;": '\U000025AE',
+ "mcomma;": '\U00002A29',
+ "mcy;": '\U0000043C',
+ "mdash;": '\U00002014',
+ "measuredangle;": '\U00002221',
+ "mfr;": '\U0001D52A',
+ "mho;": '\U00002127',
+ "micro;": '\U000000B5',
+ "mid;": '\U00002223',
+ "midast;": '\U0000002A',
+ "midcir;": '\U00002AF0',
+ "middot;": '\U000000B7',
+ "minus;": '\U00002212',
+ "minusb;": '\U0000229F',
+ "minusd;": '\U00002238',
+ "minusdu;": '\U00002A2A',
+ "mlcp;": '\U00002ADB',
+ "mldr;": '\U00002026',
+ "mnplus;": '\U00002213',
+ "models;": '\U000022A7',
+ "mopf;": '\U0001D55E',
+ "mp;": '\U00002213',
+ "mscr;": '\U0001D4C2',
+ "mstpos;": '\U0000223E',
+ "mu;": '\U000003BC',
+ "multimap;": '\U000022B8',
+ "mumap;": '\U000022B8',
+ "nLeftarrow;": '\U000021CD',
+ "nLeftrightarrow;": '\U000021CE',
+ "nRightarrow;": '\U000021CF',
+ "nVDash;": '\U000022AF',
+ "nVdash;": '\U000022AE',
+ "nabla;": '\U00002207',
+ "nacute;": '\U00000144',
+ "nap;": '\U00002249',
+ "napos;": '\U00000149',
+ "napprox;": '\U00002249',
+ "natur;": '\U0000266E',
+ "natural;": '\U0000266E',
+ "naturals;": '\U00002115',
+ "nbsp;": '\U000000A0',
+ "ncap;": '\U00002A43',
+ "ncaron;": '\U00000148',
+ "ncedil;": '\U00000146',
+ "ncong;": '\U00002247',
+ "ncup;": '\U00002A42',
+ "ncy;": '\U0000043D',
+ "ndash;": '\U00002013',
+ "ne;": '\U00002260',
+ "neArr;": '\U000021D7',
+ "nearhk;": '\U00002924',
+ "nearr;": '\U00002197',
+ "nearrow;": '\U00002197',
+ "nequiv;": '\U00002262',
+ "nesear;": '\U00002928',
+ "nexist;": '\U00002204',
+ "nexists;": '\U00002204',
+ "nfr;": '\U0001D52B',
+ "nge;": '\U00002271',
+ "ngeq;": '\U00002271',
+ "ngsim;": '\U00002275',
+ "ngt;": '\U0000226F',
+ "ngtr;": '\U0000226F',
+ "nhArr;": '\U000021CE',
+ "nharr;": '\U000021AE',
+ "nhpar;": '\U00002AF2',
+ "ni;": '\U0000220B',
+ "nis;": '\U000022FC',
+ "nisd;": '\U000022FA',
+ "niv;": '\U0000220B',
+ "njcy;": '\U0000045A',
+ "nlArr;": '\U000021CD',
+ "nlarr;": '\U0000219A',
+ "nldr;": '\U00002025',
+ "nle;": '\U00002270',
+ "nleftarrow;": '\U0000219A',
+ "nleftrightarrow;": '\U000021AE',
+ "nleq;": '\U00002270',
+ "nless;": '\U0000226E',
+ "nlsim;": '\U00002274',
+ "nlt;": '\U0000226E',
+ "nltri;": '\U000022EA',
+ "nltrie;": '\U000022EC',
+ "nmid;": '\U00002224',
+ "nopf;": '\U0001D55F',
+ "not;": '\U000000AC',
+ "notin;": '\U00002209',
+ "notinva;": '\U00002209',
+ "notinvb;": '\U000022F7',
+ "notinvc;": '\U000022F6',
+ "notni;": '\U0000220C',
+ "notniva;": '\U0000220C',
+ "notnivb;": '\U000022FE',
+ "notnivc;": '\U000022FD',
+ "npar;": '\U00002226',
+ "nparallel;": '\U00002226',
+ "npolint;": '\U00002A14',
+ "npr;": '\U00002280',
+ "nprcue;": '\U000022E0',
+ "nprec;": '\U00002280',
+ "nrArr;": '\U000021CF',
+ "nrarr;": '\U0000219B',
+ "nrightarrow;": '\U0000219B',
+ "nrtri;": '\U000022EB',
+ "nrtrie;": '\U000022ED',
+ "nsc;": '\U00002281',
+ "nsccue;": '\U000022E1',
+ "nscr;": '\U0001D4C3',
+ "nshortmid;": '\U00002224',
+ "nshortparallel;": '\U00002226',
+ "nsim;": '\U00002241',
+ "nsime;": '\U00002244',
+ "nsimeq;": '\U00002244',
+ "nsmid;": '\U00002224',
+ "nspar;": '\U00002226',
+ "nsqsube;": '\U000022E2',
+ "nsqsupe;": '\U000022E3',
+ "nsub;": '\U00002284',
+ "nsube;": '\U00002288',
+ "nsubseteq;": '\U00002288',
+ "nsucc;": '\U00002281',
+ "nsup;": '\U00002285',
+ "nsupe;": '\U00002289',
+ "nsupseteq;": '\U00002289',
+ "ntgl;": '\U00002279',
+ "ntilde;": '\U000000F1',
+ "ntlg;": '\U00002278',
+ "ntriangleleft;": '\U000022EA',
+ "ntrianglelefteq;": '\U000022EC',
+ "ntriangleright;": '\U000022EB',
+ "ntrianglerighteq;": '\U000022ED',
+ "nu;": '\U000003BD',
+ "num;": '\U00000023',
+ "numero;": '\U00002116',
+ "numsp;": '\U00002007',
+ "nvDash;": '\U000022AD',
+ "nvHarr;": '\U00002904',
+ "nvdash;": '\U000022AC',
+ "nvinfin;": '\U000029DE',
+ "nvlArr;": '\U00002902',
+ "nvrArr;": '\U00002903',
+ "nwArr;": '\U000021D6',
+ "nwarhk;": '\U00002923',
+ "nwarr;": '\U00002196',
+ "nwarrow;": '\U00002196',
+ "nwnear;": '\U00002927',
+ "oS;": '\U000024C8',
+ "oacute;": '\U000000F3',
+ "oast;": '\U0000229B',
+ "ocir;": '\U0000229A',
+ "ocirc;": '\U000000F4',
+ "ocy;": '\U0000043E',
+ "odash;": '\U0000229D',
+ "odblac;": '\U00000151',
+ "odiv;": '\U00002A38',
+ "odot;": '\U00002299',
+ "odsold;": '\U000029BC',
+ "oelig;": '\U00000153',
+ "ofcir;": '\U000029BF',
+ "ofr;": '\U0001D52C',
+ "ogon;": '\U000002DB',
+ "ograve;": '\U000000F2',
+ "ogt;": '\U000029C1',
+ "ohbar;": '\U000029B5',
+ "ohm;": '\U000003A9',
+ "oint;": '\U0000222E',
+ "olarr;": '\U000021BA',
+ "olcir;": '\U000029BE',
+ "olcross;": '\U000029BB',
+ "oline;": '\U0000203E',
+ "olt;": '\U000029C0',
+ "omacr;": '\U0000014D',
+ "omega;": '\U000003C9',
+ "omicron;": '\U000003BF',
+ "omid;": '\U000029B6',
+ "ominus;": '\U00002296',
+ "oopf;": '\U0001D560',
+ "opar;": '\U000029B7',
+ "operp;": '\U000029B9',
+ "oplus;": '\U00002295',
+ "or;": '\U00002228',
+ "orarr;": '\U000021BB',
+ "ord;": '\U00002A5D',
+ "order;": '\U00002134',
+ "orderof;": '\U00002134',
+ "ordf;": '\U000000AA',
+ "ordm;": '\U000000BA',
+ "origof;": '\U000022B6',
+ "oror;": '\U00002A56',
+ "orslope;": '\U00002A57',
+ "orv;": '\U00002A5B',
+ "oscr;": '\U00002134',
+ "oslash;": '\U000000F8',
+ "osol;": '\U00002298',
+ "otilde;": '\U000000F5',
+ "otimes;": '\U00002297',
+ "otimesas;": '\U00002A36',
+ "ouml;": '\U000000F6',
+ "ovbar;": '\U0000233D',
+ "par;": '\U00002225',
+ "para;": '\U000000B6',
+ "parallel;": '\U00002225',
+ "parsim;": '\U00002AF3',
+ "parsl;": '\U00002AFD',
+ "part;": '\U00002202',
+ "pcy;": '\U0000043F',
+ "percnt;": '\U00000025',
+ "period;": '\U0000002E',
+ "permil;": '\U00002030',
+ "perp;": '\U000022A5',
+ "pertenk;": '\U00002031',
+ "pfr;": '\U0001D52D',
+ "phi;": '\U000003C6',
+ "phiv;": '\U000003D5',
+ "phmmat;": '\U00002133',
+ "phone;": '\U0000260E',
+ "pi;": '\U000003C0',
+ "pitchfork;": '\U000022D4',
+ "piv;": '\U000003D6',
+ "planck;": '\U0000210F',
+ "planckh;": '\U0000210E',
+ "plankv;": '\U0000210F',
+ "plus;": '\U0000002B',
+ "plusacir;": '\U00002A23',
+ "plusb;": '\U0000229E',
+ "pluscir;": '\U00002A22',
+ "plusdo;": '\U00002214',
+ "plusdu;": '\U00002A25',
+ "pluse;": '\U00002A72',
+ "plusmn;": '\U000000B1',
+ "plussim;": '\U00002A26',
+ "plustwo;": '\U00002A27',
+ "pm;": '\U000000B1',
+ "pointint;": '\U00002A15',
+ "popf;": '\U0001D561',
+ "pound;": '\U000000A3',
+ "pr;": '\U0000227A',
+ "prE;": '\U00002AB3',
+ "prap;": '\U00002AB7',
+ "prcue;": '\U0000227C',
+ "pre;": '\U00002AAF',
+ "prec;": '\U0000227A',
+ "precapprox;": '\U00002AB7',
+ "preccurlyeq;": '\U0000227C',
+ "preceq;": '\U00002AAF',
+ "precnapprox;": '\U00002AB9',
+ "precneqq;": '\U00002AB5',
+ "precnsim;": '\U000022E8',
+ "precsim;": '\U0000227E',
+ "prime;": '\U00002032',
+ "primes;": '\U00002119',
+ "prnE;": '\U00002AB5',
+ "prnap;": '\U00002AB9',
+ "prnsim;": '\U000022E8',
+ "prod;": '\U0000220F',
+ "profalar;": '\U0000232E',
+ "profline;": '\U00002312',
+ "profsurf;": '\U00002313',
+ "prop;": '\U0000221D',
+ "propto;": '\U0000221D',
+ "prsim;": '\U0000227E',
+ "prurel;": '\U000022B0',
+ "pscr;": '\U0001D4C5',
+ "psi;": '\U000003C8',
+ "puncsp;": '\U00002008',
+ "qfr;": '\U0001D52E',
+ "qint;": '\U00002A0C',
+ "qopf;": '\U0001D562',
+ "qprime;": '\U00002057',
+ "qscr;": '\U0001D4C6',
+ "quaternions;": '\U0000210D',
+ "quatint;": '\U00002A16',
+ "quest;": '\U0000003F',
+ "questeq;": '\U0000225F',
+ "quot;": '\U00000022',
+ "rAarr;": '\U000021DB',
+ "rArr;": '\U000021D2',
+ "rAtail;": '\U0000291C',
+ "rBarr;": '\U0000290F',
+ "rHar;": '\U00002964',
+ "racute;": '\U00000155',
+ "radic;": '\U0000221A',
+ "raemptyv;": '\U000029B3',
+ "rang;": '\U000027E9',
+ "rangd;": '\U00002992',
+ "range;": '\U000029A5',
+ "rangle;": '\U000027E9',
+ "raquo;": '\U000000BB',
+ "rarr;": '\U00002192',
+ "rarrap;": '\U00002975',
+ "rarrb;": '\U000021E5',
+ "rarrbfs;": '\U00002920',
+ "rarrc;": '\U00002933',
+ "rarrfs;": '\U0000291E',
+ "rarrhk;": '\U000021AA',
+ "rarrlp;": '\U000021AC',
+ "rarrpl;": '\U00002945',
+ "rarrsim;": '\U00002974',
+ "rarrtl;": '\U000021A3',
+ "rarrw;": '\U0000219D',
+ "ratail;": '\U0000291A',
+ "ratio;": '\U00002236',
+ "rationals;": '\U0000211A',
+ "rbarr;": '\U0000290D',
+ "rbbrk;": '\U00002773',
+ "rbrace;": '\U0000007D',
+ "rbrack;": '\U0000005D',
+ "rbrke;": '\U0000298C',
+ "rbrksld;": '\U0000298E',
+ "rbrkslu;": '\U00002990',
+ "rcaron;": '\U00000159',
+ "rcedil;": '\U00000157',
+ "rceil;": '\U00002309',
+ "rcub;": '\U0000007D',
+ "rcy;": '\U00000440',
+ "rdca;": '\U00002937',
+ "rdldhar;": '\U00002969',
+ "rdquo;": '\U0000201D',
+ "rdquor;": '\U0000201D',
+ "rdsh;": '\U000021B3',
+ "real;": '\U0000211C',
+ "realine;": '\U0000211B',
+ "realpart;": '\U0000211C',
+ "reals;": '\U0000211D',
+ "rect;": '\U000025AD',
+ "reg;": '\U000000AE',
+ "rfisht;": '\U0000297D',
+ "rfloor;": '\U0000230B',
+ "rfr;": '\U0001D52F',
+ "rhard;": '\U000021C1',
+ "rharu;": '\U000021C0',
+ "rharul;": '\U0000296C',
+ "rho;": '\U000003C1',
+ "rhov;": '\U000003F1',
+ "rightarrow;": '\U00002192',
+ "rightarrowtail;": '\U000021A3',
+ "rightharpoondown;": '\U000021C1',
+ "rightharpoonup;": '\U000021C0',
+ "rightleftarrows;": '\U000021C4',
+ "rightleftharpoons;": '\U000021CC',
+ "rightrightarrows;": '\U000021C9',
+ "rightsquigarrow;": '\U0000219D',
+ "rightthreetimes;": '\U000022CC',
+ "ring;": '\U000002DA',
+ "risingdotseq;": '\U00002253',
+ "rlarr;": '\U000021C4',
+ "rlhar;": '\U000021CC',
+ "rlm;": '\U0000200F',
+ "rmoust;": '\U000023B1',
+ "rmoustache;": '\U000023B1',
+ "rnmid;": '\U00002AEE',
+ "roang;": '\U000027ED',
+ "roarr;": '\U000021FE',
+ "robrk;": '\U000027E7',
+ "ropar;": '\U00002986',
+ "ropf;": '\U0001D563',
+ "roplus;": '\U00002A2E',
+ "rotimes;": '\U00002A35',
+ "rpar;": '\U00000029',
+ "rpargt;": '\U00002994',
+ "rppolint;": '\U00002A12',
+ "rrarr;": '\U000021C9',
+ "rsaquo;": '\U0000203A',
+ "rscr;": '\U0001D4C7',
+ "rsh;": '\U000021B1',
+ "rsqb;": '\U0000005D',
+ "rsquo;": '\U00002019',
+ "rsquor;": '\U00002019',
+ "rthree;": '\U000022CC',
+ "rtimes;": '\U000022CA',
+ "rtri;": '\U000025B9',
+ "rtrie;": '\U000022B5',
+ "rtrif;": '\U000025B8',
+ "rtriltri;": '\U000029CE',
+ "ruluhar;": '\U00002968',
+ "rx;": '\U0000211E',
+ "sacute;": '\U0000015B',
+ "sbquo;": '\U0000201A',
+ "sc;": '\U0000227B',
+ "scE;": '\U00002AB4',
+ "scap;": '\U00002AB8',
+ "scaron;": '\U00000161',
+ "sccue;": '\U0000227D',
+ "sce;": '\U00002AB0',
+ "scedil;": '\U0000015F',
+ "scirc;": '\U0000015D',
+ "scnE;": '\U00002AB6',
+ "scnap;": '\U00002ABA',
+ "scnsim;": '\U000022E9',
+ "scpolint;": '\U00002A13',
+ "scsim;": '\U0000227F',
+ "scy;": '\U00000441',
+ "sdot;": '\U000022C5',
+ "sdotb;": '\U000022A1',
+ "sdote;": '\U00002A66',
+ "seArr;": '\U000021D8',
+ "searhk;": '\U00002925',
+ "searr;": '\U00002198',
+ "searrow;": '\U00002198',
+ "sect;": '\U000000A7',
+ "semi;": '\U0000003B',
+ "seswar;": '\U00002929',
+ "setminus;": '\U00002216',
+ "setmn;": '\U00002216',
+ "sext;": '\U00002736',
+ "sfr;": '\U0001D530',
+ "sfrown;": '\U00002322',
+ "sharp;": '\U0000266F',
+ "shchcy;": '\U00000449',
+ "shcy;": '\U00000448',
+ "shortmid;": '\U00002223',
+ "shortparallel;": '\U00002225',
+ "shy;": '\U000000AD',
+ "sigma;": '\U000003C3',
+ "sigmaf;": '\U000003C2',
+ "sigmav;": '\U000003C2',
+ "sim;": '\U0000223C',
+ "simdot;": '\U00002A6A',
+ "sime;": '\U00002243',
+ "simeq;": '\U00002243',
+ "simg;": '\U00002A9E',
+ "simgE;": '\U00002AA0',
+ "siml;": '\U00002A9D',
+ "simlE;": '\U00002A9F',
+ "simne;": '\U00002246',
+ "simplus;": '\U00002A24',
+ "simrarr;": '\U00002972',
+ "slarr;": '\U00002190',
+ "smallsetminus;": '\U00002216',
+ "smashp;": '\U00002A33',
+ "smeparsl;": '\U000029E4',
+ "smid;": '\U00002223',
+ "smile;": '\U00002323',
+ "smt;": '\U00002AAA',
+ "smte;": '\U00002AAC',
+ "softcy;": '\U0000044C',
+ "sol;": '\U0000002F',
+ "solb;": '\U000029C4',
+ "solbar;": '\U0000233F',
+ "sopf;": '\U0001D564',
+ "spades;": '\U00002660',
+ "spadesuit;": '\U00002660',
+ "spar;": '\U00002225',
+ "sqcap;": '\U00002293',
+ "sqcup;": '\U00002294',
+ "sqsub;": '\U0000228F',
+ "sqsube;": '\U00002291',
+ "sqsubset;": '\U0000228F',
+ "sqsubseteq;": '\U00002291',
+ "sqsup;": '\U00002290',
+ "sqsupe;": '\U00002292',
+ "sqsupset;": '\U00002290',
+ "sqsupseteq;": '\U00002292',
+ "squ;": '\U000025A1',
+ "square;": '\U000025A1',
+ "squarf;": '\U000025AA',
+ "squf;": '\U000025AA',
+ "srarr;": '\U00002192',
+ "sscr;": '\U0001D4C8',
+ "ssetmn;": '\U00002216',
+ "ssmile;": '\U00002323',
+ "sstarf;": '\U000022C6',
+ "star;": '\U00002606',
+ "starf;": '\U00002605',
+ "straightepsilon;": '\U000003F5',
+ "straightphi;": '\U000003D5',
+ "strns;": '\U000000AF',
+ "sub;": '\U00002282',
+ "subE;": '\U00002AC5',
+ "subdot;": '\U00002ABD',
+ "sube;": '\U00002286',
+ "subedot;": '\U00002AC3',
+ "submult;": '\U00002AC1',
+ "subnE;": '\U00002ACB',
+ "subne;": '\U0000228A',
+ "subplus;": '\U00002ABF',
+ "subrarr;": '\U00002979',
+ "subset;": '\U00002282',
+ "subseteq;": '\U00002286',
+ "subseteqq;": '\U00002AC5',
+ "subsetneq;": '\U0000228A',
+ "subsetneqq;": '\U00002ACB',
+ "subsim;": '\U00002AC7',
+ "subsub;": '\U00002AD5',
+ "subsup;": '\U00002AD3',
+ "succ;": '\U0000227B',
+ "succapprox;": '\U00002AB8',
+ "succcurlyeq;": '\U0000227D',
+ "succeq;": '\U00002AB0',
+ "succnapprox;": '\U00002ABA',
+ "succneqq;": '\U00002AB6',
+ "succnsim;": '\U000022E9',
+ "succsim;": '\U0000227F',
+ "sum;": '\U00002211',
+ "sung;": '\U0000266A',
+ "sup;": '\U00002283',
+ "sup1;": '\U000000B9',
+ "sup2;": '\U000000B2',
+ "sup3;": '\U000000B3',
+ "supE;": '\U00002AC6',
+ "supdot;": '\U00002ABE',
+ "supdsub;": '\U00002AD8',
+ "supe;": '\U00002287',
+ "supedot;": '\U00002AC4',
+ "suphsol;": '\U000027C9',
+ "suphsub;": '\U00002AD7',
+ "suplarr;": '\U0000297B',
+ "supmult;": '\U00002AC2',
+ "supnE;": '\U00002ACC',
+ "supne;": '\U0000228B',
+ "supplus;": '\U00002AC0',
+ "supset;": '\U00002283',
+ "supseteq;": '\U00002287',
+ "supseteqq;": '\U00002AC6',
+ "supsetneq;": '\U0000228B',
+ "supsetneqq;": '\U00002ACC',
+ "supsim;": '\U00002AC8',
+ "supsub;": '\U00002AD4',
+ "supsup;": '\U00002AD6',
+ "swArr;": '\U000021D9',
+ "swarhk;": '\U00002926',
+ "swarr;": '\U00002199',
+ "swarrow;": '\U00002199',
+ "swnwar;": '\U0000292A',
+ "szlig;": '\U000000DF',
+ "target;": '\U00002316',
+ "tau;": '\U000003C4',
+ "tbrk;": '\U000023B4',
+ "tcaron;": '\U00000165',
+ "tcedil;": '\U00000163',
+ "tcy;": '\U00000442',
+ "tdot;": '\U000020DB',
+ "telrec;": '\U00002315',
+ "tfr;": '\U0001D531',
+ "there4;": '\U00002234',
+ "therefore;": '\U00002234',
+ "theta;": '\U000003B8',
+ "thetasym;": '\U000003D1',
+ "thetav;": '\U000003D1',
+ "thickapprox;": '\U00002248',
+ "thicksim;": '\U0000223C',
+ "thinsp;": '\U00002009',
+ "thkap;": '\U00002248',
+ "thksim;": '\U0000223C',
+ "thorn;": '\U000000FE',
+ "tilde;": '\U000002DC',
+ "times;": '\U000000D7',
+ "timesb;": '\U000022A0',
+ "timesbar;": '\U00002A31',
+ "timesd;": '\U00002A30',
+ "tint;": '\U0000222D',
+ "toea;": '\U00002928',
+ "top;": '\U000022A4',
+ "topbot;": '\U00002336',
+ "topcir;": '\U00002AF1',
+ "topf;": '\U0001D565',
+ "topfork;": '\U00002ADA',
+ "tosa;": '\U00002929',
+ "tprime;": '\U00002034',
+ "trade;": '\U00002122',
+ "triangle;": '\U000025B5',
+ "triangledown;": '\U000025BF',
+ "triangleleft;": '\U000025C3',
+ "trianglelefteq;": '\U000022B4',
+ "triangleq;": '\U0000225C',
+ "triangleright;": '\U000025B9',
+ "trianglerighteq;": '\U000022B5',
+ "tridot;": '\U000025EC',
+ "trie;": '\U0000225C',
+ "triminus;": '\U00002A3A',
+ "triplus;": '\U00002A39',
+ "trisb;": '\U000029CD',
+ "tritime;": '\U00002A3B',
+ "trpezium;": '\U000023E2',
+ "tscr;": '\U0001D4C9',
+ "tscy;": '\U00000446',
+ "tshcy;": '\U0000045B',
+ "tstrok;": '\U00000167',
+ "twixt;": '\U0000226C',
+ "twoheadleftarrow;": '\U0000219E',
+ "twoheadrightarrow;": '\U000021A0',
+ "uArr;": '\U000021D1',
+ "uHar;": '\U00002963',
+ "uacute;": '\U000000FA',
+ "uarr;": '\U00002191',
+ "ubrcy;": '\U0000045E',
+ "ubreve;": '\U0000016D',
+ "ucirc;": '\U000000FB',
+ "ucy;": '\U00000443',
+ "udarr;": '\U000021C5',
+ "udblac;": '\U00000171',
+ "udhar;": '\U0000296E',
+ "ufisht;": '\U0000297E',
+ "ufr;": '\U0001D532',
+ "ugrave;": '\U000000F9',
+ "uharl;": '\U000021BF',
+ "uharr;": '\U000021BE',
+ "uhblk;": '\U00002580',
+ "ulcorn;": '\U0000231C',
+ "ulcorner;": '\U0000231C',
+ "ulcrop;": '\U0000230F',
+ "ultri;": '\U000025F8',
+ "umacr;": '\U0000016B',
+ "uml;": '\U000000A8',
+ "uogon;": '\U00000173',
+ "uopf;": '\U0001D566',
+ "uparrow;": '\U00002191',
+ "updownarrow;": '\U00002195',
+ "upharpoonleft;": '\U000021BF',
+ "upharpoonright;": '\U000021BE',
+ "uplus;": '\U0000228E',
+ "upsi;": '\U000003C5',
+ "upsih;": '\U000003D2',
+ "upsilon;": '\U000003C5',
+ "upuparrows;": '\U000021C8',
+ "urcorn;": '\U0000231D',
+ "urcorner;": '\U0000231D',
+ "urcrop;": '\U0000230E',
+ "uring;": '\U0000016F',
+ "urtri;": '\U000025F9',
+ "uscr;": '\U0001D4CA',
+ "utdot;": '\U000022F0',
+ "utilde;": '\U00000169',
+ "utri;": '\U000025B5',
+ "utrif;": '\U000025B4',
+ "uuarr;": '\U000021C8',
+ "uuml;": '\U000000FC',
+ "uwangle;": '\U000029A7',
+ "vArr;": '\U000021D5',
+ "vBar;": '\U00002AE8',
+ "vBarv;": '\U00002AE9',
+ "vDash;": '\U000022A8',
+ "vangrt;": '\U0000299C',
+ "varepsilon;": '\U000003F5',
+ "varkappa;": '\U000003F0',
+ "varnothing;": '\U00002205',
+ "varphi;": '\U000003D5',
+ "varpi;": '\U000003D6',
+ "varpropto;": '\U0000221D',
+ "varr;": '\U00002195',
+ "varrho;": '\U000003F1',
+ "varsigma;": '\U000003C2',
+ "vartheta;": '\U000003D1',
+ "vartriangleleft;": '\U000022B2',
+ "vartriangleright;": '\U000022B3',
+ "vcy;": '\U00000432',
+ "vdash;": '\U000022A2',
+ "vee;": '\U00002228',
+ "veebar;": '\U000022BB',
+ "veeeq;": '\U0000225A',
+ "vellip;": '\U000022EE',
+ "verbar;": '\U0000007C',
+ "vert;": '\U0000007C',
+ "vfr;": '\U0001D533',
+ "vltri;": '\U000022B2',
+ "vopf;": '\U0001D567',
+ "vprop;": '\U0000221D',
+ "vrtri;": '\U000022B3',
+ "vscr;": '\U0001D4CB',
+ "vzigzag;": '\U0000299A',
+ "wcirc;": '\U00000175',
+ "wedbar;": '\U00002A5F',
+ "wedge;": '\U00002227',
+ "wedgeq;": '\U00002259',
+ "weierp;": '\U00002118',
+ "wfr;": '\U0001D534',
+ "wopf;": '\U0001D568',
+ "wp;": '\U00002118',
+ "wr;": '\U00002240',
+ "wreath;": '\U00002240',
+ "wscr;": '\U0001D4CC',
+ "xcap;": '\U000022C2',
+ "xcirc;": '\U000025EF',
+ "xcup;": '\U000022C3',
+ "xdtri;": '\U000025BD',
+ "xfr;": '\U0001D535',
+ "xhArr;": '\U000027FA',
+ "xharr;": '\U000027F7',
+ "xi;": '\U000003BE',
+ "xlArr;": '\U000027F8',
+ "xlarr;": '\U000027F5',
+ "xmap;": '\U000027FC',
+ "xnis;": '\U000022FB',
+ "xodot;": '\U00002A00',
+ "xopf;": '\U0001D569',
+ "xoplus;": '\U00002A01',
+ "xotime;": '\U00002A02',
+ "xrArr;": '\U000027F9',
+ "xrarr;": '\U000027F6',
+ "xscr;": '\U0001D4CD',
+ "xsqcup;": '\U00002A06',
+ "xuplus;": '\U00002A04',
+ "xutri;": '\U000025B3',
+ "xvee;": '\U000022C1',
+ "xwedge;": '\U000022C0',
+ "yacute;": '\U000000FD',
+ "yacy;": '\U0000044F',
+ "ycirc;": '\U00000177',
+ "ycy;": '\U0000044B',
+ "yen;": '\U000000A5',
+ "yfr;": '\U0001D536',
+ "yicy;": '\U00000457',
+ "yopf;": '\U0001D56A',
+ "yscr;": '\U0001D4CE',
+ "yucy;": '\U0000044E',
+ "yuml;": '\U000000FF',
+ "zacute;": '\U0000017A',
+ "zcaron;": '\U0000017E',
+ "zcy;": '\U00000437',
+ "zdot;": '\U0000017C',
+ "zeetrf;": '\U00002128',
+ "zeta;": '\U000003B6',
+ "zfr;": '\U0001D537',
+ "zhcy;": '\U00000436',
+ "zigrarr;": '\U000021DD',
+ "zopf;": '\U0001D56B',
+ "zscr;": '\U0001D4CF',
+ "zwj;": '\U0000200D',
+ "zwnj;": '\U0000200C',
+ "AElig": '\U000000C6',
+ "AMP": '\U00000026',
+ "Aacute": '\U000000C1',
+ "Acirc": '\U000000C2',
+ "Agrave": '\U000000C0',
+ "Aring": '\U000000C5',
+ "Atilde": '\U000000C3',
+ "Auml": '\U000000C4',
+ "COPY": '\U000000A9',
+ "Ccedil": '\U000000C7',
+ "ETH": '\U000000D0',
+ "Eacute": '\U000000C9',
+ "Ecirc": '\U000000CA',
+ "Egrave": '\U000000C8',
+ "Euml": '\U000000CB',
+ "GT": '\U0000003E',
+ "Iacute": '\U000000CD',
+ "Icirc": '\U000000CE',
+ "Igrave": '\U000000CC',
+ "Iuml": '\U000000CF',
+ "LT": '\U0000003C',
+ "Ntilde": '\U000000D1',
+ "Oacute": '\U000000D3',
+ "Ocirc": '\U000000D4',
+ "Ograve": '\U000000D2',
+ "Oslash": '\U000000D8',
+ "Otilde": '\U000000D5',
+ "Ouml": '\U000000D6',
+ "QUOT": '\U00000022',
+ "REG": '\U000000AE',
+ "THORN": '\U000000DE',
+ "Uacute": '\U000000DA',
+ "Ucirc": '\U000000DB',
+ "Ugrave": '\U000000D9',
+ "Uuml": '\U000000DC',
+ "Yacute": '\U000000DD',
+ "aacute": '\U000000E1',
+ "acirc": '\U000000E2',
+ "acute": '\U000000B4',
+ "aelig": '\U000000E6',
+ "agrave": '\U000000E0',
+ "amp": '\U00000026',
+ "aring": '\U000000E5',
+ "atilde": '\U000000E3',
+ "auml": '\U000000E4',
+ "brvbar": '\U000000A6',
+ "ccedil": '\U000000E7',
+ "cedil": '\U000000B8',
+ "cent": '\U000000A2',
+ "copy": '\U000000A9',
+ "curren": '\U000000A4',
+ "deg": '\U000000B0',
+ "divide": '\U000000F7',
+ "eacute": '\U000000E9',
+ "ecirc": '\U000000EA',
+ "egrave": '\U000000E8',
+ "eth": '\U000000F0',
+ "euml": '\U000000EB',
+ "frac12": '\U000000BD',
+ "frac14": '\U000000BC',
+ "frac34": '\U000000BE',
+ "gt": '\U0000003E',
+ "iacute": '\U000000ED',
+ "icirc": '\U000000EE',
+ "iexcl": '\U000000A1',
+ "igrave": '\U000000EC',
+ "iquest": '\U000000BF',
+ "iuml": '\U000000EF',
+ "laquo": '\U000000AB',
+ "lt": '\U0000003C',
+ "macr": '\U000000AF',
+ "micro": '\U000000B5',
+ "middot": '\U000000B7',
+ "nbsp": '\U000000A0',
+ "not": '\U000000AC',
+ "ntilde": '\U000000F1',
+ "oacute": '\U000000F3',
+ "ocirc": '\U000000F4',
+ "ograve": '\U000000F2',
+ "ordf": '\U000000AA',
+ "ordm": '\U000000BA',
+ "oslash": '\U000000F8',
+ "otilde": '\U000000F5',
+ "ouml": '\U000000F6',
+ "para": '\U000000B6',
+ "plusmn": '\U000000B1',
+ "pound": '\U000000A3',
+ "quot": '\U00000022',
+ "raquo": '\U000000BB',
+ "reg": '\U000000AE',
+ "sect": '\U000000A7',
+ "shy": '\U000000AD',
+ "sup1": '\U000000B9',
+ "sup2": '\U000000B2',
+ "sup3": '\U000000B3',
+ "szlig": '\U000000DF',
+ "thorn": '\U000000FE',
+ "times": '\U000000D7',
+ "uacute": '\U000000FA',
+ "ucirc": '\U000000FB',
+ "ugrave": '\U000000F9',
+ "uml": '\U000000A8',
+ "uuml": '\U000000FC',
+ "yacute": '\U000000FD',
+ "yen": '\U000000A5',
+ "yuml": '\U000000FF',
+}
+
+// HTML entities that are two unicode codepoints.
+var entity2 = map[string][2]int{
+ // TODO(nigeltao): Handle replacements that are wider than their names.
+ // "nLt;": {'\u226A', '\u20D2'},
+ // "nGt;": {'\u226B', '\u20D2'},
+ "NotEqualTilde;": {'\u2242', '\u0338'},
+ "NotGreaterFullEqual;": {'\u2267', '\u0338'},
+ "NotGreaterGreater;": {'\u226B', '\u0338'},
+ "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'},
+ "NotHumpDownHump;": {'\u224E', '\u0338'},
+ "NotHumpEqual;": {'\u224F', '\u0338'},
+ "NotLeftTriangleBar;": {'\u29CF', '\u0338'},
+ "NotLessLess;": {'\u226A', '\u0338'},
+ "NotLessSlantEqual;": {'\u2A7D', '\u0338'},
+ "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'},
+ "NotNestedLessLess;": {'\u2AA1', '\u0338'},
+ "NotPrecedesEqual;": {'\u2AAF', '\u0338'},
+ "NotRightTriangleBar;": {'\u29D0', '\u0338'},
+ "NotSquareSubset;": {'\u228F', '\u0338'},
+ "NotSquareSuperset;": {'\u2290', '\u0338'},
+ "NotSubset;": {'\u2282', '\u20D2'},
+ "NotSucceedsEqual;": {'\u2AB0', '\u0338'},
+ "NotSucceedsTilde;": {'\u227F', '\u0338'},
+ "NotSuperset;": {'\u2283', '\u20D2'},
+ "ThickSpace;": {'\u205F', '\u200A'},
+ "acE;": {'\u223E', '\u0333'},
+ "bne;": {'\u003D', '\u20E5'},
+ "bnequiv;": {'\u2261', '\u20E5'},
+ "caps;": {'\u2229', '\uFE00'},
+ "cups;": {'\u222A', '\uFE00'},
+ "fjlig;": {'\u0066', '\u006A'},
+ "gesl;": {'\u22DB', '\uFE00'},
+ "gvertneqq;": {'\u2269', '\uFE00'},
+ "gvnE;": {'\u2269', '\uFE00'},
+ "lates;": {'\u2AAD', '\uFE00'},
+ "lesg;": {'\u22DA', '\uFE00'},
+ "lvertneqq;": {'\u2268', '\uFE00'},
+ "lvnE;": {'\u2268', '\uFE00'},
+ "nGg;": {'\u22D9', '\u0338'},
+ "nGtv;": {'\u226B', '\u0338'},
+ "nLl;": {'\u22D8', '\u0338'},
+ "nLtv;": {'\u226A', '\u0338'},
+ "nang;": {'\u2220', '\u20D2'},
+ "napE;": {'\u2A70', '\u0338'},
+ "napid;": {'\u224B', '\u0338'},
+ "nbump;": {'\u224E', '\u0338'},
+ "nbumpe;": {'\u224F', '\u0338'},
+ "ncongdot;": {'\u2A6D', '\u0338'},
+ "nedot;": {'\u2250', '\u0338'},
+ "nesim;": {'\u2242', '\u0338'},
+ "ngE;": {'\u2267', '\u0338'},
+ "ngeqq;": {'\u2267', '\u0338'},
+ "ngeqslant;": {'\u2A7E', '\u0338'},
+ "nges;": {'\u2A7E', '\u0338'},
+ "nlE;": {'\u2266', '\u0338'},
+ "nleqq;": {'\u2266', '\u0338'},
+ "nleqslant;": {'\u2A7D', '\u0338'},
+ "nles;": {'\u2A7D', '\u0338'},
+ "notinE;": {'\u22F9', '\u0338'},
+ "notindot;": {'\u22F5', '\u0338'},
+ "nparsl;": {'\u2AFD', '\u20E5'},
+ "npart;": {'\u2202', '\u0338'},
+ "npre;": {'\u2AAF', '\u0338'},
+ "npreceq;": {'\u2AAF', '\u0338'},
+ "nrarrc;": {'\u2933', '\u0338'},
+ "nrarrw;": {'\u219D', '\u0338'},
+ "nsce;": {'\u2AB0', '\u0338'},
+ "nsubE;": {'\u2AC5', '\u0338'},
+ "nsubset;": {'\u2282', '\u20D2'},
+ "nsubseteqq;": {'\u2AC5', '\u0338'},
+ "nsucceq;": {'\u2AB0', '\u0338'},
+ "nsupE;": {'\u2AC6', '\u0338'},
+ "nsupset;": {'\u2283', '\u20D2'},
+ "nsupseteqq;": {'\u2AC6', '\u0338'},
+ "nvap;": {'\u224D', '\u20D2'},
+ "nvge;": {'\u2265', '\u20D2'},
+ "nvgt;": {'\u003E', '\u20D2'},
+ "nvle;": {'\u2264', '\u20D2'},
+ "nvlt;": {'\u003C', '\u20D2'},
+ "nvltrie;": {'\u22B4', '\u20D2'},
+ "nvrtrie;": {'\u22B5', '\u20D2'},
+ "nvsim;": {'\u223C', '\u20D2'},
+ "race;": {'\u223D', '\u0331'},
+ "smtes;": {'\u2AAC', '\uFE00'},
+ "sqcaps;": {'\u2293', '\uFE00'},
+ "sqcups;": {'\u2294', '\uFE00'},
+ "varsubsetneq;": {'\u228A', '\uFE00'},
+ "varsubsetneqq;": {'\u2ACB', '\uFE00'},
+ "varsupsetneq;": {'\u228B', '\uFE00'},
+ "varsupsetneqq;": {'\u2ACC', '\uFE00'},
+ "vnsub;": {'\u2282', '\u20D2'},
+ "vnsup;": {'\u2283', '\u20D2'},
+ "vsubnE;": {'\u2ACB', '\uFE00'},
+ "vsubne;": {'\u228A', '\uFE00'},
+ "vsupnE;": {'\u2ACC', '\uFE00'},
+ "vsupne;": {'\u228B', '\uFE00'},
+}
diff --git a/libgo/go/html/entity_test.go b/libgo/go/html/entity_test.go
new file mode 100644
index 000000000..a1eb4d4f0
--- /dev/null
+++ b/libgo/go/html/entity_test.go
@@ -0,0 +1,26 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "testing"
+ "utf8"
+)
+
+func TestEntityLength(t *testing.T) {
+ // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key).
+ // The +1 comes from the leading "&". This property implies that the length of
+ // unescaped text is <= the length of escaped text.
+ for k, v := range entity {
+ if 1+len(k) < utf8.RuneLen(v) {
+ t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v))
+ }
+ }
+ for k, v := range entity2 {
+ if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) {
+ t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v[0]) + string(v[1]))
+ }
+ }
+}
diff --git a/libgo/go/html/escape.go b/libgo/go/html/escape.go
new file mode 100644
index 000000000..2799f6908
--- /dev/null
+++ b/libgo/go/html/escape.go
@@ -0,0 +1,224 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "strings"
+ "utf8"
+)
+
+// These replacements permit compatibility with old numeric entities that
+// assumed Windows-1252 encoding.
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
+var replacementTable = [...]int{
+ '\u20AC', // First entry is what 0x80 should be replaced with.
+ '\u0081',
+ '\u201A',
+ '\u0192',
+ '\u201E',
+ '\u2026',
+ '\u2020',
+ '\u2021',
+ '\u02C6',
+ '\u2030',
+ '\u0160',
+ '\u2039',
+ '\u0152',
+ '\u008D',
+ '\u017D',
+ '\u008F',
+ '\u0090',
+ '\u2018',
+ '\u2019',
+ '\u201C',
+ '\u201D',
+ '\u2022',
+ '\u2013',
+ '\u2014',
+ '\u02DC',
+ '\u2122',
+ '\u0161',
+ '\u203A',
+ '\u0153',
+ '\u009D',
+ '\u017E',
+ '\u0178', // Last entry is 0x9F.
+ // 0x00->'\uFFFD' is handled programmatically.
+ // 0x0D->'\u000D' is a no-op.
+}
+
+// unescapeEntity reads an entity like "&lt;" from b[src:] and writes the
+// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
+// Precondition: b[src] == '&' && dst <= src.
+func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
+
+ // i starts at 1 because we already know that s[0] == '&'.
+ i, s := 1, b[src:]
+
+ if len(s) <= 1 {
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+
+ if s[i] == '#' {
+ if len(s) <= 3 { // We need to have at least "&#.".
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+ i++
+ c := s[i]
+ hex := false
+ if c == 'x' || c == 'X' {
+ hex = true
+ i++
+ }
+
+ x := 0
+ for i < len(s) {
+ c = s[i]
+ i++
+ if hex {
+ if '0' <= c && c <= '9' {
+ x = 16*x + int(c) - '0'
+ continue
+ } else if 'a' <= c && c <= 'f' {
+ x = 16*x + int(c) - 'a' + 10
+ continue
+ } else if 'A' <= c && c <= 'F' {
+ x = 16*x + int(c) - 'A' + 10
+ continue
+ }
+ } else if '0' <= c && c <= '9' {
+ x = 10*x + int(c) - '0'
+ continue
+ }
+ if c != ';' {
+ i--
+ }
+ break
+ }
+
+ if i <= 3 { // No characters matched.
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+
+ if 0x80 <= x && x <= 0x9F {
+ // Replace characters from Windows-1252 with UTF-8 equivalents.
+ x = replacementTable[x-0x80]
+ } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF {
+ // Replace invalid characters with the replacement character.
+ x = '\uFFFD'
+ }
+
+ return dst + utf8.EncodeRune(b[dst:], x), src + i
+ }
+
+ // Consume the maximum number of characters possible, with the
+ // consumed characters matching one of the named references.
+
+ // TODO(nigeltao): unescape("&notit;") should be "¬it;"
+ for i < len(s) {
+ c := s[i]
+ i++
+ // Lower-cased characters are more common in entities, so we check for them first.
+ if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' {
+ continue
+ }
+ if c != ';' {
+ i--
+ }
+ break
+ }
+
+ entityName := string(s[1:i])
+ if x := entity[entityName]; x != 0 {
+ return dst + utf8.EncodeRune(b[dst:], x), src + i
+ } else if x := entity2[entityName]; x[0] != 0 { // Check if it's a two-character entity.
+ dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
+ return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
+ }
+
+ dst1, src1 = dst+i, src+i
+ copy(b[dst:dst1], b[src:src1])
+ return dst1, src1
+}
+
+// unescape unescapes b's entities in-place, so that "a&lt;b" becomes "a<b".
+func unescape(b []byte) []byte {
+ for i, c := range b {
+ if c == '&' {
+ dst, src := unescapeEntity(b, i, i)
+ for src < len(b) {
+ c := b[src]
+ if c == '&' {
+ dst, src = unescapeEntity(b, dst, src)
+ } else {
+ b[dst] = c
+ dst, src = dst+1, src+1
+ }
+ }
+ return b[0:dst]
+ }
+ }
+ return b
+}
+
+const escapedChars = `&'<>"`
+
+func escape(buf *bytes.Buffer, s string) {
+ i := strings.IndexAny(s, escapedChars)
+ for i != -1 {
+ buf.WriteString(s[0:i])
+ var esc string
+ switch s[i] {
+ case '&':
+ esc = "&amp;"
+ case '\'':
+ esc = "&apos;"
+ case '<':
+ esc = "&lt;"
+ case '>':
+ esc = "&gt;"
+ case '"':
+ esc = "&quot;"
+ default:
+ panic("unrecognized escape character")
+ }
+ s = s[i+1:]
+ buf.WriteString(esc)
+ i = strings.IndexAny(s, escapedChars)
+ }
+ buf.WriteString(s)
+}
+
+// EscapeString escapes special characters like "<" to become "&lt;". It
+// escapes only five such characters: amp, apos, lt, gt and quot.
+// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
+// always true.
+func EscapeString(s string) string {
+ if strings.IndexAny(s, escapedChars) == -1 {
+ return s
+ }
+ buf := bytes.NewBuffer(nil)
+ escape(buf, s)
+ return buf.String()
+}
+
+// UnescapeString unescapes entities like "&lt;" to become "<". It unescapes a
+// larger range of entities than EscapeString escapes. For example, "&aacute;"
+// unescapes to "á", as does "&#225;" and "&xE1;".
+// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
+// always true.
+func UnescapeString(s string) string {
+ for _, c := range s {
+ if c == '&' {
+ return string(unescape([]byte(s)))
+ }
+ }
+ return s
+}
diff --git a/libgo/go/html/parse.go b/libgo/go/html/parse.go
new file mode 100644
index 000000000..2ef90a873
--- /dev/null
+++ b/libgo/go/html/parse.go
@@ -0,0 +1,666 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "io"
+ "os"
+)
+
+// A NodeType is the type of a Node.
+type NodeType int
+
+const (
+ ErrorNode NodeType = iota
+ TextNode
+ DocumentNode
+ ElementNode
+ CommentNode
+)
+
+// A Node consists of a NodeType and some Data (tag name for element nodes,
+// content for text) and are part of a tree of Nodes. Element nodes may also
+// contain a slice of Attributes. Data is unescaped, so that it looks like
+// "a<b" rather than "a&lt;b".
+type Node struct {
+ Parent *Node
+ Child []*Node
+ Type NodeType
+ Data string
+ Attr []Attribute
+}
+
+// A parser implements the HTML5 parsing algorithm:
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#tree-construction
+type parser struct {
+ // tokenizer provides the tokens for the parser.
+ tokenizer *Tokenizer
+ // tok is the most recently read token.
+ tok Token
+ // Self-closing tags like <hr/> are re-interpreted as a two-token sequence:
+ // <hr> followed by </hr>. hasSelfClosingToken is true if we have just read
+ // the synthetic start tag and the next one due is the matching end tag.
+ hasSelfClosingToken bool
+ // doc is the document root element.
+ doc *Node
+ // The stack of open elements (section 10.2.3.2).
+ stack []*Node
+ // Element pointers (section 10.2.3.4).
+ head, form *Node
+ // Other parsing state flags (section 10.2.3.5).
+ scripting, framesetOK bool
+}
+
+// push pushes onto the stack of open elements.
+func (p *parser) push(n *Node) {
+ p.stack = append(p.stack, n)
+}
+
+// top returns the top of the stack of open elements.
+// This is also known as the current node.
+func (p *parser) top() *Node {
+ if n := len(p.stack); n > 0 {
+ return p.stack[n-1]
+ }
+ return p.doc
+}
+
+// pop pops the top of the stack of open elements.
+// It will panic if the stack is empty.
+func (p *parser) pop() *Node {
+ n := len(p.stack)
+ ret := p.stack[n-1]
+ p.stack = p.stack[:n-1]
+ return ret
+}
+
+// stopTags for use in popUntil. These come from section 10.2.3.2.
+var (
+ defaultScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object"}
+ listItemScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object", "ol", "ul"}
+ buttonScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object", "button"}
+ tableScopeStopTags = []string{"html", "table"}
+)
+
+// popUntil pops the stack of open elements at the highest element whose tag
+// is in matchTags, provided there is no higher element in stopTags. It returns
+// whether or not there was such an element. If there was not, popUntil leaves
+// the stack unchanged.
+//
+// For example, if the stack was:
+// ["html", "body", "font", "table", "b", "i", "u"]
+// then popUntil([]string{"html, "table"}, "font") would return false, but
+// popUntil([]string{"html, "table"}, "i") would return true and the resultant
+// stack would be:
+// ["html", "body", "font", "table", "b"]
+//
+// If an element's tag is in both stopTags and matchTags, then the stack will
+// be popped and the function returns true (provided, of course, there was no
+// higher element in the stack that was also in stopTags). For example,
+// popUntil([]string{"html, "table"}, "table") would return true and leave:
+// ["html", "body", "font"]
+func (p *parser) popUntil(stopTags []string, matchTags ...string) bool {
+ for i := len(p.stack) - 1; i >= 0; i-- {
+ tag := p.stack[i].Data
+ for _, t := range matchTags {
+ if t == tag {
+ p.stack = p.stack[:i]
+ return true
+ }
+ }
+ for _, t := range stopTags {
+ if t == tag {
+ return false
+ }
+ }
+ }
+ return false
+}
+
+// addChild adds a child node n to the top element, and pushes n if it is an
+// element node (text nodes are not part of the stack of open elements).
+func (p *parser) addChild(n *Node) {
+ m := p.top()
+ m.Child = append(m.Child, n)
+ if n.Type == ElementNode {
+ p.push(n)
+ }
+}
+
+// addText calls addChild with a text node.
+func (p *parser) addText(text string) {
+ // TODO: merge s with previous text, if the preceding node is a text node.
+ // TODO: distinguish whitespace text from others.
+ p.addChild(&Node{
+ Type: TextNode,
+ Data: text,
+ })
+}
+
+// addElement calls addChild with an element node.
+func (p *parser) addElement(tag string, attr []Attribute) {
+ p.addChild(&Node{
+ Type: ElementNode,
+ Data: tag,
+ Attr: attr,
+ })
+}
+
+// Section 10.2.3.3.
+func (p *parser) addFormattingElement(tag string, attr []Attribute) {
+ p.addElement(tag, attr)
+ // TODO.
+}
+
+// Section 10.2.3.3.
+func (p *parser) reconstructActiveFormattingElements() {
+ // TODO.
+}
+
+// read reads the next token. This is usually from the tokenizer, but it may
+// be the synthesized end tag implied by a self-closing tag.
+func (p *parser) read() os.Error {
+ if p.hasSelfClosingToken {
+ p.hasSelfClosingToken = false
+ p.tok.Type = EndTagToken
+ p.tok.Attr = nil
+ return nil
+ }
+ p.tokenizer.Next()
+ p.tok = p.tokenizer.Token()
+ switch p.tok.Type {
+ case ErrorToken:
+ return p.tokenizer.Error()
+ case SelfClosingTagToken:
+ p.hasSelfClosingToken = true
+ p.tok.Type = StartTagToken
+ }
+ return nil
+}
+
+// Section 10.2.4.
+func (p *parser) acknowledgeSelfClosingTag() {
+ p.hasSelfClosingToken = false
+}
+
+// An insertion mode (section 10.2.3.1) is the state transition function from
+// a particular state in the HTML5 parser's state machine. It updates the
+// parser's fields depending on parser.token (where ErrorToken means EOF). In
+// addition to returning the next insertionMode state, it also returns whether
+// the token was consumed.
+type insertionMode func(*parser) (insertionMode, bool)
+
+// useTheRulesFor runs the delegate insertionMode over p, returning the actual
+// insertionMode unless the delegate caused a state transition.
+// Section 10.2.3.1, "using the rules for".
+func useTheRulesFor(p *parser, actual, delegate insertionMode) (insertionMode, bool) {
+ im, consumed := delegate(p)
+ if im != delegate {
+ return im, consumed
+ }
+ return actual, consumed
+}
+
+// Section 10.2.5.4.
+func initialIM(p *parser) (insertionMode, bool) {
+ // TODO: check p.tok for DOCTYPE.
+ return beforeHTMLIM, false
+}
+
+// Section 10.2.5.5.
+func beforeHTMLIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ attr []Attribute
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ implied = true
+ case TextToken:
+ // TODO: distinguish whitespace text from others.
+ implied = true
+ case StartTagToken:
+ if p.tok.Data == "html" {
+ add = true
+ attr = p.tok.Attr
+ } else {
+ implied = true
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "head", "body", "html", "br":
+ implied = true
+ default:
+ // Ignore the token.
+ }
+ }
+ if add || implied {
+ p.addElement("html", attr)
+ }
+ return beforeHeadIM, !implied
+}
+
+// Section 10.2.5.6.
+func beforeHeadIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ attr []Attribute
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ implied = true
+ case TextToken:
+ // TODO: distinguish whitespace text from others.
+ implied = true
+ case StartTagToken:
+ switch p.tok.Data {
+ case "head":
+ add = true
+ attr = p.tok.Attr
+ case "html":
+ return useTheRulesFor(p, beforeHeadIM, inBodyIM)
+ default:
+ implied = true
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "head", "body", "html", "br":
+ implied = true
+ default:
+ // Ignore the token.
+ }
+ }
+ if add || implied {
+ p.addElement("head", attr)
+ }
+ return inHeadIM, !implied
+}
+
+// Section 10.2.5.7.
+func inHeadIM(p *parser) (insertionMode, bool) {
+ var (
+ pop bool
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken, TextToken:
+ implied = true
+ case StartTagToken:
+ switch p.tok.Data {
+ case "meta":
+ // TODO.
+ case "script":
+ // TODO.
+ default:
+ implied = true
+ }
+ case EndTagToken:
+ if p.tok.Data == "head" {
+ pop = true
+ }
+ // TODO.
+ }
+ if pop || implied {
+ n := p.pop()
+ if n.Data != "head" {
+ panic("html: bad parser state")
+ }
+ return afterHeadIM, !implied
+ }
+ return inHeadIM, !implied
+}
+
+// Section 10.2.5.9.
+func afterHeadIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ attr []Attribute
+ framesetOK bool
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken, TextToken:
+ implied = true
+ framesetOK = true
+ case StartTagToken:
+ switch p.tok.Data {
+ case "html":
+ // TODO.
+ case "body":
+ add = true
+ attr = p.tok.Attr
+ framesetOK = false
+ case "frameset":
+ // TODO.
+ case "base", "basefont", "bgsound", "link", "meta", "noframes", "script", "style", "title":
+ // TODO.
+ case "head":
+ // TODO.
+ default:
+ implied = true
+ framesetOK = true
+ }
+ case EndTagToken:
+ // TODO.
+ }
+ if add || implied {
+ p.addElement("body", attr)
+ p.framesetOK = framesetOK
+ }
+ return inBodyIM, !implied
+}
+
+// Section 10.2.5.10.
+func inBodyIM(p *parser) (insertionMode, bool) {
+ var endP bool
+ switch p.tok.Type {
+ case TextToken:
+ p.addText(p.tok.Data)
+ p.framesetOK = false
+ case StartTagToken:
+ switch p.tok.Data {
+ case "address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", "p", "section", "summary", "ul":
+ // TODO: Do the proper "does the stack of open elements has a p element in button scope" algorithm in section 10.2.3.2.
+ n := p.top()
+ if n.Type == ElementNode && n.Data == "p" {
+ endP = true
+ } else {
+ p.addElement(p.tok.Data, p.tok.Attr)
+ }
+ case "h1", "h2", "h3", "h4", "h5", "h6":
+ // TODO: auto-insert </p> if necessary.
+ switch n := p.top(); n.Data {
+ case "h1", "h2", "h3", "h4", "h5", "h6":
+ p.pop()
+ }
+ p.addElement(p.tok.Data, p.tok.Attr)
+ case "b", "big", "code", "em", "font", "i", "s", "small", "strike", "strong", "tt", "u":
+ p.reconstructActiveFormattingElements()
+ p.addFormattingElement(p.tok.Data, p.tok.Attr)
+ case "area", "br", "embed", "img", "input", "keygen", "wbr":
+ p.reconstructActiveFormattingElements()
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.pop()
+ p.acknowledgeSelfClosingTag()
+ p.framesetOK = false
+ case "table":
+ // TODO: auto-insert </p> if necessary, depending on quirks mode.
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.framesetOK = false
+ return inTableIM, true
+ case "hr":
+ // TODO: auto-insert </p> if necessary.
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.pop()
+ p.acknowledgeSelfClosingTag()
+ p.framesetOK = false
+ default:
+ // TODO.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "body":
+ // TODO: autoclose the stack of open elements.
+ return afterBodyIM, true
+ case "a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u":
+ // TODO: implement the "adoption agency" algorithm:
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency
+ if p.tok.Data == p.top().Data {
+ p.pop()
+ }
+ default:
+ // TODO.
+ }
+ }
+ if endP {
+ // TODO: do the proper algorithm.
+ n := p.pop()
+ if n.Type != ElementNode || n.Data != "p" {
+ panic("unreachable")
+ }
+ }
+ return inBodyIM, !endP
+}
+
+// Section 10.2.5.12.
+func inTableIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ data string
+ attr []Attribute
+ consumed bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ // Stop parsing.
+ return nil, true
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ switch p.tok.Data {
+ case "tbody", "tfoot", "thead":
+ add = true
+ data = p.tok.Data
+ attr = p.tok.Attr
+ consumed = true
+ case "td", "th", "tr":
+ add = true
+ data = "tbody"
+ default:
+ // TODO.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "table":
+ if p.popUntil(tableScopeStopTags, "table") {
+ // TODO: "reset the insertion mode appropriately" as per 10.2.3.1.
+ return inBodyIM, false
+ }
+ // Ignore the token.
+ return inTableIM, true
+ case "body", "caption", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr":
+ // Ignore the token.
+ return inTableIM, true
+ }
+ }
+ if add {
+ // TODO: clear the stack back to a table context.
+ p.addElement(data, attr)
+ return inTableBodyIM, consumed
+ }
+ // TODO: return useTheRulesFor(inTableIM, inBodyIM, p) unless etc. etc. foster parenting.
+ return inTableIM, true
+}
+
+// Section 10.2.5.16.
+func inTableBodyIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ data string
+ attr []Attribute
+ consumed bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ // TODO.
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ switch p.tok.Data {
+ case "tr":
+ add = true
+ data = p.tok.Data
+ attr = p.tok.Attr
+ consumed = true
+ case "td", "th":
+ add = true
+ data = "tr"
+ consumed = false
+ default:
+ // TODO.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "table":
+ if p.popUntil(tableScopeStopTags, "tbody", "thead", "tfoot") {
+ return inTableIM, false
+ }
+ // Ignore the token.
+ return inTableBodyIM, true
+ case "body", "caption", "col", "colgroup", "html", "td", "th", "tr":
+ // Ignore the token.
+ return inTableBodyIM, true
+ }
+ }
+ if add {
+ // TODO: clear the stack back to a table body context.
+ p.addElement(data, attr)
+ return inRowIM, consumed
+ }
+ return useTheRulesFor(p, inTableBodyIM, inTableIM)
+}
+
+// Section 10.2.5.17.
+func inRowIM(p *parser) (insertionMode, bool) {
+ switch p.tok.Type {
+ case ErrorToken:
+ // TODO.
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ switch p.tok.Data {
+ case "td", "th":
+ // TODO: clear the stack back to a table row context.
+ p.addElement(p.tok.Data, p.tok.Attr)
+ // TODO: insert a marker at the end of the list of active formatting elements.
+ return inCellIM, true
+ default:
+ // TODO.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "tr":
+ // TODO.
+ case "table":
+ if p.popUntil(tableScopeStopTags, "tr") {
+ return inTableBodyIM, false
+ }
+ // Ignore the token.
+ return inRowIM, true
+ case "tbody", "tfoot", "thead":
+ // TODO.
+ case "body", "caption", "col", "colgroup", "html", "td", "th":
+ // Ignore the token.
+ return inRowIM, true
+ default:
+ // TODO.
+ }
+ }
+ return useTheRulesFor(p, inRowIM, inTableIM)
+}
+
+// Section 10.2.5.18.
+func inCellIM(p *parser) (insertionMode, bool) {
+ var (
+ closeTheCellAndReprocess bool
+ )
+ switch p.tok.Type {
+ case StartTagToken:
+ switch p.tok.Data {
+ case "caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr":
+ // TODO: check for "td" or "th" in table scope.
+ closeTheCellAndReprocess = true
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "td", "th":
+ // TODO.
+ case "body", "caption", "col", "colgroup", "html":
+ // TODO.
+ case "table", "tbody", "tfoot", "thead", "tr":
+ // TODO: check for matching element in table scope.
+ closeTheCellAndReprocess = true
+ }
+ }
+ if closeTheCellAndReprocess {
+ if p.popUntil(tableScopeStopTags, "td") || p.popUntil(tableScopeStopTags, "th") {
+ // TODO: clear the list of active formatting elements up to the last marker.
+ return inRowIM, false
+ }
+ }
+ return useTheRulesFor(p, inCellIM, inBodyIM)
+}
+
+// Section 10.2.5.22.
+func afterBodyIM(p *parser) (insertionMode, bool) {
+ switch p.tok.Type {
+ case ErrorToken:
+ // TODO.
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ // TODO.
+ case EndTagToken:
+ switch p.tok.Data {
+ case "html":
+ // TODO: autoclose the stack of open elements.
+ return afterAfterBodyIM, true
+ default:
+ // TODO.
+ }
+ }
+ return afterBodyIM, true
+}
+
+// Section 10.2.5.25.
+func afterAfterBodyIM(p *parser) (insertionMode, bool) {
+ switch p.tok.Type {
+ case ErrorToken:
+ // Stop parsing.
+ return nil, true
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ if p.tok.Data == "html" {
+ return useTheRulesFor(p, afterAfterBodyIM, inBodyIM)
+ }
+ }
+ return inBodyIM, false
+}
+
+// Parse returns the parse tree for the HTML from the given Reader.
+// The input is assumed to be UTF-8 encoded.
+func Parse(r io.Reader) (*Node, os.Error) {
+ p := &parser{
+ tokenizer: NewTokenizer(r),
+ doc: &Node{
+ Type: DocumentNode,
+ },
+ scripting: true,
+ framesetOK: true,
+ }
+ // Iterate until EOF. Any other error will cause an early return.
+ im, consumed := initialIM, true
+ for {
+ if consumed {
+ if err := p.read(); err != nil {
+ if err == os.EOF {
+ break
+ }
+ return nil, err
+ }
+ }
+ im, consumed = im(p)
+ }
+ // Loop until the final token (the ErrorToken signifying EOF) is consumed.
+ for {
+ if im, consumed = im(p); consumed {
+ break
+ }
+ }
+ return p.doc, nil
+}
diff --git a/libgo/go/html/parse_test.go b/libgo/go/html/parse_test.go
new file mode 100644
index 000000000..d153533b5
--- /dev/null
+++ b/libgo/go/html/parse_test.go
@@ -0,0 +1,158 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+)
+
+type devNull struct{}
+
+func (devNull) Write(p []byte) (int, os.Error) {
+ return len(p), nil
+}
+
+func pipeErr(err os.Error) io.Reader {
+ pr, pw := io.Pipe()
+ pw.CloseWithError(err)
+ return pr
+}
+
+func readDat(filename string, c chan io.Reader) {
+ f, err := os.Open("testdata/webkit/"+filename, os.O_RDONLY, 0600)
+ if err != nil {
+ c <- pipeErr(err)
+ return
+ }
+ defer f.Close()
+
+ // Loop through the lines of the file. Each line beginning with "#" denotes
+ // a new section, which is returned as a separate io.Reader.
+ r := bufio.NewReader(f)
+ var pw *io.PipeWriter
+ for {
+ line, err := r.ReadSlice('\n')
+ if err != nil {
+ if pw != nil {
+ pw.CloseWithError(err)
+ pw = nil
+ } else {
+ c <- pipeErr(err)
+ }
+ return
+ }
+ if len(line) == 0 {
+ continue
+ }
+ if line[0] == '#' {
+ if pw != nil {
+ pw.Close()
+ }
+ var pr *io.PipeReader
+ pr, pw = io.Pipe()
+ c <- pr
+ continue
+ }
+ if line[0] != '|' {
+ // Strip the trailing '\n'.
+ line = line[:len(line)-1]
+ }
+ if pw != nil {
+ if _, err := pw.Write(line); err != nil {
+ pw.CloseWithError(err)
+ pw = nil
+ }
+ }
+ }
+}
+
+func dumpLevel(w io.Writer, n *Node, level int) os.Error {
+ io.WriteString(w, "| ")
+ for i := 0; i < level; i++ {
+ io.WriteString(w, " ")
+ }
+ switch n.Type {
+ case ErrorNode:
+ return os.NewError("unexpected ErrorNode")
+ case DocumentNode:
+ return os.NewError("unexpected DocumentNode")
+ case ElementNode:
+ fmt.Fprintf(w, "<%s>", EscapeString(n.Data))
+ case TextNode:
+ fmt.Fprintf(w, "%q", EscapeString(n.Data))
+ case CommentNode:
+ return os.NewError("COMMENT")
+ default:
+ return os.NewError("unknown node type")
+ }
+ io.WriteString(w, "\n")
+ for _, c := range n.Child {
+ if err := dumpLevel(w, c, level+1); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func dump(n *Node) (string, os.Error) {
+ if n == nil || len(n.Child) == 0 {
+ return "", nil
+ }
+ b := bytes.NewBuffer(nil)
+ for _, child := range n.Child {
+ if err := dumpLevel(b, child, 0); err != nil {
+ return "", err
+ }
+ }
+ return b.String(), nil
+}
+
+func TestParser(t *testing.T) {
+ // TODO(nigeltao): Process all the .dat files, not just the first one.
+ filenames := []string{
+ "tests1.dat",
+ }
+ for _, filename := range filenames {
+ rc := make(chan io.Reader)
+ go readDat(filename, rc)
+ // TODO(nigeltao): Process all test cases, not just a subset.
+ for i := 0; i < 22; i++ {
+ // Parse the #data section.
+ b, err := ioutil.ReadAll(<-rc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ text := string(b)
+ doc, err := Parse(strings.NewReader(text))
+ if err != nil {
+ t.Fatal(err)
+ }
+ actual, err := dump(doc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Skip the #error section.
+ if _, err := io.Copy(devNull{}, <-rc); err != nil {
+ t.Fatal(err)
+ }
+ // Compare the parsed tree to the #document section.
+ b, err = ioutil.ReadAll(<-rc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expected := string(b)
+ if actual != expected {
+ t.Errorf("%s test #%d %q, actual vs expected:\n----\n%s----\n%s----", filename, i, text, actual, expected)
+ }
+ }
+ }
+}
diff --git a/libgo/go/html/testdata/webkit/README b/libgo/go/html/testdata/webkit/README
new file mode 100644
index 000000000..9b4c2d8be
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/README
@@ -0,0 +1,28 @@
+The *.dat files in this directory are copied from The WebKit Open Source
+Project, specifically $WEBKITROOT/LayoutTests/html5lib/resources.
+WebKit is licensed under a BSD style license.
+http://webkit.org/coding/bsd-license.html says:
+
+Copyright (C) 2009 Apple Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/libgo/go/html/testdata/webkit/comments01.dat b/libgo/go/html/testdata/webkit/comments01.dat
new file mode 100644
index 000000000..388d95287
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/comments01.dat
@@ -0,0 +1,126 @@
+#data
+FOO<!-- BAR -->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -->
+| "BAZ"
+
+#data
+FOO<!-- BAR --!>BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- >BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX --!>BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -->
+| "BAZ"
+
+#data
+FOO<!-- BAR -- <QUX> -- MUX -- >BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- BAR -- <QUX> -- MUX -- -->
+| "BAZ"
+
+#data
+FOO<!---->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+FOO<!--->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+FOO<!-->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- -->
+| "BAZ"
+
+#data
+<?xml version="1.0">Hi
+#errors
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+| <head>
+| <body>
+| "Hi"
+
+#data
+<?xml version="1.0">
+#errors
+#document
+| <!-- ?xml version="1.0" -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?xml version
+#errors
+#document
+| <!-- ?xml version -->
+| <html>
+| <head>
+| <body>
diff --git a/libgo/go/html/testdata/webkit/doctype01.dat b/libgo/go/html/testdata/webkit/doctype01.dat
new file mode 100644
index 000000000..575129c14
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/doctype01.dat
@@ -0,0 +1,335 @@
+#data
+<!DOCTYPE html>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!dOctYpE HtMl>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPEhtml>Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE>Hello
+#errors
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE >Hello
+#errors
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato taco>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato taco "ddd>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato sYstEM ggg>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM taco >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM 'taco"'>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "taco">Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEM "tai'co">Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato SYSTEMtaco "ddd">Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato grass SYSTEM taco>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIc >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato pUbLIcgoof>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC goof>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "go'of">Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go'of'>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC 'go:hh of' >Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE potato PUBLIC "W3C-//dfdf" SYSTEM ggg>Hello
+#errors
+#document
+| <!DOCTYPE potato>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">Hello
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE ...>Hello
+#errors
+#document
+| <!DOCTYPE ...>
+| <html>
+| <head>
+| <body>
+| "Hello"
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] "uri" [
+<!-- internal declarations -->
+]>
+#errors
+#document
+| <!DOCTYPE root-element>
+| <html>
+| <head>
+| <body>
+| "
+]>"
+
+#data
+<!DOCTYPE html PUBLIC
+ "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
+ "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML SYSTEM "http://www.w3.org/DTD/HTML4-strict.dtd"><body><b>Mine!</b></body>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <b>
+| "Mine!"
diff --git a/libgo/go/html/testdata/webkit/dom2string.js b/libgo/go/html/testdata/webkit/dom2string.js
new file mode 100644
index 000000000..45897fda4
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/dom2string.js
@@ -0,0 +1,135 @@
+String.prototype.toAsciiLowerCase = function () {
+ var output = "";
+ for (var i = 0, len = this.length; i < len; ++i) {
+ if (this.charCodeAt(i) >= 0x41 && this.charCodeAt(i) <= 0x5A) {
+ output += String.fromCharCode(this.charCodeAt(i) + 0x20)
+ } else {
+ output += this.charAt(i);
+ }
+ }
+ return output;
+}
+
+function indent(ancestors) {
+ var str = "";
+ if (ancestors > 0) {
+ while (ancestors--)
+ str += " ";
+ }
+ return str;
+}
+
+function dom2string(node, ancestors) {
+ var str = "";
+ if (typeof ancestors == "undefined")
+ var ancestors = 0;
+ if (!node.firstChild)
+ return "| ";
+ var parent = node;
+ var current = node.firstChild;
+ var next = null;
+ var misnested = null;
+ for (;;) {
+ str += "\n| " + indent(ancestors);
+ switch (current.nodeType) {
+ case 10:
+ str += '<!DOCTYPE ' + current.nodeName + '>';
+ break;
+ case 8:
+ try {
+ str += '<!-- ' + current.nodeValue + ' -->';
+ } catch (e) {
+ str += '<!-- -->';
+ }
+ if (parent != current.parentNode) {
+ return str += ' (misnested... aborting)';
+ }
+ break;
+ case 7:
+ str += '<?' + current.nodeName + current.nodeValue + '>';
+ break;
+ case 4:
+ str += '<![CDATA[ ' + current.nodeValue + ' ]]>';
+ break;
+ case 3:
+ str += '"' + current.nodeValue + '"';
+ if (parent != current.parentNode) {
+ return str += ' (misnested... aborting)';
+ }
+ break;
+ case 1:
+ str += "<";
+ switch (current.namespaceURI) {
+ case "http://www.w3.org/2000/svg":
+ str += "svg ";
+ break;
+ case "http://www.w3.org/1998/Math/MathML":
+ str += "math ";
+ break;
+ }
+ if (current.localName && current.namespaceURI && current.namespaceURI != null) {
+ str += current.localName;
+ } else {
+ str += current.nodeName.toAsciiLowerCase();
+ }
+ str += '>';
+ if (parent != current.parentNode) {
+ return str += ' (misnested... aborting)';
+ } else {
+ if (current.attributes) {
+ var attrNames = [];
+ var attrPos = {};
+ for (var j = 0; j < current.attributes.length; j += 1) {
+ if (current.attributes[j].specified) {
+ var name = "";
+ switch (current.attributes[j].namespaceURI) {
+ case "http://www.w3.org/XML/1998/namespace":
+ name += "xml ";
+ break;
+ case "http://www.w3.org/2000/xmlns/":
+ name += "xmlns ";
+ break;
+ case "http://www.w3.org/1999/xlink":
+ name += "xlink ";
+ break;
+ }
+ if (current.attributes[j].localName) {
+ name += current.attributes[j].localName;
+ } else {
+ name += current.attributes[j].nodeName;
+ }
+ attrNames.push(name);
+ attrPos[name] = j;
+ }
+ }
+ if (attrNames.length > 0) {
+ attrNames.sort();
+ for (var j = 0; j < attrNames.length; j += 1) {
+ str += "\n| " + indent(1 + ancestors) + attrNames[j];
+ str += '="' + current.attributes[attrPos[attrNames[j]]].nodeValue + '"';
+ }
+ }
+ }
+ if (next = current.firstChild) {
+ parent = current;
+ current = next;
+ ancestors++;
+ continue;
+ }
+ }
+ break;
+ }
+ for (;;) {
+ if (next = current.nextSibling) {
+ current = next;
+ break;
+ }
+ current = current.parentNode;
+ parent = parent.parentNode;
+ ancestors--;
+ if (current == node) {
+ return str.substring(1);
+ }
+ }
+ }
+}
diff --git a/libgo/go/html/testdata/webkit/entities01.dat b/libgo/go/html/testdata/webkit/entities01.dat
new file mode 100644
index 000000000..926642e2e
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/entities01.dat
@@ -0,0 +1,612 @@
+#data
+FOO&gt;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>BAR"
+
+#data
+FOO&gtBAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>BAR"
+
+#data
+FOO&gt BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO> BAR"
+
+#data
+FOO&gt;;;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO>;;BAR"
+
+#data
+I'm &notit; I tell you
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "I'm ¬it; I tell you"
+
+#data
+I'm &notin; I tell you
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "I'm ∉ I tell you"
+
+#data
+FOO& BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO& BAR"
+
+#data
+FOO&<BAR>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&"
+| <bar>
+
+#data
+FOO&&&&gt;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&&&>BAR"
+
+#data
+FOO&#41;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO)BAR"
+
+#data
+FOO&#x41;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOABAR"
+
+#data
+FOO&#X41;BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOABAR"
+
+#data
+FOO&#BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#BAR"
+
+#data
+FOO&#ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#ZOO"
+
+#data
+FOO&#xBAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOºR"
+
+#data
+FOO&#xZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#xZOO"
+
+#data
+FOO&#XZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO&#XZOO"
+
+#data
+FOO&#41BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO)BAR"
+
+#data
+FOO&#x41BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO䆺R"
+
+#data
+FOO&#x41ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOAZOO"
+
+#data
+FOO&#x0000;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#x000D;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO ZOO"
+
+#data
+FOO&#x0078;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOxZOO"
+
+#data
+FOO&#x0079;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOyZOO"
+
+#data
+FOO&#x0080;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO€ZOO"
+
+#data
+FOO&#x0081;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x0082;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‚ZOO"
+
+#data
+FOO&#x0083;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOƒZOO"
+
+#data
+FOO&#x0084;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO„ZOO"
+
+#data
+FOO&#x0085;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO…ZOO"
+
+#data
+FOO&#x0086;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO†ZOO"
+
+#data
+FOO&#x0087;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‡ZOO"
+
+#data
+FOO&#x0088;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOˆZOO"
+
+#data
+FOO&#x0089;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‰ZOO"
+
+#data
+FOO&#x008A;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŠZOO"
+
+#data
+FOO&#x008B;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‹ZOO"
+
+#data
+FOO&#x008C;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŒZOO"
+
+#data
+FOO&#x008D;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x008E;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŽZOO"
+
+#data
+FOO&#x008F;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x0090;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x0091;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO‘ZOO"
+
+#data
+FOO&#x0092;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO’ZOO"
+
+#data
+FOO&#x0093;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO“ZOO"
+
+#data
+FOO&#x0094;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO”ZOO"
+
+#data
+FOO&#x0095;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO•ZOO"
+
+#data
+FOO&#x0096;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO–ZOO"
+
+#data
+FOO&#x0097;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO—ZOO"
+
+#data
+FOO&#x0098;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO˜ZOO"
+
+#data
+FOO&#x0099;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO™ZOO"
+
+#data
+FOO&#x009A;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOšZOO"
+
+#data
+FOO&#x009B;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO›ZOO"
+
+#data
+FOO&#x009C;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOœZOO"
+
+#data
+FOO&#x009D;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x009E;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOžZOO"
+
+#data
+FOO&#x009F;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOŸZOO"
+
+#data
+FOO&#x00A0;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO ZOO"
+
+#data
+FOO&#xD7FF;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO퟿ZOO"
+
+#data
+FOO&#xD800;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xD801;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xDFFE;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xDFFF;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xE000;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOOZOO"
+
+#data
+FOO&#x10FFFE;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO􏿾ZOO"
+
+#data
+FOO&#x1087D4;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO􈟔ZOO"
+
+#data
+FOO&#x10FFFF;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO􏿿ZOO"
+
+#data
+FOO&#x110000;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
+
+#data
+FOO&#xFFFFFF;ZOO
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO�ZOO"
diff --git a/libgo/go/html/testdata/webkit/entities02.dat b/libgo/go/html/testdata/webkit/entities02.dat
new file mode 100644
index 000000000..0b4dd6681
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/entities02.dat
@@ -0,0 +1,129 @@
+#data
+<div bar="ZZ&gt;YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>YY"
+
+#data
+<div bar="ZZ&"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar='ZZ&'></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar=ZZ&></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&"
+
+#data
+<div bar="ZZ&gt=YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gt=YY"
+
+#data
+<div bar="ZZ&gt0YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gt0YY"
+
+#data
+<div bar="ZZ&gt9YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gt9YY"
+
+#data
+<div bar="ZZ&gtaYY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gtaYY"
+
+#data
+<div bar="ZZ&gtZYY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&gtZYY"
+
+#data
+<div bar="ZZ&gt YY"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ> YY"
+
+#data
+<div bar="ZZ&gt"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
+
+#data
+<div bar='ZZ&gt'></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
+
+#data
+<div bar=ZZ&gt></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ>"
diff --git a/libgo/go/html/testdata/webkit/scriptdata01.dat b/libgo/go/html/testdata/webkit/scriptdata01.dat
new file mode 100644
index 000000000..76b67f4ba
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/scriptdata01.dat
@@ -0,0 +1,308 @@
+#data
+FOO<script>'Hello'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'Hello'"
+| "BAR"
+
+#data
+FOO<script></script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script >BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script/>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script></script/ >BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script type="text/plain"></scriptx>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "</scriptx>BAR"
+
+#data
+FOO<script></script foo=">" dd>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "BAR"
+
+#data
+FOO<script>'<'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<'"
+| "BAR"
+
+#data
+FOO<script>'<!'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!'"
+| "BAR"
+
+#data
+FOO<script>'<!-'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-'"
+| "BAR"
+
+#data
+FOO<script>'<!--'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!--'"
+| "BAR"
+
+#data
+FOO<script>'<!---'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!---'"
+| "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-->'"
+| "BAR"
+
+#data
+FOO<script>'<!-->'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-->'"
+| "BAR"
+
+#data
+FOO<script>'<!-- potato'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- potato'"
+| "BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- <sCrIpt'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt>'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> -'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> --'</script>BAR"
+
+#data
+FOO<script>'<!-- <sCrIpt> -->'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| "'<!-- <sCrIpt> -->'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> --!>'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> --!>'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt> -- >'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt> -- >'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt '</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt '</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt/'</script>BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt\'</script>BAR
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt\'"
+| "BAR"
+
+#data
+FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR</script>QUX
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <script>
+| type="text/plain"
+| "'<!-- <sCrIpt/'</script>BAR"
+| "QUX"
diff --git a/libgo/go/html/testdata/webkit/tests1.dat b/libgo/go/html/testdata/webkit/tests1.dat
new file mode 100644
index 000000000..ad58d314f
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests1.dat
@@ -0,0 +1,1949 @@
+#data
+Test
+#errors
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<p>One<p>Two
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| "One"
+| <p>
+| "Two"
+
+#data
+Line1<br>Line2<br>Line3<br>Line4
+#errors
+Line: 1 Col: 5 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "Line1"
+| <br>
+| "Line2"
+| <br>
+| "Line3"
+| <br>
+| "Line4"
+
+#data
+<html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head><body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></head><body></body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head><body></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end tag (body).
+Line: 1 Col: 26 Unexpected end tag (html).
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><head><body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<html><body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<head></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (html). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</head>
+#errors
+Line: 1 Col: 7 Unexpected end tag (head). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</body>
+#errors
+Line: 1 Col: 7 Unexpected end tag (body). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected end tag (body) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+</html>
+#errors
+Line: 1 Col: 7 Unexpected end tag (html). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected end tag (html) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<b><table><td><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<b><table><td></b><i></table>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 30 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+| "X"
+
+#data
+<h1>Hello<h2>World
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+13: Heading cannot be a child of another heading.
+18: End of file seen and there were open elements.
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| "Hello"
+| <h2>
+| "World"
+
+#data
+<a><p>X<a>Y</a>Z</p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 10 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 24 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <p>
+| <a>
+| "X"
+| <a>
+| "Y"
+| "Z"
+
+#data
+<b><button></b></button></b>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <button>
+
+#data
+<p><b><div><marquee></p></b></div>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+Line: 1 Col: 24 Unexpected end tag (p). Ignored.
+Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <div>
+| <b>
+| <marquee>
+| <p>
+| "X"
+
+#data
+<script><div></script></div><title><p></title><p><p>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected end tag (div). Ignored.
+#document
+| <html>
+| <head>
+| <script>
+| "<div>"
+| <title>
+| "<p>"
+| <body>
+| <p>
+| <p>
+
+#data
+<!--><div>--<!-->
+#errors
+Line: 1 Col: 5 Incorrect comment.
+Line: 1 Col: 10 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 17 Incorrect comment.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <!-- -->
+| <html>
+| <head>
+| <body>
+| <div>
+| "--"
+| <!-- -->
+
+#data
+<p><hr></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <hr>
+| <p>
+
+#data
+<select><b><option><select><option></b></select>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
+Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 48 Unexpected end tag (select). Ignored.
+Line: 1 Col: 49 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <option>
+| "X"
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><b>X</b>C<a>Y
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 63 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 64 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| <table>
+| <a>
+| <a>
+| <b>
+| "X"
+| "C"
+| <a>
+| "Y"
+
+#data
+<a X>0<b>1<a Y>2
+#errors
+Line: 1 Col: 5 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| x=""
+| "0"
+| <b>
+| "1"
+| <b>
+| <a>
+| y=""
+| "2"
+
+#data
+<!-----><font><div>hello<table>excite!<b>me!<th><i>please!</tr><!--X-->
+#errors
+Line: 1 Col: 7 Unexpected '-' after '--' found in comment.
+Line: 1 Col: 14 Unexpected start tag (font). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 41 Unexpected start tag (b) in table context caused voodoo mode.
+Line: 1 Col: 48 Unexpected implied end tag (b) in the table phase.
+Line: 1 Col: 48 Unexpected table cell start tag (th) in the table body phase.
+Line: 1 Col: 63 Got table cell end tag (th) while required end tags are missing.
+Line: 1 Col: 71 Unexpected end of file. Expected table content.
+#document
+| <!-- - -->
+| <html>
+| <head>
+| <body>
+| <font>
+| <div>
+| "helloexcite!"
+| <b>
+| "me!"
+| <table>
+| <tbody>
+| <tr>
+| <th>
+| <i>
+| "please!"
+| <!-- X -->
+
+#data
+<!DOCTYPE html><li>hello<li>world<ul>how<li>do</ul>you</body><!--do-->
+#errors
+Line: 1 Col: 61 Unexpected end tag (li). Missing end tag (body).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <li>
+| "hello"
+| <li>
+| "world"
+| <ul>
+| "how"
+| <li>
+| "do"
+| "you"
+| <!-- do -->
+
+#data
+<!DOCTYPE html>A<option>B<optgroup>C<select>D</option>E
+#errors
+Line: 1 Col: 54 Unexpected end tag (option) in the select phase. Ignored.
+Line: 1 Col: 55 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "A"
+| <option>
+| "B"
+| <optgroup>
+| "C"
+| <select>
+| "DE"
+
+#data
+<
+#errors
+Line: 1 Col: 1 Expected tag name. Got something else instead
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "<"
+
+#data
+<#
+#errors
+Line: 1 Col: 1 Expected tag name. Got something else instead
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "<#"
+
+#data
+</
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected end of file.
+Line: 1 Col: 2 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "</"
+
+#data
+</#
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character '#' found.
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- # -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?#
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?# -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!#
+#errors
+Line: 1 Col: 3 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- # -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?COMMENT?>
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 11 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?COMMENT? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!COMMENT>
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 10 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COMMENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+</ COMMENT >
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
+Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COMMENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+<?COM--MENT?>
+#errors
+Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
+Line: 1 Col: 13 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- ?COM--MENT? -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!COM--MENT>
+#errors
+Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
+Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COM--MENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+</ COM--MENT >
+#errors
+Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
+Line: 1 Col: 14 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- COM--MENT -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><style> EOF
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| " EOF"
+| <body>
+
+#data
+<!DOCTYPE html><script> <!-- </script> --> </script> EOF
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| " <!-- "
+| " "
+| <body>
+| "--> EOF"
+
+#data
+<b><p></b>TEST
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 10 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <p>
+| <b>
+| "TEST"
+
+#data
+<p id=a><b><p id=b></b>TEST
+#errors
+Line: 1 Col: 8 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end tag (p). Ignored.
+Line: 1 Col: 23 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| id="a"
+| <b>
+| <p>
+| id="b"
+| "TEST"
+
+#data
+<b id=a><p><b id=b></p></b>TEST
+#errors
+Line: 1 Col: 8 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (p). Ignored.
+Line: 1 Col: 27 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 31 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| id="a"
+| <p>
+| <b>
+| id="b"
+| "TEST"
+
+#data
+<!DOCTYPE html><title>U-test</title><body><div><p>Test<u></p></div></body>
+#errors
+Line: 1 Col: 61 Unexpected end tag (p). Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "U-test"
+| <body>
+| <div>
+| <p>
+| "Test"
+| <u>
+
+#data
+<!DOCTYPE html><font><table></font></table></font>
+#errors
+Line: 1 Col: 35 Unexpected end tag (font) in table context caused voodoo mode.
+Line: 1 Col: 35 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <table>
+
+#data
+<font><p>hello<b>cruel</font>world
+#errors
+Line: 1 Col: 6 Unexpected start tag (font). Expected DOCTYPE.
+Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <font>
+| "hello"
+| <b>
+| "cruel"
+| <b>
+| "world"
+
+#data
+<b>Test</i>Test
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 11 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "TestTest"
+
+#data
+<b>A<cite>B<div>C
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| "C"
+
+#data
+<b>A<cite>B<div>C</cite>D
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end tag (cite). Ignored.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| "CD"
+
+#data
+<b>A<cite>B<div>C</b>D
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 21 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 22 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "A"
+| <cite>
+| "B"
+| <div>
+| <b>
+| "C"
+| "D"
+
+#data
+<cite><b><cite><i><cite><i><cite><i><div>X</b>TEST
+#errors
+Line: 1 Col: 6 Unexpected start tag (cite). Expected DOCTYPE.
+Line: 1 Col: 46 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 50 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <cite>
+| <b>
+| <cite>
+| <i>
+| <cite>
+| <i>
+| <cite>
+| <i>
+| <i>
+| <i>
+| <i>
+| <div>
+| <b>
+| "X"
+| "TEST"
+
+#data
+
+#errors
+Line: 1 Col: 0 Unexpected End of file. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<DIV>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 5 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<DIV> abc
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 9 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc"
+
+#data
+<DIV> abc <B>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+
+#data
+<DIV> abc <B> def
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def"
+
+#data
+<DIV> abc <B> def <I>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+
+#data
+<DIV> abc <B> def <I> ghi
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi"
+
+#data
+<DIV> abc <B> def <I> ghi <P>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <p>
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <p>
+| " jkl"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 38 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <b>
+| " jkl "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <b>
+| " jkl "
+| " mno"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr"
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P>
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr "
+
+#data
+<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P> stu
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 60 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| " abc "
+| <b>
+| " def "
+| <i>
+| " ghi "
+| <i>
+| <p>
+| <i>
+| <b>
+| " jkl "
+| " mno "
+| " pqr "
+| " stu"
+
+#data
+<test attribute---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
+#errors
+Line: 1 Col: 1040 Unexpected start tag (test). Expected DOCTYPE.
+Line: 1 Col: 1040 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <test>
+| attribute----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------=""
+
+#data
+<a href="blah">aba<table><a href="foo">br<tr><td></td></tr>x</table>aoe
+#errors
+Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 39 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 39 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 39 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 45 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "aba"
+| <a>
+| href="foo"
+| "br"
+| <a>
+| href="foo"
+| "x"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "aoe"
+
+#data
+<a href="blah">aba<table><tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 60 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "abax"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "br"
+| "aoe"
+
+#data
+<table><a href="blah">aba<tr><td><a href="foo">br</td></tr>x</table>aoe
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 29 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="blah"
+| "aba"
+| <a>
+| href="blah"
+| "x"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| href="foo"
+| "br"
+| <a>
+| href="blah"
+| "aoe"
+
+#data
+<a href=a>aa<marquee>aa<a href=b>bb</marquee>aa
+#errors
+Line: 1 Col: 10 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 45 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| href="a"
+| "aa"
+| <marquee>
+| "aa"
+| <a>
+| href="b"
+| "bb"
+| "aa"
+
+#data
+<wbr><strike><code></strike><code><strike></code>
+#errors
+Line: 1 Col: 5 Unexpected start tag (wbr). Expected DOCTYPE.
+Line: 1 Col: 28 End tag (strike) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 49 Unexpected end tag (code). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <wbr>
+| <strike>
+| <code>
+| <code>
+| <code>
+| <strike>
+
+#data
+<title><meta></title><link><title><meta></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "<meta>"
+| <link>
+| <title>
+| "<meta>"
+| <body>
+
+#data
+<style><!--</style><meta><script>--><link></script>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 51 Unexpected end of file. Expected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <meta>
+| <script>
+| "--><link>"
+| <body>
+
+#data
+<head><meta></head><link>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected start tag (link) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <meta>
+| <link>
+| <body>
+
+#data
+<table><tr><tr><td><td><span><th><span>X</table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 33 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 48 Got table cell end tag (th) while required end tags are missing.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <tr>
+| <td>
+| <td>
+| <span>
+| <th>
+| <span>
+| "X"
+
+#data
+<body><body><base><link><meta><title><p></title><body><p></body>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (body).
+Line: 1 Col: 54 Unexpected start tag (body).
+Line: 1 Col: 64 Unexpected end tag (p). Missing end tag (body).
+#document
+| <html>
+| <head>
+| <body>
+| <base>
+| <link>
+| <meta>
+| <title>
+| "<p>"
+| <p>
+
+#data
+<textarea><p></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<p>"
+
+#data
+<p><image></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected start tag (image). Treated as img.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <img>
+
+#data
+<a><table><a></table><p><a><div><a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 13 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 13 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 21 Unexpected end tag (table). Expected end tag (a).
+Line: 1 Col: 27 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 27 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 32 Unexpected end tag (p). Ignored.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 35 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <p>
+| <a>
+| <div>
+| <a>
+
+#data
+<head></p><meta><p>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end tag (p). Ignored.
+#document
+| <html>
+| <head>
+| <meta>
+| <body>
+| <p>
+
+#data
+<head></html><meta><p>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected start tag (meta).
+#document
+| <html>
+| <head>
+| <body>
+| <meta>
+| <p>
+
+#data
+<b><table><td><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<b><table><td></b><i></table>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <i>
+
+#data
+<h1><h2>
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+8: Heading cannot be a child of another heading.
+8: End of file seen and there were open elements.
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| <h2>
+
+#data
+<a><p><a></a></p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 9 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 21 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <p>
+| <a>
+| <a>
+
+#data
+<b><button></b></button></b>
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <button>
+
+#data
+<p><b><div><marquee></p></b></div>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+Line: 1 Col: 24 Unexpected end tag (p). Ignored.
+Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <div>
+| <b>
+| <marquee>
+| <p>
+
+#data
+<script></script></div><title></title><p><p>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (div). Ignored.
+#document
+| <html>
+| <head>
+| <script>
+| <title>
+| <body>
+| <p>
+| <p>
+
+#data
+<p><hr></p>
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end tag (p). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <hr>
+| <p>
+
+#data
+<select><b><option><select><option></b></select>
+#errors
+Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
+Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 48 Unexpected end tag (select). Ignored.
+Line: 1 Col: 48 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <option>
+
+#data
+<html><head><title></title><body></body></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| <body>
+
+#data
+<a><table><td><a><table></table><a></tr><a></table><a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
+Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
+Line: 1 Col: 54 Unexpected start tag (a) implies end tag (a).
+Line: 1 Col: 54 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
+Line: 1 Col: 54 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <a>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <a>
+| <table>
+| <a>
+| <a>
+
+#data
+<ul><li></li><div><li></div><li><li><div><li><address><li><b><em></b><li></ul>
+#errors
+Line: 1 Col: 4 Unexpected start tag (ul). Expected DOCTYPE.
+Line: 1 Col: 45 Missing end tag (div, li).
+Line: 1 Col: 58 Missing end tag (address, li).
+Line: 1 Col: 69 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| <li>
+| <li>
+| <li>
+| <div>
+| <li>
+| <address>
+| <li>
+| <b>
+| <em>
+| <li>
+
+#data
+<ul><li><ul></li><li>a</li></ul></li></ul>
+#errors
+XXX: fix me
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <ul>
+| <li>
+| "a"
+
+#data
+<frameset><frame><frameset><frame></frameset><noframes></noframes></frameset>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <frameset>
+| <frame>
+| <frameset>
+| <frame>
+| <noframes>
+
+#data
+<h1><table><td><h3></table><h3></h1>
+#errors
+4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+15: “td” start tag in table body.
+27: Unclosed elements.
+31: Heading cannot be a child of another heading.
+36: End tag “h1” seen but there were unclosed elements.
+#document
+| <html>
+| <head>
+| <body>
+| <h1>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <h3>
+| <h3>
+
+#data
+<table><colgroup><col><colgroup><col><col><col><colgroup><col><col><thead><tr><td></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <col>
+| <colgroup>
+| <col>
+| <col>
+| <col>
+| <colgroup>
+| <col>
+| <col>
+| <thead>
+| <tr>
+| <td>
+
+#data
+<table><col><tbody><col><tr><col><td><col></table><col>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 55 Unexpected start tag col. Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <td>
+| <colgroup>
+| <col>
+
+#data
+<table><colgroup><tbody><colgroup><tr><colgroup><td><colgroup></table><colgroup>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 52 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 80 Unexpected start tag colgroup. Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+| <tbody>
+| <colgroup>
+| <tbody>
+| <tr>
+| <colgroup>
+| <tbody>
+| <tr>
+| <td>
+| <colgroup>
+
+#data
+</strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
+#errors
+Line: 1 Col: 9 Unexpected end tag (strong). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end tag (strong) after the (implied) root element.
+Line: 1 Col: 13 Unexpected end tag (b) after the (implied) root element.
+Line: 1 Col: 18 Unexpected end tag (em) after the (implied) root element.
+Line: 1 Col: 22 Unexpected end tag (i) after the (implied) root element.
+Line: 1 Col: 26 Unexpected end tag (u) after the (implied) root element.
+Line: 1 Col: 35 Unexpected end tag (strike) after the (implied) root element.
+Line: 1 Col: 39 Unexpected end tag (s) after the (implied) root element.
+Line: 1 Col: 47 Unexpected end tag (blink) after the (implied) root element.
+Line: 1 Col: 52 Unexpected end tag (tt) after the (implied) root element.
+Line: 1 Col: 58 Unexpected end tag (pre) after the (implied) root element.
+Line: 1 Col: 64 Unexpected end tag (big) after the (implied) root element.
+Line: 1 Col: 72 Unexpected end tag (small) after the (implied) root element.
+Line: 1 Col: 79 Unexpected end tag (font) after the (implied) root element.
+Line: 1 Col: 88 Unexpected end tag (select) after the (implied) root element.
+Line: 1 Col: 93 Unexpected end tag (h1) after the (implied) root element.
+Line: 1 Col: 98 Unexpected end tag (h2) after the (implied) root element.
+Line: 1 Col: 103 Unexpected end tag (h3) after the (implied) root element.
+Line: 1 Col: 108 Unexpected end tag (h4) after the (implied) root element.
+Line: 1 Col: 113 Unexpected end tag (h5) after the (implied) root element.
+Line: 1 Col: 118 Unexpected end tag (h6) after the (implied) root element.
+Line: 1 Col: 125 Unexpected end tag (body) after the (implied) root element.
+Line: 1 Col: 130 Unexpected end tag (br). Treated as br element.
+Line: 1 Col: 134 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 140 This element (img) has no end tag.
+Line: 1 Col: 148 Unexpected end tag (title). Ignored.
+Line: 1 Col: 155 Unexpected end tag (span). Ignored.
+Line: 1 Col: 163 Unexpected end tag (style). Ignored.
+Line: 1 Col: 172 Unexpected end tag (script). Ignored.
+Line: 1 Col: 180 Unexpected end tag (table). Ignored.
+Line: 1 Col: 185 Unexpected end tag (th). Ignored.
+Line: 1 Col: 190 Unexpected end tag (td). Ignored.
+Line: 1 Col: 195 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 203 This element (frame) has no end tag.
+Line: 1 Col: 210 This element (area) has no end tag.
+Line: 1 Col: 217 Unexpected end tag (link). Ignored.
+Line: 1 Col: 225 This element (param) has no end tag.
+Line: 1 Col: 230 This element (hr) has no end tag.
+Line: 1 Col: 238 This element (input) has no end tag.
+Line: 1 Col: 244 Unexpected end tag (col). Ignored.
+Line: 1 Col: 251 Unexpected end tag (base). Ignored.
+Line: 1 Col: 258 Unexpected end tag (meta). Ignored.
+Line: 1 Col: 269 This element (basefont) has no end tag.
+Line: 1 Col: 279 This element (bgsound) has no end tag.
+Line: 1 Col: 287 This element (embed) has no end tag.
+Line: 1 Col: 296 This element (spacer) has no end tag.
+Line: 1 Col: 300 Unexpected end tag (p). Ignored.
+Line: 1 Col: 305 End tag (dd) seen too early. Expected other end tag.
+Line: 1 Col: 310 End tag (dt) seen too early. Expected other end tag.
+Line: 1 Col: 320 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 331 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 339 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 347 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 355 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 365 End tag (address) seen too early. Expected other end tag.
+Line: 1 Col: 378 End tag (blockquote) seen too early. Expected other end tag.
+Line: 1 Col: 387 End tag (center) seen too early. Expected other end tag.
+Line: 1 Col: 393 Unexpected end tag (dir). Ignored.
+Line: 1 Col: 399 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 404 End tag (dl) seen too early. Expected other end tag.
+Line: 1 Col: 415 End tag (fieldset) seen too early. Expected other end tag.
+Line: 1 Col: 425 End tag (listing) seen too early. Expected other end tag.
+Line: 1 Col: 432 End tag (menu) seen too early. Expected other end tag.
+Line: 1 Col: 437 End tag (ol) seen too early. Expected other end tag.
+Line: 1 Col: 442 End tag (ul) seen too early. Expected other end tag.
+Line: 1 Col: 447 End tag (li) seen too early. Expected other end tag.
+Line: 1 Col: 454 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 460 This element (wbr) has no end tag.
+Line: 1 Col: 476 End tag (button) seen too early. Expected other end tag.
+Line: 1 Col: 486 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 495 End tag (object) seen too early. Expected other end tag.
+Line: 1 Col: 513 Unexpected end tag (html). Ignored.
+Line: 1 Col: 513 Unexpected end tag (frameset). Ignored.
+Line: 1 Col: 520 Unexpected end tag (head). Ignored.
+Line: 1 Col: 529 Unexpected end tag (iframe). Ignored.
+Line: 1 Col: 537 This element (image) has no end tag.
+Line: 1 Col: 547 This element (isindex) has no end tag.
+Line: 1 Col: 557 Unexpected end tag (noembed). Ignored.
+Line: 1 Col: 568 Unexpected end tag (noframes). Ignored.
+Line: 1 Col: 579 Unexpected end tag (noscript). Ignored.
+Line: 1 Col: 590 Unexpected end tag (optgroup). Ignored.
+Line: 1 Col: 599 Unexpected end tag (option). Ignored.
+Line: 1 Col: 611 Unexpected end tag (plaintext). Ignored.
+Line: 1 Col: 622 Unexpected end tag (textarea). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+| <p>
+
+#data
+<table><tr></strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (strong) in table context caused voodoo mode.
+Line: 1 Col: 20 End tag (strong) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 24 Unexpected end tag (b) in table context caused voodoo mode.
+Line: 1 Col: 24 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 29 Unexpected end tag (em) in table context caused voodoo mode.
+Line: 1 Col: 29 End tag (em) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 33 Unexpected end tag (i) in table context caused voodoo mode.
+Line: 1 Col: 33 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 37 Unexpected end tag (u) in table context caused voodoo mode.
+Line: 1 Col: 37 End tag (u) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 46 Unexpected end tag (strike) in table context caused voodoo mode.
+Line: 1 Col: 46 End tag (strike) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 50 Unexpected end tag (s) in table context caused voodoo mode.
+Line: 1 Col: 50 End tag (s) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 58 Unexpected end tag (blink) in table context caused voodoo mode.
+Line: 1 Col: 58 Unexpected end tag (blink). Ignored.
+Line: 1 Col: 63 Unexpected end tag (tt) in table context caused voodoo mode.
+Line: 1 Col: 63 End tag (tt) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 69 Unexpected end tag (pre) in table context caused voodoo mode.
+Line: 1 Col: 69 End tag (pre) seen too early. Expected other end tag.
+Line: 1 Col: 75 Unexpected end tag (big) in table context caused voodoo mode.
+Line: 1 Col: 75 End tag (big) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 83 Unexpected end tag (small) in table context caused voodoo mode.
+Line: 1 Col: 83 End tag (small) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 90 Unexpected end tag (font) in table context caused voodoo mode.
+Line: 1 Col: 90 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 99 Unexpected end tag (select) in table context caused voodoo mode.
+Line: 1 Col: 99 Unexpected end tag (select). Ignored.
+Line: 1 Col: 104 Unexpected end tag (h1) in table context caused voodoo mode.
+Line: 1 Col: 104 End tag (h1) seen too early. Expected other end tag.
+Line: 1 Col: 109 Unexpected end tag (h2) in table context caused voodoo mode.
+Line: 1 Col: 109 End tag (h2) seen too early. Expected other end tag.
+Line: 1 Col: 114 Unexpected end tag (h3) in table context caused voodoo mode.
+Line: 1 Col: 114 End tag (h3) seen too early. Expected other end tag.
+Line: 1 Col: 119 Unexpected end tag (h4) in table context caused voodoo mode.
+Line: 1 Col: 119 End tag (h4) seen too early. Expected other end tag.
+Line: 1 Col: 124 Unexpected end tag (h5) in table context caused voodoo mode.
+Line: 1 Col: 124 End tag (h5) seen too early. Expected other end tag.
+Line: 1 Col: 129 Unexpected end tag (h6) in table context caused voodoo mode.
+Line: 1 Col: 129 End tag (h6) seen too early. Expected other end tag.
+Line: 1 Col: 136 Unexpected end tag (body) in the table row phase. Ignored.
+Line: 1 Col: 141 Unexpected end tag (br) in table context caused voodoo mode.
+Line: 1 Col: 141 Unexpected end tag (br). Treated as br element.
+Line: 1 Col: 145 Unexpected end tag (a) in table context caused voodoo mode.
+Line: 1 Col: 145 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 151 Unexpected end tag (img) in table context caused voodoo mode.
+Line: 1 Col: 151 This element (img) has no end tag.
+Line: 1 Col: 159 Unexpected end tag (title) in table context caused voodoo mode.
+Line: 1 Col: 159 Unexpected end tag (title). Ignored.
+Line: 1 Col: 166 Unexpected end tag (span) in table context caused voodoo mode.
+Line: 1 Col: 166 Unexpected end tag (span). Ignored.
+Line: 1 Col: 174 Unexpected end tag (style) in table context caused voodoo mode.
+Line: 1 Col: 174 Unexpected end tag (style). Ignored.
+Line: 1 Col: 183 Unexpected end tag (script) in table context caused voodoo mode.
+Line: 1 Col: 183 Unexpected end tag (script). Ignored.
+Line: 1 Col: 196 Unexpected end tag (th). Ignored.
+Line: 1 Col: 201 Unexpected end tag (td). Ignored.
+Line: 1 Col: 206 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 214 This element (frame) has no end tag.
+Line: 1 Col: 221 This element (area) has no end tag.
+Line: 1 Col: 228 Unexpected end tag (link). Ignored.
+Line: 1 Col: 236 This element (param) has no end tag.
+Line: 1 Col: 241 This element (hr) has no end tag.
+Line: 1 Col: 249 This element (input) has no end tag.
+Line: 1 Col: 255 Unexpected end tag (col). Ignored.
+Line: 1 Col: 262 Unexpected end tag (base). Ignored.
+Line: 1 Col: 269 Unexpected end tag (meta). Ignored.
+Line: 1 Col: 280 This element (basefont) has no end tag.
+Line: 1 Col: 290 This element (bgsound) has no end tag.
+Line: 1 Col: 298 This element (embed) has no end tag.
+Line: 1 Col: 307 This element (spacer) has no end tag.
+Line: 1 Col: 311 Unexpected end tag (p). Ignored.
+Line: 1 Col: 316 End tag (dd) seen too early. Expected other end tag.
+Line: 1 Col: 321 End tag (dt) seen too early. Expected other end tag.
+Line: 1 Col: 331 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 342 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 350 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 358 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 366 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 376 End tag (address) seen too early. Expected other end tag.
+Line: 1 Col: 389 End tag (blockquote) seen too early. Expected other end tag.
+Line: 1 Col: 398 End tag (center) seen too early. Expected other end tag.
+Line: 1 Col: 404 Unexpected end tag (dir). Ignored.
+Line: 1 Col: 410 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 415 End tag (dl) seen too early. Expected other end tag.
+Line: 1 Col: 426 End tag (fieldset) seen too early. Expected other end tag.
+Line: 1 Col: 436 End tag (listing) seen too early. Expected other end tag.
+Line: 1 Col: 443 End tag (menu) seen too early. Expected other end tag.
+Line: 1 Col: 448 End tag (ol) seen too early. Expected other end tag.
+Line: 1 Col: 453 End tag (ul) seen too early. Expected other end tag.
+Line: 1 Col: 458 End tag (li) seen too early. Expected other end tag.
+Line: 1 Col: 465 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
+Line: 1 Col: 471 This element (wbr) has no end tag.
+Line: 1 Col: 487 End tag (button) seen too early. Expected other end tag.
+Line: 1 Col: 497 End tag (marquee) seen too early. Expected other end tag.
+Line: 1 Col: 506 End tag (object) seen too early. Expected other end tag.
+Line: 1 Col: 524 Unexpected end tag (html). Ignored.
+Line: 1 Col: 524 Unexpected end tag (frameset). Ignored.
+Line: 1 Col: 531 Unexpected end tag (head). Ignored.
+Line: 1 Col: 540 Unexpected end tag (iframe). Ignored.
+Line: 1 Col: 548 This element (image) has no end tag.
+Line: 1 Col: 558 This element (isindex) has no end tag.
+Line: 1 Col: 568 Unexpected end tag (noembed). Ignored.
+Line: 1 Col: 579 Unexpected end tag (noframes). Ignored.
+Line: 1 Col: 590 Unexpected end tag (noscript). Ignored.
+Line: 1 Col: 601 Unexpected end tag (optgroup). Ignored.
+Line: 1 Col: 610 Unexpected end tag (option). Ignored.
+Line: 1 Col: 622 Unexpected end tag (plaintext). Ignored.
+Line: 1 Col: 633 Unexpected end tag (textarea). Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+| <table>
+| <tbody>
+| <tr>
+| <p>
+
+#data
+<frameset>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 10 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
diff --git a/libgo/go/html/testdata/webkit/tests10.dat b/libgo/go/html/testdata/webkit/tests10.dat
new file mode 100644
index 000000000..877c9a3d7
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests10.dat
@@ -0,0 +1,430 @@
+#data
+<!DOCTYPE html><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<!DOCTYPE html><body><svg></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<!DOCTYPE html><body><select><svg></svg></select>
+#errors
+35: Stray “svg” start tag.
+42: Stray end tag “svg”
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!DOCTYPE html><body><select><option><svg></svg></option></select>
+#errors
+43: Stray “svg” start tag.
+50: Stray end tag “svg”
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!DOCTYPE html><body><table><svg></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+41: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+46: Stray end tag “g”.
+53: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><svg><g>foo</g><g>bar</g></svg></table>
+#errors
+34: Start tag “svg” seen in “table”.
+46: Stray end tag “g”.
+58: Stray end tag “g”.
+65: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><svg><g>foo</g><g>bar</g></svg></tbody></table>
+#errors
+41: Start tag “svg” seen in “table”.
+53: Stray end tag “g”.
+65: Stray end tag “g”.
+72: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+| <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><svg><g>foo</g><g>bar</g></svg></tr></tbody></table>
+#errors
+45: Start tag “svg” seen in “table”.
+57: Stray end tag “g”.
+69: Stray end tag “g”.
+76: Stray end tag “svg”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g></svg><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+70: HTML start tag “p” in a foreign namespace context.
+81: “table” closed but “caption” was still open.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g>baz</table><p>quux
+#errors
+78: “table” closed but “caption” was still open.
+78: Unclosed elements on stack.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+44: Start tag “svg” seen in “table”.
+56: Stray end tag “g”.
+68: Stray end tag “g”.
+71: HTML start tag “p” in a foreign namespace context.
+71: Start tag “p” seen in “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+| <table>
+| <colgroup>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+50: Stray “svg” start tag.
+54: Stray “g” start tag.
+62: Stray end tag “g”
+66: Stray “g” start tag.
+74: Stray end tag “g”
+77: Stray “p” start tag.
+88: “table” end tag with “select” open.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| "foobarbaz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
+#errors
+36: Start tag “select” seen in “table”.
+42: Stray “svg” start tag.
+46: Stray “g” start tag.
+54: Stray end tag “g”
+58: Stray “g” start tag.
+66: Stray end tag “g”
+69: Stray “p” start tag.
+80: “table” end tag with “select” open.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "foobarbaz"
+| <table>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body></body></html><svg><g>foo</g><g>bar</g><p>baz
+#errors
+41: Stray “svg” start tag.
+68: HTML start tag “p” in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body></body><svg><g>foo</g><g>bar</g><p>baz
+#errors
+34: Stray “svg” start tag.
+61: HTML start tag “p” in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg g>
+| "foo"
+| <svg g>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><frameset><svg><g></g><g></g><p><span>
+#errors
+31: Stray “svg” start tag.
+35: Stray “g” start tag.
+40: Stray end tag “g”
+44: Stray “g” start tag.
+49: Stray end tag “g”
+52: Stray “p” start tag.
+58: Stray “span” start tag.
+58: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><svg><g></g><g></g><p><span>
+#errors
+42: Stray “svg” start tag.
+46: Stray “g” start tag.
+51: Stray end tag “g”
+55: Stray “g” start tag.
+60: Stray end tag “g”
+63: Stray “p” start tag.
+69: Stray “span” start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><svg xlink:href=foo></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| <svg svg>
+| xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo></g></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo />bar</svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <svg svg>
+| <svg g>
+| xlink href="foo"
+| xml lang="en"
+| "bar"
diff --git a/libgo/go/html/testdata/webkit/tests11.dat b/libgo/go/html/testdata/webkit/tests11.dat
new file mode 100644
index 000000000..638cde479
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests11.dat
@@ -0,0 +1,482 @@
+#data
+<!DOCTYPE html><body><svg attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentScriptType=""
+| contentStyleType=""
+| diffuseConstant=""
+| edgeMode=""
+| externalResourcesRequired=""
+| filterRes=""
+| filterUnits=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><BODY><SVG ATTRIBUTENAME='' ATTRIBUTETYPE='' BASEFREQUENCY='' BASEPROFILE='' CALCMODE='' CLIPPATHUNITS='' CONTENTSCRIPTTYPE='' CONTENTSTYLETYPE='' DIFFUSECONSTANT='' EDGEMODE='' EXTERNALRESOURCESREQUIRED='' FILTERRES='' FILTERUNITS='' GLYPHREF='' GRADIENTTRANSFORM='' GRADIENTUNITS='' KERNELMATRIX='' KERNELUNITLENGTH='' KEYPOINTS='' KEYSPLINES='' KEYTIMES='' LENGTHADJUST='' LIMITINGCONEANGLE='' MARKERHEIGHT='' MARKERUNITS='' MARKERWIDTH='' MASKCONTENTUNITS='' MASKUNITS='' NUMOCTAVES='' PATHLENGTH='' PATTERNCONTENTUNITS='' PATTERNTRANSFORM='' PATTERNUNITS='' POINTSATX='' POINTSATY='' POINTSATZ='' PRESERVEALPHA='' PRESERVEASPECTRATIO='' PRIMITIVEUNITS='' REFX='' REFY='' REPEATCOUNT='' REPEATDUR='' REQUIREDEXTENSIONS='' REQUIREDFEATURES='' SPECULARCONSTANT='' SPECULAREXPONENT='' SPREADMETHOD='' STARTOFFSET='' STDDEVIATION='' STITCHTILES='' SURFACESCALE='' SYSTEMLANGUAGE='' TABLEVALUES='' TARGETX='' TARGETY='' TEXTLENGTH='' VIEWBOX='' VIEWTARGET='' XCHANNELSELECTOR='' YCHANNELSELECTOR='' ZOOMANDPAN=''></SVG>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentScriptType=""
+| contentStyleType=""
+| diffuseConstant=""
+| edgeMode=""
+| externalResourcesRequired=""
+| filterRes=""
+| filterUnits=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><body><svg attributename='' attributetype='' basefrequency='' baseprofile='' calcmode='' clippathunits='' contentscripttype='' contentstyletype='' diffuseconstant='' edgemode='' externalresourcesrequired='' filterres='' filterunits='' glyphref='' gradienttransform='' gradientunits='' kernelmatrix='' kernelunitlength='' keypoints='' keysplines='' keytimes='' lengthadjust='' limitingconeangle='' markerheight='' markerunits='' markerwidth='' maskcontentunits='' maskunits='' numoctaves='' pathlength='' patterncontentunits='' patterntransform='' patternunits='' pointsatx='' pointsaty='' pointsatz='' preservealpha='' preserveaspectratio='' primitiveunits='' refx='' refy='' repeatcount='' repeatdur='' requiredextensions='' requiredfeatures='' specularconstant='' specularexponent='' spreadmethod='' startoffset='' stddeviation='' stitchtiles='' surfacescale='' systemlanguage='' tablevalues='' targetx='' targety='' textlength='' viewbox='' viewtarget='' xchannelselector='' ychannelselector='' zoomandpan=''></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| attributeName=""
+| attributeType=""
+| baseFrequency=""
+| baseProfile=""
+| calcMode=""
+| clipPathUnits=""
+| contentScriptType=""
+| contentStyleType=""
+| diffuseConstant=""
+| edgeMode=""
+| externalResourcesRequired=""
+| filterRes=""
+| filterUnits=""
+| glyphRef=""
+| gradientTransform=""
+| gradientUnits=""
+| kernelMatrix=""
+| kernelUnitLength=""
+| keyPoints=""
+| keySplines=""
+| keyTimes=""
+| lengthAdjust=""
+| limitingConeAngle=""
+| markerHeight=""
+| markerUnits=""
+| markerWidth=""
+| maskContentUnits=""
+| maskUnits=""
+| numOctaves=""
+| pathLength=""
+| patternContentUnits=""
+| patternTransform=""
+| patternUnits=""
+| pointsAtX=""
+| pointsAtY=""
+| pointsAtZ=""
+| preserveAlpha=""
+| preserveAspectRatio=""
+| primitiveUnits=""
+| refX=""
+| refY=""
+| repeatCount=""
+| repeatDur=""
+| requiredExtensions=""
+| requiredFeatures=""
+| specularConstant=""
+| specularExponent=""
+| spreadMethod=""
+| startOffset=""
+| stdDeviation=""
+| stitchTiles=""
+| surfaceScale=""
+| systemLanguage=""
+| tableValues=""
+| targetX=""
+| targetY=""
+| textLength=""
+| viewBox=""
+| viewTarget=""
+| xChannelSelector=""
+| yChannelSelector=""
+| zoomAndPan=""
+
+#data
+<!DOCTYPE html><body><math attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| attributename=""
+| attributetype=""
+| basefrequency=""
+| baseprofile=""
+| calcmode=""
+| clippathunits=""
+| contentscripttype=""
+| contentstyletype=""
+| diffuseconstant=""
+| edgemode=""
+| externalresourcesrequired=""
+| filterres=""
+| filterunits=""
+| glyphref=""
+| gradienttransform=""
+| gradientunits=""
+| kernelmatrix=""
+| kernelunitlength=""
+| keypoints=""
+| keysplines=""
+| keytimes=""
+| lengthadjust=""
+| limitingconeangle=""
+| markerheight=""
+| markerunits=""
+| markerwidth=""
+| maskcontentunits=""
+| maskunits=""
+| numoctaves=""
+| pathlength=""
+| patterncontentunits=""
+| patterntransform=""
+| patternunits=""
+| pointsatx=""
+| pointsaty=""
+| pointsatz=""
+| preservealpha=""
+| preserveaspectratio=""
+| primitiveunits=""
+| refx=""
+| refy=""
+| repeatcount=""
+| repeatdur=""
+| requiredextensions=""
+| requiredfeatures=""
+| specularconstant=""
+| specularexponent=""
+| spreadmethod=""
+| startoffset=""
+| stddeviation=""
+| stitchtiles=""
+| surfacescale=""
+| systemlanguage=""
+| tablevalues=""
+| targetx=""
+| targety=""
+| textlength=""
+| viewbox=""
+| viewtarget=""
+| xchannelselector=""
+| ychannelselector=""
+| zoomandpan=""
+
+#data
+<!DOCTYPE html><body><svg><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><body><svg><altglyph /><altglyphdef /><altglyphitem /><animatecolor /><animatemotion /><animatetransform /><clippath /><feblend /><fecolormatrix /><fecomponenttransfer /><fecomposite /><feconvolvematrix /><fediffuselighting /><fedisplacementmap /><fedistantlight /><feflood /><fefunca /><fefuncb /><fefuncg /><fefuncr /><fegaussianblur /><feimage /><femerge /><femergenode /><femorphology /><feoffset /><fepointlight /><fespecularlighting /><fespotlight /><fetile /><feturbulence /><foreignobject /><glyphref /><lineargradient /><radialgradient /><textpath /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><BODY><SVG><ALTGLYPH /><ALTGLYPHDEF /><ALTGLYPHITEM /><ANIMATECOLOR /><ANIMATEMOTION /><ANIMATETRANSFORM /><CLIPPATH /><FEBLEND /><FECOLORMATRIX /><FECOMPONENTTRANSFER /><FECOMPOSITE /><FECONVOLVEMATRIX /><FEDIFFUSELIGHTING /><FEDISPLACEMENTMAP /><FEDISTANTLIGHT /><FEFLOOD /><FEFUNCA /><FEFUNCB /><FEFUNCG /><FEFUNCR /><FEGAUSSIANBLUR /><FEIMAGE /><FEMERGE /><FEMERGENODE /><FEMORPHOLOGY /><FEOFFSET /><FEPOINTLIGHT /><FESPECULARLIGHTING /><FESPOTLIGHT /><FETILE /><FETURBULENCE /><FOREIGNOBJECT /><GLYPHREF /><LINEARGRADIENT /><RADIALGRADIENT /><TEXTPATH /></SVG>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg altGlyph>
+| <svg altGlyphDef>
+| <svg altGlyphItem>
+| <svg animateColor>
+| <svg animateMotion>
+| <svg animateTransform>
+| <svg clipPath>
+| <svg feBlend>
+| <svg feColorMatrix>
+| <svg feComponentTransfer>
+| <svg feComposite>
+| <svg feConvolveMatrix>
+| <svg feDiffuseLighting>
+| <svg feDisplacementMap>
+| <svg feDistantLight>
+| <svg feFlood>
+| <svg feFuncA>
+| <svg feFuncB>
+| <svg feFuncG>
+| <svg feFuncR>
+| <svg feGaussianBlur>
+| <svg feImage>
+| <svg feMerge>
+| <svg feMergeNode>
+| <svg feMorphology>
+| <svg feOffset>
+| <svg fePointLight>
+| <svg feSpecularLighting>
+| <svg feSpotLight>
+| <svg feTile>
+| <svg feTurbulence>
+| <svg foreignObject>
+| <svg glyphRef>
+| <svg linearGradient>
+| <svg radialGradient>
+| <svg textPath>
+
+#data
+<!DOCTYPE html><body><math><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math altglyph>
+| <math altglyphdef>
+| <math altglyphitem>
+| <math animatecolor>
+| <math animatemotion>
+| <math animatetransform>
+| <math clippath>
+| <math feblend>
+| <math fecolormatrix>
+| <math fecomponenttransfer>
+| <math fecomposite>
+| <math feconvolvematrix>
+| <math fediffuselighting>
+| <math fedisplacementmap>
+| <math fedistantlight>
+| <math feflood>
+| <math fefunca>
+| <math fefuncb>
+| <math fefuncg>
+| <math fefuncr>
+| <math fegaussianblur>
+| <math feimage>
+| <math femerge>
+| <math femergenode>
+| <math femorphology>
+| <math feoffset>
+| <math fepointlight>
+| <math fespecularlighting>
+| <math fespotlight>
+| <math fetile>
+| <math feturbulence>
+| <math foreignobject>
+| <math glyphref>
+| <math lineargradient>
+| <math radialgradient>
+| <math textpath>
+
+#data
+<!DOCTYPE html><body><svg><solidColor /></svg>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg solidcolor>
diff --git a/libgo/go/html/testdata/webkit/tests12.dat b/libgo/go/html/testdata/webkit/tests12.dat
new file mode 100644
index 000000000..63107d277
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests12.dat
@@ -0,0 +1,62 @@
+#data
+<!DOCTYPE html><body><p>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "foo"
+| <math math>
+| <math mtext>
+| <i>
+| "baz"
+| <math annotation-xml>
+| <svg svg>
+| <svg desc>
+| <b>
+| "eggs"
+| <svg g>
+| <svg foreignObject>
+| <p>
+| "spam"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <img>
+| <svg g>
+| "quux"
+| "bar"
+
+#data
+<!DOCTYPE html><body>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "foo"
+| <math math>
+| <math mtext>
+| <i>
+| "baz"
+| <math annotation-xml>
+| <svg svg>
+| <svg desc>
+| <b>
+| "eggs"
+| <svg g>
+| <svg foreignObject>
+| <p>
+| "spam"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <img>
+| <svg g>
+| "quux"
+| "bar"
diff --git a/libgo/go/html/testdata/webkit/tests13.dat b/libgo/go/html/testdata/webkit/tests13.dat
new file mode 100644
index 000000000..d180e8e90
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests13.dat
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
+<html><head>
+<title>404 Not Found</title>
+</head><body>
+<h1>Not Found</h1>
+<p>The requested URL /html5lib-tests/data/tests13.dat was not found on this server.</p>
+<p>Additionally, a 404 Not Found
+error was encountered while trying to use an ErrorDocument to handle the request.</p>
+</body></html>
diff --git a/libgo/go/html/testdata/webkit/tests14.dat b/libgo/go/html/testdata/webkit/tests14.dat
new file mode 100644
index 000000000..72f8015f6
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests14.dat
@@ -0,0 +1,74 @@
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xyz:abc>
+
+#data
+<!DOCTYPE html><html><body><xyz:abc></xyz:abc><span></span>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xyz:abc>
+| <span>
+
+#data
+<!DOCTYPE html><html><html abc:def=gh><xyz:abc></xyz:abc>
+#errors
+15: Unexpected start tag html
+#document
+| <!DOCTYPE html>
+| <html>
+| abc:def="gh"
+| <head>
+| <body>
+| <xyz:abc>
+
+#data
+<!DOCTYPE html><html xml:lang=bar><html xml:lang=foo>
+#errors
+15: Unexpected start tag html
+#document
+| <!DOCTYPE html>
+| <html>
+| xml:lang="bar"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html 123=456>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| 123="456"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html 123=456><html 789=012>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| 123="456"
+| 789="012"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><html><body 789=012>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| 789="012" \ No newline at end of file
diff --git a/libgo/go/html/testdata/webkit/tests15.dat b/libgo/go/html/testdata/webkit/tests15.dat
new file mode 100644
index 000000000..7f016cae3
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests15.dat
@@ -0,0 +1,208 @@
+#data
+<!DOCTYPE html><p><b><i><u></p> <p>X
+#errors
+Line: 1 Col: 31 Unexpected end tag (p). Ignored.
+Line: 1 Col: 36 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <i>
+| <u>
+| <b>
+| <i>
+| <u>
+| " "
+| <p>
+| "X"
+
+#data
+<p><b><i><u></p>
+<p>X
+#errors
+Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end tag (p). Ignored.
+Line: 2 Col: 4 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <b>
+| <i>
+| <u>
+| <b>
+| <i>
+| <u>
+| "
+"
+| <p>
+| "X"
+
+#data
+<!doctype html></html> <head>
+#errors
+Line: 1 Col: 22 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " "
+
+#data
+<!doctype html></body><meta>
+#errors
+Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <meta>
+
+#data
+<html></html><!-- foo -->
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (html) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+| <!-- foo -->
+
+#data
+<!doctype html></body><title>X</title>
+#errors
+Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+
+#data
+<!doctype html><table> X<meta></table>
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 30 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " X"
+| <meta>
+| <table>
+
+#data
+<!doctype html><table> x</table>
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x"
+| <table>
+
+#data
+<!doctype html><table> x </table>
+#errors
+Line: 1 Col: 25 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x "
+| <table>
+
+#data
+<!doctype html><table><tr> x</table>
+#errors
+Line: 1 Col: 28 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| " x"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><table>X<style> <tr>x </style> </table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <style>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div>
+#errors
+Line: 1 Col: 30 Unexpected start tag (a) in table context caused voodoo mode.
+Line: 1 Col: 37 Unexpected end tag (a) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <a>
+| "foo"
+| <table>
+| " "
+| <tbody>
+| <tr>
+| <td>
+| "bar"
+| " "
+
+#data
+<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes>
+#errors
+6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+13: Stray start tag “frame”.
+21: Stray end tag “frame”.
+29: Stray end tag “frame”.
+39: “frameset” start tag after “body” already open.
+105: End of file seen inside an [R]CDATA element.
+105: End of file seen and there were open elements.
+XXX: These errors are wrong, please fix me!
+#document
+| <html>
+| <head>
+| <frameset>
+| <frame>
+| <frameset>
+| <frame>
+| <noframes>
+| "</frameset><noframes>"
+
+#data
+<!DOCTYPE html><object></html>
+#errors
+1: Expected closing tag. Unexpected end of file
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <object> \ No newline at end of file
diff --git a/libgo/go/html/testdata/webkit/tests16.dat b/libgo/go/html/testdata/webkit/tests16.dat
new file mode 100644
index 000000000..937dba9f4
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests16.dat
@@ -0,0 +1,2277 @@
+#data
+<!doctype html><script>
+#errors
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script>a
+#errors
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "a"
+| <body>
+
+#data
+<!doctype html><script><
+#errors
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<"
+| <body>
+
+#data
+<!doctype html><script></
+#errors
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</"
+| <body>
+
+#data
+<!doctype html><script></S
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</S"
+| <body>
+
+#data
+<!doctype html><script></SC
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SC"
+| <body>
+
+#data
+<!doctype html><script></SCR
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCR"
+| <body>
+
+#data
+<!doctype html><script></SCRI
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRI"
+| <body>
+
+#data
+<!doctype html><script></SCRIP
+#errors
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRIP"
+| <body>
+
+#data
+<!doctype html><script></SCRIPT
+#errors
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</SCRIPT"
+| <body>
+
+#data
+<!doctype html><script></SCRIPT
+#errors
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script></s
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</s"
+| <body>
+
+#data
+<!doctype html><script></sc
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</sc"
+| <body>
+
+#data
+<!doctype html><script></scr
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scr"
+| <body>
+
+#data
+<!doctype html><script></scri
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scri"
+| <body>
+
+#data
+<!doctype html><script></scrip
+#errors
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</scrip"
+| <body>
+
+#data
+<!doctype html><script></script
+#errors
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "</script"
+| <body>
+
+#data
+<!doctype html><script></script
+#errors
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<!doctype html><script><!
+#errors
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!"
+| <body>
+
+#data
+<!doctype html><script><!a
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!a"
+| <body>
+
+#data
+<!doctype html><script><!-
+#errors
+Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!-"
+| <body>
+
+#data
+<!doctype html><script><!-a
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!-a"
+| <body>
+
+#data
+<!doctype html><script><!--
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<!doctype html><script><!--a
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--a"
+| <body>
+
+#data
+<!doctype html><script><!--<
+#errors
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<"
+| <body>
+
+#data
+<!doctype html><script><!--<a
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<a"
+| <body>
+
+#data
+<!doctype html><script><!--</
+#errors
+Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--</"
+| <body>
+
+#data
+<!doctype html><script><!--</script
+#errors
+Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--</script"
+| <body>
+
+#data
+<!doctype html><script><!--</script
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<!doctype html><script><!--<s
+#errors
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<s"
+| <body>
+
+#data
+<!doctype html><script><!--<script
+#errors
+Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script"
+| <body>
+
+#data
+<!doctype html><script><!--<script
+#errors
+Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script "
+| <body>
+
+#data
+<!doctype html><script><!--<script <
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script <"
+| <body>
+
+#data
+<!doctype html><script><!--<script <a
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script <a"
+| <body>
+
+#data
+<!doctype html><script><!--<script </
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </"
+| <body>
+
+#data
+<!doctype html><script><!--<script </s
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </s"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script
+#errors
+Line: 1 Col: 43 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script"
+| <body>
+
+#data
+<!doctype html><script><!--<script </scripta
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </scripta"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script>
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script>"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script/
+#errors
+Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script/"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script <
+#errors
+Line: 1 Col: 45 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script <a
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <a"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script
+#errors
+Line: 1 Col: 52 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </script"
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script
+#errors
+Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script/
+#errors
+Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script </script </script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<!doctype html><script><!--<script -
+#errors
+Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -"
+| <body>
+
+#data
+<!doctype html><script><!--<script -a
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -a"
+| <body>
+
+#data
+<!doctype html><script><!--<script -<
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -<"
+| <body>
+
+#data
+<!doctype html><script><!--<script --
+#errors
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --"
+| <body>
+
+#data
+<!doctype html><script><!--<script --a
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --a"
+| <body>
+
+#data
+<!doctype html><script><!--<script --<
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --<"
+| <body>
+
+#data
+<!doctype html><script><!--<script -->
+#errors
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --><
+#errors
+Line: 1 Col: 39 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --><"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></
+#errors
+Line: 1 Col: 40 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --></"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script
+#errors
+Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script --></script"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script
+#errors
+Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script/
+#errors
+Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script --></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<!doctype html><script><!--<script><\/script>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script><\/script>-->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt>--></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt>-->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>--><!--</script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>--><!--"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-- ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>-- >"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- -></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- ->"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>- - ></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- - >"
+| <body>
+
+#data
+<!doctype html><script><!--<script></script><script></script>-></script>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>->"
+| <body>
+
+#data
+<!doctype html><script><!--<script>--!></script>X
+#errors
+Line: 1 Col: 49 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script>--!></script>X"
+| <body>
+
+#data
+<!doctype html><script><!--<scr'+'ipt></script>--></script>
+#errors
+Line: 1 Col: 59 Unexpected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<scr'+'ipt>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><script><!--<script></scr'+'ipt></script>X
+#errors
+Line: 1 Col: 57 Unexpected end of file. Expected end tag (script).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt></script>X"
+| <body>
+
+#data
+<!doctype html><style><!--<style></style>--></style>
+#errors
+Line: 1 Col: 52 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--<style>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><style><!--</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "X"
+
+#data
+<!doctype html><style><!--...</style>...--></style>
+#errors
+Line: 1 Col: 51 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <body>
+| "...-->"
+
+#data
+<!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+| <body>
+| "X"
+
+#data
+<!doctype html><style><!--...<style><!--...--!></style>--></style>
+#errors
+Line: 1 Col: 66 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--...<style><!--...--!>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><style><!--...</style><!-- --><style>@import ...</style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <!-- -->
+| <style>
+| "@import ..."
+| <body>
+
+#data
+<!doctype html><style>...<style><!--...</style><!-- --></style>
+#errors
+Line: 1 Col: 63 Unexpected end tag (style).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "...<style><!--..."
+| <!-- -->
+| <body>
+
+#data
+<!doctype html><style>...<!--[if IE]><style>...</style>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <style>
+| "...<!--[if IE]><style>..."
+| <body>
+| "X"
+
+#data
+<!doctype html><title><!--<title></title>--></title>
+#errors
+Line: 1 Col: 52 Unexpected end tag (title).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "<!--<title>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><title>&lt;/title></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "</title>"
+| <body>
+
+#data
+<!doctype html><title>foo/title><link></head><body>X
+#errors
+Line: 1 Col: 52 Unexpected end of file. Expected end tag (title).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "foo/title><link></head><body>X"
+| <body>
+
+#data
+<!doctype html><noscript><!--<noscript></noscript>--></noscript>
+#errors
+Line: 1 Col: 64 Unexpected end tag (noscript).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<!--<noscript>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "X"
+| <noscript>
+| "-->"
+
+#data
+<!doctype html><noscript><iframe></noscript>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noscript>
+| "<iframe>"
+| <body>
+| "X"
+
+#data
+<!doctype html><noframes><!--<noframes></noframes>--></noframes>
+#errors
+Line: 1 Col: 64 Unexpected end tag (noframes).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noframes>
+| "<!--<noframes>"
+| <body>
+| "-->"
+
+#data
+<!doctype html><noframes><body><script><!--...</script></body></noframes></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <noframes>
+| "<body><script><!--...</script></body>"
+| <body>
+
+#data
+<!doctype html><textarea><!--<textarea></textarea>--></textarea>
+#errors
+Line: 1 Col: 64 Unexpected end tag (textarea).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--<textarea>"
+| "-->"
+
+#data
+<!doctype html><textarea>&lt;/textarea></textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "</textarea>"
+
+#data
+<!doctype html><iframe><!--<iframe></iframe>--></iframe>
+#errors
+Line: 1 Col: 56 Unexpected end tag (iframe).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "<!--<iframe>"
+| "-->"
+
+#data
+<!doctype html><iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "...<!--X->...<!--/X->..."
+
+#data
+<!doctype html><xmp><!--<xmp></xmp>--></xmp>
+#errors
+Line: 1 Col: 44 Unexpected end tag (xmp).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <xmp>
+| "<!--<xmp>"
+| "-->"
+
+#data
+<!doctype html><noembed><!--<noembed></noembed>--></noembed>
+#errors
+Line: 1 Col: 60 Unexpected end tag (noembed).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <noembed>
+| "<!--<noembed>"
+| "-->"
+
+#data
+<script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 8 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script>a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "a"
+| <body>
+
+#data
+<script><
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<"
+| <body>
+
+#data
+<script></
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</"
+| <body>
+
+#data
+<script></S
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</S"
+| <body>
+
+#data
+<script></SC
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SC"
+| <body>
+
+#data
+<script></SCR
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCR"
+| <body>
+
+#data
+<script></SCRI
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRI"
+| <body>
+
+#data
+<script></SCRIP
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRIP"
+| <body>
+
+#data
+<script></SCRIPT
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</SCRIPT"
+| <body>
+
+#data
+<script></SCRIPT
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script></s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</s"
+| <body>
+
+#data
+<script></sc
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</sc"
+| <body>
+
+#data
+<script></scr
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</scr"
+| <body>
+
+#data
+<script></scri
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</scri"
+| <body>
+
+#data
+<script></scrip
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</scrip"
+| <body>
+
+#data
+<script></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</script"
+| <body>
+
+#data
+<script></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<script><!
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!"
+| <body>
+
+#data
+<script><!a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!a"
+| <body>
+
+#data
+<script><!-
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!-"
+| <body>
+
+#data
+<script><!-a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!-a"
+| <body>
+
+#data
+<script><!--
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<script><!--a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--a"
+| <body>
+
+#data
+<script><!--<
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<"
+| <body>
+
+#data
+<script><!--<a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<a"
+| <body>
+
+#data
+<script><!--</
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--</"
+| <body>
+
+#data
+<script><!--</script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--</script"
+| <body>
+
+#data
+<script><!--</script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--"
+| <body>
+
+#data
+<script><!--<s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<s"
+| <body>
+
+#data
+<script><!--<script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script"
+| <body>
+
+#data
+<script><!--<script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script "
+| <body>
+
+#data
+<script><!--<script <
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script <"
+| <body>
+
+#data
+<script><!--<script <a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script <a"
+| <body>
+
+#data
+<script><!--<script </
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </"
+| <body>
+
+#data
+<script><!--<script </s
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </s"
+| <body>
+
+#data
+<script><!--<script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script"
+| <body>
+
+#data
+<script><!--<script </scripta
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </scripta"
+| <body>
+
+#data
+<script><!--<script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script>"
+| <body>
+
+#data
+<script><!--<script </script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script/"
+| <body>
+
+#data
+<script><!--<script </script <
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <"
+| <body>
+
+#data
+<script><!--<script </script <a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script <a"
+| <body>
+
+#data
+<script><!--<script </script </
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </"
+| <body>
+
+#data
+<script><!--<script </script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script </script"
+| <body>
+
+#data
+<script><!--<script </script </script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script </script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script </script </script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script </script "
+| <body>
+
+#data
+<script><!--<script -
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -"
+| <body>
+
+#data
+<script><!--<script -a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -a"
+| <body>
+
+#data
+<script><!--<script --
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --"
+| <body>
+
+#data
+<script><!--<script --a
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --a"
+| <body>
+
+#data
+<script><!--<script -->
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --><
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --><"
+| <body>
+
+#data
+<script><!--<script --></
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --></"
+| <body>
+
+#data
+<script><!--<script --></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script --></script"
+| <body>
+
+#data
+<script><!--<script --></script
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --></script/
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script --></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script -->"
+| <body>
+
+#data
+<script><!--<script><\/script>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script><\/script>-->"
+| <body>
+
+#data
+<script><!--<script></scr'+'ipt>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt>-->"
+| <body>
+
+#data
+<script><!--<script></script><script></script></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>"
+| <body>
+
+#data
+<script><!--<script></script><script></script>--><!--</script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>--><!--"
+| <body>
+
+#data
+<script><!--<script></script><script></script>-- ></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>-- >"
+| <body>
+
+#data
+<script><!--<script></script><script></script>- -></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- ->"
+| <body>
+
+#data
+<script><!--<script></script><script></script>- - ></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>- - >"
+| <body>
+
+#data
+<script><!--<script></script><script></script>-></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></script><script></script>->"
+| <body>
+
+#data
+<script><!--<script>--!></script>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script>--!></script>X"
+| <body>
+
+#data
+<script><!--<scr'+'ipt></script>--></script>
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 44 Unexpected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<scr'+'ipt>"
+| <body>
+| "-->"
+
+#data
+<script><!--<script></scr'+'ipt></script>X
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 42 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "<!--<script></scr'+'ipt></script>X"
+| <body>
+
+#data
+<style><!--<style></style>--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--<style>"
+| <body>
+| "-->"
+
+#data
+<style><!--</style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "<!--"
+| <body>
+| "X"
+
+#data
+<style><!--...</style>...--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 36 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <body>
+| "...-->"
+
+#data
+<style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
+| <body>
+| "X"
+
+#data
+<style><!--...<style><!--...--!></style>--></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 51 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "<!--...<style><!--...--!>"
+| <body>
+| "-->"
+
+#data
+<style><!--...</style><!-- --><style>@import ...</style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "<!--..."
+| <!-- -->
+| <style>
+| "@import ..."
+| <body>
+
+#data
+<style>...<style><!--...</style><!-- --></style>
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 48 Unexpected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| "...<style><!--..."
+| <!-- -->
+| <body>
+
+#data
+<style>...<!--[if IE]><style>...</style>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| "...<!--[if IE]><style>..."
+| <body>
+| "X"
+
+#data
+<title><!--<title></title>--></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "<!--<title>"
+| <body>
+| "-->"
+
+#data
+<title>&lt;/title></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "</title>"
+| <body>
+
+#data
+<title>foo/title><link></head><body>X
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 37 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "foo/title><link></head><body>X"
+| <body>
+
+#data
+<noscript><!--<noscript></noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (noscript).
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--<noscript>"
+| <body>
+| "-->"
+
+#data
+<noscript><!--</noscript>X<noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "X"
+| <noscript>
+| "-->"
+
+#data
+<noscript><iframe></noscript>X
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noscript>
+| "<iframe>"
+| <body>
+| "X"
+
+#data
+<noframes><!--<noframes></noframes>--></noframes>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (noframes).
+#document
+| <html>
+| <head>
+| <noframes>
+| "<!--<noframes>"
+| <body>
+| "-->"
+
+#data
+<noframes><body><script><!--...</script></body></noframes></html>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noframes>
+| "<body><script><!--...</script></body>"
+| <body>
+
+#data
+<textarea><!--<textarea></textarea>--></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 49 Unexpected end tag (textarea).
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "<!--<textarea>"
+| "-->"
+
+#data
+<textarea>&lt;/textarea></textarea>
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "</textarea>"
+
+#data
+<iframe><!--<iframe></iframe>--></iframe>
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+Line: 1 Col: 41 Unexpected end tag (iframe).
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "<!--<iframe>"
+| "-->"
+
+#data
+<iframe>...<!--X->...<!--/X->...</iframe>
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| "...<!--X->...<!--/X->..."
+
+#data
+<xmp><!--<xmp></xmp>--></xmp>
+#errors
+Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
+Line: 1 Col: 29 Unexpected end tag (xmp).
+#document
+| <html>
+| <head>
+| <body>
+| <xmp>
+| "<!--<xmp>"
+| "-->"
+
+#data
+<noembed><!--<noembed></noembed>--></noembed>
+#errors
+Line: 1 Col: 9 Unexpected start tag (noembed). Expected DOCTYPE.
+Line: 1 Col: 45 Unexpected end tag (noembed).
+#document
+| <html>
+| <head>
+| <body>
+| <noembed>
+| "<!--<noembed>"
+| "-->"
+
+#data
+<!doctype html><table>
+
+#errors
+Line 2 Col 0 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| "
+"
+
+#data
+<!doctype html><table><td><span><font></span><span>
+#errors
+Line 1 Col 26 Unexpected table cell start tag (td) in the table body phase.
+Line 1 Col 45 Unexpected end tag (span).
+Line 1 Col 51 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <span>
+| <font>
+| <font>
+| <span>
+
+#data
+<!doctype html><form><table></form><form></table></form>
+#errors
+35: Stray end tag “form”.
+41: Start tag “form” seen in “table”.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <table>
+| <form>
diff --git a/libgo/go/html/testdata/webkit/tests2.dat b/libgo/go/html/testdata/webkit/tests2.dat
new file mode 100644
index 000000000..d33996e0c
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests2.dat
@@ -0,0 +1,738 @@
+#data
+<!DOCTYPE html>Test
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<textarea>test</div>test
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 24 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "test</div>test"
+
+#data
+<table><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 11 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><td>test</tbody></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "test"
+
+#data
+<frame>test
+#errors
+Line: 1 Col: 7 Unexpected start tag (frame). Expected DOCTYPE.
+Line: 1 Col: 7 Unexpected start tag frame. Ignored.
+#document
+| <html>
+| <head>
+| <body>
+| "test"
+
+#data
+<!DOCTYPE html><frameset>test
+#errors
+Line: 1 Col: 29 Unepxected characters in the frameset phase. Characters ignored.
+Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset><!DOCTYPE html>
+#errors
+Line: 1 Col: 40 Unexpected DOCTYPE. Ignored.
+Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><font><p><b>test</font>
+#errors
+Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <font>
+| <b>
+| "test"
+
+#data
+<!DOCTYPE html><dt><div><dd>
+#errors
+Line: 1 Col: 28 Missing end tag (div, dt).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <dt>
+| <div>
+| <dd>
+
+#data
+<script></x
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
+#document
+| <html>
+| <head>
+| <script>
+| "</x"
+| <body>
+
+#data
+<table><plaintext><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 18 Unexpected start tag (plaintext) in table context caused voodoo mode.
+Line: 1 Col: 22 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "<td>"
+| <table>
+
+#data
+<plaintext></plaintext>
+#errors
+Line: 1 Col: 11 Unexpected start tag (plaintext). Expected DOCTYPE.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <plaintext>
+| "</plaintext>"
+
+#data
+<!DOCTYPE html><table><tr>TEST
+#errors
+Line: 1 Col: 30 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 30 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "TEST"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4>
+#errors
+Line: 1 Col: 37 Unexpected start tag (body).
+Line: 1 Col: 53 Unexpected start tag (body).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| t1="1"
+| t2="2"
+| t3="3"
+| t4="4"
+
+#data
+</b test
+#errors
+Line: 1 Col: 8 Unexpected end of file in attribute name.
+Line: 1 Col: 8 End tag contains unexpected attributes.
+Line: 1 Col: 8 Unexpected end tag (b). Expected DOCTYPE.
+Line: 1 Col: 8 Unexpected end tag (b) after the (implied) root element.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html></b test<b &=&amp>X
+#errors
+Line: 1 Col: 32 Named entity didn't end with ';'.
+Line: 1 Col: 33 End tag contains unexpected attributes.
+Line: 1 Col: 33 Unexpected end tag (b) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+
+#data
+<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 54 Unexpected end of file in the tag name.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| type="text/x-foobar;baz"
+| "X</SCRipt"
+| <body>
+
+#data
+&
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&"
+
+#data
+&#
+#errors
+Line: 1 Col: 1 Numeric entity expected. Got end of file instead.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&#"
+
+#data
+&#X
+#errors
+Line: 1 Col: 3 Numeric entity expected but none found.
+Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&#X"
+
+#data
+&#x
+#errors
+Line: 1 Col: 3 Numeric entity expected but none found.
+Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&#x"
+
+#data
+&#45
+#errors
+Line: 1 Col: 4 Numeric entity didn't end with ';'.
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "-"
+
+#data
+&x-test
+#errors
+Line: 1 Col: 1 Named entity expected. Got none.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&x-test"
+
+#data
+<!doctypehtml><p><li>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <li>
+
+#data
+<!doctypehtml><p><dt>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <dt>
+
+#data
+<!doctypehtml><p><dd>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <dd>
+
+#data
+<!doctypehtml><p><form>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <form>
+
+#data
+<!DOCTYPE html><p></P>X
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| "X"
+
+#data
+&AMP
+#errors
+Line: 1 Col: 4 Named entity didn't end with ';'.
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&"
+
+#data
+&AMp;
+#errors
+Line: 1 Col: 1 Named entity expected. Got none.
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "&AMp;"
+
+#data
+<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY>
+#errors
+Line: 1 Col: 110 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly>
+
+#data
+<!DOCTYPE html>X</body>X
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "XX"
+
+#data
+<!DOCTYPE html><!-- X
+#errors
+Line: 1 Col: 21 Unexpected end of file in comment.
+#document
+| <!DOCTYPE html>
+| <!-- X -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><table><caption>test TEST</caption><td>test
+#errors
+Line: 1 Col: 54 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| "test TEST"
+| <tbody>
+| <tr>
+| <td>
+| "test"
+
+#data
+<!DOCTYPE html><select><option><optgroup>
+#errors
+Line: 1 Col: 41 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| <optgroup>
+
+#data
+<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option>
+#errors
+Line: 1 Col: 68 Unexpected select start tag in the select phase treated as select end tag.
+Line: 1 Col: 76 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+| <option>
+| <option>
+| <option>
+
+#data
+<!DOCTYPE html><select><optgroup><option><optgroup>
+#errors
+Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+| <option>
+| <optgroup>
+
+#data
+<!DOCTYPE html><font><input><input></font>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <font>
+| <input>
+| <input>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX
+#errors
+Line: 1 Col: 29 Unexpected end of file in comment (-)
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><!-- XXX - XXX - XXX -->
+#errors
+#document
+| <!DOCTYPE html>
+| <!-- XXX - XXX - XXX -->
+| <html>
+| <head>
+| <body>
+
+#data
+<isindex test=x name=x>
+#errors
+Line: 1 Col: 23 Unexpected start tag (isindex). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected start tag isindex. Don't use it!
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+| <hr>
+| <label>
+| "This is a searchable index. Insert your search keywords here: "
+| <input>
+| name="isindex"
+| test="x"
+| <hr>
+
+#data
+test
+test
+#errors
+Line: 2 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "test
+test"
+
+#data
+<!DOCTYPE html><body><title>test</body></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "test</body>"
+
+#data
+<!DOCTYPE html><body><title>X</title><meta name=z><link rel=foo><style>
+x { content:"</style" } </style>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+| <meta>
+| name="z"
+| <link>
+| rel="foo"
+| <style>
+| "
+x { content:"</style" } "
+
+#data
+<!DOCTYPE html><select><optgroup></optgroup></select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <optgroup>
+
+#data
+
+
+#errors
+Line: 2 Col: 1 Unexpected End of file. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html> <html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><script>
+</script> <title>x</title> </head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <script>
+| "
+"
+| " "
+| <title>
+| "x"
+| " "
+| <body>
+
+#data
+<!DOCTYPE html><html><body><html id=x>
+#errors
+Line: 1 Col: 38 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html>X</body><html id="x">
+#errors
+Line: 1 Col: 36 Unexpected start tag token (html) in the after body phase.
+Line: 1 Col: 36 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+| "X"
+
+#data
+<!DOCTYPE html><head><html id=x>
+#errors
+Line: 1 Col: 32 html needs to be the first start tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| id="x"
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html>X</html>X
+#errors
+Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "XX"
+
+#data
+<!DOCTYPE html>X</html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X "
+
+#data
+<!DOCTYPE html>X</html><p>X
+#errors
+Line: 1 Col: 26 Unexpected start tag (p).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <p>
+| "X"
+
+#data
+<!DOCTYPE html>X<p/x/y/z>
+#errors
+Line: 1 Col: 19 Expected a > after the /.
+Line: 1 Col: 21 Solidus (/) incorrectly placed in tag.
+Line: 1 Col: 23 Solidus (/) incorrectly placed in tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <p>
+| x=""
+| y=""
+| z=""
+
+#data
+<!DOCTYPE html><!--x--
+#errors
+Line: 1 Col: 22 Unexpected end of file in comment (--).
+#document
+| <!DOCTYPE html>
+| <!-- x -->
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE html><table><tr><td></p></table>
+#errors
+Line: 1 Col: 34 Unexpected end tag (p). Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <p>
+
+#data
+<!DOCTYPE <!DOCTYPE HTML>><!--<!--x-->-->
+#errors
+Line: 1 Col: 20 Expected space or '>'. Got ''
+Line: 1 Col: 25 Erroneous DOCTYPE.
+Line: 1 Col: 35 Unexpected character in comment found.
+#document
+| <!DOCTYPE <!doctype>
+| <html>
+| <head>
+| <body>
+| ">"
+| <!-- <!--x -->
+| "-->"
diff --git a/libgo/go/html/testdata/webkit/tests3.dat b/libgo/go/html/testdata/webkit/tests3.dat
new file mode 100644
index 000000000..b0781a87e
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests3.dat
@@ -0,0 +1,293 @@
+#data
+<head></head><style></style>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected start tag (style) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <style>
+| <body>
+
+#data
+<head></head><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected start tag (script) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <script>
+| <body>
+
+#data
+<head></head><!-- --><style></style><!-- --><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+Line: 1 Col: 28 Unexpected start tag (style) that can be in head. Moved.
+#document
+| <html>
+| <head>
+| <style>
+| <script>
+| <!-- -->
+| <!-- -->
+| <body>
+
+#data
+<head></head><!-- -->x<style></style><!-- --><script></script>
+#errors
+Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <!-- -->
+| <body>
+| "x"
+| <style>
+| <!-- -->
+| <script>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+
+foo</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>
+foo
+</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "foo
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x</pre><span>
+</span></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x"
+| <span>
+| "
+"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x
+y</pre></body></html>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x
+y"
+
+#data
+<!DOCTYPE html><html><head></head><body><pre>x<div>
+y</pre></body></html>
+#errors
+Line: 2 Col: 7 End tag (pre) seen too early. Expected other end tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "x"
+| <div>
+| "
+y"
+
+#data
+<!DOCTYPE html><HTML><META><HEAD></HEAD></HTML>
+#errors
+Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <meta>
+| <body>
+
+#data
+<!DOCTYPE html><HTML><HEAD><head></HEAD></HTML>
+#errors
+Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<textarea>foo<span>bar</span><i>baz
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "foo<span>bar</span><i>baz"
+
+#data
+<title>foo<span>bar</em><i>baz
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 30 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "foo<span>bar</em><i>baz"
+| <body>
+
+#data
+<!DOCTYPE html><textarea>
+</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+
+#data
+<!DOCTYPE html><textarea>
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "foo"
+
+#data
+<!DOCTYPE html><textarea>
+
+foo</textarea>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <textarea>
+| "
+foo"
+
+#data
+<!DOCTYPE html><html><head></head><body><ul><li><div><p><li></ul></body></html>
+#errors
+Line: 1 Col: 60 Missing end tag (div, li).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| <p>
+| <li>
+
+#data
+<!doctype html><nobr><nobr><nobr>
+#errors
+Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 33 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <nobr>
+| <nobr>
+| <nobr>
+
+#data
+<!doctype html><nobr><nobr></nobr><nobr>
+#errors
+Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
+Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <nobr>
+| <nobr>
+| <nobr>
+
+#data
+<!doctype html><html><body><p><table></table></body></html>
+#errors
+Not known
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <table>
+
+#data
+<p><table></table>
+#errors
+Not known
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <table>
diff --git a/libgo/go/html/testdata/webkit/tests4.dat b/libgo/go/html/testdata/webkit/tests4.dat
new file mode 100644
index 000000000..3c506326d
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests4.dat
@@ -0,0 +1,59 @@
+#data
+direct div content
+#errors
+#document-fragment
+div
+#document
+| "direct div content"
+
+#data
+direct textarea content
+#errors
+#document-fragment
+textarea
+#document
+| "direct textarea content"
+
+#data
+textarea content with <em>pseudo</em> <foo>markup
+#errors
+#document-fragment
+textarea
+#document
+| "textarea content with <em>pseudo</em> <foo>markup"
+
+#data
+this is &#x0043;DATA inside a <style> element
+#errors
+#document-fragment
+style
+#document
+| "this is &#x0043;DATA inside a <style> element"
+
+#data
+</plaintext>
+#errors
+#document-fragment
+plaintext
+#document
+| "</plaintext>"
+
+#data
+setting html's innerHTML
+#errors
+Line: 1 Col: 24 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| "setting html's innerHTML"
+
+#data
+<title>setting head's innerHTML</title>
+#errors
+#document-fragment
+head
+#document
+| <title>
+| "setting head's innerHTML"
diff --git a/libgo/go/html/testdata/webkit/tests5.dat b/libgo/go/html/testdata/webkit/tests5.dat
new file mode 100644
index 000000000..d7b5128a4
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests5.dat
@@ -0,0 +1,191 @@
+#data
+<style> <!-- </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end of file. Expected end tag (style).
+#document
+| <html>
+| <head>
+| <style>
+| " <!-- "
+| <body>
+| "x"
+
+#data
+<style> <!-- </style> --> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<style> <!--> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!--> "
+| <body>
+| "x"
+
+#data
+<style> <!---> </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!---> "
+| <body>
+| "x"
+
+#data
+<iframe> <!---> </iframe>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| " <!---> "
+| "x"
+
+#data
+<iframe> <!--- </iframe>->x</iframe> --> </iframe>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <iframe>
+| " <!--- "
+| "->x --> x"
+
+#data
+<script> <!-- </script> --> </script>x
+#errors
+Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <script>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<title> <!-- </title> --> </title>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| " <!-- "
+| " "
+| <body>
+| "--> x"
+
+#data
+<textarea> <!--- </textarea>->x</textarea> --> </textarea>x
+#errors
+Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <textarea>
+| " <!--- "
+| "->x --> x"
+
+#data
+<style> <!</-- </style>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <style>
+| " <!</-- "
+| <body>
+| "x"
+
+#data
+<p><xmp></xmp>
+#errors
+XXX: Unknown
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| <xmp>
+
+#data
+<xmp> <!-- > --> </xmp>
+#errors
+Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <xmp>
+| " <!-- > --> "
+
+#data
+<title>&amp;</title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "&"
+| <body>
+
+#data
+<title><!--&amp;--></title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <title>
+| "<!--&-->"
+| <body>
+
+#data
+<title><!--</title>
+#errors
+Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
+Line: 1 Col: 19 Unexpected end of file. Expected end tag (title).
+#document
+| <html>
+| <head>
+| <title>
+| "<!--"
+| <body>
+
+#data
+<noscript><!--</noscript>--></noscript>
+#errors
+Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <noscript>
+| "<!--"
+| <body>
+| "-->"
diff --git a/libgo/go/html/testdata/webkit/tests6.dat b/libgo/go/html/testdata/webkit/tests6.dat
new file mode 100644
index 000000000..2fb79967f
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests6.dat
@@ -0,0 +1,653 @@
+#data
+<!doctype html></head> <head>
+#errors
+Line: 1 Col: 29 Unexpected start tag head. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| " "
+| <body>
+
+#data
+<!doctype html><form><div></form><div>
+#errors
+33: End tag "form" seen but there were unclosed elements.
+38: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <form>
+| <div>
+| <div>
+
+#data
+<!doctype html><title>&amp;</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "&"
+| <body>
+
+#data
+<!doctype html><title><!--&amp;--></title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "<!--&-->"
+| <body>
+
+#data
+<!doctype>
+#errors
+Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
+Line: 1 Col: 10 Unexpected > character. Expected DOCTYPE name.
+Line: 1 Col: 10 Erroneous DOCTYPE.
+#document
+| <!DOCTYPE >
+| <html>
+| <head>
+| <body>
+
+#data
+<!---x
+#errors
+Line: 1 Col: 6 Unexpected end of file in comment.
+Line: 1 Col: 6 Unexpected End of file. Expected DOCTYPE.
+#document
+| <!-- -x -->
+| <html>
+| <head>
+| <body>
+
+#data
+<body>
+<div>
+#errors
+Line: 1 Col: 6 Unexpected start tag (body).
+Line: 2 Col: 5 Expected closing tag. Unexpected end of file.
+#document-fragment
+div
+#document
+| "
+"
+| <div>
+
+#data
+<frameset></frameset>
+foo
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 3 Unexpected non-space characters in the after frameset phase. Ignored.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+<noframes>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 10 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+| <noframes>
+
+#data
+<frameset></frameset>
+<div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 5 Unexpected start tag (div) in the after frameset phase. Ignored.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+</html>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<frameset></frameset>
+</div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 2 Col: 6 Unexpected end tag (div) in the after frameset phase. Ignored.
+#document
+| <html>
+| <head>
+| <frameset>
+| "
+"
+
+#data
+<form><form>
+#errors
+Line: 1 Col: 6 Unexpected start tag (form). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (form).
+Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <form>
+
+#data
+<button><button>
+#errors
+Line: 1 Col: 8 Unexpected start tag (button). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (button) implies end tag (button).
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <button>
+| <button>
+
+#data
+<table><tr><td></th>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (th). Ignored.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><caption><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (td). Ignored.
+Line: 1 Col: 20 Unexpected table cell start tag (td) in the table body phase.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<table><caption><div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+</caption><div>
+#errors
+Line: 1 Col: 10 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption><div></caption>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 31 Unexpected end tag (caption). Missing end tag (div).
+Line: 1 Col: 31 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+<table><caption></table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 24 Unexpected end table tag in caption. Generates implied end caption.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+
+#data
+</table><div>
+#errors
+Line: 1 Col: 8 Unexpected end table tag in caption. Generates implied end caption.
+Line: 1 Col: 8 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
+#document-fragment
+caption
+#document
+| <div>
+
+#data
+<table><caption></body></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 23 Unexpected end tag (body). Ignored.
+Line: 1 Col: 29 Unexpected end tag (col). Ignored.
+Line: 1 Col: 40 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 47 Unexpected end tag (html). Ignored.
+Line: 1 Col: 55 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 60 Unexpected end tag (td). Ignored.
+Line: 1 Col: 68 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 73 Unexpected end tag (th). Ignored.
+Line: 1 Col: 81 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 86 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 86 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+
+#data
+<table><caption><div></div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 27 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <div>
+
+#data
+<table><tr><td></body></caption></col></colgroup></html>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end tag (body). Ignored.
+Line: 1 Col: 32 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 38 Unexpected end tag (col). Ignored.
+Line: 1 Col: 49 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 56 Unexpected end tag (html). Ignored.
+Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+</table></tbody></tfoot></thead></tr><div>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 16 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 24 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 32 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 37 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
+#document-fragment
+td
+#document
+| <div>
+
+#data
+<table><colgroup>foo
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 20 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| "foo"
+| <table>
+| <colgroup>
+
+#data
+foo<col>
+#errors
+Line: 1 Col: 3 Unexpected end tag (colgroup). Ignored.
+#document-fragment
+colgroup
+#document
+| <col>
+
+#data
+<table><colgroup></col>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 23 This element (col) has no end tag.
+Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <colgroup>
+
+#data
+<frameset><div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag token (div) in the frameset phase. Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</frameset><frame>
+#errors
+Line: 1 Col: 11 Unexpected end tag token (frameset) in the frameset phase (innerHTML).
+#document-fragment
+frameset
+#document
+| <frame>
+
+#data
+<frameset></div>
+#errors
+Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected end tag token (div) in the frameset phase. Ignored.
+Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</body><div>
+#errors
+Line: 1 Col: 7 Unexpected end tag (body). Ignored.
+Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
+#document-fragment
+body
+#document
+| <div>
+
+#data
+<table><tr><div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 16 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+</tr><td>
+#errors
+Line: 1 Col: 5 Unexpected end tag (tr). Ignored.
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+</tbody></tfoot></thead><td>
+#errors
+Line: 1 Col: 8 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 16 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 24 Unexpected end tag (thead). Ignored.
+#document-fragment
+tr
+#document
+| <td>
+
+#data
+<table><tr><div><td>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 20 Unexpected implied end tag (div) in the table row phase.
+Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+
+#data
+<caption><col><colgroup><tbody><tfoot><thead><tr>
+#errors
+Line: 1 Col: 9 Unexpected start tag (caption).
+Line: 1 Col: 14 Unexpected start tag (col).
+Line: 1 Col: 24 Unexpected start tag (colgroup).
+Line: 1 Col: 31 Unexpected start tag (tbody).
+Line: 1 Col: 38 Unexpected start tag (tfoot).
+Line: 1 Col: 45 Unexpected start tag (thead).
+Line: 1 Col: 49 Unexpected end of file. Expected table content.
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></thead>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 22 Unexpected end tag (thead) in the table body phase. Ignored.
+Line: 1 Col: 22 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+</table><tr>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 12 Unexpected end of file. Expected table content.
+#document-fragment
+tbody
+#document
+| <tr>
+
+#data
+<table><tbody></body></caption></col></colgroup></html></td></th></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 21 Unexpected end tag (body) in the table body phase. Ignored.
+Line: 1 Col: 31 Unexpected end tag (caption) in the table body phase. Ignored.
+Line: 1 Col: 37 Unexpected end tag (col) in the table body phase. Ignored.
+Line: 1 Col: 48 Unexpected end tag (colgroup) in the table body phase. Ignored.
+Line: 1 Col: 55 Unexpected end tag (html) in the table body phase. Ignored.
+Line: 1 Col: 60 Unexpected end tag (td) in the table body phase. Ignored.
+Line: 1 Col: 65 Unexpected end tag (th) in the table body phase. Ignored.
+Line: 1 Col: 70 Unexpected end tag (tr) in the table body phase. Ignored.
+Line: 1 Col: 70 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+<table><tbody></div>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 20 Unexpected end tag (div) in table context caused voodoo mode.
+Line: 1 Col: 20 End tag (div) seen too early. Expected other end tag.
+Line: 1 Col: 20 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+
+#data
+<table><table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected start tag (table) implies end tag (table).
+Line: 1 Col: 14 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <table>
+
+#data
+<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 14 Unexpected end tag (body). Ignored.
+Line: 1 Col: 24 Unexpected end tag (caption). Ignored.
+Line: 1 Col: 30 Unexpected end tag (col). Ignored.
+Line: 1 Col: 41 Unexpected end tag (colgroup). Ignored.
+Line: 1 Col: 48 Unexpected end tag (html). Ignored.
+Line: 1 Col: 56 Unexpected end tag (tbody). Ignored.
+Line: 1 Col: 61 Unexpected end tag (td). Ignored.
+Line: 1 Col: 69 Unexpected end tag (tfoot). Ignored.
+Line: 1 Col: 74 Unexpected end tag (th). Ignored.
+Line: 1 Col: 82 Unexpected end tag (thead). Ignored.
+Line: 1 Col: 87 Unexpected end tag (tr). Ignored.
+Line: 1 Col: 87 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+
+#data
+</table><tr>
+#errors
+Line: 1 Col: 8 Unexpected end tag (table). Ignored.
+Line: 1 Col: 12 Unexpected end of file. Expected table content.
+#document-fragment
+table
+#document
+| <tbody>
+| <tr>
+
+#data
+<body></body></html>
+#errors
+Line: 1 Col: 20 Unexpected html end tag in inner html mode.
+Line: 1 Col: 20 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+
+#data
+<html><frameset></frameset></html>
+#errors
+Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <frameset>
+| " "
+
+#data
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"><html></html>
+#errors
+Line: 1 Col: 50 Erroneous DOCTYPE.
+Line: 1 Col: 63 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "">
+| <html>
+| <head>
+| <body>
+
+#data
+<param><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (param). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+<source><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (source). Expected DOCTYPE.
+Line: 1 Col: 17 Unexpected start tag (frameset).
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</html><frameset></frameset>
+#errors
+7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+17: Stray “frameset” start tag.
+17: “frameset” start tag seen.
+#document
+| <html>
+| <head>
+| <frameset>
+
+#data
+</body><frameset></frameset>
+#errors
+7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
+17: Stray “frameset” start tag.
+17: “frameset” start tag seen.
+#document
+| <html>
+| <head>
+| <frameset>
diff --git a/libgo/go/html/testdata/webkit/tests7.dat b/libgo/go/html/testdata/webkit/tests7.dat
new file mode 100644
index 000000000..f5193c660
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests7.dat
@@ -0,0 +1,390 @@
+#data
+<!doctype html><body><title>X</title>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+
+#data
+<!doctype html><table><title>X</title></table>
+#errors
+Line: 1 Col: 29 Unexpected start tag (title) in table context caused voodoo mode.
+Line: 1 Col: 38 Unexpected end tag (title) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <title>
+| "X"
+| <table>
+
+#data
+<!doctype html><head></head><title>X</title>
+#errors
+Line: 1 Col: 35 Unexpected start tag (title) that can be in head. Moved.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "X"
+| <body>
+
+#data
+<!doctype html></head><title>X</title>
+#errors
+Line: 1 Col: 29 Unexpected start tag (title) that can be in head. Moved.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <title>
+| "X"
+| <body>
+
+#data
+<!doctype html><table><meta></table>
+#errors
+Line: 1 Col: 28 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <meta>
+| <table>
+
+#data
+<!doctype html><table>X<tr><td><table> <meta></table></table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 45 Unexpected start tag (meta) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <meta>
+| <table>
+| " "
+
+#data
+<!doctype html><html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!doctype html> <head>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!doctype html><table><style> <tr>x </style> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <style>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><table><TBODY><script> <tr>x </script> </table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <script>
+| " <tr>x "
+| " "
+
+#data
+<!doctype html><p><applet><p>X</p></applet>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <applet>
+| <p>
+| "X"
+
+#data
+<!doctype html><listing>
+X</listing>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <listing>
+| "X"
+
+#data
+<!doctype html><select><input>X
+#errors
+Line: 1 Col: 30 Unexpected input start tag in the select phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <input>
+| "X"
+
+#data
+<!doctype html><select><select>X
+#errors
+Line: 1 Col: 31 Unexpected select start tag in the select phase treated as select end tag.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+
+#data
+<!doctype html><table><input type=hidDEN></table>
+#errors
+Line: 1 Col: 41 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table>X<input type=hidDEN></table>
+#errors
+Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| "X"
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table> <input type=hidDEN></table>
+#errors
+Line: 1 Col: 43 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table> <input type='hidDEN'></table>
+#errors
+Line: 1 Col: 45 Unexpected input with type hidden in table context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| " "
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table><input type=" hidden"><input type=hidDEN></table>
+#errors
+Line: 1 Col: 44 Unexpected start tag (input) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+| type=" hidden"
+| <table>
+| <input>
+| type="hidDEN"
+
+#data
+<!doctype html><table><select>X<tr>
+#errors
+Line: 1 Col: 30 Unexpected start tag (select) in table context caused voodoo mode.
+Line: 1 Col: 35 Unexpected table element start tag (trs) in the select in table phase.
+Line: 1 Col: 35 Unexpected end of file. Expected table content.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!doctype html><select>X</select>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "X"
+
+#data
+<!DOCTYPE hTmL><html></html>
+#errors
+Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML><html></html>
+#errors
+Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+
+#data
+<body>X</body></body>
+#errors
+Line: 1 Col: 21 Unexpected end tag token (body) in the after body phase.
+Line: 1 Col: 21 Unexpected EOF in inner html mode.
+#document-fragment
+html
+#document
+| <head>
+| <body>
+| "X"
+
+#data
+<div><p>a</x> b
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 13 Unexpected end tag (x). Ignored.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <p>
+| "a b"
+
+#data
+<table><tr><td><code></code> </table>
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <code>
+| " "
+
+#data
+<table><b><tr><td>aaa</td></tr>bbb</table>ccc
+#errors
+XXX: Fix me
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| <b>
+| "bbb"
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| "aaa"
+| <b>
+| "ccc"
+
+#data
+A<table><tr> B</tr> B</table>
+#errors
+XXX: Fix me
+#document
+| <html>
+| <head>
+| <body>
+| "A B B"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+A<table><tr> B</tr> </em>C</table>
+#errors
+XXX: Fix me
+#document
+| <html>
+| <head>
+| <body>
+| "A BC"
+| <table>
+| <tbody>
+| <tr>
+| " "
+
+#data
+<select><keygen>
+#errors
+Not known
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <keygen>
diff --git a/libgo/go/html/testdata/webkit/tests8.dat b/libgo/go/html/testdata/webkit/tests8.dat
new file mode 100644
index 000000000..90e6c919e
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests8.dat
@@ -0,0 +1,148 @@
+#data
+<div>
+<div></div>
+</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 3 Col: 7 Unexpected end tag (span). Ignored.
+Line: 3 Col: 8 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "
+"
+| <div>
+| "
+x"
+
+#data
+<div>x<div></div>
+</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 2 Col: 7 Unexpected end tag (span). Ignored.
+Line: 2 Col: 8 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "
+x"
+
+#data
+<div>x<div></div>x</span>x
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end tag (span). Ignored.
+Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "xx"
+
+#data
+<div>x<div></div>y</span>z
+#errors
+Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
+Line: 1 Col: 25 Unexpected end tag (span). Ignored.
+Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "yz"
+
+#data
+<table><div>x<div></div>x</span>x
+#errors
+Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
+Line: 1 Col: 12 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 18 Unexpected start tag (div) in table context caused voodoo mode.
+Line: 1 Col: 24 Unexpected end tag (div) in table context caused voodoo mode.
+Line: 1 Col: 32 Unexpected end tag (span) in table context caused voodoo mode.
+Line: 1 Col: 32 Unexpected end tag (span). Ignored.
+Line: 1 Col: 33 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "x"
+| <div>
+| "xx"
+| <table>
+
+#data
+x<table>x
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+Line: 1 Col: 9 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 9 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| "xx"
+| <table>
+
+#data
+x<table><table>x
+#errors
+Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
+Line: 1 Col: 15 Unexpected start tag (table) implies end tag (table).
+Line: 1 Col: 16 Unexpected non-space characters in table context caused voodoo mode.
+Line: 1 Col: 16 Unexpected end of file. Expected table content.
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <table>
+| "x"
+| <table>
+
+#data
+<b>a<div></div><div></b>y
+#errors
+Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
+Line: 1 Col: 24 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <b>
+| "a"
+| <div>
+| <div>
+| <b>
+| "y"
+
+#data
+<a><div><p></a>
+#errors
+Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
+Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <div>
+| <a>
+| <p>
+| <a>
diff --git a/libgo/go/html/testdata/webkit/tests9.dat b/libgo/go/html/testdata/webkit/tests9.dat
new file mode 100644
index 000000000..2b715f83d
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/tests9.dat
@@ -0,0 +1,430 @@
+#data
+<!DOCTYPE html><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+
+#data
+<!DOCTYPE html><body><math></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+
+#data
+<!DOCTYPE html><body><select><math></math></select>
+#errors
+Line: 1 Col: 35 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 42 Unexpected end tag (math) in the select phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+
+#data
+<!DOCTYPE html><body><select><option><math></math></option></select>
+#errors
+Line: 1 Col: 43 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 50 Unexpected end tag (math) in the select phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+
+#data
+<!DOCTYPE html><body><table><math></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 41 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 53 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><math><mi>foo</mi><mi>bar</mi></math></table>
+#errors
+Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 58 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 65 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+
+#data
+<!DOCTYPE html><body><table><tbody><math><mi>foo</mi><mi>bar</mi></math></tbody></table>
+#errors
+Line: 1 Col: 41 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 53 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 65 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 72 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+| <tbody>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><math><mi>foo</mi><mi>bar</mi></math></tr></tbody></table>
+#errors
+Line: 1 Col: 45 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 57 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 69 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 76 Unexpected end tag (math) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math></td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+
+#data
+<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math><p>baz</td></tr></tbody></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi></math><p>baz</caption></table>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 70 HTML start tag "p" in a foreign namespace context.
+Line: 1 Col: 81 Unexpected end table tag in caption. Generates implied end caption.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi>baz</table><p>quux
+#errors
+Line: 1 Col: 78 Unexpected end table tag in caption. Generates implied end caption.
+Line: 1 Col: 78 Unexpected end tag (caption). Missing end tag (math).
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <caption>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| "baz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><colgroup><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 44 Unexpected start tag (math) in table context caused voodoo mode.
+Line: 1 Col: 56 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 68 Unexpected end tag (mi) in table context caused voodoo mode.
+Line: 1 Col: 71 HTML start tag "p" in a foreign namespace context.
+Line: 1 Col: 71 Unexpected start tag (p) in table context caused voodoo mode.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+| <table>
+| <colgroup>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><tr><td><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 50 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 54 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 62 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 66 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 74 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 77 Unexpected start tag token (p) in the select phase. Ignored.
+Line: 1 Col: 88 Unexpected table element end tag (tables) in the select in table phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <select>
+| "foobarbaz"
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body><table><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
+#errors
+Line: 1 Col: 36 Unexpected start tag (select) in table context caused voodoo mode.
+Line: 1 Col: 42 Unexpected start tag token (math) in the select phase. Ignored.
+Line: 1 Col: 46 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 54 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 58 Unexpected start tag token (mi) in the select phase. Ignored.
+Line: 1 Col: 66 Unexpected end tag (mi) in the select phase. Ignored.
+Line: 1 Col: 69 Unexpected start tag token (p) in the select phase. Ignored.
+Line: 1 Col: 80 Unexpected table element end tag (tables) in the select in table phase.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <select>
+| "foobarbaz"
+| <table>
+| <p>
+| "quux"
+
+#data
+<!DOCTYPE html><body></body></html><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+Line: 1 Col: 41 Unexpected start tag (math).
+Line: 1 Col: 68 HTML start tag "p" in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><body></body><math><mi>foo</mi><mi>bar</mi><p>baz
+#errors
+Line: 1 Col: 34 Unexpected start tag token (math) in the after body phase.
+Line: 1 Col: 61 HTML start tag "p" in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| "foo"
+| <math mi>
+| "bar"
+| <p>
+| "baz"
+
+#data
+<!DOCTYPE html><frameset><math><mi></mi><mi></mi><p><span>
+#errors
+Line: 1 Col: 31 Unexpected start tag token (math) in the frameset phase. Ignored.
+Line: 1 Col: 35 Unexpected start tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 40 Unexpected end tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 44 Unexpected start tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 49 Unexpected end tag token (mi) in the frameset phase. Ignored.
+Line: 1 Col: 52 Unexpected start tag token (p) in the frameset phase. Ignored.
+Line: 1 Col: 58 Unexpected start tag token (span) in the frameset phase. Ignored.
+Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><frameset></frameset><math><mi></mi><mi></mi><p><span>
+#errors
+Line: 1 Col: 42 Unexpected start tag (math) in the after frameset phase. Ignored.
+Line: 1 Col: 46 Unexpected start tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 51 Unexpected end tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 55 Unexpected start tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 60 Unexpected end tag (mi) in the after frameset phase. Ignored.
+Line: 1 Col: 63 Unexpected start tag (p) in the after frameset phase. Ignored.
+Line: 1 Col: 69 Unexpected start tag (span) in the after frameset phase. Ignored.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!DOCTYPE html><body xlink:href=foo><math xlink:href=foo></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| <math math>
+| xlink href="foo"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo></mi></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo /></math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+
+#data
+<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo />bar</math>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| xlink:href="foo"
+| xml:lang="en"
+| <math math>
+| <math mi>
+| xlink href="foo"
+| xml lang="en"
+| "bar"
diff --git a/libgo/go/html/testdata/webkit/webkit01.dat b/libgo/go/html/testdata/webkit/webkit01.dat
new file mode 100644
index 000000000..544da9e8a
--- /dev/null
+++ b/libgo/go/html/testdata/webkit/webkit01.dat
@@ -0,0 +1,211 @@
+#data
+Test
+#errors
+Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
+#document
+| <html>
+| <head>
+| <body>
+| "Test"
+
+#data
+<div></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+
+#data
+<div>Test</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Test"
+
+#data
+<di
+#errors
+#document
+| <html>
+| <head>
+| <body>
+
+#data
+<div>Hello</div>
+<script>
+console.log("PASS");
+</script>
+<div>Bye</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Hello"
+| "
+"
+| <script>
+| "
+console.log("PASS");
+"
+| "
+"
+| <div>
+| "Bye"
+
+#data
+<div foo="bar">Hello</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo="bar"
+| "Hello"
+
+#data
+<div>Hello</div>
+<script>
+console.log("FOO<span>BAR</span>BAZ");
+</script>
+<div>Bye</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "Hello"
+| "
+"
+| <script>
+| "
+console.log("FOO<span>BAR</span>BAZ");
+"
+| "
+"
+| <div>
+| "Bye"
+
+#data
+<foo bar="baz"></foo><potato quack="duck"></potato>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| bar="baz"
+| <potato>
+| quack="duck"
+
+#data
+<foo bar="baz"><potato quack="duck"></potato></foo>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| bar="baz"
+| <potato>
+| quack="duck"
+
+#data
+<foo></foo bar="baz"><potato></potato quack="duck">
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <foo>
+| <potato>
+
+#data
+1<script>document.write("2")</script>3
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "1"
+| <script>
+| "document.write("2")"
+| "23"
+
+#data
+1<script>document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")</script>4
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "1"
+| <script>
+| "document.write("<script>document.write('2')</scr"+ "ipt><script>document.write('3')</scr" + "ipt>")"
+| <script>
+| "document.write('2')"
+| "2"
+| <script>
+| "document.write('3')"
+| "34"
+
+#data
+</ tttt>
+#errors
+#document
+| <!-- tttt -->
+| <html>
+| <head>
+| <body>
+
+#data
+<div FOO ><img><img></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| foo=""
+| <img>
+| <img>
+
+#data
+<p>Test</p<p>Test2</p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <p>
+| "Test"
+| "Test2"
+
+#data
+<rdar://problem/6869687>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <rdar:>
+| 6869687=""
+| problem=""
+
+#data
+<A>test< /A>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| "test< /A>"
diff --git a/libgo/go/html/token.go b/libgo/go/html/token.go
new file mode 100644
index 000000000..d63883850
--- /dev/null
+++ b/libgo/go/html/token.go
@@ -0,0 +1,398 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+)
+
+// A TokenType is the type of a Token.
+type TokenType int
+
+const (
+ // ErrorToken means that an error occurred during tokenization.
+ ErrorToken TokenType = iota
+ // TextToken means a text node.
+ TextToken
+ // A StartTagToken looks like <a>.
+ StartTagToken
+ // An EndTagToken looks like </a>.
+ EndTagToken
+ // A SelfClosingTagToken tag looks like <br/>.
+ SelfClosingTagToken
+)
+
+// String returns a string representation of the TokenType.
+func (t TokenType) String() string {
+ switch t {
+ case ErrorToken:
+ return "Error"
+ case TextToken:
+ return "Text"
+ case StartTagToken:
+ return "StartTag"
+ case EndTagToken:
+ return "EndTag"
+ case SelfClosingTagToken:
+ return "SelfClosingTag"
+ }
+ return "Invalid(" + strconv.Itoa(int(t)) + ")"
+}
+
+// An Attribute is an attribute key-value pair. Key is alphabetic (and hence
+// does not contain escapable characters like '&', '<' or '>'), and Val is
+// unescaped (it looks like "a<b" rather than "a&lt;b").
+type Attribute struct {
+ Key, Val string
+}
+
+// A Token consists of a TokenType and some Data (tag name for start and end
+// tags, content for text). A tag Token may also contain a slice of Attributes.
+// Data is unescaped for both tag and text Tokens (it looks like "a<b" rather
+// than "a&lt;b").
+type Token struct {
+ Type TokenType
+ Data string
+ Attr []Attribute
+}
+
+// tagString returns a string representation of a tag Token's Data and Attr.
+func (t Token) tagString() string {
+ if len(t.Attr) == 0 {
+ return t.Data
+ }
+ buf := bytes.NewBuffer(nil)
+ buf.WriteString(t.Data)
+ for _, a := range t.Attr {
+ buf.WriteByte(' ')
+ buf.WriteString(a.Key)
+ buf.WriteString(`="`)
+ escape(buf, a.Val)
+ buf.WriteByte('"')
+ }
+ return buf.String()
+}
+
+// String returns a string representation of the Token.
+func (t Token) String() string {
+ switch t.Type {
+ case ErrorToken:
+ return ""
+ case TextToken:
+ return EscapeString(t.Data)
+ case StartTagToken:
+ return "<" + t.tagString() + ">"
+ case EndTagToken:
+ return "</" + t.tagString() + ">"
+ case SelfClosingTagToken:
+ return "<" + t.tagString() + "/>"
+ }
+ return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
+}
+
+// A Tokenizer returns a stream of HTML Tokens.
+type Tokenizer struct {
+ // r is the source of the HTML text.
+ r io.Reader
+ // tt is the TokenType of the most recently read token. If tt == Error
+ // then err is the error associated with trying to read that token.
+ tt TokenType
+ err os.Error
+ // buf[p0:p1] holds the raw data of the most recent token.
+ // buf[p1:] is buffered input that will yield future tokens.
+ p0, p1 int
+ buf []byte
+}
+
+// Error returns the error associated with the most recent ErrorToken token.
+// This is typically os.EOF, meaning the end of tokenization.
+func (z *Tokenizer) Error() os.Error {
+ if z.tt != ErrorToken {
+ return nil
+ }
+ return z.err
+}
+
+// Raw returns the unmodified text of the current token. Calling Next, Token,
+// Text, TagName or TagAttr may change the contents of the returned slice.
+func (z *Tokenizer) Raw() []byte {
+ return z.buf[z.p0:z.p1]
+}
+
+// readByte returns the next byte from the input stream, doing a buffered read
+// from z.r into z.buf if necessary. z.buf[z.p0:z.p1] remains a contiguous byte
+// slice that holds all the bytes read so far for the current token.
+func (z *Tokenizer) readByte() (byte, os.Error) {
+ if z.p1 >= len(z.buf) {
+ // Our buffer is exhausted and we have to read from z.r.
+ // We copy z.buf[z.p0:z.p1] to the beginning of z.buf. If the length
+ // z.p1 - z.p0 is more than half the capacity of z.buf, then we
+ // allocate a new buffer before the copy.
+ c := cap(z.buf)
+ d := z.p1 - z.p0
+ var buf1 []byte
+ if 2*d > c {
+ buf1 = make([]byte, d, 2*c)
+ } else {
+ buf1 = z.buf[0:d]
+ }
+ copy(buf1, z.buf[z.p0:z.p1])
+ z.p0, z.p1, z.buf = 0, d, buf1[0:d]
+ // Now that we have copied the live bytes to the start of the buffer,
+ // we read from z.r into the remainder.
+ n, err := z.r.Read(buf1[d:cap(buf1)])
+ if err != nil {
+ return 0, err
+ }
+ z.buf = buf1[0 : d+n]
+ }
+ x := z.buf[z.p1]
+ z.p1++
+ return x, nil
+}
+
+// readTo keeps reading bytes until x is found.
+func (z *Tokenizer) readTo(x uint8) os.Error {
+ for {
+ c, err := z.readByte()
+ if err != nil {
+ return err
+ }
+ switch c {
+ case x:
+ return nil
+ case '\\':
+ _, err = z.readByte()
+ if err != nil {
+ return err
+ }
+ }
+ }
+ panic("unreachable")
+}
+
+// nextTag returns the next TokenType starting from the tag open state.
+func (z *Tokenizer) nextTag() (tt TokenType, err os.Error) {
+ c, err := z.readByte()
+ if err != nil {
+ return ErrorToken, err
+ }
+ switch {
+ case c == '/':
+ tt = EndTagToken
+ // Lower-cased characters are more common in tag names, so we check for them first.
+ case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
+ tt = StartTagToken
+ case c == '!':
+ return ErrorToken, os.NewError("html: TODO(nigeltao): implement comments")
+ case c == '?':
+ return ErrorToken, os.NewError("html: TODO(nigeltao): implement XML processing instructions")
+ default:
+ return ErrorToken, os.NewError("html: TODO(nigeltao): handle malformed tags")
+ }
+ for {
+ c, err := z.readByte()
+ if err != nil {
+ return TextToken, err
+ }
+ switch c {
+ case '"':
+ err = z.readTo('"')
+ if err != nil {
+ return TextToken, err
+ }
+ case '\'':
+ err = z.readTo('\'')
+ if err != nil {
+ return TextToken, err
+ }
+ case '>':
+ if z.buf[z.p1-2] == '/' && tt == StartTagToken {
+ return SelfClosingTagToken, nil
+ }
+ return tt, nil
+ }
+ }
+ panic("unreachable")
+}
+
+// Next scans the next token and returns its type.
+func (z *Tokenizer) Next() TokenType {
+ if z.err != nil {
+ z.tt = ErrorToken
+ return z.tt
+ }
+ z.p0 = z.p1
+ c, err := z.readByte()
+ if err != nil {
+ z.tt, z.err = ErrorToken, err
+ return z.tt
+ }
+ if c == '<' {
+ z.tt, z.err = z.nextTag()
+ return z.tt
+ }
+ for {
+ c, err := z.readByte()
+ if err != nil {
+ z.tt, z.err = ErrorToken, err
+ if err == os.EOF {
+ z.tt = TextToken
+ }
+ return z.tt
+ }
+ if c == '<' {
+ z.p1--
+ z.tt = TextToken
+ return z.tt
+ }
+ }
+ panic("unreachable")
+}
+
+// trim returns the largest j such that z.buf[i:j] contains only white space,
+// or only white space plus the final ">" or "/>" of the raw data.
+func (z *Tokenizer) trim(i int) int {
+ k := z.p1
+ for ; i < k; i++ {
+ switch z.buf[i] {
+ case ' ', '\n', '\t', '\f':
+ continue
+ case '>':
+ if i == k-1 {
+ return k
+ }
+ case '/':
+ if i == k-2 {
+ return k
+ }
+ }
+ return i
+ }
+ return k
+}
+
+// lower finds the largest alphabetic [0-9A-Za-z]* word at the start of z.buf[i:]
+// and returns that word lower-cased, as well as the trimmed cursor location
+// after that word.
+func (z *Tokenizer) lower(i int) ([]byte, int) {
+ i0 := i
+loop:
+ for ; i < z.p1; i++ {
+ c := z.buf[i]
+ switch {
+ case '0' <= c && c <= '9':
+ // No-op.
+ case 'A' <= c && c <= 'Z':
+ z.buf[i] = c + 'a' - 'A'
+ case 'a' <= c && c <= 'z':
+ // No-op.
+ default:
+ break loop
+ }
+ }
+ return z.buf[i0:i], z.trim(i)
+}
+
+// Text returns the raw data after unescaping.
+// The contents of the returned slice may change on the next call to Next.
+func (z *Tokenizer) Text() []byte {
+ s := unescape(z.Raw())
+ z.p0 = z.p1
+ return s
+}
+
+// TagName returns the lower-cased name of a tag token (the `img` out of
+// `<IMG SRC="foo">`), and whether the tag has attributes.
+// The contents of the returned slice may change on the next call to Next.
+func (z *Tokenizer) TagName() (name []byte, remaining bool) {
+ i := z.p0 + 1
+ if i >= z.p1 {
+ z.p0 = z.p1
+ return nil, false
+ }
+ if z.buf[i] == '/' {
+ i++
+ }
+ name, z.p0 = z.lower(i)
+ remaining = z.p0 != z.p1
+ return
+}
+
+// TagAttr returns the lower-cased key and unescaped value of the next unparsed
+// attribute for the current tag token, and whether there are more attributes.
+// The contents of the returned slices may change on the next call to Next.
+func (z *Tokenizer) TagAttr() (key, val []byte, remaining bool) {
+ key, i := z.lower(z.p0)
+ // Get past the "=\"".
+ if i == z.p1 || z.buf[i] != '=' {
+ return
+ }
+ i = z.trim(i + 1)
+ if i == z.p1 || z.buf[i] != '"' {
+ return
+ }
+ i = z.trim(i + 1)
+ // Copy and unescape everything up to the closing '"'.
+ dst, src := i, i
+loop:
+ for src < z.p1 {
+ c := z.buf[src]
+ switch c {
+ case '"':
+ src++
+ break loop
+ case '&':
+ dst, src = unescapeEntity(z.buf, dst, src)
+ case '\\':
+ if src == z.p1 {
+ z.buf[dst] = '\\'
+ dst++
+ } else {
+ z.buf[dst] = z.buf[src+1]
+ dst, src = dst+1, src+2
+ }
+ default:
+ z.buf[dst] = c
+ dst, src = dst+1, src+1
+ }
+ }
+ val, z.p0 = z.buf[i:dst], z.trim(src)
+ remaining = z.p0 != z.p1
+ return
+}
+
+// Token returns the next Token. The result's Data and Attr values remain valid
+// after subsequent Next calls.
+func (z *Tokenizer) Token() Token {
+ t := Token{Type: z.tt}
+ switch z.tt {
+ case TextToken:
+ t.Data = string(z.Text())
+ case StartTagToken, EndTagToken, SelfClosingTagToken:
+ var attr []Attribute
+ name, remaining := z.TagName()
+ for remaining {
+ var key, val []byte
+ key, val, remaining = z.TagAttr()
+ attr = append(attr, Attribute{string(key), string(val)})
+ }
+ t.Data = string(name)
+ t.Attr = attr
+ }
+ return t
+}
+
+// NewTokenizer returns a new HTML Tokenizer for the given Reader.
+// The input is assumed to be UTF-8 encoded.
+func NewTokenizer(r io.Reader) *Tokenizer {
+ return &Tokenizer{
+ r: r,
+ buf: make([]byte, 0, 4096),
+ }
+}
diff --git a/libgo/go/html/token_test.go b/libgo/go/html/token_test.go
new file mode 100644
index 000000000..e07999ca5
--- /dev/null
+++ b/libgo/go/html/token_test.go
@@ -0,0 +1,231 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "os"
+ "testing"
+)
+
+type tokenTest struct {
+ // A short description of the test case.
+ desc string
+ // The HTML to parse.
+ html string
+ // The string representations of the expected tokens.
+ tokens []string
+}
+
+var tokenTests = []tokenTest{
+ // A single text node. The tokenizer should not break text nodes on whitespace,
+ // nor should it normalize whitespace within a text node.
+ {
+ "text",
+ "foo bar",
+ []string{
+ "foo bar",
+ },
+ },
+ // An entity.
+ {
+ "entity",
+ "one &lt; two",
+ []string{
+ "one &lt; two",
+ },
+ },
+ // A start, self-closing and end tag. The tokenizer does not care if the start
+ // and end tokens don't match; that is the job of the parser.
+ {
+ "tags",
+ "<a>b<c/>d</e>",
+ []string{
+ "<a>",
+ "b",
+ "<c/>",
+ "d",
+ "</e>",
+ },
+ },
+ // An attribute with a backslash.
+ {
+ "backslash",
+ `<p id="a\"b">`,
+ []string{
+ `<p id="a&quot;b">`,
+ },
+ },
+ // Entities, tag name and attribute key lower-casing, and whitespace
+ // normalization within a tag.
+ {
+ "tricky",
+ "<p \t\n iD=\"a&quot;B\" foo=\"bar\"><EM>te&lt;&amp;;xt</em></p>",
+ []string{
+ `<p id="a&quot;B" foo="bar">`,
+ "<em>",
+ "te&lt;&amp;;xt",
+ "</em>",
+ "</p>",
+ },
+ },
+ // A non-existant entity. Tokenizing and converting back to a string should
+ // escape the "&" to become "&amp;".
+ {
+ "noSuchEntity",
+ `<a b="c&noSuchEntity;d">&lt;&alsoDoesntExist;&`,
+ []string{
+ `<a b="c&amp;noSuchEntity;d">`,
+ "&lt;&amp;alsoDoesntExist;&amp;",
+ },
+ },
+}
+
+func TestTokenizer(t *testing.T) {
+loop:
+ for _, tt := range tokenTests {
+ z := NewTokenizer(bytes.NewBuffer([]byte(tt.html)))
+ for i, s := range tt.tokens {
+ if z.Next() == ErrorToken {
+ t.Errorf("%s token %d: want %q got error %v", tt.desc, i, s, z.Error())
+ continue loop
+ }
+ actual := z.Token().String()
+ if s != actual {
+ t.Errorf("%s token %d: want %q got %q", tt.desc, i, s, actual)
+ continue loop
+ }
+ }
+ z.Next()
+ if z.Error() != os.EOF {
+ t.Errorf("%s: want EOF got %q", tt.desc, z.Token().String())
+ }
+ }
+}
+
+type unescapeTest struct {
+ // A short description of the test case.
+ desc string
+ // The HTML text.
+ html string
+ // The unescaped text.
+ unescaped string
+}
+
+var unescapeTests = []unescapeTest{
+ // Handle no entities.
+ {
+ "copy",
+ "A\ttext\nstring",
+ "A\ttext\nstring",
+ },
+ // Handle simple named entities.
+ {
+ "simple",
+ "&amp; &gt; &lt;",
+ "& > <",
+ },
+ // Handle hitting the end of the string.
+ {
+ "stringEnd",
+ "&amp &amp",
+ "& &",
+ },
+ // Handle entities with two codepoints.
+ {
+ "multiCodepoint",
+ "text &gesl; blah",
+ "text \u22db\ufe00 blah",
+ },
+ // Handle decimal numeric entities.
+ {
+ "decimalEntity",
+ "Delta = &#916; ",
+ "Delta = Δ ",
+ },
+ // Handle hexadecimal numeric entities.
+ {
+ "hexadecimalEntity",
+ "Lambda = &#x3bb; = &#X3Bb ",
+ "Lambda = λ = λ ",
+ },
+ // Handle numeric early termination.
+ {
+ "numericEnds",
+ "&# &#x &#128;43 &copy = &#169f = &#xa9",
+ "&# &#x €43 © = ©f = ©",
+ },
+ // Handle numeric ISO-8859-1 entity replacements.
+ {
+ "numericReplacements",
+ "Footnote&#x87;",
+ "Footnote‡",
+ },
+}
+
+func TestUnescape(t *testing.T) {
+ for _, tt := range unescapeTests {
+ unescaped := UnescapeString(tt.html)
+ if unescaped != tt.unescaped {
+ t.Errorf("TestUnescape %s: want %q, got %q", tt.desc, tt.unescaped, unescaped)
+ }
+ }
+}
+
+func TestUnescapeEscape(t *testing.T) {
+ ss := []string{
+ ``,
+ `abc def`,
+ `a & b`,
+ `a&amp;b`,
+ `a &amp b`,
+ `&quot;`,
+ `"`,
+ `"<&>"`,
+ `&quot;&lt;&amp;&gt;&quot;`,
+ `3&5==1 && 0<1, "0&lt;1", a+acute=&aacute;`,
+ }
+ for _, s := range ss {
+ if s != UnescapeString(EscapeString(s)) {
+ t.Errorf("s != UnescapeString(EscapeString(s)), s=%q", s)
+ }
+ }
+}
+
+func TestBufAPI(t *testing.T) {
+ s := "0<a>1</a>2<b>3<a>4<a>5</a>6</b>7</a>8<a/>9"
+ z := NewTokenizer(bytes.NewBuffer([]byte(s)))
+ result := bytes.NewBuffer(nil)
+ depth := 0
+loop:
+ for {
+ tt := z.Next()
+ switch tt {
+ case ErrorToken:
+ if z.Error() != os.EOF {
+ t.Error(z.Error())
+ }
+ break loop
+ case TextToken:
+ if depth > 0 {
+ result.Write(z.Text())
+ }
+ case StartTagToken, EndTagToken:
+ tn, _ := z.TagName()
+ if len(tn) == 1 && tn[0] == 'a' {
+ if tt == StartTagToken {
+ depth++
+ } else {
+ depth--
+ }
+ }
+ }
+ }
+ u := "14567"
+ v := string(result.Bytes())
+ if u != v {
+ t.Errorf("TestBufAPI: want %q got %q", u, v)
+ }
+}
diff --git a/libgo/go/http/chunked.go b/libgo/go/http/chunked.go
new file mode 100644
index 000000000..66195f06b
--- /dev/null
+++ b/libgo/go/http/chunked.go
@@ -0,0 +1,56 @@
+// 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 http
+
+import (
+ "io"
+ "os"
+ "strconv"
+)
+
+// NewChunkedWriter returns a new writer that translates writes into HTTP
+// "chunked" format before writing them to w. Closing the returned writer
+// sends the final 0-length chunk that marks the end of the stream.
+func NewChunkedWriter(w io.Writer) io.WriteCloser {
+ return &chunkedWriter{w}
+}
+
+// Writing to ChunkedWriter translates to writing in HTTP chunked Transfer
+// Encoding wire format to the undering Wire writer.
+type chunkedWriter struct {
+ Wire io.Writer
+}
+
+// Write the contents of data as one chunk to Wire.
+// NOTE: Note that the corresponding chunk-writing procedure in Conn.Write has
+// a bug since it does not check for success of io.WriteString
+func (cw *chunkedWriter) Write(data []byte) (n int, err os.Error) {
+
+ // Don't send 0-length data. It looks like EOF for chunked encoding.
+ if len(data) == 0 {
+ return 0, nil
+ }
+
+ head := strconv.Itob(len(data), 16) + "\r\n"
+
+ if _, err = io.WriteString(cw.Wire, head); err != nil {
+ return 0, err
+ }
+ if n, err = cw.Wire.Write(data); err != nil {
+ return
+ }
+ if n != len(data) {
+ err = io.ErrShortWrite
+ return
+ }
+ _, err = io.WriteString(cw.Wire, "\r\n")
+
+ return
+}
+
+func (cw *chunkedWriter) Close() os.Error {
+ _, err := io.WriteString(cw.Wire, "0\r\n")
+ return err
+}
diff --git a/libgo/go/http/client.go b/libgo/go/http/client.go
new file mode 100644
index 000000000..022f4f124
--- /dev/null
+++ b/libgo/go/http/client.go
@@ -0,0 +1,236 @@
+// 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.
+
+// Primitive HTTP client. See RFC 2616.
+
+package http
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/tls"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
+// return true if the string includes a port.
+func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
+
+// Used in Send to implement io.ReadCloser by bundling together the
+// bufio.Reader through which we read the response, and the underlying
+// network connection.
+type readClose struct {
+ io.Reader
+ io.Closer
+}
+
+// Send issues an HTTP request. Caller should close resp.Body when done reading it.
+//
+// TODO: support persistent connections (multiple requests on a single connection).
+// send() method is nonpublic because, when we refactor the code for persistent
+// connections, it may no longer make sense to have a method with this signature.
+func send(req *Request) (resp *Response, err os.Error) {
+ if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
+ return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
+ }
+
+ addr := req.URL.Host
+ if !hasPort(addr) {
+ addr += ":" + req.URL.Scheme
+ }
+ info := req.URL.RawUserinfo
+ if len(info) > 0 {
+ enc := base64.URLEncoding
+ encoded := make([]byte, enc.EncodedLen(len(info)))
+ enc.Encode(encoded, []byte(info))
+ if req.Header == nil {
+ req.Header = make(map[string]string)
+ }
+ req.Header["Authorization"] = "Basic " + string(encoded)
+ }
+
+ var conn io.ReadWriteCloser
+ if req.URL.Scheme == "http" {
+ conn, err = net.Dial("tcp", "", addr)
+ if err != nil {
+ return nil, err
+ }
+ } else { // https
+ conn, err = tls.Dial("tcp", "", addr, nil)
+ if err != nil {
+ return nil, err
+ }
+ h := req.URL.Host
+ if hasPort(h) {
+ h = h[0:strings.LastIndex(h, ":")]
+ }
+ if err := conn.(*tls.Conn).VerifyHostname(h); err != nil {
+ return nil, err
+ }
+ }
+
+ err = req.Write(conn)
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+
+ reader := bufio.NewReader(conn)
+ resp, err = ReadResponse(reader, req.Method)
+ if err != nil {
+ conn.Close()
+ return nil, err
+ }
+
+ resp.Body = readClose{resp.Body, conn}
+
+ return
+}
+
+// True if the specified HTTP status code is one for which the Get utility should
+// automatically redirect.
+func shouldRedirect(statusCode int) bool {
+ switch statusCode {
+ case StatusMovedPermanently, StatusFound, StatusSeeOther, StatusTemporaryRedirect:
+ return true
+ }
+ return false
+}
+
+// Get issues a GET to the specified URL. If the response is one of the following
+// redirect codes, it follows the redirect, up to a maximum of 10 redirects:
+//
+// 301 (Moved Permanently)
+// 302 (Found)
+// 303 (See Other)
+// 307 (Temporary Redirect)
+//
+// finalURL is the URL from which the response was fetched -- identical to the
+// input URL unless redirects were followed.
+//
+// Caller should close r.Body when done reading it.
+func Get(url string) (r *Response, finalURL string, err os.Error) {
+ // TODO: if/when we add cookie support, the redirected request shouldn't
+ // necessarily supply the same cookies as the original.
+ // TODO: set referrer header on redirects.
+ var base *URL
+ for redirect := 0; ; redirect++ {
+ if redirect >= 10 {
+ err = os.ErrorString("stopped after 10 redirects")
+ break
+ }
+
+ var req Request
+ if base == nil {
+ req.URL, err = ParseURL(url)
+ } else {
+ req.URL, err = base.ParseURL(url)
+ }
+ if err != nil {
+ break
+ }
+ url = req.URL.String()
+ if r, err = send(&req); err != nil {
+ break
+ }
+ if shouldRedirect(r.StatusCode) {
+ r.Body.Close()
+ if url = r.GetHeader("Location"); url == "" {
+ err = os.ErrorString(fmt.Sprintf("%d response missing Location header", r.StatusCode))
+ break
+ }
+ base = req.URL
+ continue
+ }
+ finalURL = url
+ return
+ }
+
+ err = &URLError{"Get", url, err}
+ return
+}
+
+// Post issues a POST to the specified URL.
+//
+// Caller should close r.Body when done reading it.
+func Post(url string, bodyType string, body io.Reader) (r *Response, err os.Error) {
+ var req Request
+ req.Method = "POST"
+ req.ProtoMajor = 1
+ req.ProtoMinor = 1
+ req.Close = true
+ req.Body = nopCloser{body}
+ req.Header = map[string]string{
+ "Content-Type": bodyType,
+ }
+ req.TransferEncoding = []string{"chunked"}
+
+ req.URL, err = ParseURL(url)
+ if err != nil {
+ return nil, err
+ }
+
+ return send(&req)
+}
+
+// PostForm issues a POST to the specified URL,
+// with data's keys and values urlencoded as the request body.
+//
+// Caller should close r.Body when done reading it.
+func PostForm(url string, data map[string]string) (r *Response, err os.Error) {
+ var req Request
+ req.Method = "POST"
+ req.ProtoMajor = 1
+ req.ProtoMinor = 1
+ req.Close = true
+ body := urlencode(data)
+ req.Body = nopCloser{body}
+ req.Header = map[string]string{
+ "Content-Type": "application/x-www-form-urlencoded",
+ "Content-Length": strconv.Itoa(body.Len()),
+ }
+ req.ContentLength = int64(body.Len())
+
+ req.URL, err = ParseURL(url)
+ if err != nil {
+ return nil, err
+ }
+
+ return send(&req)
+}
+
+// TODO: remove this function when PostForm takes a multimap.
+func urlencode(data map[string]string) (b *bytes.Buffer) {
+ m := make(map[string][]string, len(data))
+ for k, v := range data {
+ m[k] = []string{v}
+ }
+ return bytes.NewBuffer([]byte(EncodeQuery(m)))
+}
+
+// Head issues a HEAD to the specified URL.
+func Head(url string) (r *Response, err os.Error) {
+ var req Request
+ req.Method = "HEAD"
+ if req.URL, err = ParseURL(url); err != nil {
+ return
+ }
+ url = req.URL.String()
+ if r, err = send(&req); err != nil {
+ return
+ }
+ return
+}
+
+type nopCloser struct {
+ io.Reader
+}
+
+func (nopCloser) Close() os.Error { return nil }
diff --git a/libgo/go/http/client_test.go b/libgo/go/http/client_test.go
new file mode 100644
index 000000000..013653a82
--- /dev/null
+++ b/libgo/go/http/client_test.go
@@ -0,0 +1,40 @@
+// 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.
+
+// Tests for client.go
+
+package http
+
+import (
+ "io/ioutil"
+ "strings"
+ "testing"
+)
+
+func TestClient(t *testing.T) {
+ // TODO: add a proper test suite. Current test merely verifies that
+ // we can retrieve the Google robots.txt file.
+
+ r, _, err := Get("http://www.google.com/robots.txt")
+ var b []byte
+ if err == nil {
+ b, err = ioutil.ReadAll(r.Body)
+ r.Body.Close()
+ }
+ if err != nil {
+ t.Error(err)
+ } else if s := string(b); !strings.HasPrefix(s, "User-agent:") {
+ t.Errorf("Incorrect page body (did not begin with User-agent): %q", s)
+ }
+}
+
+func TestClientHead(t *testing.T) {
+ r, err := Head("http://www.google.com/robots.txt")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, ok := r.Header["Last-Modified"]; !ok {
+ t.Error("Last-Modified header not found.")
+ }
+}
diff --git a/libgo/go/http/dump.go b/libgo/go/http/dump.go
new file mode 100644
index 000000000..73ac97973
--- /dev/null
+++ b/libgo/go/http/dump.go
@@ -0,0 +1,76 @@
+// 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 http
+
+import (
+ "bytes"
+ "io"
+ "os"
+)
+
+
+// One of the copies, say from b to r2, could be avoided by using a more
+// elaborate trick where the other copy is made during Request/Response.Write.
+// This would complicate things too much, given that these functions are for
+// debugging only.
+func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err os.Error) {
+ var buf bytes.Buffer
+ if _, err = buf.ReadFrom(b); err != nil {
+ return nil, nil, err
+ }
+ if err = b.Close(); err != nil {
+ return nil, nil, err
+ }
+ return nopCloser{&buf}, nopCloser{bytes.NewBuffer(buf.Bytes())}, nil
+}
+
+// DumpRequest returns the wire representation of req,
+// optionally including the request body, for debugging.
+// DumpRequest is semantically a no-op, but in order to
+// dump the body, it reads the body data into memory and
+// changes req.Body to refer to the in-memory copy.
+func DumpRequest(req *Request, body bool) (dump []byte, err os.Error) {
+ var b bytes.Buffer
+ save := req.Body
+ if !body || req.Body == nil {
+ req.Body = nil
+ } else {
+ save, req.Body, err = drainBody(req.Body)
+ if err != nil {
+ return
+ }
+ }
+ err = req.Write(&b)
+ req.Body = save
+ if err != nil {
+ return
+ }
+ dump = b.Bytes()
+ return
+}
+
+// DumpResponse is like DumpRequest but dumps a response.
+func DumpResponse(resp *Response, body bool) (dump []byte, err os.Error) {
+ var b bytes.Buffer
+ save := resp.Body
+ savecl := resp.ContentLength
+ if !body || resp.Body == nil {
+ resp.Body = nil
+ resp.ContentLength = 0
+ } else {
+ save, resp.Body, err = drainBody(resp.Body)
+ if err != nil {
+ return
+ }
+ }
+ err = resp.Write(&b)
+ resp.Body = save
+ resp.ContentLength = savecl
+ if err != nil {
+ return
+ }
+ dump = b.Bytes()
+ return
+}
diff --git a/libgo/go/http/fs.go b/libgo/go/http/fs.go
new file mode 100644
index 000000000..bbfa58d26
--- /dev/null
+++ b/libgo/go/http/fs.go
@@ -0,0 +1,265 @@
+// 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.
+
+// HTTP file system request handler
+
+package http
+
+import (
+ "fmt"
+ "io"
+ "mime"
+ "os"
+ "path"
+ "strconv"
+ "strings"
+ "time"
+ "utf8"
+)
+
+// Heuristic: b is text if it is valid UTF-8 and doesn't
+// contain any unprintable ASCII or Unicode characters.
+func isText(b []byte) bool {
+ for len(b) > 0 && utf8.FullRune(b) {
+ rune, size := utf8.DecodeRune(b)
+ if size == 1 && rune == utf8.RuneError {
+ // decoding error
+ return false
+ }
+ if 0x7F <= rune && rune <= 0x9F {
+ return false
+ }
+ if rune < ' ' {
+ switch rune {
+ case '\n', '\r', '\t':
+ // okay
+ default:
+ // binary garbage
+ return false
+ }
+ }
+ b = b[size:]
+ }
+ return true
+}
+
+func dirList(w ResponseWriter, f *os.File) {
+ fmt.Fprintf(w, "<pre>\n")
+ for {
+ dirs, err := f.Readdir(100)
+ if err != nil || len(dirs) == 0 {
+ break
+ }
+ for _, d := range dirs {
+ name := d.Name
+ if d.IsDirectory() {
+ name += "/"
+ }
+ // TODO htmlescape
+ fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", name, name)
+ }
+ }
+ fmt.Fprintf(w, "</pre>\n")
+}
+
+func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
+ const indexPage = "/index.html"
+
+ // redirect .../index.html to .../
+ if strings.HasSuffix(r.URL.Path, indexPage) {
+ Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len(indexPage)+1], StatusMovedPermanently)
+ return
+ }
+
+ f, err := os.Open(name, os.O_RDONLY, 0)
+ if err != nil {
+ // TODO expose actual error?
+ NotFound(w, r)
+ return
+ }
+ defer f.Close()
+
+ d, err1 := f.Stat()
+ if err1 != nil {
+ // TODO expose actual error?
+ NotFound(w, r)
+ return
+ }
+
+ if redirect {
+ // redirect to canonical path: / at end of directory url
+ // r.URL.Path always begins with /
+ url := r.URL.Path
+ if d.IsDirectory() {
+ if url[len(url)-1] != '/' {
+ Redirect(w, r, url+"/", StatusMovedPermanently)
+ return
+ }
+ } else {
+ if url[len(url)-1] == '/' {
+ Redirect(w, r, url[0:len(url)-1], StatusMovedPermanently)
+ return
+ }
+ }
+ }
+
+ if t, _ := time.Parse(TimeFormat, r.Header["If-Modified-Since"]); t != nil && d.Mtime_ns/1e9 <= t.Seconds() {
+ w.WriteHeader(StatusNotModified)
+ return
+ }
+ w.SetHeader("Last-Modified", time.SecondsToUTC(d.Mtime_ns/1e9).Format(TimeFormat))
+
+ // use contents of index.html for directory, if present
+ if d.IsDirectory() {
+ index := name + indexPage
+ ff, err := os.Open(index, os.O_RDONLY, 0)
+ if err == nil {
+ defer ff.Close()
+ dd, err := ff.Stat()
+ if err == nil {
+ name = index
+ d = dd
+ f = ff
+ }
+ }
+ }
+
+ if d.IsDirectory() {
+ dirList(w, f)
+ return
+ }
+
+ // serve file
+ size := d.Size
+ code := StatusOK
+
+ // use extension to find content type.
+ ext := path.Ext(name)
+ if ctype := mime.TypeByExtension(ext); ctype != "" {
+ w.SetHeader("Content-Type", ctype)
+ } else {
+ // read first chunk to decide between utf-8 text and binary
+ var buf [1024]byte
+ n, _ := io.ReadFull(f, buf[:])
+ b := buf[:n]
+ if isText(b) {
+ w.SetHeader("Content-Type", "text-plain; charset=utf-8")
+ } else {
+ w.SetHeader("Content-Type", "application/octet-stream") // generic binary
+ }
+ f.Seek(0, 0) // rewind to output whole file
+ }
+
+ // handle Content-Range header.
+ // TODO(adg): handle multiple ranges
+ ranges, err := parseRange(r.Header["Range"], size)
+ if err != nil || len(ranges) > 1 {
+ Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
+ return
+ }
+ if len(ranges) == 1 {
+ ra := ranges[0]
+ if _, err := f.Seek(ra.start, 0); err != nil {
+ Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
+ return
+ }
+ size = ra.length
+ code = StatusPartialContent
+ w.SetHeader("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ra.start, ra.start+ra.length-1, d.Size))
+ }
+
+ w.SetHeader("Accept-Ranges", "bytes")
+ w.SetHeader("Content-Length", strconv.Itoa64(size))
+
+ w.WriteHeader(code)
+
+ if r.Method != "HEAD" {
+ io.Copyn(w, f, size)
+ }
+}
+
+// ServeFile replies to the request with the contents of the named file or directory.
+func ServeFile(w ResponseWriter, r *Request, name string) {
+ serveFile(w, r, name, false)
+}
+
+type fileHandler struct {
+ root string
+ prefix string
+}
+
+// FileServer returns a handler that serves HTTP requests
+// with the contents of the file system rooted at root.
+// It strips prefix from the incoming requests before
+// looking up the file name in the file system.
+func FileServer(root, prefix string) Handler { return &fileHandler{root, prefix} }
+
+func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
+ path := r.URL.Path
+ if !strings.HasPrefix(path, f.prefix) {
+ NotFound(w, r)
+ return
+ }
+ path = path[len(f.prefix):]
+ serveFile(w, r, f.root+"/"+path, true)
+}
+
+// httpRange specifies the byte range to be sent to the client.
+type httpRange struct {
+ start, length int64
+}
+
+// parseRange parses a Range header string as per RFC 2616.
+func parseRange(s string, size int64) ([]httpRange, os.Error) {
+ if s == "" {
+ return nil, nil // header not present
+ }
+ const b = "bytes="
+ if !strings.HasPrefix(s, b) {
+ return nil, os.NewError("invalid range")
+ }
+ var ranges []httpRange
+ for _, ra := range strings.Split(s[len(b):], ",", -1) {
+ i := strings.Index(ra, "-")
+ if i < 0 {
+ return nil, os.NewError("invalid range")
+ }
+ start, end := ra[:i], ra[i+1:]
+ var r httpRange
+ if start == "" {
+ // If no start is specified, end specifies the
+ // range start relative to the end of the file.
+ i, err := strconv.Atoi64(end)
+ if err != nil {
+ return nil, os.NewError("invalid range")
+ }
+ if i > size {
+ i = size
+ }
+ r.start = size - i
+ r.length = size - r.start
+ } else {
+ i, err := strconv.Atoi64(start)
+ if err != nil || i > size || i < 0 {
+ return nil, os.NewError("invalid range")
+ }
+ r.start = i
+ if end == "" {
+ // If no end is specified, range extends to end of the file.
+ r.length = size - r.start
+ } else {
+ i, err := strconv.Atoi64(end)
+ if err != nil || r.start > i {
+ return nil, os.NewError("invalid range")
+ }
+ if i >= size {
+ i = size - 1
+ }
+ r.length = i - r.start + 1
+ }
+ }
+ ranges = append(ranges, r)
+ }
+ return ranges, nil
+}
diff --git a/libgo/go/http/fs_test.go b/libgo/go/http/fs_test.go
new file mode 100644
index 000000000..0a5636b88
--- /dev/null
+++ b/libgo/go/http/fs_test.go
@@ -0,0 +1,172 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net"
+ "os"
+ "sync"
+ "testing"
+)
+
+var ParseRangeTests = []struct {
+ s string
+ length int64
+ r []httpRange
+}{
+ {"", 0, nil},
+ {"foo", 0, nil},
+ {"bytes=", 0, nil},
+ {"bytes=5-4", 10, nil},
+ {"bytes=0-2,5-4", 10, nil},
+ {"bytes=0-9", 10, []httpRange{{0, 10}}},
+ {"bytes=0-", 10, []httpRange{{0, 10}}},
+ {"bytes=5-", 10, []httpRange{{5, 5}}},
+ {"bytes=0-20", 10, []httpRange{{0, 10}}},
+ {"bytes=15-,0-5", 10, nil},
+ {"bytes=-5", 10, []httpRange{{5, 5}}},
+ {"bytes=-15", 10, []httpRange{{0, 10}}},
+ {"bytes=0-499", 10000, []httpRange{{0, 500}}},
+ {"bytes=500-999", 10000, []httpRange{{500, 500}}},
+ {"bytes=-500", 10000, []httpRange{{9500, 500}}},
+ {"bytes=9500-", 10000, []httpRange{{9500, 500}}},
+ {"bytes=0-0,-1", 10000, []httpRange{{0, 1}, {9999, 1}}},
+ {"bytes=500-600,601-999", 10000, []httpRange{{500, 101}, {601, 399}}},
+ {"bytes=500-700,601-999", 10000, []httpRange{{500, 201}, {601, 399}}},
+}
+
+func TestParseRange(t *testing.T) {
+ for _, test := range ParseRangeTests {
+ r := test.r
+ ranges, err := parseRange(test.s, test.length)
+ if err != nil && r != nil {
+ t.Errorf("parseRange(%q) returned error %q", test.s, err)
+ }
+ if len(ranges) != len(r) {
+ t.Errorf("len(parseRange(%q)) = %d, want %d", test.s, len(ranges), len(r))
+ continue
+ }
+ for i := range r {
+ if ranges[i].start != r[i].start {
+ t.Errorf("parseRange(%q)[%d].start = %d, want %d", test.s, i, ranges[i].start, r[i].start)
+ }
+ if ranges[i].length != r[i].length {
+ t.Errorf("parseRange(%q)[%d].length = %d, want %d", test.s, i, ranges[i].length, r[i].length)
+ }
+ }
+ }
+}
+
+const (
+ testFile = "testdata/file"
+ testFileLength = 11
+)
+
+var (
+ serverOnce sync.Once
+ serverAddr string
+)
+
+func startServer(t *testing.T) {
+ serverOnce.Do(func() {
+ HandleFunc("/ServeFile", func(w ResponseWriter, r *Request) {
+ ServeFile(w, r, "testdata/file")
+ })
+ l, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("listen:", err)
+ }
+ serverAddr = l.Addr().String()
+ go Serve(l, nil)
+ })
+}
+
+var ServeFileRangeTests = []struct {
+ start, end int
+ r string
+ code int
+}{
+ {0, testFileLength, "", StatusOK},
+ {0, 5, "0-4", StatusPartialContent},
+ {2, testFileLength, "2-", StatusPartialContent},
+ {testFileLength - 5, testFileLength, "-5", StatusPartialContent},
+ {3, 8, "3-7", StatusPartialContent},
+ {0, 0, "20-", StatusRequestedRangeNotSatisfiable},
+}
+
+func TestServeFile(t *testing.T) {
+ startServer(t)
+ var err os.Error
+
+ file, err := ioutil.ReadFile(testFile)
+ if err != nil {
+ t.Fatal("reading file:", err)
+ }
+
+ // set up the Request (re-used for all tests)
+ var req Request
+ req.Header = make(map[string]string)
+ if req.URL, err = ParseURL("http://" + serverAddr + "/ServeFile"); err != nil {
+ t.Fatal("ParseURL:", err)
+ }
+ req.Method = "GET"
+
+ // straight GET
+ _, body := getBody(t, req)
+ if !equal(body, file) {
+ t.Fatalf("body mismatch: got %q, want %q", body, file)
+ }
+
+ // Range tests
+ for _, rt := range ServeFileRangeTests {
+ req.Header["Range"] = "bytes=" + rt.r
+ if rt.r == "" {
+ req.Header["Range"] = ""
+ }
+ r, body := getBody(t, req)
+ if r.StatusCode != rt.code {
+ t.Errorf("range=%q: StatusCode=%d, want %d", rt.r, r.StatusCode, rt.code)
+ }
+ if rt.code == StatusRequestedRangeNotSatisfiable {
+ continue
+ }
+ h := fmt.Sprintf("bytes %d-%d/%d", rt.start, rt.end-1, testFileLength)
+ if rt.r == "" {
+ h = ""
+ }
+ if r.Header["Content-Range"] != h {
+ t.Errorf("header mismatch: range=%q: got %q, want %q", rt.r, r.Header["Content-Range"], h)
+ }
+ if !equal(body, file[rt.start:rt.end]) {
+ t.Errorf("body mismatch: range=%q: got %q, want %q", rt.r, body, file[rt.start:rt.end])
+ }
+ }
+}
+
+func getBody(t *testing.T, req Request) (*Response, []byte) {
+ r, err := send(&req)
+ if err != nil {
+ t.Fatal(req.URL.String(), "send:", err)
+ }
+ b, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ t.Fatal("reading Body:", err)
+ }
+ return r, b
+}
+
+func equal(a, b []byte) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := range a {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
diff --git a/libgo/go/http/lex.go b/libgo/go/http/lex.go
new file mode 100644
index 000000000..93b67e701
--- /dev/null
+++ b/libgo/go/http/lex.go
@@ -0,0 +1,144 @@
+// 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 http
+
+// This file deals with lexical matters of HTTP
+
+func isSeparator(c byte) bool {
+ switch c {
+ case '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t':
+ return true
+ }
+ return false
+}
+
+func isSpace(c byte) bool {
+ switch c {
+ case ' ', '\t', '\r', '\n':
+ return true
+ }
+ return false
+}
+
+func isCtl(c byte) bool { return (0 <= c && c <= 31) || c == 127 }
+
+func isChar(c byte) bool { return 0 <= c && c <= 127 }
+
+func isAnyText(c byte) bool { return !isCtl(c) }
+
+func isQdText(c byte) bool { return isAnyText(c) && c != '"' }
+
+func isToken(c byte) bool { return isChar(c) && !isCtl(c) && !isSeparator(c) }
+
+// Valid escaped sequences are not specified in RFC 2616, so for now, we assume
+// that they coincide with the common sense ones used by GO. Malformed
+// characters should probably not be treated as errors by a robust (forgiving)
+// parser, so we replace them with the '?' character.
+func httpUnquotePair(b byte) byte {
+ // skip the first byte, which should always be '\'
+ switch b {
+ case 'a':
+ return '\a'
+ case 'b':
+ return '\b'
+ case 'f':
+ return '\f'
+ case 'n':
+ return '\n'
+ case 'r':
+ return '\r'
+ case 't':
+ return '\t'
+ case 'v':
+ return '\v'
+ case '\\':
+ return '\\'
+ case '\'':
+ return '\''
+ case '"':
+ return '"'
+ }
+ return '?'
+}
+
+// raw must begin with a valid quoted string. Only the first quoted string is
+// parsed and is unquoted in result. eaten is the number of bytes parsed, or -1
+// upon failure.
+func httpUnquote(raw []byte) (eaten int, result string) {
+ buf := make([]byte, len(raw))
+ if raw[0] != '"' {
+ return -1, ""
+ }
+ eaten = 1
+ j := 0 // # of bytes written in buf
+ for i := 1; i < len(raw); i++ {
+ switch b := raw[i]; b {
+ case '"':
+ eaten++
+ buf = buf[0:j]
+ return i + 1, string(buf)
+ case '\\':
+ if len(raw) < i+2 {
+ return -1, ""
+ }
+ buf[j] = httpUnquotePair(raw[i+1])
+ eaten += 2
+ j++
+ i++
+ default:
+ if isQdText(b) {
+ buf[j] = b
+ } else {
+ buf[j] = '?'
+ }
+ eaten++
+ j++
+ }
+ }
+ return -1, ""
+}
+
+// This is a best effort parse, so errors are not returned, instead not all of
+// the input string might be parsed. result is always non-nil.
+func httpSplitFieldValue(fv string) (eaten int, result []string) {
+ result = make([]string, 0, len(fv))
+ raw := []byte(fv)
+ i := 0
+ chunk := ""
+ for i < len(raw) {
+ b := raw[i]
+ switch {
+ case b == '"':
+ eaten, unq := httpUnquote(raw[i:len(raw)])
+ if eaten < 0 {
+ return i, result
+ } else {
+ i += eaten
+ chunk += unq
+ }
+ case isSeparator(b):
+ if chunk != "" {
+ result = result[0 : len(result)+1]
+ result[len(result)-1] = chunk
+ chunk = ""
+ }
+ i++
+ case isToken(b):
+ chunk += string(b)
+ i++
+ case b == '\n' || b == '\r':
+ i++
+ default:
+ chunk += "?"
+ i++
+ }
+ }
+ if chunk != "" {
+ result = result[0 : len(result)+1]
+ result[len(result)-1] = chunk
+ chunk = ""
+ }
+ return i, result
+}
diff --git a/libgo/go/http/lex_test.go b/libgo/go/http/lex_test.go
new file mode 100644
index 000000000..5386f7534
--- /dev/null
+++ b/libgo/go/http/lex_test.go
@@ -0,0 +1,70 @@
+// 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 http
+
+import (
+ "testing"
+)
+
+type lexTest struct {
+ Raw string
+ Parsed int // # of parsed characters
+ Result []string
+}
+
+var lexTests = []lexTest{
+ {
+ Raw: `"abc"def,:ghi`,
+ Parsed: 13,
+ Result: []string{"abcdef", "ghi"},
+ },
+ // My understanding of the RFC is that escape sequences outside of
+ // quotes are not interpreted?
+ {
+ Raw: `"\t"\t"\t"`,
+ Parsed: 10,
+ Result: []string{"\t", "t\t"},
+ },
+ {
+ Raw: `"\yab"\r\n`,
+ Parsed: 10,
+ Result: []string{"?ab", "r", "n"},
+ },
+ {
+ Raw: "ab\f",
+ Parsed: 3,
+ Result: []string{"ab?"},
+ },
+ {
+ Raw: "\"ab \" c,de f, gh, ij\n\t\r",
+ Parsed: 23,
+ Result: []string{"ab ", "c", "de", "f", "gh", "ij"},
+ },
+}
+
+func min(x, y int) int {
+ if x <= y {
+ return x
+ }
+ return y
+}
+
+func TestSplitFieldValue(t *testing.T) {
+ for k, l := range lexTests {
+ parsed, result := httpSplitFieldValue(l.Raw)
+ if parsed != l.Parsed {
+ t.Errorf("#%d: Parsed %d, expected %d", k, parsed, l.Parsed)
+ }
+ if len(result) != len(l.Result) {
+ t.Errorf("#%d: Result len %d, expected %d", k, len(result), len(l.Result))
+ }
+ for i := 0; i < min(len(result), len(l.Result)); i++ {
+ if result[i] != l.Result[i] {
+ t.Errorf("#%d: %d-th entry mismatch. Have {%s}, expect {%s}",
+ k, i, result[i], l.Result[i])
+ }
+ }
+ }
+}
diff --git a/libgo/go/http/persist.go b/libgo/go/http/persist.go
new file mode 100644
index 000000000..8bfc09755
--- /dev/null
+++ b/libgo/go/http/persist.go
@@ -0,0 +1,303 @@
+// 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 http
+
+import (
+ "bufio"
+ "container/list"
+ "io"
+ "net"
+ "os"
+ "sync"
+)
+
+var ErrPersistEOF = &ProtocolError{"persistent connection closed"}
+
+// A ServerConn reads requests and sends responses over an underlying
+// connection, until the HTTP keepalive logic commands an end. ServerConn
+// does not close the underlying connection. Instead, the user calls Close
+// and regains control over the connection. ServerConn supports pipe-lining,
+// i.e. requests can be read out of sync (but in the same order) while the
+// respective responses are sent.
+type ServerConn struct {
+ c net.Conn
+ r *bufio.Reader
+ clsd bool // indicates a graceful close
+ re, we os.Error // read/write errors
+ lastBody io.ReadCloser
+ nread, nwritten int
+ lk sync.Mutex // protected read/write to re,we
+}
+
+// NewServerConn returns a new ServerConn reading and writing c. If r is not
+// nil, it is the buffer to use when reading c.
+func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
+ if r == nil {
+ r = bufio.NewReader(c)
+ }
+ return &ServerConn{c: c, r: r}
+}
+
+// Close detaches the ServerConn and returns the underlying connection as well
+// as the read-side bufio which may have some left over data. Close may be
+// called before Read has signaled the end of the keep-alive logic. The user
+// should not call Close while Read or Write is in progress.
+func (sc *ServerConn) Close() (c net.Conn, r *bufio.Reader) {
+ sc.lk.Lock()
+ defer sc.lk.Unlock()
+ c = sc.c
+ r = sc.r
+ sc.c = nil
+ sc.r = nil
+ return
+}
+
+// Read returns the next request on the wire. An ErrPersistEOF is returned if
+// it is gracefully determined that there are no more requests (e.g. after the
+// first request on an HTTP/1.0 connection, or after a Connection:close on a
+// HTTP/1.1 connection). Read can be called concurrently with Write, but not
+// with another Read.
+func (sc *ServerConn) Read() (req *Request, err os.Error) {
+
+ sc.lk.Lock()
+ if sc.we != nil { // no point receiving if write-side broken or closed
+ defer sc.lk.Unlock()
+ return nil, sc.we
+ }
+ if sc.re != nil {
+ defer sc.lk.Unlock()
+ return nil, sc.re
+ }
+ sc.lk.Unlock()
+
+ // Make sure body is fully consumed, even if user does not call body.Close
+ if sc.lastBody != nil {
+ // body.Close is assumed to be idempotent and multiple calls to
+ // it should return the error that its first invokation
+ // returned.
+ err = sc.lastBody.Close()
+ sc.lastBody = nil
+ if err != nil {
+ sc.lk.Lock()
+ defer sc.lk.Unlock()
+ sc.re = err
+ return nil, err
+ }
+ }
+
+ req, err = ReadRequest(sc.r)
+ if err != nil {
+ sc.lk.Lock()
+ defer sc.lk.Unlock()
+ if err == io.ErrUnexpectedEOF {
+ // A close from the opposing client is treated as a
+ // graceful close, even if there was some unparse-able
+ // data before the close.
+ sc.re = ErrPersistEOF
+ return nil, sc.re
+ } else {
+ sc.re = err
+ return
+ }
+ }
+ sc.lastBody = req.Body
+ sc.nread++
+ if req.Close {
+ sc.lk.Lock()
+ defer sc.lk.Unlock()
+ sc.re = ErrPersistEOF
+ return req, sc.re
+ }
+ return
+}
+
+// Pending returns the number of unanswered requests
+// that have been received on the connection.
+func (sc *ServerConn) Pending() int {
+ sc.lk.Lock()
+ defer sc.lk.Unlock()
+ return sc.nread - sc.nwritten
+}
+
+// Write writes a repsonse. To close the connection gracefully, set the
+// Response.Close field to true. Write should be considered operational until
+// it returns an error, regardless of any errors returned on the Read side.
+// Write can be called concurrently with Read, but not with another Write.
+func (sc *ServerConn) Write(resp *Response) os.Error {
+
+ sc.lk.Lock()
+ if sc.we != nil {
+ defer sc.lk.Unlock()
+ return sc.we
+ }
+ sc.lk.Unlock()
+ if sc.nread <= sc.nwritten {
+ return os.NewError("persist server pipe count")
+ }
+
+ if resp.Close {
+ // After signaling a keep-alive close, any pipelined unread
+ // requests will be lost. It is up to the user to drain them
+ // before signaling.
+ sc.lk.Lock()
+ sc.re = ErrPersistEOF
+ sc.lk.Unlock()
+ }
+
+ err := resp.Write(sc.c)
+ if err != nil {
+ sc.lk.Lock()
+ defer sc.lk.Unlock()
+ sc.we = err
+ return err
+ }
+ sc.nwritten++
+
+ return nil
+}
+
+// A ClientConn sends request and receives headers over an underlying
+// connection, while respecting the HTTP keepalive logic. ClientConn is not
+// responsible for closing the underlying connection. One must call Close to
+// regain control of that connection and deal with it as desired.
+type ClientConn struct {
+ c net.Conn
+ r *bufio.Reader
+ re, we os.Error // read/write errors
+ lastBody io.ReadCloser
+ nread, nwritten int
+ reqm list.List // request methods in order of execution
+ lk sync.Mutex // protects read/write to reqm,re,we
+}
+
+// NewClientConn returns a new ClientConn reading and writing c. If r is not
+// nil, it is the buffer to use when reading c.
+func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
+ if r == nil {
+ r = bufio.NewReader(c)
+ }
+ return &ClientConn{c: c, r: r}
+}
+
+// Close detaches the ClientConn and returns the underlying connection as well
+// as the read-side bufio which may have some left over data. Close may be
+// called before the user or Read have signaled the end of the keep-alive
+// logic. The user should not call Close while Read or Write is in progress.
+func (cc *ClientConn) Close() (c net.Conn, r *bufio.Reader) {
+ cc.lk.Lock()
+ c = cc.c
+ r = cc.r
+ cc.c = nil
+ cc.r = nil
+ cc.reqm.Init()
+ cc.lk.Unlock()
+ return
+}
+
+// Write writes a request. An ErrPersistEOF error is returned if the connection
+// has been closed in an HTTP keepalive sense. If req.Close equals true, the
+// keepalive connection is logically closed after this request and the opposing
+// server is informed. An ErrUnexpectedEOF indicates the remote closed the
+// underlying TCP connection, which is usually considered as graceful close.
+// Write can be called concurrently with Read, but not with another Write.
+func (cc *ClientConn) Write(req *Request) os.Error {
+
+ cc.lk.Lock()
+ if cc.re != nil { // no point sending if read-side closed or broken
+ defer cc.lk.Unlock()
+ return cc.re
+ }
+ if cc.we != nil {
+ defer cc.lk.Unlock()
+ return cc.we
+ }
+ cc.lk.Unlock()
+
+ if req.Close {
+ // We write the EOF to the write-side error, because there
+ // still might be some pipelined reads
+ cc.lk.Lock()
+ cc.we = ErrPersistEOF
+ cc.lk.Unlock()
+ }
+
+ err := req.Write(cc.c)
+ if err != nil {
+ cc.lk.Lock()
+ defer cc.lk.Unlock()
+ cc.we = err
+ return err
+ }
+ cc.nwritten++
+ cc.lk.Lock()
+ cc.reqm.PushBack(req.Method)
+ cc.lk.Unlock()
+
+ return nil
+}
+
+// Pending returns the number of unanswered requests
+// that have been sent on the connection.
+func (cc *ClientConn) Pending() int {
+ cc.lk.Lock()
+ defer cc.lk.Unlock()
+ return cc.nwritten - cc.nread
+}
+
+// Read reads the next response from the wire. A valid response might be
+// returned together with an ErrPersistEOF, which means that the remote
+// requested that this be the last request serviced. Read can be called
+// concurrently with Write, but not with another Read.
+func (cc *ClientConn) Read() (resp *Response, err os.Error) {
+
+ cc.lk.Lock()
+ if cc.re != nil {
+ defer cc.lk.Unlock()
+ return nil, cc.re
+ }
+ cc.lk.Unlock()
+
+ if cc.nread >= cc.nwritten {
+ return nil, os.NewError("persist client pipe count")
+ }
+
+ // Make sure body is fully consumed, even if user does not call body.Close
+ if cc.lastBody != nil {
+ // body.Close is assumed to be idempotent and multiple calls to
+ // it should return the error that its first invokation
+ // returned.
+ err = cc.lastBody.Close()
+ cc.lastBody = nil
+ if err != nil {
+ cc.lk.Lock()
+ defer cc.lk.Unlock()
+ cc.re = err
+ return nil, err
+ }
+ }
+
+ cc.lk.Lock()
+ m := cc.reqm.Front()
+ cc.reqm.Remove(m)
+ cc.lk.Unlock()
+ resp, err = ReadResponse(cc.r, m.Value.(string))
+ if err != nil {
+ cc.lk.Lock()
+ defer cc.lk.Unlock()
+ cc.re = err
+ return
+ }
+ cc.lastBody = resp.Body
+
+ cc.nread++
+
+ if resp.Close {
+ cc.lk.Lock()
+ defer cc.lk.Unlock()
+ cc.re = ErrPersistEOF // don't send any more requests
+ return resp, cc.re
+ }
+ return
+}
diff --git a/libgo/go/http/pprof/pprof.go b/libgo/go/http/pprof/pprof.go
new file mode 100644
index 000000000..f7db9aab9
--- /dev/null
+++ b/libgo/go/http/pprof/pprof.go
@@ -0,0 +1,92 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pprof serves via its HTTP server runtime profiling data
+// in the format expected by the pprof visualization tool.
+// For more information about pprof, see
+// http://code.google.com/p/google-perftools/.
+//
+// The package is typically only imported for the side effect of
+// registering its HTTP handlers.
+// The handled paths all begin with /debug/pprof/.
+//
+// To use pprof, link this package into your program:
+// import _ "http/pprof"
+//
+// Then use the pprof tool to look at the heap profile:
+//
+// pprof http://localhost:6060/debug/pprof/heap
+//
+package pprof
+
+import (
+ "bufio"
+ "fmt"
+ "http"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "strconv"
+ "strings"
+)
+
+func init() {
+ http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
+ http.Handle("/debug/pprof/heap", http.HandlerFunc(Heap))
+ http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
+}
+
+// Cmdline responds with the running program's
+// command line, with arguments separated by NUL bytes.
+// The package initialization registers it as /debug/pprof/cmdline.
+func Cmdline(w http.ResponseWriter, r *http.Request) {
+ w.SetHeader("content-type", "text/plain; charset=utf-8")
+ fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
+}
+
+// Heap responds with the pprof-formatted heap profile.
+// The package initialization registers it as /debug/pprof/heap.
+func Heap(w http.ResponseWriter, r *http.Request) {
+ w.SetHeader("content-type", "text/plain; charset=utf-8")
+ pprof.WriteHeapProfile(w)
+}
+
+// Symbol looks up the program counters listed in the request,
+// responding with a table mapping program counters to function names.
+// The package initialization registers it as /debug/pprof/symbol.
+func Symbol(w http.ResponseWriter, r *http.Request) {
+ w.SetHeader("content-type", "text/plain; charset=utf-8")
+
+ // We don't know how many symbols we have, but we
+ // do have symbol information. Pprof only cares whether
+ // this number is 0 (no symbols available) or > 0.
+ fmt.Fprintf(w, "num_symbols: 1\n")
+
+ var b *bufio.Reader
+ if r.Method == "POST" {
+ b = bufio.NewReader(r.Body)
+ } else {
+ b = bufio.NewReader(strings.NewReader(r.URL.RawQuery))
+ }
+
+ for {
+ word, err := b.ReadSlice('+')
+ if err == nil {
+ word = word[0 : len(word)-1] // trim +
+ }
+ pc, _ := strconv.Btoui64(string(word), 0)
+ if pc != 0 {
+ f := runtime.FuncForPC(uintptr(pc))
+ if f != nil {
+ fmt.Fprintf(w, "%#x %s\n", pc, f.Name())
+ }
+ }
+
+ // Wait until here to check for err; the last
+ // symbol will have an err because it doesn't end in +.
+ if err != nil {
+ break
+ }
+ }
+}
diff --git a/libgo/go/http/readrequest_test.go b/libgo/go/http/readrequest_test.go
new file mode 100644
index 000000000..5e1cbcbcb
--- /dev/null
+++ b/libgo/go/http/readrequest_test.go
@@ -0,0 +1,132 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "testing"
+)
+
+type reqTest struct {
+ Raw string
+ Req Request
+ Body string
+}
+
+var reqTests = []reqTest{
+ // Baseline test; All Request fields included for template use
+ {
+ "GET http://www.techcrunch.com/ HTTP/1.1\r\n" +
+ "Host: www.techcrunch.com\r\n" +
+ "User-Agent: Fake\r\n" +
+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" +
+ "Accept-Language: en-us,en;q=0.5\r\n" +
+ "Accept-Encoding: gzip,deflate\r\n" +
+ "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" +
+ "Keep-Alive: 300\r\n" +
+ "Content-Length: 7\r\n" +
+ "Proxy-Connection: keep-alive\r\n\r\n" +
+ "abcdef\n???",
+
+ Request{
+ Method: "GET",
+ RawURL: "http://www.techcrunch.com/",
+ URL: &URL{
+ Raw: "http://www.techcrunch.com/",
+ Scheme: "http",
+ RawPath: "/",
+ RawAuthority: "www.techcrunch.com",
+ RawUserinfo: "",
+ Host: "www.techcrunch.com",
+ Path: "/",
+ RawQuery: "",
+ Fragment: "",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: map[string]string{
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
+ "Accept-Language": "en-us,en;q=0.5",
+ "Accept-Encoding": "gzip,deflate",
+ "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
+ "Keep-Alive": "300",
+ "Proxy-Connection": "keep-alive",
+ "Content-Length": "7",
+ },
+ Close: false,
+ ContentLength: 7,
+ Host: "www.techcrunch.com",
+ Referer: "",
+ UserAgent: "Fake",
+ Form: map[string][]string{},
+ },
+
+ "abcdef\n",
+ },
+
+ // Tests that we don't parse a path that looks like a
+ // scheme-relative URI as a scheme-relative URI.
+ {
+ "GET //user@host/is/actually/a/path/ HTTP/1.1\r\n" +
+ "Host: test\r\n\r\n",
+
+ Request{
+ Method: "GET",
+ RawURL: "//user@host/is/actually/a/path/",
+ URL: &URL{
+ Raw: "//user@host/is/actually/a/path/",
+ Scheme: "",
+ RawPath: "//user@host/is/actually/a/path/",
+ RawAuthority: "",
+ RawUserinfo: "",
+ Host: "",
+ Path: "//user@host/is/actually/a/path/",
+ RawQuery: "",
+ Fragment: "",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: map[string]string{},
+ Close: false,
+ ContentLength: -1,
+ Host: "test",
+ Referer: "",
+ UserAgent: "",
+ Form: map[string][]string{},
+ },
+
+ "",
+ },
+}
+
+func TestReadRequest(t *testing.T) {
+ for i := range reqTests {
+ tt := &reqTests[i]
+ var braw bytes.Buffer
+ braw.WriteString(tt.Raw)
+ req, err := ReadRequest(bufio.NewReader(&braw))
+ if err != nil {
+ t.Errorf("#%d: %s", i, err)
+ continue
+ }
+ rbody := req.Body
+ req.Body = nil
+ diff(t, fmt.Sprintf("#%d Request", i), req, &tt.Req)
+ var bout bytes.Buffer
+ if rbody != nil {
+ io.Copy(&bout, rbody)
+ rbody.Close()
+ }
+ body := bout.String()
+ if body != tt.Body {
+ t.Errorf("#%d: Body = %q want %q", i, body, tt.Body)
+ }
+ }
+}
diff --git a/libgo/go/http/request.go b/libgo/go/http/request.go
new file mode 100644
index 000000000..04bebaaf5
--- /dev/null
+++ b/libgo/go/http/request.go
@@ -0,0 +1,693 @@
+// 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.
+
+// HTTP Request reading and parsing.
+
+// The http package implements parsing of HTTP requests, replies,
+// and URLs and provides an extensible HTTP server and a basic
+// HTTP client.
+package http
+
+import (
+ "bufio"
+ "bytes"
+ "container/vector"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "mime"
+ "mime/multipart"
+ "os"
+ "strconv"
+ "strings"
+)
+
+const (
+ maxLineLength = 4096 // assumed <= bufio.defaultBufSize
+ maxValueLength = 4096
+ maxHeaderLines = 1024
+ chunkSize = 4 << 10 // 4 KB chunks
+)
+
+// HTTP request parsing errors.
+type ProtocolError struct {
+ os.ErrorString
+}
+
+var (
+ ErrLineTooLong = &ProtocolError{"header line too long"}
+ ErrHeaderTooLong = &ProtocolError{"header too long"}
+ ErrShortBody = &ProtocolError{"entity body too short"}
+ ErrNotSupported = &ProtocolError{"feature not supported"}
+ ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"}
+ ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
+ ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"}
+ ErrMissingBoundary = &ProtocolError{"no multipart boundary param Content-Type"}
+)
+
+type badStringError struct {
+ what string
+ str string
+}
+
+func (e *badStringError) String() string { return fmt.Sprintf("%s %q", e.what, e.str) }
+
+var reqExcludeHeader = map[string]bool{
+ "Host": true,
+ "User-Agent": true,
+ "Referer": true,
+ "Content-Length": true,
+ "Transfer-Encoding": true,
+ "Trailer": true,
+}
+
+// A Request represents a parsed HTTP request header.
+type Request struct {
+ Method string // GET, POST, PUT, etc.
+ RawURL string // The raw URL given in the request.
+ URL *URL // Parsed URL.
+ Proto string // "HTTP/1.0"
+ ProtoMajor int // 1
+ ProtoMinor int // 0
+
+ // A header maps request lines to their values.
+ // If the header says
+ //
+ // accept-encoding: gzip, deflate
+ // Accept-Language: en-us
+ // Connection: keep-alive
+ //
+ // then
+ //
+ // Header = map[string]string{
+ // "Accept-Encoding": "gzip, deflate",
+ // "Accept-Language": "en-us",
+ // "Connection": "keep-alive",
+ // }
+ //
+ // HTTP defines that header names are case-insensitive.
+ // The request parser implements this by canonicalizing the
+ // name, making the first character and any characters
+ // following a hyphen uppercase and the rest lowercase.
+ Header map[string]string
+
+ // The message body.
+ Body io.ReadCloser
+
+ // ContentLength records the length of the associated content.
+ // The value -1 indicates that the length is unknown.
+ // Values >= 0 indicate that the given number of bytes may be read from Body.
+ ContentLength int64
+
+ // TransferEncoding lists the transfer encodings from outermost to innermost.
+ // An empty list denotes the "identity" encoding.
+ TransferEncoding []string
+
+ // Whether to close the connection after replying to this request.
+ Close bool
+
+ // The host on which the URL is sought.
+ // Per RFC 2616, this is either the value of the Host: header
+ // 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 map[string][]string
+
+ // Trailer maps trailer keys to values. Like for Header, if the
+ // response has multiple trailer lines with the same key, they will be
+ // concatenated, delimited by commas.
+ Trailer map[string]string
+}
+
+// ProtoAtLeast returns whether the HTTP protocol used
+// in the request is at least major.minor.
+func (r *Request) ProtoAtLeast(major, minor int) bool {
+ return r.ProtoMajor > major ||
+ r.ProtoMajor == major && r.ProtoMinor >= minor
+}
+
+// MultipartReader returns a MIME multipart reader if this is a
+// multipart/form-data POST request, else returns nil and an error.
+func (r *Request) MultipartReader() (multipart.Reader, os.Error) {
+ v, ok := r.Header["Content-Type"]
+ if !ok {
+ return nil, ErrNotMultipart
+ }
+ d, params := mime.ParseMediaType(v)
+ if d != "multipart/form-data" {
+ return nil, ErrNotMultipart
+ }
+ boundary, ok := params["boundary"]
+ if !ok {
+ return nil, ErrMissingBoundary
+ }
+ return multipart.NewReader(r.Body, boundary), nil
+}
+
+// Return value if nonempty, def otherwise.
+func valueOrDefault(value, def string) string {
+ if value != "" {
+ return value
+ }
+ return def
+}
+
+const defaultUserAgent = "Go http package"
+
+// Write writes an HTTP/1.1 request -- header and body -- in wire format.
+// This method consults the following fields of req:
+// Host
+// RawURL, if non-empty, or else URL
+// Method (defaults to "GET")
+// UserAgent (defaults to defaultUserAgent)
+// Referer
+// Header
+// Body
+//
+// If Body is present, Write forces "Transfer-Encoding: chunked" as a header
+// and then closes Body when finished sending it.
+func (req *Request) Write(w io.Writer) os.Error {
+ host := req.Host
+ if host == "" {
+ host = req.URL.Host
+ }
+
+ uri := req.RawURL
+ if uri == "" {
+ uri = valueOrDefault(urlEscape(req.URL.Path, encodePath), "/")
+ if req.URL.RawQuery != "" {
+ uri += "?" + req.URL.RawQuery
+ }
+ }
+
+ fmt.Fprintf(w, "%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)
+ }
+
+ // Process Body,ContentLength,Close,Trailer
+ tw, err := newTransferWriter(req)
+ if err != nil {
+ return err
+ }
+ err = tw.WriteHeader(w)
+ 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 = writeSortedKeyValue(w, req.Header, reqExcludeHeader)
+ if err != nil {
+ return err
+ }
+
+ io.WriteString(w, "\r\n")
+
+ // Write body and trailer
+ err = tw.WriteBody(w)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// Read a line of bytes (up to \n) from b.
+// Give up if the line exceeds maxLineLength.
+// The returned bytes are a pointer into storage in
+// the bufio, so they are only valid until the next bufio read.
+func readLineBytes(b *bufio.Reader) (p []byte, err os.Error) {
+ if p, err = b.ReadSlice('\n'); err != nil {
+ // We always know when EOF is coming.
+ // If the caller asked for a line, there should be a line.
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ } else if err == bufio.ErrBufferFull {
+ err = ErrLineTooLong
+ }
+ return nil, err
+ }
+ if len(p) >= maxLineLength {
+ return nil, ErrLineTooLong
+ }
+
+ // Chop off trailing white space.
+ var i int
+ for i = len(p); i > 0; i-- {
+ if c := p[i-1]; c != ' ' && c != '\r' && c != '\t' && c != '\n' {
+ break
+ }
+ }
+ return p[0:i], nil
+}
+
+// readLineBytes, but convert the bytes into a string.
+func readLine(b *bufio.Reader) (s string, err os.Error) {
+ p, e := readLineBytes(b)
+ if e != nil {
+ return "", e
+ }
+ return string(p), nil
+}
+
+var colon = []byte{':'}
+
+// Read a key/value pair from b.
+// A key/value has the form Key: Value\r\n
+// and the Value can continue on multiple lines if each continuation line
+// starts with a space.
+func readKeyValue(b *bufio.Reader) (key, value string, err os.Error) {
+ line, e := readLineBytes(b)
+ if e != nil {
+ return "", "", e
+ }
+ if len(line) == 0 {
+ return "", "", nil
+ }
+
+ // Scan first line for colon.
+ i := bytes.Index(line, colon)
+ if i < 0 {
+ goto Malformed
+ }
+
+ key = string(line[0:i])
+ if strings.Contains(key, " ") {
+ // Key field has space - no good.
+ goto Malformed
+ }
+
+ // Skip initial space before value.
+ for i++; i < len(line); i++ {
+ if line[i] != ' ' {
+ break
+ }
+ }
+ value = string(line[i:])
+
+ // Look for extension lines, which must begin with space.
+ for {
+ c, e := b.ReadByte()
+ if c != ' ' {
+ if e != os.EOF {
+ b.UnreadByte()
+ }
+ break
+ }
+
+ // Eat leading space.
+ for c == ' ' {
+ if c, e = b.ReadByte(); e != nil {
+ if e == os.EOF {
+ e = io.ErrUnexpectedEOF
+ }
+ return "", "", e
+ }
+ }
+ b.UnreadByte()
+
+ // Read the rest of the line and add to value.
+ if line, e = readLineBytes(b); e != nil {
+ return "", "", e
+ }
+ value += " " + string(line)
+
+ if len(value) >= maxValueLength {
+ return "", "", &badStringError{"value too long for key", key}
+ }
+ }
+ return key, value, nil
+
+Malformed:
+ return "", "", &badStringError{"malformed header line", string(line)}
+}
+
+// Convert decimal at s[i:len(s)] to integer,
+// returning value, string position where the digits stopped,
+// and whether there was a valid number (digits, not too big).
+func atoi(s string, i int) (n, i1 int, ok bool) {
+ const Big = 1000000
+ if i >= len(s) || s[i] < '0' || s[i] > '9' {
+ return 0, 0, false
+ }
+ n = 0
+ for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+ n = n*10 + int(s[i]-'0')
+ if n > Big {
+ return 0, 0, false
+ }
+ }
+ return n, i, true
+}
+
+// Parse HTTP version: "HTTP/1.2" -> (1, 2, true).
+func parseHTTPVersion(vers string) (int, int, bool) {
+ if len(vers) < 5 || vers[0:5] != "HTTP/" {
+ return 0, 0, false
+ }
+ major, i, ok := atoi(vers, 5)
+ if !ok || i >= len(vers) || vers[i] != '.' {
+ return 0, 0, false
+ }
+ var minor int
+ minor, i, ok = atoi(vers, i+1)
+ if !ok || i != len(vers) {
+ return 0, 0, false
+ }
+ return major, minor, true
+}
+
+// CanonicalHeaderKey returns the canonical format of the
+// HTTP header key s. The canonicalization converts the first
+// letter and any letter following a hyphen to upper case;
+// the rest are converted to lowercase. For example, the
+// canonical key for "accept-encoding" is "Accept-Encoding".
+func CanonicalHeaderKey(s string) string {
+ // canonicalize: first letter upper case
+ // and upper case after each dash.
+ // (Host, User-Agent, If-Modified-Since).
+ // HTTP headers are ASCII only, so no Unicode issues.
+ var a []byte
+ upper := true
+ for i := 0; i < len(s); i++ {
+ v := s[i]
+ if upper && 'a' <= v && v <= 'z' {
+ if a == nil {
+ a = []byte(s)
+ }
+ a[i] = v + 'A' - 'a'
+ }
+ if !upper && 'A' <= v && v <= 'Z' {
+ if a == nil {
+ a = []byte(s)
+ }
+ a[i] = v + 'a' - 'A'
+ }
+ upper = false
+ if v == '-' {
+ upper = true
+ }
+ }
+ if a != nil {
+ return string(a)
+ }
+ return s
+}
+
+type chunkedReader struct {
+ r *bufio.Reader
+ n uint64 // unread bytes in chunk
+ err os.Error
+}
+
+func newChunkedReader(r *bufio.Reader) *chunkedReader {
+ return &chunkedReader{r: r}
+}
+
+func (cr *chunkedReader) beginChunk() {
+ // chunk-size CRLF
+ var line string
+ line, cr.err = readLine(cr.r)
+ if cr.err != nil {
+ return
+ }
+ cr.n, cr.err = strconv.Btoui64(line, 16)
+ if cr.err != nil {
+ return
+ }
+ if cr.n == 0 {
+ // trailer CRLF
+ for {
+ line, cr.err = readLine(cr.r)
+ if cr.err != nil {
+ return
+ }
+ if line == "" {
+ break
+ }
+ }
+ cr.err = os.EOF
+ }
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err os.Error) {
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ if cr.n == 0 {
+ cr.beginChunk()
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ }
+ if uint64(len(b)) > cr.n {
+ b = b[0:cr.n]
+ }
+ n, cr.err = cr.r.Read(b)
+ cr.n -= uint64(n)
+ if cr.n == 0 && cr.err == nil {
+ // end of chunk (CRLF)
+ b := make([]byte, 2)
+ if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil {
+ if b[0] != '\r' || b[1] != '\n' {
+ cr.err = os.NewError("malformed chunked encoding")
+ }
+ }
+ }
+ return n, cr.err
+}
+
+// ReadRequest reads and parses a request from b.
+func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
+ req = new(Request)
+
+ // First line: GET /index.html HTTP/1.0
+ var s string
+ if s, err = readLine(b); err != nil {
+ return nil, err
+ }
+
+ var f []string
+ if f = strings.Split(s, " ", 3); len(f) < 3 {
+ return nil, &badStringError{"malformed HTTP request", s}
+ }
+ req.Method, req.RawURL, req.Proto = f[0], f[1], f[2]
+ var ok bool
+ if req.ProtoMajor, req.ProtoMinor, ok = parseHTTPVersion(req.Proto); !ok {
+ return nil, &badStringError{"malformed HTTP version", req.Proto}
+ }
+
+ if req.URL, err = ParseRequestURL(req.RawURL); err != nil {
+ return nil, err
+ }
+
+ // Subsequent lines: Key: value.
+ nheader := 0
+ req.Header = make(map[string]string)
+ for {
+ var key, value string
+ if key, value, err = readKeyValue(b); err != nil {
+ return nil, err
+ }
+ if key == "" {
+ break
+ }
+ if nheader++; nheader >= maxHeaderLines {
+ return nil, ErrHeaderTooLong
+ }
+
+ key = CanonicalHeaderKey(key)
+
+ // RFC 2616 says that if you send the same header key
+ // multiple times, it has to be semantically equivalent
+ // to concatenating the values separated by commas.
+ oldvalue, present := req.Header[key]
+ if present {
+ req.Header[key] = oldvalue + "," + value
+ } else {
+ req.Header[key] = value
+ }
+ }
+
+ // RFC2616: Must treat
+ // GET /index.html HTTP/1.1
+ // Host: www.google.com
+ // and
+ // GET http://www.google.com/index.html HTTP/1.1
+ // Host: doesntmatter
+ // the same. In the second case, any Host line is ignored.
+ req.Host = req.URL.Host
+ if req.Host == "" {
+ req.Host = req.Header["Host"]
+ }
+ req.Header["Host"] = "", false
+
+ fixPragmaCacheControl(req.Header)
+
+ // Pull out useful fields as a convenience to clients.
+ req.Referer = req.Header["Referer"]
+ req.Header["Referer"] = "", false
+
+ req.UserAgent = req.Header["User-Agent"]
+ req.Header["User-Agent"] = "", false
+
+ // TODO: Parse specific header values:
+ // Accept
+ // Accept-Encoding
+ // Accept-Language
+ // Authorization
+ // Cache-Control
+ // Connection
+ // Date
+ // Expect
+ // From
+ // If-Match
+ // If-Modified-Since
+ // If-None-Match
+ // If-Range
+ // If-Unmodified-Since
+ // Max-Forwards
+ // Proxy-Authorization
+ // Referer [sic]
+ // TE (transfer-codings)
+ // Trailer
+ // Transfer-Encoding
+ // Upgrade
+ // User-Agent
+ // Via
+ // Warning
+
+ err = readTransfer(req, b)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// ParseQuery parses the URL-encoded query string and returns
+// a map listing the values specified for each key.
+// ParseQuery always returns a non-nil map containing all the
+// valid query parameters found; err describes the first decoding error
+// encountered, if any.
+func ParseQuery(query string) (m map[string][]string, err os.Error) {
+ m = make(map[string][]string)
+ err = parseQuery(m, query)
+ return
+}
+
+func parseQuery(m map[string][]string, query string) (err os.Error) {
+ for _, kv := range strings.Split(query, "&", -1) {
+ if len(kv) == 0 {
+ continue
+ }
+ kvPair := strings.Split(kv, "=", 2)
+
+ var key, value string
+ var e os.Error
+ key, e = URLUnescape(kvPair[0])
+ if e == nil && len(kvPair) > 1 {
+ value, e = URLUnescape(kvPair[1])
+ }
+ if e != nil {
+ err = e
+ continue
+ }
+ vec := vector.StringVector(m[key])
+ vec.Push(value)
+ m[key] = vec
+ }
+ return err
+}
+
+// ParseForm parses the request body as a form for POST requests, or the raw query for GET requests.
+// It is idempotent.
+func (r *Request) ParseForm() (err os.Error) {
+ if r.Form != nil {
+ return
+ }
+
+ r.Form = make(map[string][]string)
+ if r.URL != nil {
+ err = parseQuery(r.Form, r.URL.RawQuery)
+ }
+ if r.Method == "POST" {
+ if r.Body == nil {
+ return os.ErrorString("missing form body")
+ }
+ ct := r.Header["Content-Type"]
+ switch strings.Split(ct, ";", 2)[0] {
+ case "text/plain", "application/x-www-form-urlencoded", "":
+ b, e := ioutil.ReadAll(r.Body)
+ if e != nil {
+ if err == nil {
+ err = e
+ }
+ break
+ }
+ e = parseQuery(r.Form, string(b))
+ if err == nil {
+ err = e
+ }
+ // TODO(dsymonds): Handle multipart/form-data
+ default:
+ return &badStringError{"unknown Content-Type", ct}
+ }
+ }
+ return err
+}
+
+// FormValue returns the first value for the named component of the query.
+// FormValue calls ParseForm if necessary.
+func (r *Request) FormValue(key string) string {
+ if r.Form == nil {
+ r.ParseForm()
+ }
+ if vs := r.Form[key]; len(vs) > 0 {
+ return vs[0]
+ }
+ return ""
+}
+
+func (r *Request) expectsContinue() bool {
+ expectation, ok := r.Header["Expect"]
+ return ok && strings.ToLower(expectation) == "100-continue"
+}
+
+func (r *Request) wantsHttp10KeepAlive() bool {
+ if r.ProtoMajor != 1 || r.ProtoMinor != 0 {
+ return false
+ }
+ value, exists := r.Header["Connection"]
+ if !exists {
+ return false
+ }
+ return strings.Contains(strings.ToLower(value), "keep-alive")
+}
diff --git a/libgo/go/http/request_test.go b/libgo/go/http/request_test.go
new file mode 100644
index 000000000..d25e5e5e7
--- /dev/null
+++ b/libgo/go/http/request_test.go
@@ -0,0 +1,155 @@
+// 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 http
+
+import (
+ "bytes"
+ "reflect"
+ "regexp"
+ "strings"
+ "testing"
+)
+
+type stringMultimap map[string][]string
+
+type parseTest struct {
+ query string
+ out stringMultimap
+}
+
+var parseTests = []parseTest{
+ {
+ query: "a=1&b=2",
+ out: stringMultimap{"a": []string{"1"}, "b": []string{"2"}},
+ },
+ {
+ query: "a=1&a=2&a=banana",
+ out: stringMultimap{"a": []string{"1", "2", "banana"}},
+ },
+ {
+ query: "ascii=%3Ckey%3A+0x90%3E",
+ out: stringMultimap{"ascii": []string{"<key: 0x90>"}},
+ },
+}
+
+func TestParseForm(t *testing.T) {
+ for i, test := range parseTests {
+ form, err := ParseQuery(test.query)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+ if len(form) != len(test.out) {
+ t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out))
+ }
+ for k, evs := range test.out {
+ vs, ok := form[k]
+ if !ok {
+ t.Errorf("test %d: Missing key %q", i, k)
+ continue
+ }
+ if len(vs) != len(evs) {
+ t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs))
+ continue
+ }
+ for j, ev := range evs {
+ if v := vs[j]; v != ev {
+ t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev)
+ }
+ }
+ }
+ }
+}
+
+func TestQuery(t *testing.T) {
+ req := &Request{Method: "GET"}
+ req.URL, _ = ParseURL("http://www.google.com/search?q=foo&q=bar")
+ if q := req.FormValue("q"); q != "foo" {
+ t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
+ }
+}
+
+func TestPostQuery(t *testing.T) {
+ req := &Request{Method: "POST"}
+ req.URL, _ = ParseURL("http://www.google.com/search?q=foo&q=bar&both=x")
+ req.Header = map[string]string{"Content-Type": "application/x-www-form-urlencoded; boo!"}
+ req.Body = nopCloser{strings.NewReader("z=post&both=y")}
+ if q := req.FormValue("q"); q != "foo" {
+ t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
+ }
+ if z := req.FormValue("z"); z != "post" {
+ t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
+ }
+ if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"x", "y"}) {
+ t.Errorf(`req.FormValue("both") = %q, want ["x", "y"]`, both)
+ }
+}
+
+type stringMap map[string]string
+type parseContentTypeTest struct {
+ contentType stringMap
+ error bool
+}
+
+var parseContentTypeTests = []parseContentTypeTest{
+ {contentType: stringMap{"Content-Type": "text/plain"}},
+ {contentType: stringMap{"Content-Type": ""}},
+ {contentType: stringMap{"Content-Type": "text/plain; boundary="}},
+ {
+ contentType: stringMap{"Content-Type": "application/unknown"},
+ error: true,
+ },
+}
+
+func TestPostContentTypeParsing(t *testing.T) {
+ for i, test := range parseContentTypeTests {
+ req := &Request{
+ Method: "POST",
+ Header: test.contentType,
+ Body: nopCloser{bytes.NewBufferString("body")},
+ }
+ err := req.ParseForm()
+ if !test.error && err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ }
+ if test.error && err == nil {
+ t.Errorf("test %d should have returned error", i)
+ }
+ }
+}
+
+func TestMultipartReader(t *testing.T) {
+ req := &Request{
+ Method: "POST",
+ Header: stringMap{"Content-Type": `multipart/form-data; boundary="foo123"`},
+ Body: nopCloser{new(bytes.Buffer)},
+ }
+ multipart, err := req.MultipartReader()
+ if multipart == nil {
+ t.Errorf("expected multipart; error: %v", err)
+ }
+
+ req.Header = stringMap{"Content-Type": "text/plain"}
+ multipart, err = req.MultipartReader()
+ if multipart != nil {
+ t.Errorf("unexpected multipart for text/plain")
+ }
+}
+
+func TestRedirect(t *testing.T) {
+ const (
+ start = "http://google.com/"
+ endRe = "^http://www\\.google\\.[a-z.]+/$"
+ )
+ var end = regexp.MustCompile(endRe)
+ r, url, err := Get(start)
+ if err != nil {
+ t.Fatal(err)
+ }
+ r.Body.Close()
+ if r.StatusCode != 200 || !end.MatchString(url) {
+ t.Fatalf("Get(%s) got status %d at %q, want 200 matching %q", start, r.StatusCode, url, endRe)
+ }
+}
diff --git a/libgo/go/http/requestwrite_test.go b/libgo/go/http/requestwrite_test.go
new file mode 100644
index 000000000..3ceabe4ee
--- /dev/null
+++ b/libgo/go/http/requestwrite_test.go
@@ -0,0 +1,139 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bytes"
+ "testing"
+)
+
+type reqWriteTest struct {
+ Req Request
+ Raw string
+}
+
+var reqWriteTests = []reqWriteTest{
+ // HTTP/1.1 => chunked coding; no body; no trailer
+ {
+ Request{
+ Method: "GET",
+ RawURL: "http://www.techcrunch.com/",
+ URL: &URL{
+ Raw: "http://www.techcrunch.com/",
+ Scheme: "http",
+ RawPath: "http://www.techcrunch.com/",
+ RawAuthority: "www.techcrunch.com",
+ RawUserinfo: "",
+ Host: "www.techcrunch.com",
+ Path: "/",
+ RawQuery: "",
+ Fragment: "",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: map[string]string{
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
+ "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
+ "Accept-Encoding": "gzip,deflate",
+ "Accept-Language": "en-us,en;q=0.5",
+ "Keep-Alive": "300",
+ "Proxy-Connection": "keep-alive",
+ },
+ Body: nil,
+ Close: false,
+ Host: "www.techcrunch.com",
+ Referer: "",
+ UserAgent: "Fake",
+ Form: map[string][]string{},
+ },
+
+ "GET http://www.techcrunch.com/ HTTP/1.1\r\n" +
+ "Host: www.techcrunch.com\r\n" +
+ "User-Agent: Fake\r\n" +
+ "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" +
+ "Accept-Encoding: gzip,deflate\r\n" +
+ "Accept-Language: en-us,en;q=0.5\r\n" +
+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" +
+ "Keep-Alive: 300\r\n" +
+ "Proxy-Connection: keep-alive\r\n\r\n",
+ },
+ // HTTP/1.1 => chunked coding; body; empty trailer
+ {
+ Request{
+ Method: "GET",
+ URL: &URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/search",
+ },
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: map[string]string{},
+ Body: nopCloser{bytes.NewBufferString("abcdef")},
+ TransferEncoding: []string{"chunked"},
+ },
+
+ "GET /search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ "6\r\nabcdef\r\n0\r\n\r\n",
+ },
+ // HTTP/1.1 POST => chunked coding; body; empty trailer
+ {
+ Request{
+ Method: "POST",
+ URL: &URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/search",
+ },
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: map[string]string{},
+ Close: true,
+ Body: nopCloser{bytes.NewBufferString("abcdef")},
+ TransferEncoding: []string{"chunked"},
+ },
+
+ "POST /search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Connection: close\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ "6\r\nabcdef\r\n0\r\n\r\n",
+ },
+ // default to HTTP/1.1
+ {
+ Request{
+ Method: "GET",
+ RawURL: "/search",
+ Host: "www.google.com",
+ },
+
+ "GET /search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "\r\n",
+ },
+}
+
+func TestRequestWrite(t *testing.T) {
+ for i := range reqWriteTests {
+ tt := &reqWriteTests[i]
+ var braw bytes.Buffer
+ err := tt.Req.Write(&braw)
+ if err != nil {
+ t.Errorf("error writing #%d: %s", i, err)
+ continue
+ }
+ sraw := braw.String()
+ if sraw != tt.Raw {
+ t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, tt.Raw, sraw)
+ continue
+ }
+ }
+}
diff --git a/libgo/go/http/response.go b/libgo/go/http/response.go
new file mode 100644
index 000000000..a24726110
--- /dev/null
+++ b/libgo/go/http/response.go
@@ -0,0 +1,251 @@
+// 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.
+
+// HTTP Response reading and parsing.
+
+package http
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+var respExcludeHeader = map[string]bool{
+ "Content-Length": true,
+ "Transfer-Encoding": true,
+ "Trailer": true,
+}
+
+// Response represents the response from an HTTP request.
+//
+type Response struct {
+ Status string // e.g. "200 OK"
+ StatusCode int // e.g. 200
+ Proto string // e.g. "HTTP/1.0"
+ ProtoMajor int // e.g. 1
+ ProtoMinor int // e.g. 0
+
+ // RequestMethod records the method used in the HTTP request.
+ // Header fields such as Content-Length have method-specific meaning.
+ RequestMethod string // e.g. "HEAD", "CONNECT", "GET", etc.
+
+ // Header maps header keys to values. If the response had multiple
+ // headers with the same key, they will be concatenated, with comma
+ // delimiters. (Section 4.2 of RFC 2616 requires that multiple headers
+ // be semantically equivalent to a comma-delimited sequence.) Values
+ // duplicated by other fields in this struct (e.g., ContentLength) are
+ // omitted from Header.
+ //
+ // Keys in the map are canonicalized (see CanonicalHeaderKey).
+ Header map[string]string
+
+ // Body represents the response body.
+ Body io.ReadCloser
+
+ // ContentLength records the length of the associated content. The
+ // value -1 indicates that the length is unknown. Unless RequestMethod
+ // is "HEAD", values >= 0 indicate that the given number of bytes may
+ // be read from Body.
+ ContentLength int64
+
+ // Contains transfer encodings from outer-most to inner-most. Value is
+ // nil, means that "identity" encoding is used.
+ TransferEncoding []string
+
+ // Close records whether the header directed that the connection be
+ // closed after reading Body. The value is advice for clients: neither
+ // ReadResponse nor Response.Write ever closes a connection.
+ Close bool
+
+ // Trailer maps trailer keys to values. Like for Header, if the
+ // response has multiple trailer lines with the same key, they will be
+ // concatenated, delimited by commas.
+ Trailer map[string]string
+}
+
+// ReadResponse reads and returns an HTTP response from r. The RequestMethod
+// parameter specifies the method used in the corresponding request (e.g.,
+// "GET", "HEAD"). Clients must call resp.Body.Close when finished reading
+// resp.Body. After that call, clients can inspect resp.Trailer to find
+// key/value pairs included in the response trailer.
+func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os.Error) {
+
+ resp = new(Response)
+
+ resp.RequestMethod = strings.ToUpper(requestMethod)
+
+ // Parse the first line of the response.
+ line, err := readLine(r)
+ if err != nil {
+ return nil, err
+ }
+ f := strings.Split(line, " ", 3)
+ if len(f) < 2 {
+ return nil, &badStringError{"malformed HTTP response", line}
+ }
+ reasonPhrase := ""
+ if len(f) > 2 {
+ reasonPhrase = f[2]
+ }
+ resp.Status = f[1] + " " + reasonPhrase
+ resp.StatusCode, err = strconv.Atoi(f[1])
+ if err != nil {
+ return nil, &badStringError{"malformed HTTP status code", f[1]}
+ }
+
+ resp.Proto = f[0]
+ var ok bool
+ if resp.ProtoMajor, resp.ProtoMinor, ok = parseHTTPVersion(resp.Proto); !ok {
+ return nil, &badStringError{"malformed HTTP version", resp.Proto}
+ }
+
+ // Parse the response headers.
+ nheader := 0
+ resp.Header = make(map[string]string)
+ for {
+ key, value, err := readKeyValue(r)
+ if err != nil {
+ return nil, err
+ }
+ if key == "" {
+ break // end of response header
+ }
+ if nheader++; nheader >= maxHeaderLines {
+ return nil, ErrHeaderTooLong
+ }
+ resp.AddHeader(key, value)
+ }
+
+ fixPragmaCacheControl(resp.Header)
+
+ err = readTransfer(resp, r)
+ if err != nil {
+ return nil, err
+ }
+
+ return resp, nil
+}
+
+// RFC2616: Should treat
+// Pragma: no-cache
+// like
+// Cache-Control: no-cache
+func fixPragmaCacheControl(header map[string]string) {
+ if header["Pragma"] == "no-cache" {
+ if _, presentcc := header["Cache-Control"]; !presentcc {
+ header["Cache-Control"] = "no-cache"
+ }
+ }
+}
+
+// AddHeader adds a value under the given key. Keys are not case sensitive.
+func (r *Response) AddHeader(key, value string) {
+ key = CanonicalHeaderKey(key)
+
+ oldValues, oldValuesPresent := r.Header[key]
+ if oldValuesPresent {
+ r.Header[key] = oldValues + "," + value
+ } else {
+ r.Header[key] = value
+ }
+}
+
+// GetHeader returns the value of the response header with the given key.
+// If there were multiple headers with this key, their values are concatenated,
+// with a comma delimiter. If there were no response headers with the given
+// key, GetHeader returns an empty string. Keys are not case sensitive.
+func (r *Response) GetHeader(key string) (value string) {
+ return r.Header[CanonicalHeaderKey(key)]
+}
+
+// ProtoAtLeast returns whether the HTTP protocol used
+// in the response is at least major.minor.
+func (r *Response) ProtoAtLeast(major, minor int) bool {
+ return r.ProtoMajor > major ||
+ r.ProtoMajor == major && r.ProtoMinor >= minor
+}
+
+// Writes the response (header, body and trailer) in wire format. This method
+// consults the following fields of resp:
+//
+// StatusCode
+// ProtoMajor
+// ProtoMinor
+// RequestMethod
+// TransferEncoding
+// Trailer
+// Body
+// ContentLength
+// Header, values for non-canonical keys will have unpredictable behavior
+//
+func (resp *Response) Write(w io.Writer) os.Error {
+
+ // RequestMethod should be upper-case
+ resp.RequestMethod = strings.ToUpper(resp.RequestMethod)
+
+ // Status line
+ text := resp.Status
+ if text == "" {
+ var ok bool
+ text, ok = statusText[resp.StatusCode]
+ if !ok {
+ text = "status code " + strconv.Itoa(resp.StatusCode)
+ }
+ }
+ io.WriteString(w, "HTTP/"+strconv.Itoa(resp.ProtoMajor)+".")
+ io.WriteString(w, strconv.Itoa(resp.ProtoMinor)+" ")
+ io.WriteString(w, strconv.Itoa(resp.StatusCode)+" "+text+"\r\n")
+
+ // Process Body,ContentLength,Close,Trailer
+ tw, err := newTransferWriter(resp)
+ if err != nil {
+ return err
+ }
+ err = tw.WriteHeader(w)
+ if err != nil {
+ return err
+ }
+
+ // Rest of header
+ err = writeSortedKeyValue(w, resp.Header, respExcludeHeader)
+ if err != nil {
+ return err
+ }
+
+ // End-of-header
+ io.WriteString(w, "\r\n")
+
+ // Write body and trailer
+ err = tw.WriteBody(w)
+ if err != nil {
+ return err
+ }
+
+ // Success
+ return nil
+}
+
+func writeSortedKeyValue(w io.Writer, kvm map[string]string, exclude map[string]bool) os.Error {
+ kva := make([]string, len(kvm))
+ i := 0
+ for k, v := range kvm {
+ if !exclude[k] {
+ kva[i] = fmt.Sprint(k + ": " + v + "\r\n")
+ i++
+ }
+ }
+ kva = kva[0:i]
+ sort.SortStrings(kva)
+ for _, l := range kva {
+ if _, err := io.WriteString(w, l); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/libgo/go/http/response_test.go b/libgo/go/http/response_test.go
new file mode 100644
index 000000000..89a8c3b44
--- /dev/null
+++ b/libgo/go/http/response_test.go
@@ -0,0 +1,203 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "reflect"
+ "testing"
+)
+
+type respTest struct {
+ Raw string
+ Resp Response
+ Body string
+}
+
+var respTests = []respTest{
+ // Unchunked response without Content-Length.
+ {
+ "HTTP/1.0 200 OK\r\n" +
+ "Connection: close\r\n" +
+ "\r\n" +
+ "Body here\n",
+
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ RequestMethod: "GET",
+ Header: map[string]string{
+ "Connection": "close", // TODO(rsc): Delete?
+ },
+ Close: true,
+ ContentLength: -1,
+ },
+
+ "Body here\n",
+ },
+
+ // Unchunked response with Content-Length.
+ {
+ "HTTP/1.0 200 OK\r\n" +
+ "Content-Length: 10\r\n" +
+ "Connection: close\r\n" +
+ "\r\n" +
+ "Body here\n",
+
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ RequestMethod: "GET",
+ Header: map[string]string{
+ "Connection": "close", // TODO(rsc): Delete?
+ "Content-Length": "10", // TODO(rsc): Delete?
+ },
+ Close: true,
+ ContentLength: 10,
+ },
+
+ "Body here\n",
+ },
+
+ // Chunked response without Content-Length.
+ {
+ "HTTP/1.0 200 OK\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "\r\n" +
+ "0a\r\n" +
+ "Body here\n" +
+ "0\r\n" +
+ "\r\n",
+
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ RequestMethod: "GET",
+ Header: map[string]string{},
+ Close: true,
+ ContentLength: -1,
+ TransferEncoding: []string{"chunked"},
+ },
+
+ "Body here\n",
+ },
+
+ // Chunked response with Content-Length.
+ {
+ "HTTP/1.0 200 OK\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "Content-Length: 10\r\n" +
+ "\r\n" +
+ "0a\r\n" +
+ "Body here\n" +
+ "0\r\n" +
+ "\r\n",
+
+ Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ RequestMethod: "GET",
+ Header: map[string]string{},
+ Close: true,
+ ContentLength: -1, // TODO(rsc): Fix?
+ TransferEncoding: []string{"chunked"},
+ },
+
+ "Body here\n",
+ },
+
+ // Status line without a Reason-Phrase, but trailing space.
+ // (permitted by RFC 2616)
+ {
+ "HTTP/1.0 303 \r\n\r\n",
+ Response{
+ Status: "303 ",
+ StatusCode: 303,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ RequestMethod: "GET",
+ Header: map[string]string{},
+ Close: true,
+ ContentLength: -1,
+ },
+
+ "",
+ },
+
+ // Status line without a Reason-Phrase, and no trailing space.
+ // (not permitted by RFC 2616, but we'll accept it anyway)
+ {
+ "HTTP/1.0 303\r\n\r\n",
+ Response{
+ Status: "303 ",
+ StatusCode: 303,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ RequestMethod: "GET",
+ Header: map[string]string{},
+ Close: true,
+ ContentLength: -1,
+ },
+
+ "",
+ },
+}
+
+func TestReadResponse(t *testing.T) {
+ for i := range respTests {
+ tt := &respTests[i]
+ var braw bytes.Buffer
+ braw.WriteString(tt.Raw)
+ resp, err := ReadResponse(bufio.NewReader(&braw), tt.Resp.RequestMethod)
+ if err != nil {
+ t.Errorf("#%d: %s", i, err)
+ continue
+ }
+ rbody := resp.Body
+ resp.Body = nil
+ diff(t, fmt.Sprintf("#%d Response", i), resp, &tt.Resp)
+ var bout bytes.Buffer
+ if rbody != nil {
+ io.Copy(&bout, rbody)
+ rbody.Close()
+ }
+ body := bout.String()
+ if body != tt.Body {
+ t.Errorf("#%d: Body = %q want %q", i, body, tt.Body)
+ }
+ }
+}
+
+func diff(t *testing.T, prefix string, have, want interface{}) {
+ hv := reflect.NewValue(have).(*reflect.PtrValue).Elem().(*reflect.StructValue)
+ wv := reflect.NewValue(want).(*reflect.PtrValue).Elem().(*reflect.StructValue)
+ if hv.Type() != wv.Type() {
+ t.Errorf("%s: type mismatch %v vs %v", prefix, hv.Type(), wv.Type())
+ }
+ for i := 0; i < hv.NumField(); i++ {
+ hf := hv.Field(i).Interface()
+ wf := wv.Field(i).Interface()
+ if !reflect.DeepEqual(hf, wf) {
+ t.Errorf("%s: %s = %v want %v", prefix, hv.Type().(*reflect.StructType).Field(i).Name, hf, wf)
+ }
+ }
+}
diff --git a/libgo/go/http/responsewrite_test.go b/libgo/go/http/responsewrite_test.go
new file mode 100644
index 000000000..9f10be562
--- /dev/null
+++ b/libgo/go/http/responsewrite_test.go
@@ -0,0 +1,85 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "bytes"
+ "testing"
+)
+
+type respWriteTest struct {
+ Resp Response
+ Raw string
+}
+
+var respWriteTests = []respWriteTest{
+ // HTTP/1.0, identity coding; no trailer
+ {
+ Response{
+ StatusCode: 503,
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ RequestMethod: "GET",
+ Header: map[string]string{},
+ Body: nopCloser{bytes.NewBufferString("abcdef")},
+ ContentLength: 6,
+ },
+
+ "HTTP/1.0 503 Service Unavailable\r\n" +
+ "Content-Length: 6\r\n\r\n" +
+ "abcdef",
+ },
+ // Unchunked response without Content-Length.
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ RequestMethod: "GET",
+ Header: map[string]string{},
+ Body: nopCloser{bytes.NewBufferString("abcdef")},
+ ContentLength: -1,
+ },
+ "HTTP/1.0 200 OK\r\n" +
+ "\r\n" +
+ "abcdef",
+ },
+ // HTTP/1.1, chunked coding; empty trailer; close
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ RequestMethod: "GET",
+ Header: map[string]string{},
+ Body: nopCloser{bytes.NewBufferString("abcdef")},
+ ContentLength: 6,
+ TransferEncoding: []string{"chunked"},
+ Close: true,
+ },
+
+ "HTTP/1.1 200 OK\r\n" +
+ "Connection: close\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ "6\r\nabcdef\r\n0\r\n\r\n",
+ },
+}
+
+func TestResponseWrite(t *testing.T) {
+ for i := range respWriteTests {
+ tt := &respWriteTests[i]
+ var braw bytes.Buffer
+ err := tt.Resp.Write(&braw)
+ if err != nil {
+ t.Errorf("error writing #%d: %s", i, err)
+ continue
+ }
+ sraw := braw.String()
+ if sraw != tt.Raw {
+ t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, tt.Raw, sraw)
+ continue
+ }
+ }
+}
diff --git a/libgo/go/http/serve_test.go b/libgo/go/http/serve_test.go
new file mode 100644
index 000000000..053d6dca4
--- /dev/null
+++ b/libgo/go/http/serve_test.go
@@ -0,0 +1,220 @@
+// 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.
+
+// End-to-end serving tests
+
+package http
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "os"
+ "net"
+ "testing"
+)
+
+type dummyAddr string
+type oneConnListener struct {
+ conn net.Conn
+}
+
+func (l *oneConnListener) Accept() (c net.Conn, err os.Error) {
+ c = l.conn
+ if c == nil {
+ err = os.EOF
+ return
+ }
+ err = nil
+ l.conn = nil
+ return
+}
+
+func (l *oneConnListener) Close() os.Error {
+ return nil
+}
+
+func (l *oneConnListener) Addr() net.Addr {
+ return dummyAddr("test-address")
+}
+
+func (a dummyAddr) Network() string {
+ return string(a)
+}
+
+func (a dummyAddr) String() string {
+ return string(a)
+}
+
+type testConn struct {
+ readBuf bytes.Buffer
+ writeBuf bytes.Buffer
+}
+
+func (c *testConn) Read(b []byte) (int, os.Error) {
+ return c.readBuf.Read(b)
+}
+
+func (c *testConn) Write(b []byte) (int, os.Error) {
+ return c.writeBuf.Write(b)
+}
+
+func (c *testConn) Close() os.Error {
+ return nil
+}
+
+func (c *testConn) LocalAddr() net.Addr {
+ return dummyAddr("local-addr")
+}
+
+func (c *testConn) RemoteAddr() net.Addr {
+ return dummyAddr("remote-addr")
+}
+
+func (c *testConn) SetTimeout(nsec int64) os.Error {
+ return nil
+}
+
+func (c *testConn) SetReadTimeout(nsec int64) os.Error {
+ return nil
+}
+
+func (c *testConn) SetWriteTimeout(nsec int64) os.Error {
+ return nil
+}
+
+func TestConsumingBodyOnNextConn(t *testing.T) {
+ conn := new(testConn)
+ for i := 0; i < 2; i++ {
+ conn.readBuf.Write([]byte(
+ "POST / HTTP/1.1\r\n" +
+ "Host: test\r\n" +
+ "Content-Length: 11\r\n" +
+ "\r\n" +
+ "foo=1&bar=1"))
+ }
+
+ reqNum := 0
+ ch := make(chan *Request)
+ servech := make(chan os.Error)
+ listener := &oneConnListener{conn}
+ handler := func(res ResponseWriter, req *Request) {
+ reqNum++
+ t.Logf("Got request #%d: %v", reqNum, req)
+ ch <- req
+ }
+
+ go func() {
+ servech <- Serve(listener, HandlerFunc(handler))
+ }()
+
+ var req *Request
+ t.Log("Waiting for first request.")
+ req = <-ch
+ if req == nil {
+ t.Fatal("Got nil first request.")
+ }
+ if req.Method != "POST" {
+ t.Errorf("For request #1's method, got %q; expected %q",
+ req.Method, "POST")
+ }
+
+ t.Log("Waiting for second request.")
+ req = <-ch
+ if req == nil {
+ t.Fatal("Got nil first request.")
+ }
+ if req.Method != "POST" {
+ t.Errorf("For request #2's method, got %q; expected %q",
+ req.Method, "POST")
+ }
+
+ t.Log("Waiting for EOF.")
+ if serveerr := <-servech; serveerr != os.EOF {
+ t.Errorf("Serve returned %q; expected EOF", serveerr)
+ }
+}
+
+type responseWriterMethodCall struct {
+ method string
+ headerKey, headerValue string // if method == "SetHeader"
+ bytesWritten []byte // if method == "Write"
+ responseCode int // if method == "WriteHeader"
+}
+
+type recordingResponseWriter struct {
+ log []*responseWriterMethodCall
+}
+
+func (rw *recordingResponseWriter) RemoteAddr() string {
+ return "1.2.3.4"
+}
+
+func (rw *recordingResponseWriter) UsingTLS() bool {
+ return false
+}
+
+func (rw *recordingResponseWriter) SetHeader(k, v string) {
+ rw.log = append(rw.log, &responseWriterMethodCall{method: "SetHeader", headerKey: k, headerValue: v})
+}
+
+func (rw *recordingResponseWriter) Write(buf []byte) (int, os.Error) {
+ rw.log = append(rw.log, &responseWriterMethodCall{method: "Write", bytesWritten: buf})
+ return len(buf), nil
+}
+
+func (rw *recordingResponseWriter) WriteHeader(code int) {
+ rw.log = append(rw.log, &responseWriterMethodCall{method: "WriteHeader", responseCode: code})
+}
+
+func (rw *recordingResponseWriter) Flush() {
+ rw.log = append(rw.log, &responseWriterMethodCall{method: "Flush"})
+}
+
+func (rw *recordingResponseWriter) Hijack() (io.ReadWriteCloser, *bufio.ReadWriter, os.Error) {
+ panic("Not supported")
+}
+
+// Tests for http://code.google.com/p/go/issues/detail?id=900
+func TestMuxRedirectLeadingSlashes(t *testing.T) {
+ paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
+ for _, path := range paths {
+ req, err := ReadRequest(bufio.NewReader(bytes.NewBufferString("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n")))
+ if err != nil {
+ t.Errorf("%s", err)
+ }
+ mux := NewServeMux()
+ resp := new(recordingResponseWriter)
+ resp.log = make([]*responseWriterMethodCall, 0)
+
+ mux.ServeHTTP(resp, req)
+
+ dumpLog := func() {
+ t.Logf("For path %q:", path)
+ for _, call := range resp.log {
+ t.Logf("Got call: %s, header=%s, value=%s, buf=%q, code=%d", call.method,
+ call.headerKey, call.headerValue, call.bytesWritten, call.responseCode)
+ }
+ }
+
+ if len(resp.log) != 2 {
+ dumpLog()
+ t.Errorf("expected 2 calls to response writer; got %d", len(resp.log))
+ return
+ }
+
+ if resp.log[0].method != "SetHeader" ||
+ resp.log[0].headerKey != "Location" || resp.log[0].headerValue != "/foo.txt" {
+ dumpLog()
+ t.Errorf("Expected SetHeader of Location to /foo.txt")
+ return
+ }
+
+ if resp.log[1].method != "WriteHeader" || resp.log[1].responseCode != StatusMovedPermanently {
+ dumpLog()
+ t.Errorf("Expected WriteHeader of StatusMovedPermanently")
+ return
+ }
+ }
+}
diff --git a/libgo/go/http/server.go b/libgo/go/http/server.go
new file mode 100644
index 000000000..644724f58
--- /dev/null
+++ b/libgo/go/http/server.go
@@ -0,0 +1,766 @@
+// 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.
+
+// HTTP server. See RFC 2616.
+
+// TODO(rsc):
+// logging
+// cgi support
+// post support
+
+package http
+
+import (
+ "bufio"
+ "crypto/rand"
+ "crypto/tls"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "os"
+ "path"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// Errors introduced by the HTTP server.
+var (
+ ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush")
+ ErrBodyNotAllowed = os.NewError("http: response status code does not allow body")
+ ErrHijacked = os.NewError("Conn has been hijacked")
+)
+
+// Objects implementing the Handler interface can be
+// registered to serve a particular path or subtree
+// in the HTTP server.
+//
+// ServeHTTP should write reply headers and data to the ResponseWriter
+// and then return. Returning signals that the request is finished
+// and that the HTTP server can move on to the next request on
+// the connection.
+type Handler interface {
+ ServeHTTP(ResponseWriter, *Request)
+}
+
+// A ResponseWriter interface is used by an HTTP handler to
+// construct an HTTP response.
+type ResponseWriter interface {
+ // RemoteAddr returns the address of the client that sent the current request
+ RemoteAddr() string
+
+ // UsingTLS returns true if the client is connected using TLS
+ UsingTLS() bool
+
+ // SetHeader sets a header line in the eventual response.
+ // For example, SetHeader("Content-Type", "text/html; charset=utf-8")
+ // will result in the header line
+ //
+ // Content-Type: text/html; charset=utf-8
+ //
+ // being sent. UTF-8 encoded HTML is the default setting for
+ // Content-Type in this library, so users need not make that
+ // particular call. Calls to SetHeader after WriteHeader (or Write)
+ // are ignored.
+ SetHeader(string, string)
+
+ // Write writes the data to the connection as part of an HTTP reply.
+ // If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
+ // before writing the data.
+ Write([]byte) (int, os.Error)
+
+ // WriteHeader sends an HTTP response header with status code.
+ // If WriteHeader is not called explicitly, the first call to Write
+ // will trigger an implicit WriteHeader(http.StatusOK).
+ // Thus explicit calls to WriteHeader are mainly used to
+ // send error codes.
+ WriteHeader(int)
+
+ // Flush sends any buffered data to the client.
+ Flush()
+
+ // Hijack lets the caller take over the connection.
+ // After a call to Hijack(), the HTTP server library
+ // will not do anything else with the connection.
+ // It becomes the caller's responsibility to manage
+ // and close the connection.
+ Hijack() (io.ReadWriteCloser, *bufio.ReadWriter, os.Error)
+}
+
+// A conn represents the server side of an HTTP connection.
+type conn struct {
+ remoteAddr string // network address of remote side
+ handler Handler // request handler
+ rwc io.ReadWriteCloser // i/o connection
+ buf *bufio.ReadWriter // buffered rwc
+ hijacked bool // connection has been hijacked by handler
+ usingTLS bool // a flag indicating connection over TLS
+}
+
+// A response represents the server side of an HTTP response.
+type response struct {
+ conn *conn
+ req *Request // request for this response
+ chunking bool // using chunked transfer encoding for reply body
+ wroteHeader bool // reply header has been written
+ wroteContinue bool // 100 Continue response was written
+ header map[string]string // reply header parameters
+ written int64 // number of bytes written in body
+ status int // status code passed to WriteHeader
+
+ // close connection after this reply. set on request and
+ // updated after response from handler if there's a
+ // "Connection: keep-alive" response header and a
+ // Content-Length.
+ closeAfterReply bool
+}
+
+// Create new connection from rwc.
+func newConn(rwc net.Conn, handler Handler) (c *conn, err os.Error) {
+ c = new(conn)
+ c.remoteAddr = rwc.RemoteAddr().String()
+ c.handler = handler
+ c.rwc = rwc
+ _, c.usingTLS = rwc.(*tls.Conn)
+ br := bufio.NewReader(rwc)
+ bw := bufio.NewWriter(rwc)
+ c.buf = bufio.NewReadWriter(br, bw)
+ return c, nil
+}
+
+// wrapper around io.ReaderCloser which on first read, sends an
+// HTTP/1.1 100 Continue header
+type expectContinueReader struct {
+ resp *response
+ readCloser io.ReadCloser
+}
+
+func (ecr *expectContinueReader) Read(p []byte) (n int, err os.Error) {
+ if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked {
+ ecr.resp.wroteContinue = true
+ io.WriteString(ecr.resp.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n")
+ ecr.resp.conn.buf.Flush()
+ }
+ return ecr.readCloser.Read(p)
+}
+
+func (ecr *expectContinueReader) Close() os.Error {
+ return ecr.readCloser.Close()
+}
+
+// TimeFormat is the time format to use with
+// time.Parse and time.Time.Format when parsing
+// or generating times in HTTP headers.
+// It is like time.RFC1123 but hard codes GMT as the time zone.
+const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
+
+// Read next request from connection.
+func (c *conn) readRequest() (w *response, err os.Error) {
+ if c.hijacked {
+ return nil, ErrHijacked
+ }
+ var req *Request
+ if req, err = ReadRequest(c.buf.Reader); err != nil {
+ return nil, err
+ }
+
+ w = new(response)
+ w.conn = c
+ w.req = req
+ w.header = make(map[string]string)
+
+ // Expect 100 Continue support
+ if req.expectsContinue() && req.ProtoAtLeast(1, 1) {
+ // Wrap the Body reader with one that replies on the connection
+ req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
+ }
+
+ // Default output is HTML encoded in UTF-8.
+ w.SetHeader("Content-Type", "text/html; charset=utf-8")
+ w.SetHeader("Date", time.UTC().Format(TimeFormat))
+
+ if req.Method == "HEAD" {
+ // do nothing
+ } else if req.ProtoAtLeast(1, 1) {
+ // HTTP/1.1 or greater: use chunked transfer encoding
+ // to avoid closing the connection at EOF.
+ w.chunking = true
+ w.SetHeader("Transfer-Encoding", "chunked")
+ } else {
+ // HTTP version < 1.1: cannot do chunked transfer
+ // encoding, so signal EOF by closing connection.
+ // Will be overridden if the HTTP handler ends up
+ // writing a Content-Length and the client requested
+ // "Connection: keep-alive"
+ w.closeAfterReply = true
+ }
+
+ return w, nil
+}
+
+// UsingTLS implements the ResponseWriter.UsingTLS
+func (w *response) UsingTLS() bool {
+ return w.conn.usingTLS
+}
+
+// RemoteAddr implements the ResponseWriter.RemoteAddr method
+func (w *response) RemoteAddr() string { return w.conn.remoteAddr }
+
+// SetHeader implements the ResponseWriter.SetHeader method
+func (w *response) SetHeader(hdr, val string) { w.header[CanonicalHeaderKey(hdr)] = val }
+
+// WriteHeader implements the ResponseWriter.WriteHeader method
+func (w *response) WriteHeader(code int) {
+ if w.conn.hijacked {
+ log.Print("http: response.WriteHeader on hijacked connection")
+ return
+ }
+ if w.wroteHeader {
+ log.Print("http: multiple response.WriteHeader calls")
+ return
+ }
+ w.wroteHeader = true
+ w.status = code
+ if code == StatusNotModified {
+ // Must not have body.
+ w.header["Content-Type"] = "", false
+ w.header["Transfer-Encoding"] = "", false
+ w.chunking = false
+ }
+ // Cannot use Content-Length with non-identity Transfer-Encoding.
+ if w.chunking {
+ w.header["Content-Length"] = "", false
+ }
+ if !w.req.ProtoAtLeast(1, 0) {
+ return
+ }
+ proto := "HTTP/1.0"
+ if w.req.ProtoAtLeast(1, 1) {
+ proto = "HTTP/1.1"
+ }
+ codestring := strconv.Itoa(code)
+ text, ok := statusText[code]
+ if !ok {
+ text = "status code " + codestring
+ }
+ io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n")
+ for k, v := range w.header {
+ io.WriteString(w.conn.buf, k+": "+v+"\r\n")
+ }
+ io.WriteString(w.conn.buf, "\r\n")
+}
+
+// Write implements the ResponseWriter.Write method
+func (w *response) Write(data []byte) (n int, err os.Error) {
+ if w.conn.hijacked {
+ log.Print("http: response.Write on hijacked connection")
+ return 0, ErrHijacked
+ }
+ if !w.wroteHeader {
+ if w.req.wantsHttp10KeepAlive() {
+ _, hasLength := w.header["Content-Length"]
+ if hasLength {
+ _, connectionHeaderSet := w.header["Connection"]
+ if !connectionHeaderSet {
+ w.header["Connection"] = "keep-alive"
+ }
+ }
+ }
+ w.WriteHeader(StatusOK)
+ }
+ if len(data) == 0 {
+ return 0, nil
+ }
+
+ if w.status == StatusNotModified || w.req.Method == "HEAD" {
+ // Must not have body.
+ return 0, ErrBodyNotAllowed
+ }
+
+ w.written += int64(len(data)) // ignoring errors, for errorKludge
+
+ // TODO(rsc): if chunking happened after the buffering,
+ // then there would be fewer chunk headers.
+ // On the other hand, it would make hijacking more difficult.
+ if w.chunking {
+ fmt.Fprintf(w.conn.buf, "%x\r\n", len(data)) // TODO(rsc): use strconv not fmt
+ }
+ n, err = w.conn.buf.Write(data)
+ if err == nil && w.chunking {
+ if n != len(data) {
+ err = io.ErrShortWrite
+ }
+ if err == nil {
+ io.WriteString(w.conn.buf, "\r\n")
+ }
+ }
+
+ return n, err
+}
+
+// If this is an error reply (4xx or 5xx)
+// and the handler wrote some data explaining the error,
+// some browsers (i.e., Chrome, Internet Explorer)
+// will show their own error instead unless the error is
+// long enough. The minimum lengths used in those
+// browsers are in the 256-512 range.
+// Pad to 1024 bytes.
+func errorKludge(w *response) {
+ const min = 1024
+
+ // Is this an error?
+ if kind := w.status / 100; kind != 4 && kind != 5 {
+ return
+ }
+
+ // Did the handler supply any info? Enough?
+ if w.written == 0 || w.written >= min {
+ return
+ }
+
+ // Is it a broken browser?
+ var msg string
+ switch agent := w.req.UserAgent; {
+ case strings.Contains(agent, "MSIE"):
+ msg = "Internet Explorer"
+ case strings.Contains(agent, "Chrome/"):
+ msg = "Chrome"
+ default:
+ return
+ }
+ msg += " would ignore this error page if this text weren't here.\n"
+
+ // Is it text? ("Content-Type" is always in the map)
+ baseType := strings.Split(w.header["Content-Type"], ";", 2)[0]
+ switch baseType {
+ case "text/html":
+ io.WriteString(w, "<!-- ")
+ for w.written < min {
+ io.WriteString(w, msg)
+ }
+ io.WriteString(w, " -->")
+ case "text/plain":
+ io.WriteString(w, "\n")
+ for w.written < min {
+ io.WriteString(w, msg)
+ }
+ }
+}
+
+func (w *response) finishRequest() {
+ // If this was an HTTP/1.0 request with keep-alive and we sent a Content-Length
+ // back, we can make this a keep-alive response ...
+ if w.req.wantsHttp10KeepAlive() {
+ _, sentLength := w.header["Content-Length"]
+ if sentLength && w.header["Connection"] == "keep-alive" {
+ w.closeAfterReply = false
+ }
+ }
+ if !w.wroteHeader {
+ w.WriteHeader(StatusOK)
+ }
+ errorKludge(w)
+ if w.chunking {
+ io.WriteString(w.conn.buf, "0\r\n")
+ // trailer key/value pairs, followed by blank line
+ io.WriteString(w.conn.buf, "\r\n")
+ }
+ w.conn.buf.Flush()
+ w.req.Body.Close()
+}
+
+// Flush implements the ResponseWriter.Flush method.
+func (w *response) Flush() {
+ if !w.wroteHeader {
+ w.WriteHeader(StatusOK)
+ }
+ w.conn.buf.Flush()
+}
+
+// Close the connection.
+func (c *conn) close() {
+ if c.buf != nil {
+ c.buf.Flush()
+ c.buf = nil
+ }
+ if c.rwc != nil {
+ c.rwc.Close()
+ c.rwc = nil
+ }
+}
+
+// Serve a new connection.
+func (c *conn) serve() {
+ for {
+ w, err := c.readRequest()
+ if err != nil {
+ break
+ }
+ // HTTP cannot have multiple simultaneous active requests.[*]
+ // Until the server replies to this request, it can't read another,
+ // so we might as well run the handler in this goroutine.
+ // [*] Not strictly true: HTTP pipelining. We could let them all process
+ // in parallel even if their responses need to be serialized.
+ c.handler.ServeHTTP(w, w.req)
+ if c.hijacked {
+ return
+ }
+ w.finishRequest()
+ if w.closeAfterReply {
+ break
+ }
+ }
+ c.close()
+}
+
+// Hijack impements the ResponseWriter.Hijack method.
+func (w *response) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.Error) {
+ if w.conn.hijacked {
+ return nil, nil, ErrHijacked
+ }
+ w.conn.hijacked = true
+ rwc = w.conn.rwc
+ buf = w.conn.buf
+ w.conn.rwc = nil
+ w.conn.buf = nil
+ return
+}
+
+// The HandlerFunc type is an adapter to allow the use of
+// ordinary functions as HTTP handlers. If f is a function
+// with the appropriate signature, HandlerFunc(f) is a
+// Handler object that calls f.
+type HandlerFunc func(ResponseWriter, *Request)
+
+// ServeHTTP calls f(w, req).
+func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
+ f(w, r)
+}
+
+// Helper handlers
+
+// Error replies to the request with the specified error message and HTTP code.
+func Error(w ResponseWriter, error string, code int) {
+ w.SetHeader("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(code)
+ fmt.Fprintln(w, error)
+}
+
+// NotFound replies to the request with an HTTP 404 not found error.
+func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) }
+
+// NotFoundHandler returns a simple request handler
+// that replies to each request with a ``404 page not found'' reply.
+func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
+
+// Redirect replies to the request with a redirect to url,
+// which may be a path relative to the request path.
+func Redirect(w ResponseWriter, r *Request, url string, code int) {
+ if u, err := ParseURL(url); err == nil {
+ // If url was relative, make absolute by
+ // combining with request path.
+ // The browser would probably do this for us,
+ // but doing it ourselves is more reliable.
+
+ // NOTE(rsc): RFC 2616 says that the Location
+ // line must be an absolute URI, like
+ // "http://www.google.com/redirect/",
+ // not a path like "/redirect/".
+ // Unfortunately, we don't know what to
+ // put in the host name section to get the
+ // client to connect to us again, so we can't
+ // know the right absolute URI to send back.
+ // Because of this problem, no one pays attention
+ // to the RFC; they all send back just a new path.
+ // So do we.
+ oldpath := r.URL.Path
+ if oldpath == "" { // should not happen, but avoid a crash if it does
+ oldpath = "/"
+ }
+ if u.Scheme == "" {
+ // no leading http://server
+ if url == "" || url[0] != '/' {
+ // make relative path absolute
+ olddir, _ := path.Split(oldpath)
+ url = olddir + url
+ }
+
+ // clean up but preserve trailing slash
+ trailing := url[len(url)-1] == '/'
+ url = path.Clean(url)
+ if trailing && url[len(url)-1] != '/' {
+ url += "/"
+ }
+ }
+ }
+
+ w.SetHeader("Location", url)
+ w.WriteHeader(code)
+
+ // RFC2616 recommends that a short note "SHOULD" be included in the
+ // response because older user agents may not understand 301/307.
+ // Shouldn't send the response for POST or HEAD; that leaves GET.
+ if r.Method == "GET" {
+ note := "<a href=\"" + htmlEscape(url) + "\">" + statusText[code] + "</a>.\n"
+ fmt.Fprintln(w, note)
+ }
+}
+
+func htmlEscape(s string) string {
+ s = strings.Replace(s, "&", "&amp;", -1)
+ s = strings.Replace(s, "<", "&lt;", -1)
+ s = strings.Replace(s, ">", "&gt;", -1)
+ s = strings.Replace(s, "\"", "&quot;", -1)
+ s = strings.Replace(s, "'", "&apos;", -1)
+ return s
+}
+
+// Redirect to a fixed URL
+type redirectHandler struct {
+ url string
+ code int
+}
+
+func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) {
+ Redirect(w, r, rh.url, rh.code)
+}
+
+// RedirectHandler returns a request handler that redirects
+// each request it receives to the given url using the given
+// status code.
+func RedirectHandler(url string, code int) Handler {
+ return &redirectHandler{url, code}
+}
+
+// ServeMux is an HTTP request multiplexer.
+// It matches the URL of each incoming request against a list of registered
+// patterns and calls the handler for the pattern that
+// most closely matches the URL.
+//
+// Patterns named fixed paths, like "/favicon.ico",
+// or subtrees, like "/images/" (note the trailing slash).
+// Patterns must begin with /.
+// Longer patterns take precedence over shorter ones, so that
+// if there are handlers registered for both "/images/"
+// and "/images/thumbnails/", the latter handler will be
+// called for paths beginning "/images/thumbnails/" and the
+// former will receiver requests for any other paths in the
+// "/images/" subtree.
+//
+// In the future, the pattern syntax may be relaxed to allow
+// an optional host-name at the beginning of the pattern,
+// so that a handler might register for the two patterns
+// "/codesearch" and "codesearch.google.com/"
+// without taking over requests for http://www.google.com/.
+//
+// ServeMux also takes care of sanitizing the URL request path,
+// redirecting any request containing . or .. elements to an
+// equivalent .- and ..-free URL.
+type ServeMux struct {
+ m map[string]Handler
+}
+
+// NewServeMux allocates and returns a new ServeMux.
+func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} }
+
+// DefaultServeMux is the default ServeMux used by Serve.
+var DefaultServeMux = NewServeMux()
+
+// Does path match pattern?
+func pathMatch(pattern, path string) bool {
+ if len(pattern) == 0 {
+ // should not happen
+ return false
+ }
+ n := len(pattern)
+ if pattern[n-1] != '/' {
+ return pattern == path
+ }
+ return len(path) >= n && path[0:n] == pattern
+}
+
+// Return the canonical path for p, eliminating . and .. elements.
+func cleanPath(p string) string {
+ if p == "" {
+ return "/"
+ }
+ if p[0] != '/' {
+ p = "/" + p
+ }
+ np := path.Clean(p)
+ // path.Clean removes trailing slash except for root;
+ // put the trailing slash back if necessary.
+ if p[len(p)-1] == '/' && np != "/" {
+ np += "/"
+ }
+ return np
+}
+
+// ServeHTTP dispatches the request to the handler whose
+// pattern most closely matches the request URL.
+func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
+ // Clean path to canonical form and redirect.
+ if p := cleanPath(r.URL.Path); p != r.URL.Path {
+ w.SetHeader("Location", p)
+ w.WriteHeader(StatusMovedPermanently)
+ return
+ }
+
+ // Most-specific (longest) pattern wins.
+ var h Handler
+ var n = 0
+ for k, v := range mux.m {
+ if !pathMatch(k, r.URL.Path) {
+ continue
+ }
+ if h == nil || len(k) > n {
+ n = len(k)
+ h = v
+ }
+ }
+ if h == nil {
+ h = NotFoundHandler()
+ }
+ h.ServeHTTP(w, r)
+}
+
+// Handle registers the handler for the given pattern.
+func (mux *ServeMux) Handle(pattern string, handler Handler) {
+ if pattern == "" || pattern[0] != '/' {
+ panic("http: invalid pattern " + pattern)
+ }
+
+ mux.m[pattern] = handler
+
+ // Helpful behavior:
+ // If pattern is /tree/, insert permanent redirect for /tree.
+ n := len(pattern)
+ if n > 0 && pattern[n-1] == '/' {
+ mux.m[pattern[0:n-1]] = RedirectHandler(pattern, StatusMovedPermanently)
+ }
+}
+
+// HandleFunc registers the handler function for the given pattern.
+func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
+ mux.Handle(pattern, HandlerFunc(handler))
+}
+
+// Handle registers the handler for the given pattern
+// in the DefaultServeMux.
+func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
+
+// HandleFunc registers the handler function for the given pattern
+// in the DefaultServeMux.
+func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
+ DefaultServeMux.HandleFunc(pattern, handler)
+}
+
+// Serve accepts incoming HTTP connections on the listener l,
+// creating a new service thread for each. The service threads
+// read requests and then call handler to reply to them.
+// Handler is typically nil, in which case the DefaultServeMux is used.
+func Serve(l net.Listener, handler Handler) os.Error {
+ if handler == nil {
+ handler = DefaultServeMux
+ }
+ for {
+ rw, e := l.Accept()
+ if e != nil {
+ return e
+ }
+ c, err := newConn(rw, handler)
+ if err != nil {
+ continue
+ }
+ go c.serve()
+ }
+ panic("not reached")
+}
+
+// ListenAndServe listens on the TCP network address addr
+// and then calls Serve with handler to handle requests
+// on incoming connections. Handler is typically nil,
+// in which case the DefaultServeMux is used.
+//
+// A trivial example server is:
+//
+// package main
+//
+// import (
+// "http"
+// "io"
+// "log"
+// )
+//
+// // hello world, the web server
+// func HelloServer(w http.ResponseWriter, req *http.Request) {
+// io.WriteString(w, "hello, world!\n")
+// }
+//
+// func main() {
+// http.HandleFunc("/hello", HelloServer)
+// err := http.ListenAndServe(":12345", nil)
+// if err != nil {
+// log.Exit("ListenAndServe: ", err.String())
+// }
+// }
+func ListenAndServe(addr string, handler Handler) os.Error {
+ l, e := net.Listen("tcp", addr)
+ if e != nil {
+ return e
+ }
+ e = Serve(l, handler)
+ l.Close()
+ return e
+}
+
+// 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.
+//
+// A trivial example server is:
+//
+// import (
+// "http"
+// "log"
+// )
+//
+// func handler(w http.ResponseWriter, req *http.Request) {
+// w.SetHeader("Content-Type", "text/plain")
+// w.Write([]byte("This is an example server.\n"))
+// }
+//
+// func main() {
+// http.HandleFunc("/", handler)
+// log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/")
+// err := http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil)
+// if err != nil {
+// log.Exit(err)
+// }
+// }
+//
+// 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 {
+ config := &tls.Config{
+ Rand: rand.Reader,
+ Time: time.Seconds,
+ NextProtos: []string{"http/1.1"},
+ }
+
+ var err os.Error
+ config.Certificates = make([]tls.Certificate, 1)
+ config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+ if err != nil {
+ return err
+ }
+
+ conn, err := net.Listen("tcp", addr)
+ if err != nil {
+ return err
+ }
+
+ tlsListener := tls.NewListener(conn, config)
+ return Serve(tlsListener, handler)
+}
diff --git a/libgo/go/http/status.go b/libgo/go/http/status.go
new file mode 100644
index 000000000..b6e2d65c6
--- /dev/null
+++ b/libgo/go/http/status.go
@@ -0,0 +1,106 @@
+// 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 http
+
+// HTTP status codes, defined in RFC 2616.
+const (
+ StatusContinue = 100
+ StatusSwitchingProtocols = 101
+
+ StatusOK = 200
+ StatusCreated = 201
+ StatusAccepted = 202
+ StatusNonAuthoritativeInfo = 203
+ StatusNoContent = 204
+ StatusResetContent = 205
+ StatusPartialContent = 206
+
+ StatusMultipleChoices = 300
+ StatusMovedPermanently = 301
+ StatusFound = 302
+ StatusSeeOther = 303
+ StatusNotModified = 304
+ StatusUseProxy = 305
+ StatusTemporaryRedirect = 307
+
+ StatusBadRequest = 400
+ StatusUnauthorized = 401
+ StatusPaymentRequired = 402
+ StatusForbidden = 403
+ StatusNotFound = 404
+ StatusMethodNotAllowed = 405
+ StatusNotAcceptable = 406
+ StatusProxyAuthRequired = 407
+ StatusRequestTimeout = 408
+ StatusConflict = 409
+ StatusGone = 410
+ StatusLengthRequired = 411
+ StatusPreconditionFailed = 412
+ StatusRequestEntityTooLarge = 413
+ StatusRequestURITooLong = 414
+ StatusUnsupportedMediaType = 415
+ StatusRequestedRangeNotSatisfiable = 416
+ StatusExpectationFailed = 417
+
+ StatusInternalServerError = 500
+ StatusNotImplemented = 501
+ StatusBadGateway = 502
+ StatusServiceUnavailable = 503
+ StatusGatewayTimeout = 504
+ StatusHTTPVersionNotSupported = 505
+)
+
+var statusText = map[int]string{
+ StatusContinue: "Continue",
+ StatusSwitchingProtocols: "Switching Protocols",
+
+ StatusOK: "OK",
+ StatusCreated: "Created",
+ StatusAccepted: "Accepted",
+ StatusNonAuthoritativeInfo: "Non-Authoritative Information",
+ StatusNoContent: "No Content",
+ StatusResetContent: "Reset Content",
+ StatusPartialContent: "Partial Content",
+
+ StatusMultipleChoices: "Multiple Choices",
+ StatusMovedPermanently: "Moved Permanently",
+ StatusFound: "Found",
+ StatusSeeOther: "See Other",
+ StatusNotModified: "Not Modified",
+ StatusUseProxy: "Use Proxy",
+ StatusTemporaryRedirect: "Temporary Redirect",
+
+ StatusBadRequest: "Bad Request",
+ StatusUnauthorized: "Unauthorized",
+ StatusPaymentRequired: "Payment Required",
+ StatusForbidden: "Forbidden",
+ StatusNotFound: "Not Found",
+ StatusMethodNotAllowed: "Method Not Allowed",
+ StatusNotAcceptable: "Not Acceptable",
+ StatusProxyAuthRequired: "Proxy Authentication Required",
+ StatusRequestTimeout: "Request Timeout",
+ StatusConflict: "Conflict",
+ StatusGone: "Gone",
+ StatusLengthRequired: "Length Required",
+ StatusPreconditionFailed: "Precondition Failed",
+ StatusRequestEntityTooLarge: "Request Entity Too Large",
+ StatusRequestURITooLong: "Request URI Too Long",
+ StatusUnsupportedMediaType: "Unsupported Media Type",
+ StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
+ StatusExpectationFailed: "Expectation Failed",
+
+ StatusInternalServerError: "Internal Server Error",
+ StatusNotImplemented: "Not Implemented",
+ StatusBadGateway: "Bad Gateway",
+ StatusServiceUnavailable: "Service Unavailable",
+ StatusGatewayTimeout: "Gateway Timeout",
+ StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
+}
+
+// StatusText returns a text for the HTTP status code. It returns the empty
+// string if the code is unknown.
+func StatusText(code int) string {
+ return statusText[code]
+}
diff --git a/libgo/go/http/testdata/file b/libgo/go/http/testdata/file
new file mode 100644
index 000000000..11f11f9be
--- /dev/null
+++ b/libgo/go/http/testdata/file
@@ -0,0 +1 @@
+0123456789
diff --git a/libgo/go/http/transfer.go b/libgo/go/http/transfer.go
new file mode 100644
index 000000000..e62885d62
--- /dev/null
+++ b/libgo/go/http/transfer.go
@@ -0,0 +1,441 @@
+// 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 http
+
+import (
+ "bufio"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// transferWriter inspects the fields of a user-supplied Request or Response,
+// sanitizes them without changing the user object and provides methods for
+// writing the respective header, body and trailer in wire format.
+type transferWriter struct {
+ Body io.ReadCloser
+ ResponseToHEAD bool
+ ContentLength int64
+ Close bool
+ TransferEncoding []string
+ Trailer map[string]string
+}
+
+func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
+ t = &transferWriter{}
+
+ // Extract relevant fields
+ atLeastHTTP11 := false
+ switch rr := r.(type) {
+ case *Request:
+ t.Body = rr.Body
+ t.ContentLength = rr.ContentLength
+ t.Close = rr.Close
+ t.TransferEncoding = rr.TransferEncoding
+ t.Trailer = rr.Trailer
+ atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
+ case *Response:
+ t.Body = rr.Body
+ t.ContentLength = rr.ContentLength
+ t.Close = rr.Close
+ t.TransferEncoding = rr.TransferEncoding
+ t.Trailer = rr.Trailer
+ atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
+ t.ResponseToHEAD = noBodyExpected(rr.RequestMethod)
+ }
+
+ // Sanitize Body,ContentLength,TransferEncoding
+ if t.ResponseToHEAD {
+ t.Body = nil
+ t.TransferEncoding = nil
+ // ContentLength is expected to hold Content-Length
+ if t.ContentLength < 0 {
+ return nil, ErrMissingContentLength
+ }
+ } else {
+ if !atLeastHTTP11 || t.Body == nil {
+ t.TransferEncoding = nil
+ }
+ if chunked(t.TransferEncoding) {
+ t.ContentLength = -1
+ } else if t.Body == nil { // no chunking, no body
+ t.ContentLength = 0
+ }
+ }
+
+ // Sanitize Trailer
+ if !chunked(t.TransferEncoding) {
+ t.Trailer = nil
+ }
+
+ return t, nil
+}
+
+func noBodyExpected(requestMethod string) bool {
+ return requestMethod == "HEAD"
+}
+
+func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
+ if t.Close {
+ _, err = io.WriteString(w, "Connection: close\r\n")
+ if err != nil {
+ return
+ }
+ }
+
+ // Write Content-Length and/or Transfer-Encoding whose values are a
+ // function of the sanitized field triple (Body, ContentLength,
+ // TransferEncoding)
+ if chunked(t.TransferEncoding) {
+ _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
+ if err != nil {
+ return
+ }
+ } else if t.ContentLength > 0 || t.ResponseToHEAD {
+ io.WriteString(w, "Content-Length: ")
+ _, err = io.WriteString(w, strconv.Itoa64(t.ContentLength)+"\r\n")
+ if err != nil {
+ return
+ }
+ }
+
+ // Write Trailer header
+ if t.Trailer != nil {
+ // TODO: At some point, there should be a generic mechanism for
+ // writing long headers, using HTTP line splitting
+ io.WriteString(w, "Trailer: ")
+ needComma := false
+ for k := range t.Trailer {
+ k = CanonicalHeaderKey(k)
+ switch k {
+ case "Transfer-Encoding", "Trailer", "Content-Length":
+ return &badStringError{"invalid Trailer key", k}
+ }
+ if needComma {
+ io.WriteString(w, ",")
+ }
+ io.WriteString(w, k)
+ needComma = true
+ }
+ _, err = io.WriteString(w, "\r\n")
+ }
+
+ return
+}
+
+func (t *transferWriter) WriteBody(w io.Writer) (err os.Error) {
+ // Write body
+ if t.Body != nil {
+ if chunked(t.TransferEncoding) {
+ cw := NewChunkedWriter(w)
+ _, err = io.Copy(cw, t.Body)
+ if err == nil {
+ err = cw.Close()
+ }
+ } else if t.ContentLength == -1 {
+ _, err = io.Copy(w, t.Body)
+ } else {
+ _, err = io.Copy(w, io.LimitReader(t.Body, t.ContentLength))
+ }
+ if err != nil {
+ return err
+ }
+ if err = t.Body.Close(); err != nil {
+ return err
+ }
+ }
+
+ // TODO(petar): Place trailer writer code here.
+ if chunked(t.TransferEncoding) {
+ // Last chunk, empty trailer
+ _, err = io.WriteString(w, "\r\n")
+ }
+
+ return
+}
+
+type transferReader struct {
+ // Input
+ Header map[string]string
+ StatusCode int
+ RequestMethod string
+ ProtoMajor int
+ ProtoMinor int
+ // Output
+ Body io.ReadCloser
+ ContentLength int64
+ TransferEncoding []string
+ Close bool
+ Trailer map[string]string
+}
+
+// msg is *Request or *Response.
+func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
+ t := &transferReader{}
+
+ // Unify input
+ switch rr := msg.(type) {
+ case *Response:
+ t.Header = rr.Header
+ t.StatusCode = rr.StatusCode
+ t.RequestMethod = rr.RequestMethod
+ t.ProtoMajor = rr.ProtoMajor
+ t.ProtoMinor = rr.ProtoMinor
+ t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header)
+ case *Request:
+ t.Header = rr.Header
+ t.ProtoMajor = rr.ProtoMajor
+ t.ProtoMinor = rr.ProtoMinor
+ // Transfer semantics for Requests are exactly like those for
+ // Responses with status code 200, responding to a GET method
+ t.StatusCode = 200
+ t.RequestMethod = "GET"
+ }
+
+ // Default to HTTP/1.1
+ if t.ProtoMajor == 0 && t.ProtoMinor == 0 {
+ t.ProtoMajor, t.ProtoMinor = 1, 1
+ }
+
+ // Transfer encoding, content length
+ t.TransferEncoding, err = fixTransferEncoding(t.Header)
+ if err != nil {
+ return err
+ }
+
+ t.ContentLength, err = fixLength(t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
+ if err != nil {
+ return err
+ }
+
+ // Trailer
+ t.Trailer, err = fixTrailer(t.Header, t.TransferEncoding)
+ if err != nil {
+ return err
+ }
+
+ // Prepare body reader. ContentLength < 0 means chunked encoding
+ // or close connection when finished, since multipart is not supported yet
+ switch {
+ case chunked(t.TransferEncoding):
+ t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
+ case t.ContentLength >= 0:
+ // TODO: limit the Content-Length. This is an easy DoS vector.
+ t.Body = &body{Reader: io.LimitReader(r, t.ContentLength), closing: t.Close}
+ default:
+ // t.ContentLength < 0, i.e. "Content-Length" not mentioned in header
+ if t.Close {
+ // Close semantics (i.e. HTTP/1.0)
+ t.Body = &body{Reader: r, closing: t.Close}
+ } else {
+ // Persistent connection (i.e. HTTP/1.1)
+ t.Body = &body{Reader: io.LimitReader(r, 0), closing: t.Close}
+ }
+ // TODO(petar): It may be a good idea, for extra robustness, to
+ // assume ContentLength=0 for GET requests (and other special
+ // cases?). This logic should be in fixLength().
+ }
+
+ // Unify output
+ switch rr := msg.(type) {
+ case *Request:
+ rr.Body = t.Body
+ rr.ContentLength = t.ContentLength
+ rr.TransferEncoding = t.TransferEncoding
+ rr.Close = t.Close
+ rr.Trailer = t.Trailer
+ case *Response:
+ rr.Body = t.Body
+ rr.ContentLength = t.ContentLength
+ rr.TransferEncoding = t.TransferEncoding
+ rr.Close = t.Close
+ rr.Trailer = t.Trailer
+ }
+
+ return nil
+}
+
+// Checks whether chunked is part of the encodings stack
+func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
+
+// Sanitize transfer encoding
+func fixTransferEncoding(header map[string]string) ([]string, os.Error) {
+ raw, present := header["Transfer-Encoding"]
+ if !present {
+ return nil, nil
+ }
+
+ header["Transfer-Encoding"] = "", false
+ encodings := strings.Split(raw, ",", -1)
+ te := make([]string, 0, len(encodings))
+ // TODO: Even though we only support "identity" and "chunked"
+ // encodings, the loop below is designed with foresight. One
+ // invariant that must be maintained is that, if present,
+ // chunked encoding must always come first.
+ for _, encoding := range encodings {
+ encoding = strings.ToLower(strings.TrimSpace(encoding))
+ // "identity" encoding is not recored
+ if encoding == "identity" {
+ break
+ }
+ if encoding != "chunked" {
+ return nil, &badStringError{"unsupported transfer encoding", encoding}
+ }
+ te = te[0 : len(te)+1]
+ te[len(te)-1] = encoding
+ }
+ if len(te) > 1 {
+ return nil, &badStringError{"too many transfer encodings", strings.Join(te, ",")}
+ }
+ if len(te) > 0 {
+ // Chunked encoding trumps Content-Length. See RFC 2616
+ // Section 4.4. Currently len(te) > 0 implies chunked
+ // encoding.
+ header["Content-Length"] = "", false
+ return te, nil
+ }
+
+ return nil, nil
+}
+
+// Determine the expected body length, using RFC 2616 Section 4.4. This
+// function is not a method, because ultimately it should be shared by
+// ReadResponse and ReadRequest.
+func fixLength(status int, requestMethod string, header map[string]string, te []string) (int64, os.Error) {
+
+ // Logic based on response type or status
+ if noBodyExpected(requestMethod) {
+ return 0, nil
+ }
+ if status/100 == 1 {
+ return 0, nil
+ }
+ switch status {
+ case 204, 304:
+ return 0, nil
+ }
+
+ // Logic based on Transfer-Encoding
+ if chunked(te) {
+ return -1, nil
+ }
+
+ // Logic based on Content-Length
+ if cl, present := header["Content-Length"]; present {
+ cl = strings.TrimSpace(cl)
+ if cl != "" {
+ n, err := strconv.Atoi64(cl)
+ if err != nil || n < 0 {
+ return -1, &badStringError{"bad Content-Length", cl}
+ }
+ return n, nil
+ } else {
+ header["Content-Length"] = "", false
+ }
+ }
+
+ // Logic based on media type. The purpose of the following code is just
+ // to detect whether the unsupported "multipart/byteranges" is being
+ // used. A proper Content-Type parser is needed in the future.
+ if strings.Contains(strings.ToLower(header["Content-Type"]), "multipart/byteranges") {
+ return -1, ErrNotSupported
+ }
+
+ // Body-EOF logic based on other methods (like closing, or chunked coding)
+ return -1, nil
+}
+
+// Determine whether to hang up after sending a request and body, or
+// receiving a response and body
+// 'header' is the request headers
+func shouldClose(major, minor int, header map[string]string) bool {
+ if major < 1 {
+ return true
+ } else if major == 1 && minor == 0 {
+ v, present := header["Connection"]
+ if !present {
+ return true
+ }
+ v = strings.ToLower(v)
+ if !strings.Contains(v, "keep-alive") {
+ return true
+ }
+ return false
+ } else if v, present := header["Connection"]; present {
+ // TODO: Should split on commas, toss surrounding white space,
+ // and check each field.
+ if v == "close" {
+ header["Connection"] = "", false
+ return true
+ }
+ }
+ return false
+}
+
+// Parse the trailer header
+func fixTrailer(header map[string]string, te []string) (map[string]string, os.Error) {
+ raw, present := header["Trailer"]
+ if !present {
+ return nil, nil
+ }
+
+ header["Trailer"] = "", false
+ trailer := make(map[string]string)
+ keys := strings.Split(raw, ",", -1)
+ for _, key := range keys {
+ key = CanonicalHeaderKey(strings.TrimSpace(key))
+ switch key {
+ case "Transfer-Encoding", "Trailer", "Content-Length":
+ return nil, &badStringError{"bad trailer key", key}
+ }
+ trailer[key] = ""
+ }
+ if len(trailer) == 0 {
+ return nil, nil
+ }
+ if !chunked(te) {
+ // Trailer and no chunking
+ return nil, ErrUnexpectedTrailer
+ }
+ return trailer, nil
+}
+
+// body turns a Reader into a ReadCloser.
+// Close ensures that the body has been fully read
+// and then reads the trailer if necessary.
+type body struct {
+ io.Reader
+ hdr interface{} // non-nil (Response or Request) value means read trailer
+ r *bufio.Reader // underlying wire-format reader for the trailer
+ closing bool // is the connection to be closed after reading body?
+}
+
+func (b *body) Close() os.Error {
+ if b.hdr == nil && b.closing {
+ // no trailer and closing the connection next.
+ // no point in reading to EOF.
+ return nil
+ }
+
+ trashBuf := make([]byte, 1024) // local for thread safety
+ for {
+ _, err := b.Read(trashBuf)
+ if err == nil {
+ continue
+ }
+ if err == os.EOF {
+ break
+ }
+ return err
+ }
+ if b.hdr == nil { // not reading trailer
+ return nil
+ }
+
+ // TODO(petar): Put trailer reader code here
+
+ return nil
+}
diff --git a/libgo/go/http/url.go b/libgo/go/http/url.go
new file mode 100644
index 000000000..efd90d81e
--- /dev/null
+++ b/libgo/go/http/url.go
@@ -0,0 +1,595 @@
+// 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.
+
+// Parse URLs (actually URIs, but that seems overly pedantic).
+// RFC 3986
+
+package http
+
+import (
+ "os"
+ "strconv"
+ "strings"
+)
+
+// URLError reports an error and the operation and URL that caused it.
+type URLError struct {
+ Op string
+ URL string
+ Error os.Error
+}
+
+func (e *URLError) String() string { return e.Op + " " + e.URL + ": " + e.Error.String() }
+
+func ishex(c byte) bool {
+ switch {
+ case '0' <= c && c <= '9':
+ return true
+ case 'a' <= c && c <= 'f':
+ return true
+ case 'A' <= c && c <= 'F':
+ return true
+ }
+ return false
+}
+
+func unhex(c byte) byte {
+ switch {
+ case '0' <= c && c <= '9':
+ return c - '0'
+ case 'a' <= c && c <= 'f':
+ return c - 'a' + 10
+ case 'A' <= c && c <= 'F':
+ return c - 'A' + 10
+ }
+ return 0
+}
+
+type encoding int
+
+const (
+ encodePath encoding = 1 + iota
+ encodeUserPassword
+ encodeQueryComponent
+ encodeFragment
+ encodeOpaque
+)
+
+
+type URLEscapeError string
+
+func (e URLEscapeError) String() string {
+ return "invalid URL escape " + strconv.Quote(string(e))
+}
+
+// Return true if the specified character should be escaped when
+// appearing in a URL string, according to RFC 2396.
+// When 'all' is true the full range of reserved characters are matched.
+func shouldEscape(c byte, mode encoding) bool {
+ // RFC 2396 §2.3 Unreserved characters (alphanum)
+ if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
+ return false
+ }
+ switch c {
+ case '-', '_', '.', '!', '~', '*', '\'', '(', ')': // §2.3 Unreserved characters (mark)
+ return false
+
+ case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved)
+ // Different sections of the URL allow a few of
+ // the reserved characters to appear unescaped.
+ switch mode {
+ case encodePath: // §3.3
+ // The RFC allows : @ & = + $ , but saves / ; for assigning
+ // meaning to individual path segments. This package
+ // only manipulates the path as a whole, so we allow those
+ // last two as well. Clients that need to distinguish between
+ // `/foo;y=z/bar` and `/foo%3by=z/bar` will have to re-decode RawPath.
+ // That leaves only ? to escape.
+ return c == '?'
+
+ case encodeUserPassword: // §3.2.2
+ // The RFC allows ; : & = + $ , in userinfo, so we must escape only @ and /.
+ // The parsing of userinfo treats : as special so we must escape that too.
+ return c == '@' || c == '/' || c == ':'
+
+ case encodeQueryComponent: // §3.4
+ // The RFC reserves (so we must escape) everything.
+ return true
+
+ case encodeFragment: // §4.1
+ // The RFC text is silent but the grammar allows
+ // everything, so escape nothing.
+ return false
+
+ case encodeOpaque: // §3 opaque_part
+ // The RFC allows opaque_part to use all characters
+ // except that the leading / must be escaped.
+ // (We implement that case in String.)
+ return false
+ }
+ }
+
+ // Everything else must be escaped.
+ return true
+}
+
+
+// URLUnescape unescapes a string in ``URL encoded'' form,
+// converting %AB into the byte 0xAB and '+' into ' ' (space).
+// It returns an error if any % is not followed
+// by two hexadecimal digits.
+// Despite the name, this encoding applies only to individual
+// components of the query portion of the URL.
+func URLUnescape(s string) (string, os.Error) {
+ return urlUnescape(s, encodeQueryComponent)
+}
+
+// urlUnescape is like URLUnescape but mode specifies
+// which section of the URL is being unescaped.
+func urlUnescape(s string, mode encoding) (string, os.Error) {
+ // Count %, check that they're well-formed.
+ n := 0
+ hasPlus := false
+ for i := 0; i < len(s); {
+ switch s[i] {
+ case '%':
+ n++
+ if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
+ s = s[i:]
+ if len(s) > 3 {
+ s = s[0:3]
+ }
+ return "", URLEscapeError(s)
+ }
+ i += 3
+ case '+':
+ hasPlus = mode == encodeQueryComponent
+ i++
+ default:
+ i++
+ }
+ }
+
+ if n == 0 && !hasPlus {
+ return s, nil
+ }
+
+ t := make([]byte, len(s)-2*n)
+ j := 0
+ for i := 0; i < len(s); {
+ switch s[i] {
+ case '%':
+ t[j] = unhex(s[i+1])<<4 | unhex(s[i+2])
+ j++
+ i += 3
+ case '+':
+ if mode == encodeQueryComponent {
+ t[j] = ' '
+ } else {
+ t[j] = '+'
+ }
+ j++
+ i++
+ default:
+ t[j] = s[i]
+ j++
+ i++
+ }
+ }
+ return string(t), nil
+}
+
+// URLEscape converts a string into ``URL encoded'' form.
+// Despite the name, this encoding applies only to individual
+// components of the query portion of the URL.
+func URLEscape(s string) string {
+ return urlEscape(s, encodeQueryComponent)
+}
+
+func urlEscape(s string, mode encoding) string {
+ spaceCount, hexCount := 0, 0
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if shouldEscape(c, mode) {
+ if c == ' ' && mode == encodeQueryComponent {
+ spaceCount++
+ } else {
+ hexCount++
+ }
+ }
+ }
+
+ if spaceCount == 0 && hexCount == 0 {
+ return s
+ }
+
+ t := make([]byte, len(s)+2*hexCount)
+ j := 0
+ for i := 0; i < len(s); i++ {
+ switch c := s[i]; {
+ case c == ' ' && mode == encodeQueryComponent:
+ t[j] = '+'
+ j++
+ case shouldEscape(c, mode):
+ t[j] = '%'
+ t[j+1] = "0123456789abcdef"[c>>4]
+ t[j+2] = "0123456789abcdef"[c&15]
+ j += 3
+ default:
+ t[j] = s[i]
+ j++
+ }
+ }
+ return string(t)
+}
+
+// UnescapeUserinfo parses the RawUserinfo field of a URL
+// as the form user or user:password and unescapes and returns
+// the two halves.
+//
+// This functionality should only be used with legacy web sites.
+// RFC 2396 warns that interpreting Userinfo this way
+// ``is NOT RECOMMENDED, because the passing of authentication
+// information in clear text (such as URI) has proven to be a
+// security risk in almost every case where it has been used.''
+func UnescapeUserinfo(rawUserinfo string) (user, password string, err os.Error) {
+ u, p := split(rawUserinfo, ':', true)
+ if user, err = urlUnescape(u, encodeUserPassword); err != nil {
+ return "", "", err
+ }
+ if password, err = urlUnescape(p, encodeUserPassword); err != nil {
+ return "", "", err
+ }
+ return
+}
+
+// EscapeUserinfo combines user and password in the form
+// user:password (or just user if password is empty) and then
+// escapes it for use as the URL.RawUserinfo field.
+//
+// This functionality should only be used with legacy web sites.
+// RFC 2396 warns that interpreting Userinfo this way
+// ``is NOT RECOMMENDED, because the passing of authentication
+// information in clear text (such as URI) has proven to be a
+// security risk in almost every case where it has been used.''
+func EscapeUserinfo(user, password string) string {
+ raw := urlEscape(user, encodeUserPassword)
+ if password != "" {
+ raw += ":" + urlEscape(password, encodeUserPassword)
+ }
+ return raw
+}
+
+// A URL represents a parsed URL (technically, a URI reference).
+// The general form represented is:
+// scheme://[userinfo@]host/path[?query][#fragment]
+// The Raw, RawAuthority, RawPath, and RawQuery fields are in "wire format"
+// (special characters must be hex-escaped if not meant to have special meaning).
+// All other fields are logical values; '+' or '%' represent themselves.
+//
+// The various Raw values are supplied in wire format because
+// clients typically have to split them into pieces before further
+// decoding.
+type URL struct {
+ Raw string // the original string
+ Scheme string // scheme
+ RawAuthority string // [userinfo@]host
+ RawUserinfo string // userinfo
+ Host string // host
+ RawPath string // /path[?query][#fragment]
+ Path string // /path
+ OpaquePath bool // path is opaque (unrooted when scheme is present)
+ RawQuery string // query
+ Fragment string // fragment
+}
+
+// Maybe rawurl is of the form scheme:path.
+// (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*)
+// If so, return scheme, path; else return "", rawurl.
+func getscheme(rawurl string) (scheme, path string, err os.Error) {
+ for i := 0; i < len(rawurl); i++ {
+ c := rawurl[i]
+ switch {
+ case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
+ // do nothing
+ case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
+ if i == 0 {
+ return "", rawurl, nil
+ }
+ case c == ':':
+ if i == 0 {
+ return "", "", os.ErrorString("missing protocol scheme")
+ }
+ return rawurl[0:i], rawurl[i+1:], nil
+ default:
+ // we have encountered an invalid character,
+ // so there is no valid scheme
+ return "", rawurl, nil
+ }
+ }
+ return "", rawurl, nil
+}
+
+// Maybe s is of the form t c u.
+// If so, return t, c u (or t, u if cutc == true).
+// If not, return s, "".
+func split(s string, c byte, cutc bool) (string, string) {
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ if cutc {
+ return s[0:i], s[i+1:]
+ }
+ return s[0:i], s[i:]
+ }
+ }
+ return s, ""
+}
+
+// ParseURL parses rawurl into a URL structure.
+// The string rawurl is assumed not to have a #fragment suffix.
+// (Web browsers strip #fragment before sending the URL to a web server.)
+// The rawurl may be relative or absolute.
+func ParseURL(rawurl string) (url *URL, err os.Error) {
+ return parseURL(rawurl, false)
+}
+
+// ParseRequestURL parses rawurl into a URL structure. It assumes that
+// rawurl was received from an HTTP request, so the rawurl is interpreted
+// only as an absolute URI or an absolute path.
+// The string rawurl is assumed not to have a #fragment suffix.
+// (Web browsers strip #fragment before sending the URL to a web server.)
+func ParseRequestURL(rawurl string) (url *URL, err os.Error) {
+ return parseURL(rawurl, true)
+}
+
+// parseURL parses a URL from a string in one of two contexts. If
+// viaRequest is true, the URL is assumed to have arrived via an HTTP request,
+// 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) {
+ if rawurl == "" {
+ err = os.ErrorString("empty url")
+ goto Error
+ }
+ url = new(URL)
+ url.Raw = rawurl
+
+ // 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, "/")
+
+ if url.Scheme != "" && !leadingSlash {
+ // RFC 2396:
+ // Absolute URI (has scheme) with non-rooted path
+ // is uninterpreted. It doesn't even have a ?query.
+ // This is the case that handles mailto:name@example.com.
+ url.RawPath = path
+
+ if url.Path, err = urlUnescape(path, encodeOpaque); err != nil {
+ goto Error
+ }
+ url.OpaquePath = true
+ } else {
+ if viaRequest && !leadingSlash {
+ err = os.ErrorString("invalid URI for request")
+ goto Error
+ }
+
+ // Split off query before parsing path further.
+ url.RawPath = path
+ path, query := split(path, '?', false)
+ if len(query) > 1 {
+ url.RawQuery = query[1:]
+ }
+
+ // Maybe path is //authority/path
+ if (url.Scheme != "" || !viaRequest) &&
+ strings.HasPrefix(path, "//") && !strings.HasPrefix(path, "///") {
+ url.RawAuthority, path = split(path[2:], '/', false)
+ url.RawPath = url.RawPath[2+len(url.RawAuthority):]
+ }
+
+ // Split authority into userinfo@host.
+ // If there's no @, split's default is wrong. Check explicitly.
+ var rawHost string
+ if strings.Index(url.RawAuthority, "@") < 0 {
+ rawHost = url.RawAuthority
+ } else {
+ url.RawUserinfo, rawHost = split(url.RawAuthority, '@', true)
+ }
+
+ // We leave RawAuthority only in raw form because clients
+ // of common protocols should be using Userinfo and Host
+ // instead. Clients that wish to use RawAuthority will have to
+ // interpret it themselves: RFC 2396 does not define the meaning.
+
+ if strings.Contains(rawHost, "%") {
+ // Host cannot contain escaped characters.
+ err = os.ErrorString("hexadecimal escape in host")
+ goto Error
+ }
+ url.Host = rawHost
+
+ if url.Path, err = urlUnescape(path, encodePath); err != nil {
+ goto Error
+ }
+ }
+ return url, nil
+
+Error:
+ return nil, &URLError{"parse", rawurl, err}
+
+}
+
+// ParseURLReference is like ParseURL but allows a trailing #fragment.
+func ParseURLReference(rawurlref string) (url *URL, err os.Error) {
+ // Cut off #frag.
+ rawurl, frag := split(rawurlref, '#', false)
+ if url, err = ParseURL(rawurl); err != nil {
+ return nil, err
+ }
+ url.Raw += frag
+ url.RawPath += frag
+ if len(frag) > 1 {
+ frag = frag[1:]
+ if url.Fragment, err = urlUnescape(frag, encodeFragment); err != nil {
+ return nil, &URLError{"parse", rawurl, err}
+ }
+ }
+ return url, nil
+}
+
+// String reassembles url into a valid URL string.
+//
+// There are redundant fields stored in the URL structure:
+// the String method consults Scheme, Path, Host, RawUserinfo,
+// RawQuery, and Fragment, but not Raw, RawPath or Authority.
+func (url *URL) String() string {
+ result := ""
+ if url.Scheme != "" {
+ result += url.Scheme + ":"
+ }
+ if url.Host != "" || url.RawUserinfo != "" {
+ result += "//"
+ if url.RawUserinfo != "" {
+ // hide the password, if any
+ info := url.RawUserinfo
+ if i := strings.Index(info, ":"); i >= 0 {
+ info = info[0:i] + ":******"
+ }
+ result += info + "@"
+ }
+ result += url.Host
+ }
+ if url.OpaquePath {
+ path := url.Path
+ if strings.HasPrefix(path, "/") {
+ result += "%2f"
+ path = path[1:]
+ }
+ result += urlEscape(path, encodeOpaque)
+ } else {
+ result += urlEscape(url.Path, encodePath)
+ }
+ if url.RawQuery != "" {
+ result += "?" + url.RawQuery
+ }
+ if url.Fragment != "" {
+ result += "#" + urlEscape(url.Fragment, encodeFragment)
+ }
+ return result
+}
+
+// EncodeQuery encodes the query represented as a multimap.
+func EncodeQuery(m map[string][]string) string {
+ parts := make([]string, 0, len(m)) // will be large enough for most uses
+ for k, vs := range m {
+ prefix := URLEscape(k) + "="
+ for _, v := range vs {
+ parts = append(parts, prefix+URLEscape(v))
+ }
+ }
+ return strings.Join(parts, "&")
+}
+
+// resolvePath applies special path segments from refs and applies
+// them to base, per RFC 2396.
+func resolvePath(basepath string, refpath string) string {
+ base := strings.Split(basepath, "/", -1)
+ refs := strings.Split(refpath, "/", -1)
+ if len(base) == 0 {
+ base = []string{""}
+ }
+ for idx, ref := range refs {
+ switch {
+ case ref == ".":
+ base[len(base)-1] = ""
+ case ref == "..":
+ newLen := len(base) - 1
+ if newLen < 1 {
+ newLen = 1
+ }
+ base = base[0:newLen]
+ base[len(base)-1] = ""
+ default:
+ if idx == 0 || base[len(base)-1] == "" {
+ base[len(base)-1] = ref
+ } else {
+ base = append(base, ref)
+ }
+ }
+ }
+ return strings.Join(base, "/")
+}
+
+// IsAbs returns true if the URL is absolute.
+func (url *URL) IsAbs() bool {
+ return url.Scheme != ""
+}
+
+// ParseURL parses a URL in the context of a base URL. The URL in ref
+// may be relative or absolute. ParseURL returns nil, err on parse
+// failure, otherwise its return value is the same as ResolveReference.
+func (base *URL) ParseURL(ref string) (*URL, os.Error) {
+ refurl, err := ParseURL(ref)
+ if err != nil {
+ return nil, err
+ }
+ return base.ResolveReference(refurl), nil
+}
+
+// ResolveReference resolves a URI reference to an absolute URI from
+// an absolute base URI, per RFC 2396 Section 5.2. The URI reference
+// may be relative or absolute. ResolveReference always returns a new
+// URL instance, even if the returned URL is identical to either the
+// base or reference. If ref is an absolute URL, then ResolveReference
+// ignores base and returns a copy of ref.
+func (base *URL) ResolveReference(ref *URL) *URL {
+ url := new(URL)
+ switch {
+ case ref.IsAbs():
+ *url = *ref
+ default:
+ // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ *url = *base
+ if ref.RawAuthority != "" {
+ // The "net_path" case.
+ url.RawAuthority = ref.RawAuthority
+ url.Host = ref.Host
+ url.RawUserinfo = ref.RawUserinfo
+ }
+ switch {
+ case url.OpaquePath:
+ url.Path = ref.Path
+ url.RawPath = ref.RawPath
+ url.RawQuery = ref.RawQuery
+ case strings.HasPrefix(ref.Path, "/"):
+ // The "abs_path" case.
+ url.Path = ref.Path
+ url.RawPath = ref.RawPath
+ url.RawQuery = ref.RawQuery
+ default:
+ // The "rel_path" case.
+ path := resolvePath(base.Path, ref.Path)
+ if !strings.HasPrefix(path, "/") {
+ path = "/" + path
+ }
+ url.Path = path
+ url.RawPath = url.Path
+ url.RawQuery = ref.RawQuery
+ if ref.RawQuery != "" {
+ url.RawPath += "?" + url.RawQuery
+ }
+ }
+
+ url.Fragment = ref.Fragment
+ }
+ url.Raw = url.String()
+ return url
+}
diff --git a/libgo/go/http/url_test.go b/libgo/go/http/url_test.go
new file mode 100644
index 000000000..0801f7ff3
--- /dev/null
+++ b/libgo/go/http/url_test.go
@@ -0,0 +1,675 @@
+// 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 http
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "testing"
+)
+
+// TODO(rsc):
+// test URLUnescape
+// test URLEscape
+// test ParseURL
+
+type URLTest struct {
+ in string
+ out *URL
+ roundtrip string // expected result of reserializing the URL; empty means same as "in".
+}
+
+var urltests = []URLTest{
+ // no path
+ {
+ "http://www.google.com",
+ &URL{
+ Raw: "http://www.google.com",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ },
+ "",
+ },
+ // path
+ {
+ "http://www.google.com/",
+ &URL{
+ Raw: "http://www.google.com/",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/",
+ Path: "/",
+ },
+ "",
+ },
+ // path with hex escaping
+ {
+ "http://www.google.com/file%20one%26two",
+ &URL{
+ Raw: "http://www.google.com/file%20one%26two",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/file%20one%26two",
+ Path: "/file one&two",
+ },
+ "http://www.google.com/file%20one&two",
+ },
+ // user
+ {
+ "ftp://webmaster@www.google.com/",
+ &URL{
+ Raw: "ftp://webmaster@www.google.com/",
+ Scheme: "ftp",
+ RawAuthority: "webmaster@www.google.com",
+ RawUserinfo: "webmaster",
+ Host: "www.google.com",
+ RawPath: "/",
+ Path: "/",
+ },
+ "",
+ },
+ // escape sequence in username
+ {
+ "ftp://john%20doe@www.google.com/",
+ &URL{
+ Raw: "ftp://john%20doe@www.google.com/",
+ Scheme: "ftp",
+ RawAuthority: "john%20doe@www.google.com",
+ RawUserinfo: "john%20doe",
+ Host: "www.google.com",
+ RawPath: "/",
+ Path: "/",
+ },
+ "ftp://john%20doe@www.google.com/",
+ },
+ // query
+ {
+ "http://www.google.com/?q=go+language",
+ &URL{
+ Raw: "http://www.google.com/?q=go+language",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go+language",
+ Path: "/",
+ RawQuery: "q=go+language",
+ },
+ "",
+ },
+ // query with hex escaping: NOT parsed
+ {
+ "http://www.google.com/?q=go%20language",
+ &URL{
+ Raw: "http://www.google.com/?q=go%20language",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go%20language",
+ Path: "/",
+ RawQuery: "q=go%20language",
+ },
+ "",
+ },
+ // %20 outside query
+ {
+ "http://www.google.com/a%20b?q=c+d",
+ &URL{
+ Raw: "http://www.google.com/a%20b?q=c+d",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/a%20b?q=c+d",
+ Path: "/a b",
+ RawQuery: "q=c+d",
+ },
+ "",
+ },
+ // path without leading /, so no query parsing
+ {
+ "http:www.google.com/?q=go+language",
+ &URL{
+ Raw: "http:www.google.com/?q=go+language",
+ Scheme: "http",
+ RawPath: "www.google.com/?q=go+language",
+ Path: "www.google.com/?q=go+language",
+ OpaquePath: true,
+ },
+ "http:www.google.com/?q=go+language",
+ },
+ // path without leading /, so no query parsing
+ {
+ "http:%2f%2fwww.google.com/?q=go+language",
+ &URL{
+ Raw: "http:%2f%2fwww.google.com/?q=go+language",
+ Scheme: "http",
+ RawPath: "%2f%2fwww.google.com/?q=go+language",
+ Path: "//www.google.com/?q=go+language",
+ OpaquePath: true,
+ },
+ "http:%2f/www.google.com/?q=go+language",
+ },
+ // non-authority
+ {
+ "mailto:/webmaster@golang.org",
+ &URL{
+ Raw: "mailto:/webmaster@golang.org",
+ Scheme: "mailto",
+ RawPath: "/webmaster@golang.org",
+ Path: "/webmaster@golang.org",
+ },
+ "",
+ },
+ // non-authority
+ {
+ "mailto:webmaster@golang.org",
+ &URL{
+ Raw: "mailto:webmaster@golang.org",
+ Scheme: "mailto",
+ RawPath: "webmaster@golang.org",
+ Path: "webmaster@golang.org",
+ OpaquePath: true,
+ },
+ "",
+ },
+ // unescaped :// in query should not create a scheme
+ {
+ "/foo?query=http://bad",
+ &URL{
+ Raw: "/foo?query=http://bad",
+ RawPath: "/foo?query=http://bad",
+ Path: "/foo",
+ RawQuery: "query=http://bad",
+ },
+ "",
+ },
+ // leading // without scheme should create an authority
+ {
+ "//foo",
+ &URL{
+ RawAuthority: "foo",
+ Raw: "//foo",
+ Host: "foo",
+ Scheme: "",
+ RawPath: "",
+ Path: "",
+ },
+ "",
+ },
+ // leading // without scheme, with userinfo, path, and query
+ {
+ "//user@foo/path?a=b",
+ &URL{
+ Raw: "//user@foo/path?a=b",
+ RawAuthority: "user@foo",
+ RawUserinfo: "user",
+ Scheme: "",
+ RawPath: "/path?a=b",
+ Path: "/path",
+ RawQuery: "a=b",
+ Host: "foo",
+ },
+ "",
+ },
+ // Three leading slashes isn't an authority, but doesn't return an error.
+ // (We can't return an error, as this code is also used via
+ // ServeHTTP -> ReadRequest -> ParseURL, which is arguably a
+ // different URL parsing context, but currently shares the
+ // same codepath)
+ {
+ "///threeslashes",
+ &URL{
+ RawAuthority: "",
+ Raw: "///threeslashes",
+ Host: "",
+ Scheme: "",
+ RawPath: "///threeslashes",
+ Path: "///threeslashes",
+ },
+ "",
+ },
+ {
+ "http://user:password@google.com",
+ &URL{
+ Raw: "http://user:password@google.com",
+ Scheme: "http",
+ RawAuthority: "user:password@google.com",
+ RawUserinfo: "user:password",
+ Host: "google.com",
+ },
+ "http://user:******@google.com",
+ },
+ {
+ "http://user:longerpass@google.com",
+ &URL{
+ Raw: "http://user:longerpass@google.com",
+ Scheme: "http",
+ RawAuthority: "user:longerpass@google.com",
+ RawUserinfo: "user:longerpass",
+ Host: "google.com",
+ },
+ "http://user:******@google.com",
+ },
+}
+
+var urlnofragtests = []URLTest{
+ {
+ "http://www.google.com/?q=go+language#foo",
+ &URL{
+ Raw: "http://www.google.com/?q=go+language#foo",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go+language#foo",
+ Path: "/",
+ RawQuery: "q=go+language#foo",
+ },
+ "",
+ },
+}
+
+var urlfragtests = []URLTest{
+ {
+ "http://www.google.com/?q=go+language#foo",
+ &URL{
+ Raw: "http://www.google.com/?q=go+language#foo",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go+language#foo",
+ Path: "/",
+ RawQuery: "q=go+language",
+ Fragment: "foo",
+ },
+ "",
+ },
+ {
+ "http://www.google.com/?q=go+language#foo%26bar",
+ &URL{
+ Raw: "http://www.google.com/?q=go+language#foo%26bar",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go+language#foo%26bar",
+ Path: "/",
+ RawQuery: "q=go+language",
+ Fragment: "foo&bar",
+ },
+ "http://www.google.com/?q=go+language#foo&bar",
+ },
+}
+
+// more useful string for debugging than fmt's struct printer
+func ufmt(u *URL) string {
+ return fmt.Sprintf("raw=%q, scheme=%q, rawpath=%q, auth=%q, userinfo=%q, host=%q, path=%q, rawq=%q, frag=%q",
+ u.Raw, u.Scheme, u.RawPath, u.RawAuthority, u.RawUserinfo,
+ u.Host, u.Path, u.RawQuery, u.Fragment)
+}
+
+func DoTest(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) {
+ for _, tt := range tests {
+ u, err := parse(tt.in)
+ if err != nil {
+ t.Errorf("%s(%q) returned error %s", name, tt.in, err)
+ continue
+ }
+ if !reflect.DeepEqual(u, tt.out) {
+ t.Errorf("%s(%q):\n\thave %v\n\twant %v\n",
+ name, tt.in, ufmt(u), ufmt(tt.out))
+ }
+ }
+}
+
+func TestParseURL(t *testing.T) {
+ DoTest(t, ParseURL, "ParseURL", urltests)
+ DoTest(t, ParseURL, "ParseURL", urlnofragtests)
+}
+
+func TestParseURLReference(t *testing.T) {
+ DoTest(t, ParseURLReference, "ParseURLReference", urltests)
+ DoTest(t, ParseURLReference, "ParseURLReference", urlfragtests)
+}
+
+const pathThatLooksSchemeRelative = "//not.a.user@not.a.host/just/a/path"
+
+var parseRequestUrlTests = []struct {
+ url string
+ expectedValid bool
+}{
+ {"http://foo.com", true},
+ {"http://foo.com/", true},
+ {"http://foo.com/path", true},
+ {"/", true},
+ {pathThatLooksSchemeRelative, true},
+ {"//not.a.user@%66%6f%6f.com/just/a/path/also", true},
+ {"foo.html", false},
+ {"../dir/", false},
+}
+
+func TestParseRequestURL(t *testing.T) {
+ for _, test := range parseRequestUrlTests {
+ _, err := ParseRequestURL(test.url)
+ valid := err == nil
+ if valid != test.expectedValid {
+ t.Errorf("Expected valid=%v for %q; got %v", test.expectedValid, test.url, valid)
+ }
+ }
+
+ url, err := ParseRequestURL(pathThatLooksSchemeRelative)
+ if err != nil {
+ t.Fatalf("Unexpected error %v", err)
+ }
+ if url.Path != pathThatLooksSchemeRelative {
+ t.Errorf("Expected path %q; got %q", pathThatLooksSchemeRelative, url.Path)
+ }
+}
+
+func DoTestString(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) {
+ for _, tt := range tests {
+ u, err := parse(tt.in)
+ if err != nil {
+ t.Errorf("%s(%q) returned error %s", name, tt.in, err)
+ continue
+ }
+ s := u.String()
+ expected := tt.in
+ if len(tt.roundtrip) > 0 {
+ expected = tt.roundtrip
+ }
+ if s != expected {
+ t.Errorf("%s(%q).String() == %q (expected %q)", name, tt.in, s, expected)
+ }
+ }
+}
+
+func TestURLString(t *testing.T) {
+ DoTestString(t, ParseURL, "ParseURL", urltests)
+ DoTestString(t, ParseURL, "ParseURL", urlnofragtests)
+ DoTestString(t, ParseURLReference, "ParseURLReference", urltests)
+ DoTestString(t, ParseURLReference, "ParseURLReference", urlfragtests)
+}
+
+type URLEscapeTest struct {
+ in string
+ out string
+ err os.Error
+}
+
+var unescapeTests = []URLEscapeTest{
+ {
+ "",
+ "",
+ nil,
+ },
+ {
+ "abc",
+ "abc",
+ nil,
+ },
+ {
+ "1%41",
+ "1A",
+ nil,
+ },
+ {
+ "1%41%42%43",
+ "1ABC",
+ nil,
+ },
+ {
+ "%4a",
+ "J",
+ nil,
+ },
+ {
+ "%6F",
+ "o",
+ nil,
+ },
+ {
+ "%", // not enough characters after %
+ "",
+ URLEscapeError("%"),
+ },
+ {
+ "%a", // not enough characters after %
+ "",
+ URLEscapeError("%a"),
+ },
+ {
+ "%1", // not enough characters after %
+ "",
+ URLEscapeError("%1"),
+ },
+ {
+ "123%45%6", // not enough characters after %
+ "",
+ URLEscapeError("%6"),
+ },
+ {
+ "%zzzzz", // invalid hex digits
+ "",
+ URLEscapeError("%zz"),
+ },
+}
+
+func TestURLUnescape(t *testing.T) {
+ for _, tt := range unescapeTests {
+ actual, err := URLUnescape(tt.in)
+ if actual != tt.out || (err != nil) != (tt.err != nil) {
+ t.Errorf("URLUnescape(%q) = %q, %s; want %q, %s", tt.in, actual, err, tt.out, tt.err)
+ }
+ }
+}
+
+var escapeTests = []URLEscapeTest{
+ {
+ "",
+ "",
+ nil,
+ },
+ {
+ "abc",
+ "abc",
+ nil,
+ },
+ {
+ "one two",
+ "one+two",
+ nil,
+ },
+ {
+ "10%",
+ "10%25",
+ nil,
+ },
+ {
+ " ?&=#+%!<>#\"{}|\\^[]`☺\t",
+ "+%3f%26%3d%23%2b%25!%3c%3e%23%22%7b%7d%7c%5c%5e%5b%5d%60%e2%98%ba%09",
+ nil,
+ },
+}
+
+func TestURLEscape(t *testing.T) {
+ for _, tt := range escapeTests {
+ actual := URLEscape(tt.in)
+ if tt.out != actual {
+ t.Errorf("URLEscape(%q) = %q, want %q", tt.in, actual, tt.out)
+ }
+
+ // for bonus points, verify that escape:unescape is an identity.
+ roundtrip, err := URLUnescape(actual)
+ if roundtrip != tt.in || err != nil {
+ t.Errorf("URLUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]")
+ }
+ }
+}
+
+type UserinfoTest struct {
+ User string
+ Password string
+ Raw string
+}
+
+var userinfoTests = []UserinfoTest{
+ {"user", "password", "user:password"},
+ {"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./",
+ "foo%3abar:~!%40%23$%25%5e&*()_+%7b%7d%7c%5b%5d%5c-=%60%3a;'%22%3c%3e?,.%2f"},
+}
+
+func TestEscapeUserinfo(t *testing.T) {
+ for _, tt := range userinfoTests {
+ if raw := EscapeUserinfo(tt.User, tt.Password); raw != tt.Raw {
+ t.Errorf("EscapeUserinfo(%q, %q) = %q, want %q", tt.User, tt.Password, raw, tt.Raw)
+ }
+ }
+}
+
+func TestUnescapeUserinfo(t *testing.T) {
+ for _, tt := range userinfoTests {
+ if user, pass, err := UnescapeUserinfo(tt.Raw); user != tt.User || pass != tt.Password || err != nil {
+ t.Errorf("UnescapeUserinfo(%q) = %q, %q, %v, want %q, %q, nil", tt.Raw, user, pass, err, tt.User, tt.Password)
+ }
+ }
+}
+
+type qMap map[string][]string
+
+type EncodeQueryTest struct {
+ m qMap
+ expected string
+ expected1 string
+}
+
+var encodeQueryTests = []EncodeQueryTest{
+ {nil, "", ""},
+ {qMap{"q": {"puppies"}, "oe": {"utf8"}}, "q=puppies&oe=utf8", "oe=utf8&q=puppies"},
+ {qMap{"q": {"dogs", "&", "7"}}, "q=dogs&q=%26&q=7", "q=dogs&q=%26&q=7"},
+}
+
+func TestEncodeQuery(t *testing.T) {
+ for _, tt := range encodeQueryTests {
+ if q := EncodeQuery(tt.m); q != tt.expected && q != tt.expected1 {
+ t.Errorf(`EncodeQuery(%+v) = %q, want %q`, tt.m, q, tt.expected)
+ }
+ }
+}
+
+var resolvePathTests = []struct {
+ base, ref, expected string
+}{
+ {"a/b", ".", "a/"},
+ {"a/b", "c", "a/c"},
+ {"a/b", "..", ""},
+ {"a/", "..", ""},
+ {"a/", "../..", ""},
+ {"a/b/c", "..", "a/"},
+ {"a/b/c", "../d", "a/d"},
+ {"a/b/c", ".././d", "a/d"},
+ {"a/b", "./..", ""},
+ {"a/./b", ".", "a/./"},
+ {"a/../", ".", "a/../"},
+ {"a/.././b", "c", "a/.././c"},
+}
+
+func TestResolvePath(t *testing.T) {
+ for _, test := range resolvePathTests {
+ got := resolvePath(test.base, test.ref)
+ if got != test.expected {
+ t.Errorf("For %q + %q got %q; expected %q", test.base, test.ref, got, test.expected)
+ }
+ }
+}
+
+var resolveReferenceTests = []struct {
+ base, rel, expected string
+}{
+ // Absolute URL references
+ {"http://foo.com?a=b", "https://bar.com/", "https://bar.com/"},
+ {"http://foo.com/", "https://bar.com/?a=b", "https://bar.com/?a=b"},
+ {"http://foo.com/bar", "mailto:foo@example.com", "mailto:foo@example.com"},
+
+ // Path-absolute references
+ {"http://foo.com/bar", "/baz", "http://foo.com/baz"},
+ {"http://foo.com/bar?a=b#f", "/baz", "http://foo.com/baz"},
+ {"http://foo.com/bar?a=b", "/baz?c=d", "http://foo.com/baz?c=d"},
+
+ // Scheme-relative
+ {"https://foo.com/bar?a=b", "//bar.com/quux", "https://bar.com/quux"},
+
+ // Path-relative references:
+
+ // ... current directory
+ {"http://foo.com", ".", "http://foo.com/"},
+ {"http://foo.com/bar", ".", "http://foo.com/"},
+ {"http://foo.com/bar/", ".", "http://foo.com/bar/"},
+
+ // ... going down
+ {"http://foo.com", "bar", "http://foo.com/bar"},
+ {"http://foo.com/", "bar", "http://foo.com/bar"},
+ {"http://foo.com/bar/baz", "quux", "http://foo.com/bar/quux"},
+
+ // ... going up
+ {"http://foo.com/bar/baz", "../quux", "http://foo.com/quux"},
+ {"http://foo.com/bar/baz", "../../../../../quux", "http://foo.com/quux"},
+ {"http://foo.com/bar", "..", "http://foo.com/"},
+ {"http://foo.com/bar/baz", "./..", "http://foo.com/"},
+
+ // "." and ".." in the base aren't special
+ {"http://foo.com/dot/./dotdot/../foo/bar", "../baz", "http://foo.com/dot/./dotdot/../baz"},
+
+ // Triple dot isn't special
+ {"http://foo.com/bar", "...", "http://foo.com/..."},
+
+ // Fragment
+ {"http://foo.com/bar", ".#frag", "http://foo.com/#frag"},
+}
+
+func TestResolveReference(t *testing.T) {
+ mustParseURL := func(url string) *URL {
+ u, err := ParseURLReference(url)
+ if err != nil {
+ t.Fatalf("Expected URL to parse: %q, got error: %v", url, err)
+ }
+ return u
+ }
+ for _, test := range resolveReferenceTests {
+ base := mustParseURL(test.base)
+ rel := mustParseURL(test.rel)
+ url := base.ResolveReference(rel)
+ urlStr := url.String()
+ if urlStr != test.expected {
+ t.Errorf("Resolving %q + %q != %q; got %q", test.base, test.rel, test.expected, urlStr)
+ }
+ }
+
+ // Test that new instances are returned.
+ base := mustParseURL("http://foo.com/")
+ abs := base.ResolveReference(mustParseURL("."))
+ if base == abs {
+ t.Errorf("Expected no-op reference to return new URL instance.")
+ }
+ barRef := mustParseURL("http://bar.com/")
+ abs = base.ResolveReference(barRef)
+ if abs == barRef {
+ t.Errorf("Expected resolution of absolute reference to return new URL instance.")
+ }
+
+ // Test the convenience wrapper too
+ base = mustParseURL("http://foo.com/path/one/")
+ abs, _ = base.ParseURL("../two")
+ expected := "http://foo.com/path/two"
+ if abs.String() != expected {
+ t.Errorf("ParseURL wrapper got %q; expected %q", abs.String(), expected)
+ }
+ _, err := base.ParseURL("")
+ if err == nil {
+ t.Errorf("Expected an error from ParseURL wrapper parsing an empty string.")
+ }
+
+}
diff --git a/libgo/go/image/color.go b/libgo/go/image/color.go
new file mode 100644
index 000000000..c1345c025
--- /dev/null
+++ b/libgo/go/image/color.go
@@ -0,0 +1,251 @@
+// 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 image
+
+// All Colors can convert themselves, with a possible loss of precision,
+// to 64-bit alpha-premultiplied RGBA. Each channel value ranges within
+// [0, 0xFFFF].
+type Color interface {
+ RGBA() (r, g, b, a uint32)
+}
+
+// An RGBAColor represents a traditional 32-bit alpha-premultiplied color,
+// having 8 bits for each of red, green, blue and alpha.
+type RGBAColor struct {
+ R, G, B, A uint8
+}
+
+func (c RGBAColor) RGBA() (r, g, b, a uint32) {
+ r = uint32(c.R)
+ r |= r << 8
+ g = uint32(c.G)
+ g |= g << 8
+ b = uint32(c.B)
+ b |= b << 8
+ a = uint32(c.A)
+ a |= a << 8
+ return
+}
+
+// An RGBA64Color represents a 64-bit alpha-premultiplied color,
+// having 16 bits for each of red, green, blue and alpha.
+type RGBA64Color struct {
+ R, G, B, A uint16
+}
+
+func (c RGBA64Color) RGBA() (r, g, b, a uint32) {
+ return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
+}
+
+// An NRGBAColor represents a non-alpha-premultiplied 32-bit color.
+type NRGBAColor struct {
+ R, G, B, A uint8
+}
+
+func (c NRGBAColor) RGBA() (r, g, b, a uint32) {
+ r = uint32(c.R)
+ r |= r << 8
+ r *= uint32(c.A)
+ r /= 0xff
+ g = uint32(c.G)
+ g |= g << 8
+ g *= uint32(c.A)
+ g /= 0xff
+ b = uint32(c.B)
+ b |= b << 8
+ b *= uint32(c.A)
+ b /= 0xff
+ a = uint32(c.A)
+ a |= a << 8
+ return
+}
+
+// An NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
+// having 16 bits for each of red, green, blue and alpha.
+type NRGBA64Color struct {
+ R, G, B, A uint16
+}
+
+func (c NRGBA64Color) RGBA() (r, g, b, a uint32) {
+ r = uint32(c.R)
+ r *= uint32(c.A)
+ r /= 0xffff
+ g = uint32(c.G)
+ g *= uint32(c.A)
+ g /= 0xffff
+ b = uint32(c.B)
+ b *= uint32(c.A)
+ b /= 0xffff
+ a = uint32(c.A)
+ return
+}
+
+// An AlphaColor represents an 8-bit alpha.
+type AlphaColor struct {
+ A uint8
+}
+
+func (c AlphaColor) RGBA() (r, g, b, a uint32) {
+ a = uint32(c.A)
+ a |= a << 8
+ return a, a, a, a
+}
+
+// An Alpha16Color represents a 16-bit alpha.
+type Alpha16Color struct {
+ A uint16
+}
+
+func (c Alpha16Color) RGBA() (r, g, b, a uint32) {
+ a = uint32(c.A)
+ return a, a, a, a
+}
+
+// A GrayColor represents an 8-bit grayscale color.
+type GrayColor struct {
+ Y uint8
+}
+
+func (c GrayColor) RGBA() (r, g, b, a uint32) {
+ y := uint32(c.Y)
+ y |= y << 8
+ return y, y, y, 0xffff
+}
+
+// A Gray16Color represents a 16-bit grayscale color.
+type Gray16Color struct {
+ Y uint16
+}
+
+func (c Gray16Color) RGBA() (r, g, b, a uint32) {
+ y := uint32(c.Y)
+ return y, y, y, 0xffff
+}
+
+// A ColorModel can convert foreign Colors, with a possible loss of precision,
+// to a Color from its own color model.
+type ColorModel interface {
+ Convert(c Color) Color
+}
+
+// The ColorModelFunc type is an adapter to allow the use of an ordinary
+// color conversion function as a ColorModel. If f is such a function,
+// ColorModelFunc(f) is a ColorModel object that invokes f to implement
+// the conversion.
+type ColorModelFunc func(Color) Color
+
+func (f ColorModelFunc) Convert(c Color) Color {
+ return f(c)
+}
+
+func toRGBAColor(c Color) Color {
+ if _, ok := c.(RGBAColor); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ return RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
+}
+
+func toRGBA64Color(c Color) Color {
+ if _, ok := c.(RGBA64Color); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ return RGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
+func toNRGBAColor(c Color) Color {
+ if _, ok := c.(NRGBAColor); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ if a == 0xffff {
+ return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff}
+ }
+ if a == 0 {
+ return NRGBAColor{0, 0, 0, 0}
+ }
+ // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
+ r = (r * 0xffff) / a
+ g = (g * 0xffff) / a
+ b = (b * 0xffff) / a
+ return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
+}
+
+func toNRGBA64Color(c Color) Color {
+ if _, ok := c.(NRGBA64Color); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ if a == 0xffff {
+ return NRGBA64Color{uint16(r), uint16(g), uint16(b), 0xffff}
+ }
+ if a == 0 {
+ return NRGBA64Color{0, 0, 0, 0}
+ }
+ // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
+ r = (r * 0xffff) / a
+ g = (g * 0xffff) / a
+ b = (b * 0xffff) / a
+ return NRGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
+func toAlphaColor(c Color) Color {
+ if _, ok := c.(AlphaColor); ok {
+ return c
+ }
+ _, _, _, a := c.RGBA()
+ return AlphaColor{uint8(a >> 8)}
+}
+
+func toAlpha16Color(c Color) Color {
+ if _, ok := c.(Alpha16Color); ok {
+ return c
+ }
+ _, _, _, a := c.RGBA()
+ return Alpha16Color{uint16(a)}
+}
+
+func toGrayColor(c Color) Color {
+ if _, ok := c.(GrayColor); ok {
+ return c
+ }
+ r, g, b, _ := c.RGBA()
+ y := (299*r + 587*g + 114*b + 500) / 1000
+ return GrayColor{uint8(y >> 8)}
+}
+
+func toGray16Color(c Color) Color {
+ if _, ok := c.(Gray16Color); ok {
+ return c
+ }
+ r, g, b, _ := c.RGBA()
+ y := (299*r + 587*g + 114*b + 500) / 1000
+ return Gray16Color{uint16(y)}
+}
+
+// The ColorModel associated with RGBAColor.
+var RGBAColorModel ColorModel = ColorModelFunc(toRGBAColor)
+
+// The ColorModel associated with RGBA64Color.
+var RGBA64ColorModel ColorModel = ColorModelFunc(toRGBA64Color)
+
+// The ColorModel associated with NRGBAColor.
+var NRGBAColorModel ColorModel = ColorModelFunc(toNRGBAColor)
+
+// The ColorModel associated with NRGBA64Color.
+var NRGBA64ColorModel ColorModel = ColorModelFunc(toNRGBA64Color)
+
+// The ColorModel associated with AlphaColor.
+var AlphaColorModel ColorModel = ColorModelFunc(toAlphaColor)
+
+// The ColorModel associated with Alpha16Color.
+var Alpha16ColorModel ColorModel = ColorModelFunc(toAlpha16Color)
+
+// The ColorModel associated with GrayColor.
+var GrayColorModel ColorModel = ColorModelFunc(toGrayColor)
+
+// The ColorModel associated with Gray16Color.
+var Gray16ColorModel ColorModel = ColorModelFunc(toGray16Color)
diff --git a/libgo/go/image/format.go b/libgo/go/image/format.go
new file mode 100644
index 000000000..1d541b094
--- /dev/null
+++ b/libgo/go/image/format.go
@@ -0,0 +1,86 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+import (
+ "bufio"
+ "io"
+ "os"
+)
+
+// An UnknownFormatErr indicates that decoding encountered an unknown format.
+var UnknownFormatErr = os.NewError("image: unknown format")
+
+// A format holds an image format's name, magic header and how to decode it.
+type format struct {
+ name, magic string
+ decode func(io.Reader) (Image, os.Error)
+ decodeConfig func(io.Reader) (Config, os.Error)
+}
+
+// Formats is the list of registered formats.
+var formats []format
+
+// RegisterFormat registers an image format for use by Decode.
+// Name is the name of the format, like "jpeg" or "png".
+// Magic is the magic prefix that identifies the format's encoding.
+// Decode is the function that decodes the encoded image.
+// DecodeConfig is the function that decodes just its configuration.
+func RegisterFormat(name, magic string, decode func(io.Reader) (Image, os.Error), decodeConfig func(io.Reader) (Config, os.Error)) {
+ formats = append(formats, format{name, magic, decode, decodeConfig})
+}
+
+// A reader is an io.Reader that can also peek ahead.
+type reader interface {
+ io.Reader
+ Peek(int) ([]byte, os.Error)
+}
+
+// AsReader converts an io.Reader to a reader.
+func asReader(r io.Reader) reader {
+ if rr, ok := r.(reader); ok {
+ return rr
+ }
+ return bufio.NewReader(r)
+}
+
+// sniff determines the format of r's data.
+func sniff(r reader) format {
+ for _, f := range formats {
+ s, err := r.Peek(len(f.magic))
+ if err == nil && string(s) == f.magic {
+ return f
+ }
+ }
+ return format{}
+}
+
+// Decode decodes an image that has been encoded in a registered format.
+// The string returned is the format name used during format registration.
+// Format registration is typically done by the init method of the codec-
+// specific package.
+func Decode(r io.Reader) (Image, string, os.Error) {
+ rr := asReader(r)
+ f := sniff(rr)
+ if f.decode == nil {
+ return nil, "", UnknownFormatErr
+ }
+ m, err := f.decode(rr)
+ return m, f.name, err
+}
+
+// DecodeConfig decodes the color model and dimensions of an image that has
+// been encoded in a registered format. The string returned is the format name
+// used during format registration. Format registration is typically done by
+// the init method of the codec-specific package.
+func DecodeConfig(r io.Reader) (Config, string, os.Error) {
+ rr := asReader(r)
+ f := sniff(rr)
+ if f.decodeConfig == nil {
+ return Config{}, "", UnknownFormatErr
+ }
+ c, err := f.decodeConfig(rr)
+ return c, f.name, err
+}
diff --git a/libgo/go/image/geom.go b/libgo/go/image/geom.go
new file mode 100644
index 000000000..ccfe9cdb0
--- /dev/null
+++ b/libgo/go/image/geom.go
@@ -0,0 +1,223 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+import (
+ "strconv"
+)
+
+// A Point is an X, Y coordinate pair. The axes increase right and down.
+type Point struct {
+ X, Y int
+}
+
+// String returns a string representation of p like "(3,4)".
+func (p Point) String() string {
+ return "(" + strconv.Itoa(p.X) + "," + strconv.Itoa(p.Y) + ")"
+}
+
+// Add returns the vector p+q.
+func (p Point) Add(q Point) Point {
+ return Point{p.X + q.X, p.Y + q.Y}
+}
+
+// Sub returns the vector p-q.
+func (p Point) Sub(q Point) Point {
+ return Point{p.X - q.X, p.Y - q.Y}
+}
+
+// Mul returns the vector p*k.
+func (p Point) Mul(k int) Point {
+ return Point{p.X * k, p.Y * k}
+}
+
+// Div returns the vector p/k.
+func (p Point) Div(k int) Point {
+ return Point{p.X / k, p.Y / k}
+}
+
+// Mod returns the point q in r such that p.X-q.X is a multiple of r's width
+// and p.Y-q.Y is a multiple of r's height.
+func (p Point) Mod(r Rectangle) Point {
+ w, h := r.Dx(), r.Dy()
+ p = p.Sub(r.Min)
+ p.X = p.X % w
+ if p.X < 0 {
+ p.X += w
+ }
+ p.Y = p.Y % h
+ if p.Y < 0 {
+ p.Y += h
+ }
+ return p.Add(r.Min)
+}
+
+// Eq returns whether p and q are equal.
+func (p Point) Eq(q Point) bool {
+ return p.X == q.X && p.Y == q.Y
+}
+
+// ZP is the zero Point.
+var ZP Point
+
+// Pt is shorthand for Point{X, Y}.
+func Pt(X, Y int) Point {
+ return Point{X, Y}
+}
+
+// A Rectangle contains the points with Min.X <= X < Max.X, Min.Y <= Y < Max.Y.
+// It is well-formed if Min.X <= Max.X and likewise for Y. Points are always
+// well-formed. A rectangle's methods always return well-formed outputs for
+// well-formed inputs.
+type Rectangle struct {
+ Min, Max Point
+}
+
+// String returns a string representation of r like "(3,4)-(6,5)".
+func (r Rectangle) String() string {
+ return r.Min.String() + "-" + r.Max.String()
+}
+
+// Dx returns r's width.
+func (r Rectangle) Dx() int {
+ return r.Max.X - r.Min.X
+}
+
+// Dy returns r's height.
+func (r Rectangle) Dy() int {
+ return r.Max.Y - r.Min.Y
+}
+
+// Size returns r's width and height.
+func (r Rectangle) Size() Point {
+ return Point{
+ r.Max.X - r.Min.X,
+ r.Max.Y - r.Min.Y,
+ }
+}
+
+// Add returns the rectangle r translated by p.
+func (r Rectangle) Add(p Point) Rectangle {
+ return Rectangle{
+ Point{r.Min.X + p.X, r.Min.Y + p.Y},
+ Point{r.Max.X + p.X, r.Max.Y + p.Y},
+ }
+}
+
+// Add returns the rectangle r translated by -p.
+func (r Rectangle) Sub(p Point) Rectangle {
+ return Rectangle{
+ Point{r.Min.X - p.X, r.Min.Y - p.Y},
+ Point{r.Max.X - p.X, r.Max.Y - p.Y},
+ }
+}
+
+// Inset returns the rectangle r inset by n, which may be negative. If either
+// of r's dimensions is less than 2*n then an empty rectangle near the center
+// of r will be returned.
+func (r Rectangle) Inset(n int) Rectangle {
+ if r.Dx() < 2*n {
+ r.Min.X = (r.Min.X + r.Max.X) / 2
+ r.Max.X = r.Min.X
+ } else {
+ r.Min.X += n
+ r.Max.X -= n
+ }
+ if r.Dy() < 2*n {
+ r.Min.Y = (r.Min.Y + r.Max.Y) / 2
+ r.Max.Y = r.Min.Y
+ } else {
+ r.Min.Y += n
+ r.Max.Y -= n
+ }
+ return r
+}
+
+// Intersect returns the largest rectangle contained by both r and s. If the
+// two rectangles do not overlap then the zero rectangle will be returned.
+func (r Rectangle) Intersect(s Rectangle) Rectangle {
+ if r.Min.X < s.Min.X {
+ r.Min.X = s.Min.X
+ }
+ if r.Min.Y < s.Min.Y {
+ r.Min.Y = s.Min.Y
+ }
+ if r.Max.X > s.Max.X {
+ r.Max.X = s.Max.X
+ }
+ if r.Max.Y > s.Max.Y {
+ r.Max.Y = s.Max.Y
+ }
+ if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
+ return ZR
+ }
+ return r
+}
+
+// Union returns the smallest rectangle that contains both r and s.
+func (r Rectangle) Union(s Rectangle) Rectangle {
+ if r.Min.X > s.Min.X {
+ r.Min.X = s.Min.X
+ }
+ if r.Min.Y > s.Min.Y {
+ r.Min.Y = s.Min.Y
+ }
+ if r.Max.X < s.Max.X {
+ r.Max.X = s.Max.X
+ }
+ if r.Max.Y < s.Max.Y {
+ r.Max.Y = s.Max.Y
+ }
+ return r
+}
+
+// Empty returns whether the rectangle contains no points.
+func (r Rectangle) Empty() bool {
+ return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
+}
+
+// Eq returns whether r and s are equal.
+func (r Rectangle) Eq(s Rectangle) bool {
+ return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y &&
+ r.Max.X == s.Max.X && r.Max.Y == s.Max.Y
+}
+
+// Overlaps returns whether r and s have a non-empty intersection.
+func (r Rectangle) Overlaps(s Rectangle) bool {
+ return r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
+ r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
+}
+
+// Contains returns whether r contains p.
+func (r Rectangle) Contains(p Point) bool {
+ return p.X >= r.Min.X && p.X < r.Max.X &&
+ p.Y >= r.Min.Y && p.Y < r.Max.Y
+}
+
+// Canon returns the canonical version of r. The returned rectangle has minimum
+// and maximum coordinates swapped if necessary so that it is well-formed.
+func (r Rectangle) Canon() Rectangle {
+ if r.Max.X < r.Min.X {
+ r.Min.X, r.Max.X = r.Max.X, r.Min.X
+ }
+ if r.Max.Y < r.Min.Y {
+ r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
+ }
+ return r
+}
+
+// ZR is the zero Rectangle.
+var ZR Rectangle
+
+// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
+func Rect(x0, y0, x1, y1 int) Rectangle {
+ if x0 > x1 {
+ x0, x1 = x1, x0
+ }
+ if y0 > y1 {
+ y0, y1 = y1, y0
+ }
+ return Rectangle{Point{x0, y0}, Point{x1, y1}}
+}
diff --git a/libgo/go/image/image.go b/libgo/go/image/image.go
new file mode 100644
index 000000000..c0e96e1f7
--- /dev/null
+++ b/libgo/go/image/image.go
@@ -0,0 +1,506 @@
+// 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.
+
+// The image package implements a basic 2-D image library.
+package image
+
+// A Config consists of an image's color model and dimensions.
+type Config struct {
+ ColorModel ColorModel
+ Width, Height int
+}
+
+// An Image is a finite rectangular grid of Colors drawn from a ColorModel.
+type Image interface {
+ // ColorModel returns the Image's ColorModel.
+ ColorModel() ColorModel
+ // Bounds returns the domain for which At can return non-zero color.
+ // The bounds do not necessarily contain the point (0, 0).
+ Bounds() Rectangle
+ // At returns the color of the pixel at (x, y).
+ // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
+ // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
+ At(x, y int) Color
+}
+
+// An RGBA is an in-memory image of RGBAColor values.
+type RGBA struct {
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []RGBAColor
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *RGBA) ColorModel() ColorModel { return RGBAColorModel }
+
+func (p *RGBA) Bounds() Rectangle { return p.Rect }
+
+func (p *RGBA) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return RGBAColor{}
+ }
+ return p.Pix[y*p.Stride+x]
+}
+
+func (p *RGBA) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toRGBAColor(c).(RGBAColor)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *RGBA) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewRGBA returns a new RGBA with the given width and height.
+func NewRGBA(w, h int) *RGBA {
+ buf := make([]RGBAColor, w*h)
+ return &RGBA{buf, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// An RGBA64 is an in-memory image of RGBA64Color values.
+type RGBA64 struct {
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []RGBA64Color
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *RGBA64) ColorModel() ColorModel { return RGBA64ColorModel }
+
+func (p *RGBA64) Bounds() Rectangle { return p.Rect }
+
+func (p *RGBA64) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return RGBA64Color{}
+ }
+ return p.Pix[y*p.Stride+x]
+}
+
+func (p *RGBA64) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toRGBA64Color(c).(RGBA64Color)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *RGBA64) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xffff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewRGBA64 returns a new RGBA64 with the given width and height.
+func NewRGBA64(w, h int) *RGBA64 {
+ pix := make([]RGBA64Color, w*h)
+ return &RGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// An NRGBA is an in-memory image of NRGBAColor values.
+type NRGBA struct {
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []NRGBAColor
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *NRGBA) ColorModel() ColorModel { return NRGBAColorModel }
+
+func (p *NRGBA) Bounds() Rectangle { return p.Rect }
+
+func (p *NRGBA) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return NRGBAColor{}
+ }
+ return p.Pix[y*p.Stride+x]
+}
+
+func (p *NRGBA) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toNRGBAColor(c).(NRGBAColor)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *NRGBA) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewNRGBA returns a new NRGBA with the given width and height.
+func NewNRGBA(w, h int) *NRGBA {
+ pix := make([]NRGBAColor, w*h)
+ return &NRGBA{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// An NRGBA64 is an in-memory image of NRGBA64Color values.
+type NRGBA64 struct {
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []NRGBA64Color
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *NRGBA64) ColorModel() ColorModel { return NRGBA64ColorModel }
+
+func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
+
+func (p *NRGBA64) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return NRGBA64Color{}
+ }
+ return p.Pix[y*p.Stride+x]
+}
+
+func (p *NRGBA64) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toNRGBA64Color(c).(NRGBA64Color)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *NRGBA64) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xffff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewNRGBA64 returns a new NRGBA64 with the given width and height.
+func NewNRGBA64(w, h int) *NRGBA64 {
+ pix := make([]NRGBA64Color, w*h)
+ return &NRGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// An Alpha is an in-memory image of AlphaColor values.
+type Alpha struct {
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []AlphaColor
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *Alpha) ColorModel() ColorModel { return AlphaColorModel }
+
+func (p *Alpha) Bounds() Rectangle { return p.Rect }
+
+func (p *Alpha) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return AlphaColor{}
+ }
+ return p.Pix[y*p.Stride+x]
+}
+
+func (p *Alpha) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toAlphaColor(c).(AlphaColor)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Alpha) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewAlpha returns a new Alpha with the given width and height.
+func NewAlpha(w, h int) *Alpha {
+ pix := make([]AlphaColor, w*h)
+ return &Alpha{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// An Alpha16 is an in-memory image of Alpha16Color values.
+type Alpha16 struct {
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []Alpha16Color
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *Alpha16) ColorModel() ColorModel { return Alpha16ColorModel }
+
+func (p *Alpha16) Bounds() Rectangle { return p.Rect }
+
+func (p *Alpha16) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return Alpha16Color{}
+ }
+ return p.Pix[y*p.Stride+x]
+}
+
+func (p *Alpha16) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toAlpha16Color(c).(Alpha16Color)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Alpha16) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xffff {
+ return false
+ }
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ return true
+}
+
+// NewAlpha16 returns a new Alpha16 with the given width and height.
+func NewAlpha16(w, h int) *Alpha16 {
+ pix := make([]Alpha16Color, w*h)
+ return &Alpha16{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// A Gray is an in-memory image of GrayColor values.
+type Gray struct {
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []GrayColor
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *Gray) ColorModel() ColorModel { return GrayColorModel }
+
+func (p *Gray) Bounds() Rectangle { return p.Rect }
+
+func (p *Gray) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return GrayColor{}
+ }
+ return p.Pix[y*p.Stride+x]
+}
+
+func (p *Gray) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toGrayColor(c).(GrayColor)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Gray) Opaque() bool {
+ return true
+}
+
+// NewGray returns a new Gray with the given width and height.
+func NewGray(w, h int) *Gray {
+ pix := make([]GrayColor, w*h)
+ return &Gray{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// A Gray16 is an in-memory image of Gray16Color values.
+type Gray16 struct {
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []Gray16Color
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *Gray16) ColorModel() ColorModel { return Gray16ColorModel }
+
+func (p *Gray16) Bounds() Rectangle { return p.Rect }
+
+func (p *Gray16) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return Gray16Color{}
+ }
+ return p.Pix[y*p.Stride+x]
+}
+
+func (p *Gray16) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toGray16Color(c).(Gray16Color)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Gray16) Opaque() bool {
+ return true
+}
+
+// NewGray16 returns a new Gray16 with the given width and height.
+func NewGray16(w, h int) *Gray16 {
+ pix := make([]Gray16Color, w*h)
+ return &Gray16{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// A PalettedColorModel represents a fixed palette of colors.
+type PalettedColorModel []Color
+
+func diff(a, b uint32) uint32 {
+ if a > b {
+ return a - b
+ }
+ return b - a
+}
+
+// Convert returns the palette color closest to c in Euclidean R,G,B space.
+func (p PalettedColorModel) Convert(c Color) Color {
+ if len(p) == 0 {
+ return nil
+ }
+ cr, cg, cb, _ := c.RGBA()
+ // Shift by 1 bit to avoid potential uint32 overflow in sum-squared-difference.
+ cr >>= 1
+ cg >>= 1
+ cb >>= 1
+ result := Color(nil)
+ bestSSD := uint32(1<<32 - 1)
+ for _, v := range p {
+ vr, vg, vb, _ := v.RGBA()
+ vr >>= 1
+ vg >>= 1
+ vb >>= 1
+ dr, dg, db := diff(cr, vr), diff(cg, vg), diff(cb, vb)
+ ssd := (dr * dr) + (dg * dg) + (db * db)
+ if ssd < bestSSD {
+ bestSSD = ssd
+ result = v
+ }
+ }
+ return result
+}
+
+// A Paletted is an in-memory image backed by a 2-D slice of uint8 values and a PalettedColorModel.
+type Paletted struct {
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []uint8
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+ // Palette is the image's palette.
+ Palette PalettedColorModel
+}
+
+func (p *Paletted) ColorModel() ColorModel { return p.Palette }
+
+func (p *Paletted) Bounds() Rectangle { return p.Rect }
+
+func (p *Paletted) At(x, y int) Color {
+ if len(p.Palette) == 0 {
+ return nil
+ }
+ if !p.Rect.Contains(Point{x, y}) {
+ return p.Palette[0]
+ }
+ return p.Palette[p.Pix[y*p.Stride+x]]
+}
+
+func (p *Paletted) ColorIndexAt(x, y int) uint8 {
+ if !p.Rect.Contains(Point{x, y}) {
+ return 0
+ }
+ return p.Pix[y*p.Stride+x]
+}
+
+func (p *Paletted) SetColorIndex(x, y int, index uint8) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = index
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Paletted) Opaque() bool {
+ for _, c := range p.Palette {
+ _, _, _, a := c.RGBA()
+ if a != 0xffff {
+ return false
+ }
+ }
+ return true
+}
+
+// NewPaletted returns a new Paletted with the given width, height and palette.
+func NewPaletted(w, h int, m PalettedColorModel) *Paletted {
+ pix := make([]uint8, w*h)
+ return &Paletted{pix, w, Rectangle{ZP, Point{w, h}}, m}
+}
diff --git a/libgo/go/image/jpeg/huffman.go b/libgo/go/image/jpeg/huffman.go
new file mode 100644
index 000000000..0d03a7317
--- /dev/null
+++ b/libgo/go/image/jpeg/huffman.go
@@ -0,0 +1,190 @@
+// 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 jpeg
+
+import (
+ "io"
+ "os"
+)
+
+// Each code is at most 16 bits long.
+const maxCodeLength = 16
+
+// Each decoded value is a uint8, so there are at most 256 such values.
+const maxNumValues = 256
+
+// Bit stream for the Huffman decoder.
+// The n least significant bits of a form the unread bits, to be read in MSB to LSB order.
+type bits struct {
+ a int // accumulator.
+ n int // the number of unread bits in a.
+ m int // mask. m==1<<(n-1) when n>0, with m==0 when n==0.
+}
+
+// Huffman table decoder, specified in section C.
+type huffman struct {
+ l [maxCodeLength]int
+ length int // sum of l[i].
+ val [maxNumValues]uint8 // the decoded values, as sorted by their encoding.
+ size [maxNumValues]int // size[i] is the number of bits to encode val[i].
+ code [maxNumValues]int // code[i] is the encoding of val[i].
+ minCode [maxCodeLength]int // min codes of length i, or -1 if no codes of that length.
+ maxCode [maxCodeLength]int // max codes of length i, or -1 if no codes of that length.
+ valIndex [maxCodeLength]int // index into val of minCode[i].
+}
+
+// Reads bytes from the io.Reader to ensure that bits.n is at least n.
+func (d *decoder) ensureNBits(n int) os.Error {
+ for d.b.n < n {
+ c, err := d.r.ReadByte()
+ if err != nil {
+ return err
+ }
+ d.b.a = d.b.a<<8 | int(c)
+ d.b.n += 8
+ if d.b.m == 0 {
+ d.b.m = 1 << 7
+ } else {
+ d.b.m <<= 8
+ }
+ // Byte stuffing, specified in section F.1.2.3.
+ if c == 0xff {
+ c, err = d.r.ReadByte()
+ if err != nil {
+ return err
+ }
+ if c != 0x00 {
+ return FormatError("missing 0xff00 sequence")
+ }
+ }
+ }
+ return nil
+}
+
+// The composition of RECEIVE and EXTEND, specified in section F.2.2.1.
+func (d *decoder) receiveExtend(t uint8) (int, os.Error) {
+ err := d.ensureNBits(int(t))
+ if err != nil {
+ return 0, err
+ }
+ d.b.n -= int(t)
+ d.b.m >>= t
+ s := 1 << t
+ x := (d.b.a >> uint8(d.b.n)) & (s - 1)
+ if x < s>>1 {
+ x += ((-1) << t) + 1
+ }
+ return x, nil
+}
+
+// Processes a Define Huffman Table marker, and initializes a huffman struct from its contents.
+// Specified in section B.2.4.2.
+func (d *decoder) processDHT(n int) os.Error {
+ for n > 0 {
+ if n < 17 {
+ return FormatError("DHT has wrong length")
+ }
+ _, err := io.ReadFull(d.r, d.tmp[0:17])
+ if err != nil {
+ return err
+ }
+ tc := d.tmp[0] >> 4
+ if tc > maxTc {
+ return FormatError("bad Tc value")
+ }
+ th := d.tmp[0] & 0x0f
+ const isBaseline = true // Progressive mode is not yet supported.
+ if th > maxTh || isBaseline && th > 1 {
+ return FormatError("bad Th value")
+ }
+ h := &d.huff[tc][th]
+
+ // Read l and val (and derive length).
+ h.length = 0
+ for i := 0; i < maxCodeLength; i++ {
+ h.l[i] = int(d.tmp[i+1])
+ h.length += h.l[i]
+ }
+ if h.length == 0 {
+ return FormatError("Huffman table has zero length")
+ }
+ if h.length > maxNumValues {
+ return FormatError("Huffman table has excessive length")
+ }
+ n -= h.length + 17
+ if n < 0 {
+ return FormatError("DHT has wrong length")
+ }
+ _, err = io.ReadFull(d.r, h.val[0:h.length])
+ if err != nil {
+ return err
+ }
+
+ // Derive size.
+ k := 0
+ for i := 0; i < maxCodeLength; i++ {
+ for j := 0; j < h.l[i]; j++ {
+ h.size[k] = i + 1
+ k++
+ }
+ }
+
+ // Derive code.
+ code := 0
+ size := h.size[0]
+ for i := 0; i < h.length; i++ {
+ if size != h.size[i] {
+ code <<= uint8(h.size[i] - size)
+ size = h.size[i]
+ }
+ h.code[i] = code
+ code++
+ }
+
+ // Derive minCode, maxCode, and valIndex.
+ k = 0
+ index := 0
+ for i := 0; i < maxCodeLength; i++ {
+ if h.l[i] == 0 {
+ h.minCode[i] = -1
+ h.maxCode[i] = -1
+ h.valIndex[i] = -1
+ } else {
+ h.minCode[i] = k
+ h.maxCode[i] = k + h.l[i] - 1
+ h.valIndex[i] = index
+ k += h.l[i]
+ index += h.l[i]
+ }
+ k <<= 1
+ }
+ }
+ return nil
+}
+
+// Returns the next Huffman-coded value from the bit stream, decoded according to h.
+// TODO(nigeltao): This decoding algorithm is simple, but slow. A lookahead table, instead of always
+// peeling off only 1 bit at at time, ought to be faster.
+func (d *decoder) decodeHuffman(h *huffman) (uint8, os.Error) {
+ if h.length == 0 {
+ return 0, FormatError("uninitialized Huffman table")
+ }
+ for i, code := 0, 0; i < maxCodeLength; i++ {
+ err := d.ensureNBits(1)
+ if err != nil {
+ return 0, err
+ }
+ if d.b.a&d.b.m != 0 {
+ code |= 1
+ }
+ d.b.n--
+ d.b.m >>= 1
+ if code <= h.maxCode[i] {
+ return h.val[h.valIndex[i]+code-h.minCode[i]], nil
+ }
+ code <<= 1
+ }
+ return 0, FormatError("bad Huffman code")
+}
diff --git a/libgo/go/image/jpeg/idct.go b/libgo/go/image/jpeg/idct.go
new file mode 100644
index 000000000..518993110
--- /dev/null
+++ b/libgo/go/image/jpeg/idct.go
@@ -0,0 +1,190 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a Go translation of idct.c from
+//
+// http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_IEC_13818-4_2004_Conformance_Testing/Video/verifier/mpeg2decode_960109.tar.gz
+//
+// which carries the following notice:
+
+/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */
+
+/*
+ * Disclaimer of Warranty
+ *
+ * These software programs are available to the user without any license fee or
+ * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims
+ * any and all warranties, whether express, implied, or statuary, including any
+ * implied warranties or merchantability or of fitness for a particular
+ * purpose. In no event shall the copyright-holder be liable for any
+ * incidental, punitive, or consequential damages of any kind whatsoever
+ * arising from the use of these programs.
+ *
+ * This disclaimer of warranty extends to the user of these programs and user's
+ * customers, employees, agents, transferees, successors, and assigns.
+ *
+ * The MPEG Software Simulation Group does not represent or warrant that the
+ * programs furnished hereunder are free of infringement of any third-party
+ * patents.
+ *
+ * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
+ * are subject to royalty fees to patent holders. Many of these patents are
+ * general enough such that they are unavoidable regardless of implementation
+ * design.
+ *
+ */
+
+package jpeg
+
+const (
+ w1 = 2841 // 2048*sqrt(2)*cos(1*pi/16)
+ w2 = 2676 // 2048*sqrt(2)*cos(2*pi/16)
+ w3 = 2408 // 2048*sqrt(2)*cos(3*pi/16)
+ w5 = 1609 // 2048*sqrt(2)*cos(5*pi/16)
+ w6 = 1108 // 2048*sqrt(2)*cos(6*pi/16)
+ w7 = 565 // 2048*sqrt(2)*cos(7*pi/16)
+
+ w1pw7 = w1 + w7
+ w1mw7 = w1 - w7
+ w2pw6 = w2 + w6
+ w2mw6 = w2 - w6
+ w3pw5 = w3 + w5
+ w3mw5 = w3 - w5
+
+ r2 = 181 // 256/sqrt(2)
+)
+
+// 2-D Inverse Discrete Cosine Transformation, followed by a +128 level shift.
+//
+// The input coefficients should already have been multiplied by the appropriate quantization table.
+// We use fixed-point computation, with the number of bits for the fractional component varying over the
+// intermediate stages. The final values are expected to range within [0, 255], after a +128 level shift.
+//
+// For more on the actual algorithm, see Z. Wang, "Fast algorithms for the discrete W transform and
+// for the discrete Fourier transform", IEEE Trans. on ASSP, Vol. ASSP- 32, pp. 803-816, Aug. 1984.
+func idct(b *[blockSize]int) {
+ // Horizontal 1-D IDCT.
+ for y := 0; y < 8; y++ {
+ // If all the AC components are zero, then the IDCT is trivial.
+ if b[y*8+1] == 0 && b[y*8+2] == 0 && b[y*8+3] == 0 &&
+ b[y*8+4] == 0 && b[y*8+5] == 0 && b[y*8+6] == 0 && b[y*8+7] == 0 {
+ dc := b[y*8+0] << 3
+ b[y*8+0] = dc
+ b[y*8+1] = dc
+ b[y*8+2] = dc
+ b[y*8+3] = dc
+ b[y*8+4] = dc
+ b[y*8+5] = dc
+ b[y*8+6] = dc
+ b[y*8+7] = dc
+ continue
+ }
+
+ // Prescale.
+ x0 := (b[y*8+0] << 11) + 128
+ x1 := b[y*8+4] << 11
+ x2 := b[y*8+6]
+ x3 := b[y*8+2]
+ x4 := b[y*8+1]
+ x5 := b[y*8+7]
+ x6 := b[y*8+5]
+ x7 := b[y*8+3]
+
+ // Stage 1.
+ x8 := w7 * (x4 + x5)
+ x4 = x8 + w1mw7*x4
+ x5 = x8 - w1pw7*x5
+ x8 = w3 * (x6 + x7)
+ x6 = x8 - w3mw5*x6
+ x7 = x8 - w3pw5*x7
+
+ // Stage 2.
+ x8 = x0 + x1
+ x0 -= x1
+ x1 = w6 * (x3 + x2)
+ x2 = x1 - w2pw6*x2
+ x3 = x1 + w2mw6*x3
+ x1 = x4 + x6
+ x4 -= x6
+ x6 = x5 + x7
+ x5 -= x7
+
+ // Stage 3.
+ x7 = x8 + x3
+ x8 -= x3
+ x3 = x0 + x2
+ x0 -= x2
+ x2 = (r2*(x4+x5) + 128) >> 8
+ x4 = (r2*(x4-x5) + 128) >> 8
+
+ // Stage 4.
+ b[8*y+0] = (x7 + x1) >> 8
+ b[8*y+1] = (x3 + x2) >> 8
+ b[8*y+2] = (x0 + x4) >> 8
+ b[8*y+3] = (x8 + x6) >> 8
+ b[8*y+4] = (x8 - x6) >> 8
+ b[8*y+5] = (x0 - x4) >> 8
+ b[8*y+6] = (x3 - x2) >> 8
+ b[8*y+7] = (x7 - x1) >> 8
+ }
+
+ // Vertical 1-D IDCT.
+ for x := 0; x < 8; x++ {
+ // Similar to the horizontal 1-D IDCT case, if all the AC components are zero, then the IDCT is trivial.
+ // However, after performing the horizontal 1-D IDCT, there are typically non-zero AC components, so
+ // we do not bother to check for the all-zero case.
+
+ // Prescale.
+ y0 := (b[8*0+x] << 8) + 8192
+ y1 := b[8*4+x] << 8
+ y2 := b[8*6+x]
+ y3 := b[8*2+x]
+ y4 := b[8*1+x]
+ y5 := b[8*7+x]
+ y6 := b[8*5+x]
+ y7 := b[8*3+x]
+
+ // Stage 1.
+ y8 := w7*(y4+y5) + 4
+ y4 = (y8 + w1mw7*y4) >> 3
+ y5 = (y8 - w1pw7*y5) >> 3
+ y8 = w3*(y6+y7) + 4
+ y6 = (y8 - w3mw5*y6) >> 3
+ y7 = (y8 - w3pw5*y7) >> 3
+
+ // Stage 2.
+ y8 = y0 + y1
+ y0 -= y1
+ y1 = w6*(y3+y2) + 4
+ y2 = (y1 - w2pw6*y2) >> 3
+ y3 = (y1 + w2mw6*y3) >> 3
+ y1 = y4 + y6
+ y4 -= y6
+ y6 = y5 + y7
+ y5 -= y7
+
+ // Stage 3.
+ y7 = y8 + y3
+ y8 -= y3
+ y3 = y0 + y2
+ y0 -= y2
+ y2 = (r2*(y4+y5) + 128) >> 8
+ y4 = (r2*(y4-y5) + 128) >> 8
+
+ // Stage 4.
+ b[8*0+x] = (y7 + y1) >> 14
+ b[8*1+x] = (y3 + y2) >> 14
+ b[8*2+x] = (y0 + y4) >> 14
+ b[8*3+x] = (y8 + y6) >> 14
+ b[8*4+x] = (y8 - y6) >> 14
+ b[8*5+x] = (y0 - y4) >> 14
+ b[8*6+x] = (y3 - y2) >> 14
+ b[8*7+x] = (y7 - y1) >> 14
+ }
+
+ // Level shift.
+ for i := range *b {
+ b[i] += 128
+ }
+}
diff --git a/libgo/go/image/jpeg/reader.go b/libgo/go/image/jpeg/reader.go
new file mode 100644
index 000000000..fb9cb11bb
--- /dev/null
+++ b/libgo/go/image/jpeg/reader.go
@@ -0,0 +1,455 @@
+// 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.
+
+// The jpeg package implements a decoder for JPEG images, as defined in ITU-T T.81.
+package jpeg
+
+// See http://www.w3.org/Graphics/JPEG/itu-t81.pdf
+
+import (
+ "bufio"
+ "image"
+ "io"
+ "os"
+)
+
+// A FormatError reports that the input is not a valid JPEG.
+type FormatError string
+
+func (e FormatError) String() string { return "invalid JPEG format: " + string(e) }
+
+// An UnsupportedError reports that the input uses a valid but unimplemented JPEG feature.
+type UnsupportedError string
+
+func (e UnsupportedError) String() string { return "unsupported JPEG feature: " + string(e) }
+
+// Component specification, specified in section B.2.2.
+type component struct {
+ c uint8 // Component identifier.
+ h uint8 // Horizontal sampling factor.
+ v uint8 // Vertical sampling factor.
+ tq uint8 // Quantization table destination selector.
+}
+
+const (
+ blockSize = 64 // A DCT block is 8x8.
+
+ dcTableClass = 0
+ acTableClass = 1
+ maxTc = 1
+ maxTh = 3
+ maxTq = 3
+
+ // We only support 4:4:4, 4:2:2 and 4:2:0 downsampling, and assume that the components are Y, Cb, Cr.
+ nComponent = 3
+ maxH = 2
+ maxV = 2
+)
+
+const (
+ soiMarker = 0xd8 // Start Of Image.
+ eoiMarker = 0xd9 // End Of Image.
+ sof0Marker = 0xc0 // Start Of Frame (Baseline).
+ sof2Marker = 0xc2 // Start Of Frame (Progressive).
+ dhtMarker = 0xc4 // Define Huffman Table.
+ dqtMarker = 0xdb // Define Quantization Table.
+ sosMarker = 0xda // Start Of Scan.
+ driMarker = 0xdd // Define Restart Interval.
+ rst0Marker = 0xd0 // ReSTart (0).
+ rst7Marker = 0xd7 // ReSTart (7).
+ app0Marker = 0xe0 // APPlication specific (0).
+ app15Marker = 0xef // APPlication specific (15).
+ comMarker = 0xfe // COMment.
+)
+
+// Maps from the zig-zag ordering to the natural ordering.
+var unzig = [blockSize]int{
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+}
+
+// If the passed in io.Reader does not also have ReadByte, then Decode will introduce its own buffering.
+type Reader interface {
+ io.Reader
+ ReadByte() (c byte, err os.Error)
+}
+
+type decoder struct {
+ r Reader
+ width, height int
+ image *image.RGBA
+ ri int // Restart Interval.
+ comps [nComponent]component
+ huff [maxTc + 1][maxTh + 1]huffman
+ quant [maxTq + 1][blockSize]int
+ b bits
+ blocks [nComponent][maxH * maxV][blockSize]int
+ tmp [1024]byte
+}
+
+// Reads and ignores the next n bytes.
+func (d *decoder) ignore(n int) os.Error {
+ for n > 0 {
+ m := len(d.tmp)
+ if m > n {
+ m = n
+ }
+ _, err := io.ReadFull(d.r, d.tmp[0:m])
+ if err != nil {
+ return err
+ }
+ n -= m
+ }
+ return nil
+}
+
+// Specified in section B.2.2.
+func (d *decoder) processSOF(n int) os.Error {
+ if n != 6+3*nComponent {
+ return UnsupportedError("SOF has wrong length")
+ }
+ _, err := io.ReadFull(d.r, d.tmp[0:6+3*nComponent])
+ if err != nil {
+ return err
+ }
+ // We only support 8-bit precision.
+ if d.tmp[0] != 8 {
+ return UnsupportedError("precision")
+ }
+ d.height = int(d.tmp[1])<<8 + int(d.tmp[2])
+ d.width = int(d.tmp[3])<<8 + int(d.tmp[4])
+ if d.tmp[5] != nComponent {
+ return UnsupportedError("SOF has wrong number of image components")
+ }
+ for i := 0; i < nComponent; i++ {
+ hv := d.tmp[7+3*i]
+ d.comps[i].c = d.tmp[6+3*i]
+ d.comps[i].h = hv >> 4
+ d.comps[i].v = hv & 0x0f
+ d.comps[i].tq = d.tmp[8+3*i]
+ // We only support YCbCr images, and 4:4:4, 4:2:2 or 4:2:0 chroma downsampling ratios. This implies that
+ // the (h, v) values for the Y component are either (1, 1), (2, 1) or (2, 2), and the
+ // (h, v) values for the Cr and Cb components must be (1, 1).
+ if i == 0 {
+ if hv != 0x11 && hv != 0x21 && hv != 0x22 {
+ return UnsupportedError("luma downsample ratio")
+ }
+ } else {
+ if hv != 0x11 {
+ return UnsupportedError("chroma downsample ratio")
+ }
+ }
+ }
+ return nil
+}
+
+// Specified in section B.2.4.1.
+func (d *decoder) processDQT(n int) os.Error {
+ const qtLength = 1 + blockSize
+ for ; n >= qtLength; n -= qtLength {
+ _, err := io.ReadFull(d.r, d.tmp[0:qtLength])
+ if err != nil {
+ return err
+ }
+ pq := d.tmp[0] >> 4
+ if pq != 0 {
+ return UnsupportedError("bad Pq value")
+ }
+ tq := d.tmp[0] & 0x0f
+ if tq > maxTq {
+ return FormatError("bad Tq value")
+ }
+ for i := range d.quant[tq] {
+ d.quant[tq][i] = int(d.tmp[i+1])
+ }
+ }
+ if n != 0 {
+ return FormatError("DQT has wrong length")
+ }
+ return nil
+}
+
+// Set the Pixel (px, py)'s RGB value, based on its YCbCr value.
+func (d *decoder) calcPixel(px, py, lumaBlock, lumaIndex, chromaIndex int) {
+ y, cb, cr := d.blocks[0][lumaBlock][lumaIndex], d.blocks[1][0][chromaIndex], d.blocks[2][0][chromaIndex]
+ // The JFIF specification (http://www.w3.org/Graphics/JPEG/jfif3.pdf, page 3) gives the formula
+ // for translating YCbCr to RGB as:
+ // R = Y + 1.402 (Cr-128)
+ // G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
+ // B = Y + 1.772 (Cb-128)
+ yPlusHalf := 100000*y + 50000
+ cb -= 128
+ cr -= 128
+ r := (yPlusHalf + 140200*cr) / 100000
+ g := (yPlusHalf - 34414*cb - 71414*cr) / 100000
+ b := (yPlusHalf + 177200*cb) / 100000
+ if r < 0 {
+ r = 0
+ } else if r > 255 {
+ r = 255
+ }
+ if g < 0 {
+ g = 0
+ } else if g > 255 {
+ g = 255
+ }
+ if b < 0 {
+ b = 0
+ } else if b > 255 {
+ b = 255
+ }
+ d.image.Pix[py*d.image.Stride+px] = image.RGBAColor{uint8(r), uint8(g), uint8(b), 0xff}
+}
+
+// Convert the MCU from YCbCr to RGB.
+func (d *decoder) convertMCU(mx, my, h0, v0 int) {
+ lumaBlock := 0
+ for v := 0; v < v0; v++ {
+ for h := 0; h < h0; h++ {
+ chromaBase := 8*4*v + 4*h
+ py := 8 * (v0*my + v)
+ for y := 0; y < 8 && py < d.height; y++ {
+ px := 8 * (h0*mx + h)
+ lumaIndex := 8 * y
+ chromaIndex := chromaBase + 8*(y/v0)
+ for x := 0; x < 8 && px < d.width; x++ {
+ d.calcPixel(px, py, lumaBlock, lumaIndex, chromaIndex)
+ if h0 == 1 {
+ chromaIndex += 1
+ } else {
+ chromaIndex += x % 2
+ }
+ lumaIndex++
+ px++
+ }
+ py++
+ }
+ lumaBlock++
+ }
+ }
+}
+
+// Specified in section B.2.3.
+func (d *decoder) processSOS(n int) os.Error {
+ if d.image == nil {
+ d.image = image.NewRGBA(d.width, d.height)
+ }
+ if n != 4+2*nComponent {
+ return UnsupportedError("SOS has wrong length")
+ }
+ _, err := io.ReadFull(d.r, d.tmp[0:4+2*nComponent])
+ if err != nil {
+ return err
+ }
+ if d.tmp[0] != nComponent {
+ return UnsupportedError("SOS has wrong number of image components")
+ }
+ var scanComps [nComponent]struct {
+ td uint8 // DC table selector.
+ ta uint8 // AC table selector.
+ }
+ h0, v0 := int(d.comps[0].h), int(d.comps[0].v) // The h and v values from the Y components.
+ for i := 0; i < nComponent; i++ {
+ cs := d.tmp[1+2*i] // Component selector.
+ if cs != d.comps[i].c {
+ return UnsupportedError("scan components out of order")
+ }
+ scanComps[i].td = d.tmp[2+2*i] >> 4
+ scanComps[i].ta = d.tmp[2+2*i] & 0x0f
+ }
+ // mxx and myy are the number of MCUs (Minimum Coded Units) in the image.
+ mxx := (d.width + 8*int(h0) - 1) / (8 * int(h0))
+ myy := (d.height + 8*int(v0) - 1) / (8 * int(v0))
+
+ mcu, expectedRST := 0, uint8(rst0Marker)
+ var allZeroes [blockSize]int
+ var dc [nComponent]int
+ for my := 0; my < myy; my++ {
+ for mx := 0; mx < mxx; mx++ {
+ for i := 0; i < nComponent; i++ {
+ qt := &d.quant[d.comps[i].tq]
+ for j := 0; j < int(d.comps[i].h*d.comps[i].v); j++ {
+ d.blocks[i][j] = allZeroes
+
+ // Decode the DC coefficient, as specified in section F.2.2.1.
+ value, err := d.decodeHuffman(&d.huff[dcTableClass][scanComps[i].td])
+ if err != nil {
+ return err
+ }
+ if value > 16 {
+ return UnsupportedError("excessive DC component")
+ }
+ dcDelta, err := d.receiveExtend(value)
+ if err != nil {
+ return err
+ }
+ dc[i] += dcDelta
+ d.blocks[i][j][0] = dc[i] * qt[0]
+
+ // Decode the AC coefficients, as specified in section F.2.2.2.
+ for k := 1; k < blockSize; k++ {
+ value, err := d.decodeHuffman(&d.huff[acTableClass][scanComps[i].ta])
+ if err != nil {
+ return err
+ }
+ v0 := value >> 4
+ v1 := value & 0x0f
+ if v1 != 0 {
+ k += int(v0)
+ if k > blockSize {
+ return FormatError("bad DCT index")
+ }
+ ac, err := d.receiveExtend(v1)
+ if err != nil {
+ return err
+ }
+ d.blocks[i][j][unzig[k]] = ac * qt[k]
+ } else {
+ if v0 != 0x0f {
+ break
+ }
+ k += 0x0f
+ }
+ }
+
+ idct(&d.blocks[i][j])
+ } // for j
+ } // for i
+ d.convertMCU(mx, my, int(d.comps[0].h), int(d.comps[0].v))
+ mcu++
+ if d.ri > 0 && mcu%d.ri == 0 && mcu < mxx*myy {
+ // A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input,
+ // but this one assumes well-formed input, and hence the restart marker follows immediately.
+ _, err := io.ReadFull(d.r, d.tmp[0:2])
+ if err != nil {
+ return err
+ }
+ if d.tmp[0] != 0xff || d.tmp[1] != expectedRST {
+ return FormatError("bad RST marker")
+ }
+ expectedRST++
+ if expectedRST == rst7Marker+1 {
+ expectedRST = rst0Marker
+ }
+ // Reset the Huffman decoder.
+ d.b = bits{}
+ // Reset the DC components, as per section F.2.1.3.1.
+ for i := 0; i < nComponent; i++ {
+ dc[i] = 0
+ }
+ }
+ } // for mx
+ } // for my
+
+ return nil
+}
+
+// Specified in section B.2.4.4.
+func (d *decoder) processDRI(n int) os.Error {
+ if n != 2 {
+ return FormatError("DRI has wrong length")
+ }
+ _, err := io.ReadFull(d.r, d.tmp[0:2])
+ if err != nil {
+ return err
+ }
+ d.ri = int(d.tmp[0])<<8 + int(d.tmp[1])
+ return nil
+}
+
+// decode reads a JPEG image from r and returns it as an image.Image.
+func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, os.Error) {
+ if rr, ok := r.(Reader); ok {
+ d.r = rr
+ } else {
+ d.r = bufio.NewReader(r)
+ }
+
+ // Check for the Start Of Image marker.
+ _, err := io.ReadFull(d.r, d.tmp[0:2])
+ if err != nil {
+ return nil, err
+ }
+ if d.tmp[0] != 0xff || d.tmp[1] != soiMarker {
+ return nil, FormatError("missing SOI marker")
+ }
+
+ // Process the remaining segments until the End Of Image marker.
+ for {
+ _, err := io.ReadFull(d.r, d.tmp[0:2])
+ if err != nil {
+ return nil, err
+ }
+ if d.tmp[0] != 0xff {
+ return nil, FormatError("missing 0xff marker start")
+ }
+ marker := d.tmp[1]
+ if marker == eoiMarker { // End Of Image.
+ break
+ }
+
+ // Read the 16-bit length of the segment. The value includes the 2 bytes for the
+ // length itself, so we subtract 2 to get the number of remaining bytes.
+ _, err = io.ReadFull(d.r, d.tmp[0:2])
+ if err != nil {
+ return nil, err
+ }
+ n := int(d.tmp[0])<<8 + int(d.tmp[1]) - 2
+ if n < 0 {
+ return nil, FormatError("short segment length")
+ }
+
+ switch {
+ case marker == sof0Marker: // Start Of Frame (Baseline).
+ err = d.processSOF(n)
+ if configOnly {
+ return nil, err
+ }
+ case marker == sof2Marker: // Start Of Frame (Progressive).
+ err = UnsupportedError("progressive mode")
+ case marker == dhtMarker: // Define Huffman Table.
+ err = d.processDHT(n)
+ case marker == dqtMarker: // Define Quantization Table.
+ err = d.processDQT(n)
+ case marker == sosMarker: // Start Of Scan.
+ err = d.processSOS(n)
+ case marker == driMarker: // Define Restart Interval.
+ err = d.processDRI(n)
+ case marker >= app0Marker && marker <= app15Marker || marker == comMarker: // APPlication specific, or COMment.
+ err = d.ignore(n)
+ default:
+ err = UnsupportedError("unknown marker")
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+ return d.image, nil
+}
+
+// Decode reads a JPEG image from r and returns it as an image.Image.
+func Decode(r io.Reader) (image.Image, os.Error) {
+ var d decoder
+ return d.decode(r, false)
+}
+
+// DecodeConfig returns the color model and dimensions of a JPEG image without
+// decoding the entire image.
+func DecodeConfig(r io.Reader) (image.Config, os.Error) {
+ var d decoder
+ if _, err := d.decode(r, true); err != nil {
+ return image.Config{}, err
+ }
+ return image.Config{image.RGBAColorModel, d.width, d.height}, nil
+}
+
+func init() {
+ image.RegisterFormat("jpeg", "\xff\xd8", Decode, DecodeConfig)
+}
diff --git a/libgo/go/image/names.go b/libgo/go/image/names.go
new file mode 100644
index 000000000..c309684ce
--- /dev/null
+++ b/libgo/go/image/names.go
@@ -0,0 +1,67 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+var (
+ // Black is an opaque black ColorImage.
+ Black = NewColorImage(Gray16Color{0})
+ // White is an opaque white ColorImage.
+ White = NewColorImage(Gray16Color{0xffff})
+ // Transparent is a fully transparent ColorImage.
+ Transparent = NewColorImage(Alpha16Color{0})
+ // Opaque is a fully opaque ColorImage.
+ Opaque = NewColorImage(Alpha16Color{0xffff})
+)
+
+// A ColorImage is an infinite-sized Image of uniform Color.
+// It implements both the Color and Image interfaces.
+type ColorImage struct {
+ C Color
+}
+
+func (c *ColorImage) RGBA() (r, g, b, a uint32) {
+ return c.C.RGBA()
+}
+
+func (c *ColorImage) ColorModel() ColorModel {
+ return ColorModelFunc(func(Color) Color { return c.C })
+}
+
+func (c *ColorImage) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
+
+func (c *ColorImage) At(x, y int) Color { return c.C }
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (c *ColorImage) Opaque() bool {
+ _, _, _, a := c.C.RGBA()
+ return a == 0xffff
+}
+
+func NewColorImage(c Color) *ColorImage {
+ return &ColorImage{c}
+}
+
+// A Tiled is an infinite-sized Image that repeats another Image in both
+// directions. Tiled{i, p}.At(x, y) will equal i.At(x+p.X, y+p.Y) for all
+// points {x+p.X, y+p.Y} within i's Bounds.
+type Tiled struct {
+ I Image
+ Offset Point
+}
+
+func (t *Tiled) ColorModel() ColorModel {
+ return t.I.ColorModel()
+}
+
+func (t *Tiled) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
+
+func (t *Tiled) At(x, y int) Color {
+ p := Point{x, y}.Add(t.Offset).Mod(t.I.Bounds())
+ return t.I.At(p.X, p.Y)
+}
+
+func NewTiled(i Image, offset Point) *Tiled {
+ return &Tiled{i, offset}
+}
diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go
new file mode 100644
index 000000000..e2d679bb4
--- /dev/null
+++ b/libgo/go/image/png/reader.go
@@ -0,0 +1,588 @@
+// 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.
+
+// The png package implements a PNG image decoder and encoder.
+//
+// The PNG specification is at http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html
+package png
+
+import (
+ "compress/zlib"
+ "fmt"
+ "hash"
+ "hash/crc32"
+ "image"
+ "io"
+ "os"
+)
+
+// Color type, as per the PNG spec.
+const (
+ ctGrayscale = 0
+ ctTrueColor = 2
+ ctPaletted = 3
+ ctGrayscaleAlpha = 4
+ ctTrueColorAlpha = 6
+)
+
+// A cb is a combination of color type and bit depth.
+const (
+ cbInvalid = iota
+ cbG8
+ cbTC8
+ cbP8
+ cbTCA8
+ cbG16
+ cbTC16
+ cbTCA16
+)
+
+// Filter type, as per the PNG spec.
+const (
+ ftNone = 0
+ ftSub = 1
+ ftUp = 2
+ ftAverage = 3
+ ftPaeth = 4
+ nFilter = 5
+)
+
+// Decoding stage.
+// The PNG specification says that the IHDR, PLTE (if present), IDAT and IEND
+// chunks must appear in that order. There may be multiple IDAT chunks, and
+// IDAT chunks must be sequential (i.e. they may not have any other chunks
+// between them).
+const (
+ dsStart = iota
+ dsSeenIHDR
+ dsSeenPLTE
+ dsSeenIDAT
+ dsSeenIEND
+)
+
+const pngHeader = "\x89PNG\r\n\x1a\n"
+
+type imgOrErr struct {
+ img image.Image
+ err os.Error
+}
+
+type decoder struct {
+ width, height int
+ palette image.PalettedColorModel
+ cb int
+ stage int
+ idatWriter io.WriteCloser
+ idatDone chan imgOrErr
+ tmp [3 * 256]byte
+}
+
+// A FormatError reports that the input is not a valid PNG.
+type FormatError string
+
+func (e FormatError) String() string { return "png: invalid format: " + string(e) }
+
+var chunkOrderError = FormatError("chunk out of order")
+
+// An IDATDecodingError wraps an inner error (such as a ZLIB decoding error) encountered while processing an IDAT chunk.
+type IDATDecodingError struct {
+ Err os.Error
+}
+
+func (e IDATDecodingError) String() string { return "png: IDAT decoding error: " + e.Err.String() }
+
+// An UnsupportedError reports that the input uses a valid but unimplemented PNG feature.
+type UnsupportedError string
+
+func (e UnsupportedError) String() string { return "png: unsupported feature: " + string(e) }
+
+// Big-endian.
+func parseUint32(b []uint8) uint32 {
+ return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
+}
+
+func abs(x int) int {
+ if x < 0 {
+ return -x
+ }
+ return x
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+ if length != 13 {
+ return FormatError("bad IHDR length")
+ }
+ _, err := io.ReadFull(r, d.tmp[0:13])
+ if err != nil {
+ return err
+ }
+ crc.Write(d.tmp[0:13])
+ if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 {
+ return UnsupportedError("compression, filter or interlace method")
+ }
+ w := int32(parseUint32(d.tmp[0:4]))
+ h := int32(parseUint32(d.tmp[4:8]))
+ if w < 0 || h < 0 {
+ return FormatError("negative dimension")
+ }
+ nPixels := int64(w) * int64(h)
+ if nPixels != int64(int(nPixels)) {
+ return UnsupportedError("dimension overflow")
+ }
+ d.cb = cbInvalid
+ switch d.tmp[8] {
+ case 8:
+ switch d.tmp[9] {
+ case ctGrayscale:
+ d.cb = cbG8
+ case ctTrueColor:
+ d.cb = cbTC8
+ case ctPaletted:
+ d.cb = cbP8
+ case ctTrueColorAlpha:
+ d.cb = cbTCA8
+ }
+ case 16:
+ switch d.tmp[9] {
+ case ctGrayscale:
+ d.cb = cbG16
+ case ctTrueColor:
+ d.cb = cbTC16
+ case ctTrueColorAlpha:
+ d.cb = cbTCA16
+ }
+ }
+ if d.cb == cbInvalid {
+ return UnsupportedError(fmt.Sprintf("bit depth %d, color type %d", d.tmp[8], d.tmp[9]))
+ }
+ d.width, d.height = int(w), int(h)
+ return nil
+}
+
+func (d *decoder) parsePLTE(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+ np := int(length / 3) // The number of palette entries.
+ if length%3 != 0 || np <= 0 || np > 256 {
+ return FormatError("bad PLTE length")
+ }
+ n, err := io.ReadFull(r, d.tmp[0:3*np])
+ if err != nil {
+ return err
+ }
+ crc.Write(d.tmp[0:n])
+ switch d.cb {
+ case cbP8:
+ d.palette = image.PalettedColorModel(make([]image.Color, np))
+ for i := 0; i < np; i++ {
+ d.palette[i] = image.RGBAColor{d.tmp[3*i+0], d.tmp[3*i+1], d.tmp[3*i+2], 0xff}
+ }
+ case cbTC8, cbTCA8, cbTC16, cbTCA16:
+ // As per the PNG spec, a PLTE chunk is optional (and for practical purposes,
+ // ignorable) for the ctTrueColor and ctTrueColorAlpha color types (section 4.1.2).
+ default:
+ return FormatError("PLTE, color type mismatch")
+ }
+ return nil
+}
+
+func (d *decoder) parsetRNS(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+ if length > 256 {
+ return FormatError("bad tRNS length")
+ }
+ n, err := io.ReadFull(r, d.tmp[0:length])
+ if err != nil {
+ return err
+ }
+ crc.Write(d.tmp[0:n])
+ switch d.cb {
+ case cbG8, cbG16:
+ return UnsupportedError("grayscale transparency")
+ case cbTC8, cbTC16:
+ return UnsupportedError("truecolor transparency")
+ case cbP8:
+ if n > len(d.palette) {
+ return FormatError("bad tRNS length")
+ }
+ for i := 0; i < n; i++ {
+ rgba := d.palette[i].(image.RGBAColor)
+ d.palette[i] = image.RGBAColor{rgba.R, rgba.G, rgba.B, d.tmp[i]}
+ }
+ case cbTCA8, cbTCA16:
+ return FormatError("tRNS, color type mismatch")
+ }
+ return nil
+}
+
+// The Paeth filter function, as per the PNG specification.
+func paeth(a, b, c uint8) uint8 {
+ p := int(a) + int(b) - int(c)
+ pa := abs(p - int(a))
+ pb := abs(p - int(b))
+ pc := abs(p - int(c))
+ if pa <= pb && pa <= pc {
+ return a
+ } else if pb <= pc {
+ return b
+ }
+ return c
+}
+
+func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
+ r, err := zlib.NewReader(idat)
+ if err != nil {
+ return nil, err
+ }
+ defer r.Close()
+ bpp := 0 // Bytes per pixel.
+ maxPalette := uint8(0)
+ var (
+ gray *image.Gray
+ rgba *image.RGBA
+ paletted *image.Paletted
+ nrgba *image.NRGBA
+ gray16 *image.Gray16
+ rgba64 *image.RGBA64
+ nrgba64 *image.NRGBA64
+ img image.Image
+ )
+ switch d.cb {
+ case cbG8:
+ bpp = 1
+ gray = image.NewGray(d.width, d.height)
+ img = gray
+ case cbTC8:
+ bpp = 3
+ rgba = image.NewRGBA(d.width, d.height)
+ img = rgba
+ case cbP8:
+ bpp = 1
+ paletted = image.NewPaletted(d.width, d.height, d.palette)
+ img = paletted
+ maxPalette = uint8(len(d.palette) - 1)
+ case cbTCA8:
+ bpp = 4
+ nrgba = image.NewNRGBA(d.width, d.height)
+ img = nrgba
+ case cbG16:
+ bpp = 2
+ gray16 = image.NewGray16(d.width, d.height)
+ img = gray16
+ case cbTC16:
+ bpp = 6
+ rgba64 = image.NewRGBA64(d.width, d.height)
+ img = rgba64
+ case cbTCA16:
+ bpp = 8
+ nrgba64 = image.NewNRGBA64(d.width, d.height)
+ img = nrgba64
+ }
+ // cr and pr are the bytes for the current and previous row.
+ // The +1 is for the per-row filter type, which is at cr[0].
+ cr := make([]uint8, 1+bpp*d.width)
+ pr := make([]uint8, 1+bpp*d.width)
+
+ for y := 0; y < d.height; y++ {
+ // Read the decompressed bytes.
+ _, err := io.ReadFull(r, cr)
+ if err != nil {
+ return nil, err
+ }
+
+ // Apply the filter.
+ cdat := cr[1:]
+ pdat := pr[1:]
+ switch cr[0] {
+ case ftNone:
+ // No-op.
+ case ftSub:
+ for i := bpp; i < len(cdat); i++ {
+ cdat[i] += cdat[i-bpp]
+ }
+ case ftUp:
+ for i := 0; i < len(cdat); i++ {
+ cdat[i] += pdat[i]
+ }
+ case ftAverage:
+ for i := 0; i < bpp; i++ {
+ cdat[i] += pdat[i] / 2
+ }
+ for i := bpp; i < len(cdat); i++ {
+ cdat[i] += uint8((int(cdat[i-bpp]) + int(pdat[i])) / 2)
+ }
+ case ftPaeth:
+ for i := 0; i < bpp; i++ {
+ cdat[i] += paeth(0, pdat[i], 0)
+ }
+ for i := bpp; i < len(cdat); i++ {
+ cdat[i] += paeth(cdat[i-bpp], pdat[i], pdat[i-bpp])
+ }
+ default:
+ return nil, FormatError("bad filter type")
+ }
+
+ // Convert from bytes to colors.
+ switch d.cb {
+ case cbG8:
+ for x := 0; x < d.width; x++ {
+ gray.Set(x, y, image.GrayColor{cdat[x]})
+ }
+ case cbTC8:
+ for x := 0; x < d.width; x++ {
+ rgba.Set(x, y, image.RGBAColor{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff})
+ }
+ case cbP8:
+ for x := 0; x < d.width; x++ {
+ if cdat[x] > maxPalette {
+ return nil, FormatError("palette index out of range")
+ }
+ paletted.SetColorIndex(x, y, cdat[x])
+ }
+ case cbTCA8:
+ for x := 0; x < d.width; x++ {
+ nrgba.Set(x, y, image.NRGBAColor{cdat[4*x+0], cdat[4*x+1], cdat[4*x+2], cdat[4*x+3]})
+ }
+ case cbG16:
+ for x := 0; x < d.width; x++ {
+ ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
+ gray16.Set(x, y, image.Gray16Color{ycol})
+ }
+ case cbTC16:
+ for x := 0; x < d.width; x++ {
+ rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
+ gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
+ bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
+ rgba64.Set(x, y, image.RGBA64Color{rcol, gcol, bcol, 0xffff})
+ }
+ case cbTCA16:
+ for x := 0; x < d.width; x++ {
+ rcol := uint16(cdat[8*x+0])<<8 | uint16(cdat[8*x+1])
+ gcol := uint16(cdat[8*x+2])<<8 | uint16(cdat[8*x+3])
+ bcol := uint16(cdat[8*x+4])<<8 | uint16(cdat[8*x+5])
+ acol := uint16(cdat[8*x+6])<<8 | uint16(cdat[8*x+7])
+ nrgba64.Set(x, y, image.NRGBA64Color{rcol, gcol, bcol, acol})
+ }
+ }
+
+ // The current row for y is the previous row for y+1.
+ pr, cr = cr, pr
+ }
+ return img, nil
+}
+
+func (d *decoder) parseIDAT(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+ // There may be more than one IDAT chunk, but their contents must be
+ // treated as if it was one continuous stream (to the zlib decoder).
+ // We bring up an io.Pipe and write the IDAT chunks into the pipe as
+ // we see them, and decode the stream in a separate go-routine, which
+ // signals its completion (successful or not) via a channel.
+ if d.idatWriter == nil {
+ pr, pw := io.Pipe()
+ d.idatWriter = pw
+ d.idatDone = make(chan imgOrErr)
+ go func() {
+ img, err := d.idatReader(pr)
+ if err == os.EOF {
+ err = FormatError("too little IDAT")
+ }
+ pr.CloseWithError(FormatError("too much IDAT"))
+ d.idatDone <- imgOrErr{img, err}
+ }()
+ }
+ var buf [4096]byte
+ for length > 0 {
+ n, err1 := r.Read(buf[0:min(len(buf), int(length))])
+ // We delay checking err1. It is possible to get n bytes and an error,
+ // but if the n bytes themselves contain a FormatError, for example, we
+ // want to report that error, and not the one that made the Read stop.
+ n, err2 := d.idatWriter.Write(buf[0:n])
+ if err2 != nil {
+ return err2
+ }
+ if err1 != nil {
+ return err1
+ }
+ crc.Write(buf[0:n])
+ length -= uint32(n)
+ }
+ return nil
+}
+
+func (d *decoder) parseIEND(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+ if length != 0 {
+ return FormatError("bad IEND length")
+ }
+ return nil
+}
+
+func (d *decoder) parseChunk(r io.Reader) os.Error {
+ // Read the length.
+ n, err := io.ReadFull(r, d.tmp[0:4])
+ if err == os.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ if err != nil {
+ return err
+ }
+ length := parseUint32(d.tmp[0:4])
+
+ // Read the chunk type.
+ n, err = io.ReadFull(r, d.tmp[0:4])
+ if err == os.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ if err != nil {
+ return err
+ }
+ crc := crc32.NewIEEE()
+ crc.Write(d.tmp[0:4])
+
+ // Read the chunk data.
+ switch string(d.tmp[0:4]) {
+ case "IHDR":
+ if d.stage != dsStart {
+ return chunkOrderError
+ }
+ d.stage = dsSeenIHDR
+ err = d.parseIHDR(r, crc, length)
+ case "PLTE":
+ if d.stage != dsSeenIHDR {
+ return chunkOrderError
+ }
+ d.stage = dsSeenPLTE
+ err = d.parsePLTE(r, crc, length)
+ case "tRNS":
+ if d.stage != dsSeenPLTE {
+ return chunkOrderError
+ }
+ err = d.parsetRNS(r, crc, length)
+ case "IDAT":
+ if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
+ return chunkOrderError
+ }
+ d.stage = dsSeenIDAT
+ err = d.parseIDAT(r, crc, length)
+ case "IEND":
+ if d.stage != dsSeenIDAT {
+ return chunkOrderError
+ }
+ d.stage = dsSeenIEND
+ err = d.parseIEND(r, crc, length)
+ default:
+ // Ignore this chunk (of a known length).
+ var ignored [4096]byte
+ for length > 0 {
+ n, err = io.ReadFull(r, ignored[0:min(len(ignored), int(length))])
+ if err != nil {
+ return err
+ }
+ crc.Write(ignored[0:n])
+ length -= uint32(n)
+ }
+ }
+ if err != nil {
+ return err
+ }
+
+ // Read the checksum.
+ n, err = io.ReadFull(r, d.tmp[0:4])
+ if err == os.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ if err != nil {
+ return err
+ }
+ if parseUint32(d.tmp[0:4]) != crc.Sum32() {
+ return FormatError("invalid checksum")
+ }
+ return nil
+}
+
+func (d *decoder) checkHeader(r io.Reader) os.Error {
+ _, err := io.ReadFull(r, d.tmp[0:8])
+ if err != nil {
+ return err
+ }
+ if string(d.tmp[0:8]) != pngHeader {
+ return FormatError("not a PNG file")
+ }
+ return nil
+}
+
+// Decode reads a PNG image from r and returns it as an image.Image.
+// The type of Image returned depends on the PNG contents.
+func Decode(r io.Reader) (image.Image, os.Error) {
+ var d decoder
+ err := d.checkHeader(r)
+ if err != nil {
+ return nil, err
+ }
+ for d.stage != dsSeenIEND {
+ err = d.parseChunk(r)
+ if err != nil {
+ break
+ }
+ }
+ var img image.Image
+ if d.idatWriter != nil {
+ d.idatWriter.Close()
+ ie := <-d.idatDone
+ if err == nil {
+ img, err = ie.img, ie.err
+ }
+ }
+ if err != nil {
+ return nil, err
+ }
+ return img, nil
+}
+
+// DecodeConfig returns the color model and dimensions of a PNG image without
+// decoding the entire image.
+func DecodeConfig(r io.Reader) (image.Config, os.Error) {
+ var d decoder
+ err := d.checkHeader(r)
+ if err != nil {
+ return image.Config{}, err
+ }
+ for {
+ err = d.parseChunk(r)
+ if err != nil {
+ return image.Config{}, err
+ }
+ if d.stage == dsSeenIHDR && d.cb != cbP8 {
+ break
+ }
+ if d.stage == dsSeenPLTE && d.cb == cbP8 {
+ break
+ }
+ }
+ var cm image.ColorModel
+ switch d.cb {
+ case cbG8:
+ cm = image.GrayColorModel
+ case cbTC8:
+ cm = image.RGBAColorModel
+ case cbP8:
+ cm = d.palette
+ case cbTCA8:
+ cm = image.NRGBAColorModel
+ case cbG16:
+ cm = image.Gray16ColorModel
+ case cbTC16:
+ cm = image.RGBA64ColorModel
+ case cbTCA16:
+ cm = image.NRGBA64ColorModel
+ }
+ return image.Config{cm, d.width, d.height}, nil
+}
+
+func init() {
+ image.RegisterFormat("png", pngHeader, Decode, DecodeConfig)
+}
diff --git a/libgo/go/image/png/reader_test.go b/libgo/go/image/png/reader_test.go
new file mode 100644
index 000000000..fefceee3a
--- /dev/null
+++ b/libgo/go/image/png/reader_test.go
@@ -0,0 +1,190 @@
+// 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 png
+
+import (
+ "bufio"
+ "fmt"
+ "image"
+ "io"
+ "os"
+ "testing"
+)
+
+// The go PNG library currently supports only a subset of the full PNG specification.
+// In particular, bit depths other than 8 or 16 are not supported, nor are grayscale-
+// alpha images.
+var filenames = []string{
+ //"basn0g01", // bit depth is not 8 or 16
+ //"basn0g02", // bit depth is not 8 or 16
+ //"basn0g04", // bit depth is not 8 or 16
+ "basn0g08",
+ "basn0g16",
+ "basn2c08",
+ "basn2c16",
+ //"basn3p01", // bit depth is not 8 or 16
+ //"basn3p02", // bit depth is not 8 or 16
+ //"basn3p04", // bit depth is not 8 or 16
+ "basn3p08",
+ //"basn4a08", // grayscale-alpha color model
+ //"basn4a16", // grayscale-alpha color model
+ "basn6a08",
+ "basn6a16",
+}
+
+func readPng(filename string) (image.Image, os.Error) {
+ f, err := os.Open(filename, os.O_RDONLY, 0444)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return Decode(f)
+}
+
+// An approximation of the sng command-line tool.
+func sng(w io.WriteCloser, filename string, png image.Image) {
+ defer w.Close()
+ bounds := png.Bounds()
+ cm := png.ColorModel()
+ var bitdepth int
+ switch cm {
+ case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel, image.GrayColorModel:
+ bitdepth = 8
+ default:
+ bitdepth = 16
+ }
+ cpm, _ := cm.(image.PalettedColorModel)
+ var paletted *image.Paletted
+ if cpm != nil {
+ bitdepth = 8
+ paletted = png.(*image.Paletted)
+ }
+
+ // Write the filename and IHDR.
+ io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n")
+ fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth)
+ switch {
+ case cm == image.RGBAColorModel, cm == image.RGBA64ColorModel:
+ io.WriteString(w, " using color;\n")
+ case cm == image.NRGBAColorModel, cm == image.NRGBA64ColorModel:
+ io.WriteString(w, " using color alpha;\n")
+ case cm == image.GrayColorModel, cm == image.Gray16ColorModel:
+ io.WriteString(w, " using grayscale;\n")
+ case cpm != nil:
+ io.WriteString(w, " using color palette;\n")
+ default:
+ io.WriteString(w, "unknown PNG decoder color model\n")
+ }
+ io.WriteString(w, "}\n")
+
+ // We fake a gAMA output. The test files have a gAMA chunk but the go PNG parser ignores it
+ // (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder").
+ io.WriteString(w, "gAMA {1.0000}\n")
+
+ // Write the PLTE (if applicable).
+ if cpm != nil {
+ io.WriteString(w, "PLTE {\n")
+ for i := 0; i < len(cpm); i++ {
+ r, g, b, _ := cpm[i].RGBA()
+ r >>= 8
+ g >>= 8
+ b >>= 8
+ fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b)
+ }
+ io.WriteString(w, "}\n")
+ }
+
+ // Write the IMAGE.
+ io.WriteString(w, "IMAGE {\n pixels hex\n")
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+ switch {
+ case cm == image.GrayColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ gray := png.At(x, y).(image.GrayColor)
+ fmt.Fprintf(w, "%02x", gray.Y)
+ }
+ case cm == image.Gray16ColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ gray16 := png.At(x, y).(image.Gray16Color)
+ fmt.Fprintf(w, "%04x ", gray16.Y)
+ }
+ case cm == image.RGBAColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ rgba := png.At(x, y).(image.RGBAColor)
+ fmt.Fprintf(w, "%02x%02x%02x ", rgba.R, rgba.G, rgba.B)
+ }
+ case cm == image.RGBA64ColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ rgba64 := png.At(x, y).(image.RGBA64Color)
+ fmt.Fprintf(w, "%04x%04x%04x ", rgba64.R, rgba64.G, rgba64.B)
+ }
+ case cm == image.NRGBAColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ nrgba := png.At(x, y).(image.NRGBAColor)
+ fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
+ }
+ case cm == image.NRGBA64ColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ nrgba64 := png.At(x, y).(image.NRGBA64Color)
+ fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
+ }
+ case cpm != nil:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ fmt.Fprintf(w, "%02x", paletted.ColorIndexAt(x, y))
+ }
+ }
+ io.WriteString(w, "\n")
+ }
+ io.WriteString(w, "}\n")
+}
+
+func TestReader(t *testing.T) {
+ for _, fn := range filenames {
+ // Read the .png file.
+ image, err := readPng("testdata/pngsuite/" + fn + ".png")
+ if err != nil {
+ t.Error(fn, err)
+ continue
+ }
+ piper, pipew := io.Pipe()
+ pb := bufio.NewReader(piper)
+ go sng(pipew, fn, image)
+ defer piper.Close()
+
+ // Read the .sng file.
+ sf, err := os.Open("testdata/pngsuite/"+fn+".sng", os.O_RDONLY, 0444)
+ if err != nil {
+ t.Error(fn, err)
+ continue
+ }
+ defer sf.Close()
+ sb := bufio.NewReader(sf)
+ if err != nil {
+ t.Error(fn, err)
+ continue
+ }
+
+ // Compare the two, in SNG format, line by line.
+ for {
+ ps, perr := pb.ReadString('\n')
+ ss, serr := sb.ReadString('\n')
+ if perr == os.EOF && serr == os.EOF {
+ break
+ }
+ if perr != nil {
+ t.Error(fn, perr)
+ break
+ }
+ if serr != nil {
+ t.Error(fn, serr)
+ break
+ }
+ if ps != ss {
+ t.Errorf("%s: Mismatch\n%sversus\n%s\n", fn, ps, ss)
+ break
+ }
+ }
+ }
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/README b/libgo/go/image/png/testdata/pngsuite/README
new file mode 100644
index 000000000..27e7c6558
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/README
@@ -0,0 +1,9 @@
+The *.png and README.original files in this directory are copied from
+libpng.org, specifically contrib/pngsuite/* in libpng-1.2.40.tar.gz.
+README.original gives the following license for those files:
+
+ Permission to use, copy, and distribute these images for any purpose
+ and without fee is hereby granted.
+
+The *.sng files in this directory were generated from the *.png files
+by the sng command-line tool.
diff --git a/libgo/go/image/png/testdata/pngsuite/README.original b/libgo/go/image/png/testdata/pngsuite/README.original
new file mode 100644
index 000000000..714d12c64
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/README.original
@@ -0,0 +1,85 @@
+
+pngsuite
+--------
+(c) Willem van Schaik, 1999
+
+Permission to use, copy, and distribute these images for any purpose and
+without fee is hereby granted.
+
+These 15 images are part of the much larger PngSuite test-set of
+images, available for developers of PNG supporting software. The
+complete set, available at http:/www.schaik.com/pngsuite/, contains
+a variety of images to test interlacing, gamma settings, ancillary
+chunks, etc.
+
+The images in this directory represent the basic PNG color-types:
+grayscale (1-16 bit deep), full color (8 or 16 bit), paletted
+(1-8 bit) and grayscale or color images with alpha channel. You
+can use them to test the proper functioning of PNG software.
+
+ filename depth type
+ ------------ ------ --------------
+ basn0g01.png 1-bit grayscale
+ basn0g02.png 2-bit grayscale
+ basn0g04.png 4-bit grayscale
+ basn0g08.png 8-bit grayscale
+ basn0g16.png 16-bit grayscale
+ basn2c08.png 8-bit truecolor
+ basn2c16.png 16-bit truecolor
+ basn3p01.png 1-bit paletted
+ basn3p02.png 2-bit paletted
+ basn3p04.png 4-bit paletted
+ basn3p08.png 8-bit paletted
+ basn4a08.png 8-bit gray with alpha
+ basn4a16.png 16-bit gray with alpha
+ basn6a08.png 8-bit RGBA
+ basn6a16.png 16-bit RGBA
+
+Here is the correct result of typing "pngtest -m *.png" in
+this directory:
+
+Testing basn0g01.png: PASS (524 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g02.png: PASS (448 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g04.png: PASS (520 zero samples)
+ Filter 0 was used 32 times
+Testing basn0g08.png: PASS (3 zero samples)
+ Filter 1 was used 9 times
+ Filter 4 was used 23 times
+Testing basn0g16.png: PASS (1 zero samples)
+ Filter 1 was used 1 times
+ Filter 2 was used 31 times
+Testing basn2c08.png: PASS (6 zero samples)
+ Filter 1 was used 5 times
+ Filter 4 was used 27 times
+Testing basn2c16.png: PASS (592 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn3p01.png: PASS (512 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p02.png: PASS (448 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p04.png: PASS (544 zero samples)
+ Filter 0 was used 32 times
+Testing basn3p08.png: PASS (4 zero samples)
+ Filter 0 was used 32 times
+Testing basn4a08.png: PASS (32 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn4a16.png: PASS (64 zero samples)
+ Filter 0 was used 1 times
+ Filter 1 was used 2 times
+ Filter 2 was used 1 times
+ Filter 4 was used 28 times
+Testing basn6a08.png: PASS (160 zero samples)
+ Filter 1 was used 1 times
+ Filter 4 was used 31 times
+Testing basn6a16.png: PASS (1072 zero samples)
+ Filter 1 was used 4 times
+ Filter 4 was used 28 times
+libpng passes test
+
+Willem van Schaik
+<willem@schaik.com>
+October 1999
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g01.png b/libgo/go/image/png/testdata/pngsuite/basn0g01.png
new file mode 100644
index 000000000..e31e1c7a6
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn0g01.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g01.sng b/libgo/go/image/png/testdata/pngsuite/basn0g01.sng
new file mode 100644
index 000000000..e712d8ec6
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn0g01.sng
@@ -0,0 +1,41 @@
+#SNG: from basn0g01.png
+IHDR {
+ width: 32; height: 32; bitdepth: 1;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+fffffffe
+fffffffc
+fffffff8
+fffffff0
+f3f3ffe0
+f3f3ffc0
+f3f3ff80
+f333ff00
+f333fe00
+f333fc00
+f807f800
+f807f000
+fccfe000
+fccfc000
+ffff8000
+ffff0000
+fffe0000
+fffc0000
+fff80fe0
+fff00fe0
+ffe00c30
+ffc00c30
+ff800fe0
+ff000fe0
+fe000c30
+fc000c30
+f8000fe0
+f0000fe0
+e0000000
+c0000000
+80000000
+00000000
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g02.png b/libgo/go/image/png/testdata/pngsuite/basn0g02.png
new file mode 100644
index 000000000..68809dd8f
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn0g02.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g02.sng b/libgo/go/image/png/testdata/pngsuite/basn0g02.sng
new file mode 100644
index 000000000..e7f2d7ea9
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn0g02.sng
@@ -0,0 +1,41 @@
+#SNG: from basn0g02.png
+IHDR {
+ width: 32; height: 32; bitdepth: 2;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+0055aaff0055aaff
+0055aaff0055aaff
+0055aaff0055aaff
+0055aaff0055aaff
+55aaff0055aaff00
+55aaff0055aaff00
+55aaff0055aaff00
+55aaff0055aaff00
+aaff0055aaff0055
+aaff0055aaff0055
+aaff0055aaff0055
+aaff0055aaff0055
+ff0055aaff0055aa
+ff0055aaff0055aa
+ff0055aaff0055aa
+ff0055aaff0055aa
+0055aaff0055aaff
+0055aaff0055aaff
+0055aaff0055aaff
+0055aaff0055aaff
+55aaff0055aaff00
+55aaff0055aaff00
+55aaff0055aaff00
+55aaff0055aaff00
+aaff0055aaff0055
+aaff0055aaff0055
+aaff0055aaff0055
+aaff0055aaff0055
+ff0055aaff0055aa
+ff0055aaff0055aa
+ff0055aaff0055aa
+ff0055aaff0055aa
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g04.png b/libgo/go/image/png/testdata/pngsuite/basn0g04.png
new file mode 100644
index 000000000..6fa089cb8
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn0g04.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g04.sng b/libgo/go/image/png/testdata/pngsuite/basn0g04.sng
new file mode 100644
index 000000000..396c508b2
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn0g04.sng
@@ -0,0 +1,41 @@
+#SNG: from basn0g04.png
+IHDR {
+ width: 32; height: 32; bitdepth: 4;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+00001111222233334444555566667777
+00001111222233334444555566667777
+00001111222233334444555566667777
+00001111222233334444555566667777
+11112222333344445555666677778888
+11112222333344445555666677778888
+11112222333344445555666677778888
+11112222333344445555666677778888
+22223333444455556666777788889999
+22223333444455556666777788889999
+22223333444455556666777788889999
+22223333444455556666777788889999
+3333444455556666777788889999aaaa
+3333444455556666777788889999aaaa
+3333444455556666777788889999aaaa
+3333444455556666777788889999aaaa
+444455556666777788889999aaaabbbb
+444455556666777788889999aaaabbbb
+444455556666777788889999aaaabbbb
+444455556666777788889999aaaabbbb
+55556666777788889999aaaabbbbcccc
+55556666777788889999aaaabbbbcccc
+55556666777788889999aaaabbbbcccc
+55556666777788889999aaaabbbbcccc
+6666777788889999aaaabbbbccccdddd
+6666777788889999aaaabbbbccccdddd
+6666777788889999aaaabbbbccccdddd
+6666777788889999aaaabbbbccccdddd
+777788889999aaaabbbbccccddddeeee
+777788889999aaaabbbbccccddddeeee
+777788889999aaaabbbbccccddddeeee
+777788889999aaaabbbbccccddddeeee
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g08.png b/libgo/go/image/png/testdata/pngsuite/basn0g08.png
new file mode 100644
index 000000000..bf522eef0
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn0g08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g08.sng b/libgo/go/image/png/testdata/pngsuite/basn0g08.sng
new file mode 100644
index 000000000..7389eb774
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn0g08.sng
@@ -0,0 +1,41 @@
+#SNG: from basn0g08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
+404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
+606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f
+808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f
+a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
+c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf
+e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
+fefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0df
+dedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bf
+bebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f
+9e9d9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f
+7e7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f
+5e5d5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f
+3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f
+1e1d1c1b1a191817161514131211100f0e0d0c0b0a0908070605040302010001
+02030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021
+22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041
+42434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061
+62636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081
+82838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1
+a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1
+c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1
+e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfefffefd
+fcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedd
+dcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebd
+bcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d
+9c9b9a999897969594939291908f8e8d8c8b8a898887868584838281807f7e7d
+7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e5d
+5c5b5a595857565554535251504f4e4d4c4b4a494847464544434241403f3e3d
+3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d
+1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100010203
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g16.png b/libgo/go/image/png/testdata/pngsuite/basn0g16.png
new file mode 100644
index 000000000..318ebcadf
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn0g16.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn0g16.sng b/libgo/go/image/png/testdata/pngsuite/basn0g16.sng
new file mode 100644
index 000000000..922391a9e
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn0g16.sng
@@ -0,0 +1,41 @@
+#SNG: from basn0g16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+0000 0900 1200 1b00 2400 2d00 3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff
+0200 0b00 1400 1d00 2600 2f00 3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff
+0400 0d00 1600 1f00 2800 3100 3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff
+0600 0f00 1800 2100 2a00 3300 3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff
+0800 1100 1a00 2300 2c00 3500 3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff
+0a00 1300 1c00 2500 2e00 3700 4000 4900 5200 5b00 6400 6d00 7600 7f00 8800 9100 9a00 a300 ac00 b500 be00 c700 d000 d900 e200 eb00 f400 fd00 edff d2ff b7ff 9cff
+0c00 1500 1e00 2700 3000 3900 4200 4b00 5400 5d00 6600 6f00 7800 8100 8a00 9300 9c00 a500 ae00 b700 c000 c900 d200 db00 e400 ed00 f600 ff00 e7ff ccff b1ff 96ff
+0e00 1700 2000 2900 3200 3b00 4400 4d00 5600 5f00 6800 7100 7a00 8300 8c00 9500 9e00 a700 b000 b900 c200 cb00 d400 dd00 e600 ef00 f800 fcff e1ff c6ff abff 90ff
+1000 1900 2200 2b00 3400 3d00 4600 4f00 5800 6100 6a00 7300 7c00 8500 8e00 9700 a000 a900 b200 bb00 c400 cd00 d600 df00 e800 f100 fa00 f6ff dbff c0ff a5ff 8aff
+1200 1b00 2400 2d00 3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff 9fff 84ff
+1400 1d00 2600 2f00 3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff 99ff 7eff
+1600 1f00 2800 3100 3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff 93ff 78ff
+1800 2100 2a00 3300 3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff 8dff 72ff
+1a00 2300 2c00 3500 3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff 87ff 6cff
+1c00 2500 2e00 3700 4000 4900 5200 5b00 6400 6d00 7600 7f00 8800 9100 9a00 a300 ac00 b500 be00 c700 d000 d900 e200 eb00 f400 fd00 edff d2ff b7ff 9cff 81ff 66ff
+1e00 2700 3000 3900 4200 4b00 5400 5d00 6600 6f00 7800 8100 8a00 9300 9c00 a500 ae00 b700 c000 c900 d200 db00 e400 ed00 f600 ff00 e7ff ccff b1ff 96ff 7bff 60ff
+2000 2900 3200 3b00 4400 4d00 5600 5f00 6800 7100 7a00 8300 8c00 9500 9e00 a700 b000 b900 c200 cb00 d400 dd00 e600 ef00 f800 fcff e1ff c6ff abff 90ff 75ff 5aff
+2200 2b00 3400 3d00 4600 4f00 5800 6100 6a00 7300 7c00 8500 8e00 9700 a000 a900 b200 bb00 c400 cd00 d600 df00 e800 f100 fa00 f6ff dbff c0ff a5ff 8aff 6fff 54ff
+2400 2d00 3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff 9fff 84ff 69ff 4eff
+2600 2f00 3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff 99ff 7eff 63ff 48ff
+2800 3100 3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff 93ff 78ff 5dff 42ff
+2a00 3300 3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff 8dff 72ff 57ff 3cff
+2c00 3500 3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff 87ff 6cff 51ff 36ff
+2e00 3700 4000 4900 5200 5b00 6400 6d00 7600 7f00 8800 9100 9a00 a300 ac00 b500 be00 c700 d000 d900 e200 eb00 f400 fd00 edff d2ff b7ff 9cff 81ff 66ff 4bff 30ff
+3000 3900 4200 4b00 5400 5d00 6600 6f00 7800 8100 8a00 9300 9c00 a500 ae00 b700 c000 c900 d200 db00 e400 ed00 f600 ff00 e7ff ccff b1ff 96ff 7bff 60ff 45ff 2aff
+3200 3b00 4400 4d00 5600 5f00 6800 7100 7a00 8300 8c00 9500 9e00 a700 b000 b900 c200 cb00 d400 dd00 e600 ef00 f800 fcff e1ff c6ff abff 90ff 75ff 5aff 3fff 24ff
+3400 3d00 4600 4f00 5800 6100 6a00 7300 7c00 8500 8e00 9700 a000 a900 b200 bb00 c400 cd00 d600 df00 e800 f100 fa00 f6ff dbff c0ff a5ff 8aff 6fff 54ff 39ff 1eff
+3600 3f00 4800 5100 5a00 6300 6c00 7500 7e00 8700 9000 9900 a200 ab00 b400 bd00 c600 cf00 d800 e100 ea00 f300 fc00 f0ff d5ff baff 9fff 84ff 69ff 4eff 33ff 18ff
+3800 4100 4a00 5300 5c00 6500 6e00 7700 8000 8900 9200 9b00 a400 ad00 b600 bf00 c800 d100 da00 e300 ec00 f500 fe00 eaff cfff b4ff 99ff 7eff 63ff 48ff 2dff 12ff
+3a00 4300 4c00 5500 5e00 6700 7000 7900 8200 8b00 9400 9d00 a600 af00 b800 c100 ca00 d300 dc00 e500 ee00 f700 ffff e4ff c9ff aeff 93ff 78ff 5dff 42ff 27ff 0cff
+3c00 4500 4e00 5700 6000 6900 7200 7b00 8400 8d00 9600 9f00 a800 b100 ba00 c300 cc00 d500 de00 e700 f000 f900 f9ff deff c3ff a8ff 8dff 72ff 57ff 3cff 21ff 06ff
+3e00 4700 5000 5900 6200 6b00 7400 7d00 8600 8f00 9800 a100 aa00 b300 bc00 c500 ce00 d700 e000 e900 f200 fb00 f3ff d8ff bdff a2ff 87ff 6cff 51ff 36ff 1bff 00ff
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn2c08.png b/libgo/go/image/png/testdata/pngsuite/basn2c08.png
new file mode 100644
index 000000000..21d2f91a8
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn2c08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn2c08.sng b/libgo/go/image/png/testdata/pngsuite/basn2c08.sng
new file mode 100644
index 000000000..09a61317b
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn2c08.sng
@@ -0,0 +1,41 @@
+#SNG: from basn2c08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ffffff fffffe fffffd fffffc fffffb fffffa fffff9 fffff8 fffff7 fffff6 fffff5 fffff4 fffff3 fffff2 fffff1 fffff0 ffffef ffffee ffffed ffffec ffffeb ffffea ffffe9 ffffe8 ffffe7 ffffe6 ffffe5 ffffe4 ffffe3 ffffe2 ffffe1 ffffe0
+ffffdf ffffde ffffdd ffffdc ffffdb ffffda ffffd9 ffffd8 ffffd7 ffffd6 ffffd5 ffffd4 ffffd3 ffffd2 ffffd1 ffffd0 ffffcf ffffce ffffcd ffffcc ffffcb ffffca ffffc9 ffffc8 ffffc7 ffffc6 ffffc5 ffffc4 ffffc3 ffffc2 ffffc1 ffffc0
+ffffbf ffffbe ffffbd ffffbc ffffbb ffffba ffffb9 ffffb8 ffffb7 ffffb6 ffffb5 ffffb4 ffffb3 ffffb2 ffffb1 ffffb0 ffffaf ffffae ffffad ffffac ffffab ffffaa ffffa9 ffffa8 ffffa7 ffffa6 ffffa5 ffffa4 ffffa3 ffffa2 ffffa1 ffffa0
+ffff9f ffff9e ffff9d ffff9c ffff9b ffff9a ffff99 ffff98 ffff97 ffff96 ffff95 ffff94 ffff93 ffff92 ffff91 ffff90 ffff8f ffff8e ffff8d ffff8c ffff8b ffff8a ffff89 ffff88 ffff87 ffff86 ffff85 ffff84 ffff83 ffff82 ffff81 ffff80
+ffff7f ffff7e ffff7d ffff7c ffff7b ffff7a ffff79 ffff78 ffff77 ffff76 ffff75 ffff74 ffff73 ffff72 ffff71 ffff70 ffff6f ffff6e ffff6d ffff6c ffff6b ffff6a ffff69 ffff68 ffff67 ffff66 ffff65 ffff64 ffff63 ffff62 ffff61 ffff60
+ffff5f ffff5e ffff5d ffff5c ffff5b ffff5a ffff59 ffff58 ffff57 ffff56 ffff55 ffff54 ffff53 ffff52 ffff51 ffff50 ffff4f ffff4e ffff4d ffff4c ffff4b ffff4a ffff49 ffff48 ffff47 ffff46 ffff45 ffff44 ffff43 ffff42 ffff41 ffff40
+ffff3f ffff3e ffff3d ffff3c ffff3b ffff3a ffff39 ffff38 ffff37 ffff36 ffff35 ffff34 ffff33 ffff32 ffff31 ffff30 ffff2f ffff2e ffff2d ffff2c ffff2b ffff2a ffff29 ffff28 ffff27 ffff26 ffff25 ffff24 ffff23 ffff22 ffff21 ffff20
+ffff1f ffff1e ffff1d ffff1c ffff1b ffff1a ffff19 ffff18 ffff17 ffff16 ffff15 ffff14 ffff13 ffff12 ffff11 ffff10 ffff0f ffff0e ffff0d ffff0c ffff0b ffff0a ffff09 ffff08 ffff07 ffff06 ffff05 ffff04 ffff03 ffff02 ffff01 ffff00
+ffffff fffeff fffdff fffcff fffbff fffaff fff9ff fff8ff fff7ff fff6ff fff5ff fff4ff fff3ff fff2ff fff1ff fff0ff ffefff ffeeff ffedff ffecff ffebff ffeaff ffe9ff ffe8ff ffe7ff ffe6ff ffe5ff ffe4ff ffe3ff ffe2ff ffe1ff ffe0ff
+ffdfff ffdeff ffddff ffdcff ffdbff ffdaff ffd9ff ffd8ff ffd7ff ffd6ff ffd5ff ffd4ff ffd3ff ffd2ff ffd1ff ffd0ff ffcfff ffceff ffcdff ffccff ffcbff ffcaff ffc9ff ffc8ff ffc7ff ffc6ff ffc5ff ffc4ff ffc3ff ffc2ff ffc1ff ffc0ff
+ffbfff ffbeff ffbdff ffbcff ffbbff ffbaff ffb9ff ffb8ff ffb7ff ffb6ff ffb5ff ffb4ff ffb3ff ffb2ff ffb1ff ffb0ff ffafff ffaeff ffadff ffacff ffabff ffaaff ffa9ff ffa8ff ffa7ff ffa6ff ffa5ff ffa4ff ffa3ff ffa2ff ffa1ff ffa0ff
+ff9fff ff9eff ff9dff ff9cff ff9bff ff9aff ff99ff ff98ff ff97ff ff96ff ff95ff ff94ff ff93ff ff92ff ff91ff ff90ff ff8fff ff8eff ff8dff ff8cff ff8bff ff8aff ff89ff ff88ff ff87ff ff86ff ff85ff ff84ff ff83ff ff82ff ff81ff ff80ff
+ff7fff ff7eff ff7dff ff7cff ff7bff ff7aff ff79ff ff78ff ff77ff ff76ff ff75ff ff74ff ff73ff ff72ff ff71ff ff70ff ff6fff ff6eff ff6dff ff6cff ff6bff ff6aff ff69ff ff68ff ff67ff ff66ff ff65ff ff64ff ff63ff ff62ff ff61ff ff60ff
+ff5fff ff5eff ff5dff ff5cff ff5bff ff5aff ff59ff ff58ff ff57ff ff56ff ff55ff ff54ff ff53ff ff52ff ff51ff ff50ff ff4fff ff4eff ff4dff ff4cff ff4bff ff4aff ff49ff ff48ff ff47ff ff46ff ff45ff ff44ff ff43ff ff42ff ff41ff ff40ff
+ff3fff ff3eff ff3dff ff3cff ff3bff ff3aff ff39ff ff38ff ff37ff ff36ff ff35ff ff34ff ff33ff ff32ff ff31ff ff30ff ff2fff ff2eff ff2dff ff2cff ff2bff ff2aff ff29ff ff28ff ff27ff ff26ff ff25ff ff24ff ff23ff ff22ff ff21ff ff20ff
+ff1fff ff1eff ff1dff ff1cff ff1bff ff1aff ff19ff ff18ff ff17ff ff16ff ff15ff ff14ff ff13ff ff12ff ff11ff ff10ff ff0fff ff0eff ff0dff ff0cff ff0bff ff0aff ff09ff ff08ff ff07ff ff06ff ff05ff ff04ff ff03ff ff02ff ff01ff ff00ff
+ffffff feffff fdffff fcffff fbffff faffff f9ffff f8ffff f7ffff f6ffff f5ffff f4ffff f3ffff f2ffff f1ffff f0ffff efffff eeffff edffff ecffff ebffff eaffff e9ffff e8ffff e7ffff e6ffff e5ffff e4ffff e3ffff e2ffff e1ffff e0ffff
+dfffff deffff ddffff dcffff dbffff daffff d9ffff d8ffff d7ffff d6ffff d5ffff d4ffff d3ffff d2ffff d1ffff d0ffff cfffff ceffff cdffff ccffff cbffff caffff c9ffff c8ffff c7ffff c6ffff c5ffff c4ffff c3ffff c2ffff c1ffff c0ffff
+bfffff beffff bdffff bcffff bbffff baffff b9ffff b8ffff b7ffff b6ffff b5ffff b4ffff b3ffff b2ffff b1ffff b0ffff afffff aeffff adffff acffff abffff aaffff a9ffff a8ffff a7ffff a6ffff a5ffff a4ffff a3ffff a2ffff a1ffff a0ffff
+9fffff 9effff 9dffff 9cffff 9bffff 9affff 99ffff 98ffff 97ffff 96ffff 95ffff 94ffff 93ffff 92ffff 91ffff 90ffff 8fffff 8effff 8dffff 8cffff 8bffff 8affff 89ffff 88ffff 87ffff 86ffff 85ffff 84ffff 83ffff 82ffff 81ffff 80ffff
+7fffff 7effff 7dffff 7cffff 7bffff 7affff 79ffff 78ffff 77ffff 76ffff 75ffff 74ffff 73ffff 72ffff 71ffff 70ffff 6fffff 6effff 6dffff 6cffff 6bffff 6affff 69ffff 68ffff 67ffff 66ffff 65ffff 64ffff 63ffff 62ffff 61ffff 60ffff
+5fffff 5effff 5dffff 5cffff 5bffff 5affff 59ffff 58ffff 57ffff 56ffff 55ffff 54ffff 53ffff 52ffff 51ffff 50ffff 4fffff 4effff 4dffff 4cffff 4bffff 4affff 49ffff 48ffff 47ffff 46ffff 45ffff 44ffff 43ffff 42ffff 41ffff 40ffff
+3fffff 3effff 3dffff 3cffff 3bffff 3affff 39ffff 38ffff 37ffff 36ffff 35ffff 34ffff 33ffff 32ffff 31ffff 30ffff 2fffff 2effff 2dffff 2cffff 2bffff 2affff 29ffff 28ffff 27ffff 26ffff 25ffff 24ffff 23ffff 22ffff 21ffff 20ffff
+1fffff 1effff 1dffff 1cffff 1bffff 1affff 19ffff 18ffff 17ffff 16ffff 15ffff 14ffff 13ffff 12ffff 11ffff 10ffff 0fffff 0effff 0dffff 0cffff 0bffff 0affff 09ffff 08ffff 07ffff 06ffff 05ffff 04ffff 03ffff 02ffff 01ffff 00ffff
+ffffff fefefe fdfdfd fcfcfc fbfbfb fafafa f9f9f9 f8f8f8 f7f7f7 f6f6f6 f5f5f5 f4f4f4 f3f3f3 f2f2f2 f1f1f1 f0f0f0 efefef eeeeee ededed ececec ebebeb eaeaea e9e9e9 e8e8e8 e7e7e7 e6e6e6 e5e5e5 e4e4e4 e3e3e3 e2e2e2 e1e1e1 e0e0e0
+dfdfdf dedede dddddd dcdcdc dbdbdb dadada d9d9d9 d8d8d8 d7d7d7 d6d6d6 d5d5d5 d4d4d4 d3d3d3 d2d2d2 d1d1d1 d0d0d0 cfcfcf cecece cdcdcd cccccc cbcbcb cacaca c9c9c9 c8c8c8 c7c7c7 c6c6c6 c5c5c5 c4c4c4 c3c3c3 c2c2c2 c1c1c1 c0c0c0
+bfbfbf bebebe bdbdbd bcbcbc bbbbbb bababa b9b9b9 b8b8b8 b7b7b7 b6b6b6 b5b5b5 b4b4b4 b3b3b3 b2b2b2 b1b1b1 b0b0b0 afafaf aeaeae adadad acacac ababab aaaaaa a9a9a9 a8a8a8 a7a7a7 a6a6a6 a5a5a5 a4a4a4 a3a3a3 a2a2a2 a1a1a1 a0a0a0
+9f9f9f 9e9e9e 9d9d9d 9c9c9c 9b9b9b 9a9a9a 999999 989898 979797 969696 959595 949494 939393 929292 919191 909090 8f8f8f 8e8e8e 8d8d8d 8c8c8c 8b8b8b 8a8a8a 898989 888888 878787 868686 858585 848484 838383 828282 818181 808080
+7f7f7f 7e7e7e 7d7d7d 7c7c7c 7b7b7b 7a7a7a 797979 787878 777777 767676 757575 747474 737373 727272 717171 707070 6f6f6f 6e6e6e 6d6d6d 6c6c6c 6b6b6b 6a6a6a 696969 686868 676767 666666 656565 646464 636363 626262 616161 606060
+5f5f5f 5e5e5e 5d5d5d 5c5c5c 5b5b5b 5a5a5a 595959 585858 575757 565656 555555 545454 535353 525252 515151 505050 4f4f4f 4e4e4e 4d4d4d 4c4c4c 4b4b4b 4a4a4a 494949 484848 474747 464646 454545 444444 434343 424242 414141 404040
+3f3f3f 3e3e3e 3d3d3d 3c3c3c 3b3b3b 3a3a3a 393939 383838 373737 363636 353535 343434 333333 323232 313131 303030 2f2f2f 2e2e2e 2d2d2d 2c2c2c 2b2b2b 2a2a2a 292929 282828 272727 262626 252525 242424 232323 222222 212121 202020
+1f1f1f 1e1e1e 1d1d1d 1c1c1c 1b1b1b 1a1a1a 191919 181818 171717 161616 151515 141414 131313 121212 111111 101010 0f0f0f 0e0e0e 0d0d0d 0c0c0c 0b0b0b 0a0a0a 090909 080808 070707 060606 050505 040404 030303 020202 010101 000000
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn2c16.png b/libgo/go/image/png/testdata/pngsuite/basn2c16.png
new file mode 100644
index 000000000..1bd4a4d0e
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn2c16.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn2c16.sng b/libgo/go/image/png/testdata/pngsuite/basn2c16.sng
new file mode 100644
index 000000000..bac7c9d91
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn2c16.sng
@@ -0,0 +1,41 @@
+#SNG: from basn2c16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using color;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ffffffff0000 f7bdffff0000 ef7bffff0000 e739ffff0000 def7ffff0000 d6b5ffff0000 ce73ffff0000 c631ffff0000 bdefffff0000 b5adffff0000 ad6bffff0000 a529ffff0000 9ce7ffff0000 94a5ffff0000 8c63ffff0000 8421ffff0000 7bdeffff0000 739cffff0000 6b5affff0000 6318ffff0000 5ad6ffff0000 5294ffff0000 4a52ffff0000 4210ffff0000 39ceffff0000 318cffff0000 294affff0000 2108ffff0000 18c6ffff0000 1084ffff0000 0842ffff0000 0000ffff0000
+fffff7bd0000 f7bdf7bd0000 ef7bf7bd0000 e739f7bd0000 def7f7bd0000 d6b5f7bd0000 ce73f7bd0000 c631f7bd0000 bdeff7bd0000 b5adf7bd0000 ad6bf7bd0000 a529f7bd0000 9ce7f7bd0000 94a5f7bd0000 8c63f7bd0000 8421f7bd0000 7bdef7bd0000 739cf7bd0000 6b5af7bd0000 6318f7bd0000 5ad6f7bd0000 5294f7bd0000 4a52f7bd0000 4210f7bd0000 39cef7bd0000 318cf7bd0000 294af7bd0000 2108f7bd0000 18c6f7bd0000 1084f7bd0000 0842f7bd0000 0000f7bd0842
+ffffef7b0000 f7bdef7b0000 ef7bef7b0000 e739ef7b0000 def7ef7b0000 d6b5ef7b0000 ce73ef7b0000 c631ef7b0000 bdefef7b0000 b5adef7b0000 ad6bef7b0000 a529ef7b0000 9ce7ef7b0000 94a5ef7b0000 8c63ef7b0000 8421ef7b0000 7bdeef7b0000 739cef7b0000 6b5aef7b0000 6318ef7b0000 5ad6ef7b0000 5294ef7b0000 4a52ef7b0000 4210ef7b0000 39ceef7b0000 318cef7b0000 294aef7b0000 2108ef7b0000 18c6ef7b0000 1084ef7b0000 0842ef7b0842 0000ef7b1084
+ffffe7390000 f7bde7390000 ef7be7390000 e739e7390000 def7e7390000 d6b5e7390000 ce73e7390000 c631e7390000 bdefe7390000 b5ade7390000 ad6be7390000 a529e7390000 9ce7e7390000 94a5e7390000 8c63e7390000 8421e7390000 7bdee7390000 739ce7390000 6b5ae7390000 6318e7390000 5ad6e7390000 5294e7390000 4a52e7390000 4210e7390000 39cee7390000 318ce7390000 294ae7390000 2108e7390000 18c6e7390000 1084e7390842 0842e7391084 0000e73918c6
+ffffdef70000 f7bddef70000 ef7bdef70000 e739def70000 def7def70000 d6b5def70000 ce73def70000 c631def70000 bdefdef70000 b5addef70000 ad6bdef70000 a529def70000 9ce7def70000 94a5def70000 8c63def70000 8421def70000 7bdedef70000 739cdef70000 6b5adef70000 6318def70000 5ad6def70000 5294def70000 4a52def70000 4210def70000 39cedef70000 318cdef70000 294adef70000 2108def70000 18c6def70842 1084def71084 0842def718c6 0000def72108
+ffffd6b50000 f7bdd6b50000 ef7bd6b50000 e739d6b50000 def7d6b50000 d6b5d6b50000 ce73d6b50000 c631d6b50000 bdefd6b50000 b5add6b50000 ad6bd6b50000 a529d6b50000 9ce7d6b50000 94a5d6b50000 8c63d6b50000 8421d6b50000 7bded6b50000 739cd6b50000 6b5ad6b50000 6318d6b50000 5ad6d6b50000 5294d6b50000 4a52d6b50000 4210d6b50000 39ced6b50000 318cd6b50000 294ad6b50000 2108d6b50842 18c6d6b51084 1084d6b518c6 0842d6b52108 0000d6b5294a
+ffffce730000 f7bdce730000 ef7bce730000 e739ce730000 def7ce730000 d6b5ce730000 ce73ce730000 c631ce730000 bdefce730000 b5adce730000 ad6bce730000 a529ce730000 9ce7ce730000 94a5ce730000 8c63ce730000 8421ce730000 7bdece730000 739cce730000 6b5ace730000 6318ce730000 5ad6ce730000 5294ce730000 4a52ce730000 4210ce730000 39cece730000 318cce730000 294ace730842 2108ce731084 18c6ce7318c6 1084ce732108 0842ce73294a 0000ce73318c
+ffffc6310000 f7bdc6310000 ef7bc6310000 e739c6310000 def7c6310000 d6b5c6310000 ce73c6310000 c631c6310000 bdefc6310000 b5adc6310000 ad6bc6310000 a529c6310000 9ce7c6310000 94a5c6310000 8c63c6310000 8421c6310000 7bdec6310000 739cc6310000 6b5ac6310000 6318c6310000 5ad6c6310000 5294c6310000 4a52c6310000 4210c6310000 39cec6310000 318cc6310842 294ac6311084 2108c63118c6 18c6c6312108 1084c631294a 0842c631318c 0000c63139ce
+ffffbdef0000 f7bdbdef0000 ef7bbdef0000 e739bdef0000 def7bdef0000 d6b5bdef0000 ce73bdef0000 c631bdef0000 bdefbdef0000 b5adbdef0000 ad6bbdef0000 a529bdef0000 9ce7bdef0000 94a5bdef0000 8c63bdef0000 8421bdef0000 7bdebdef0000 739cbdef0000 6b5abdef0000 6318bdef0000 5ad6bdef0000 5294bdef0000 4a52bdef0000 4210bdef0000 39cebdef0842 318cbdef1084 294abdef18c6 2108bdef2108 18c6bdef294a 1084bdef318c 0842bdef39ce 0000bdef4210
+ffffb5ad0000 f7bdb5ad0000 ef7bb5ad0000 e739b5ad0000 def7b5ad0000 d6b5b5ad0000 ce73b5ad0000 c631b5ad0000 bdefb5ad0000 b5adb5ad0000 ad6bb5ad0000 a529b5ad0000 9ce7b5ad0000 94a5b5ad0000 8c63b5ad0000 8421b5ad0000 7bdeb5ad0000 739cb5ad0000 6b5ab5ad0000 6318b5ad0000 5ad6b5ad0000 5294b5ad0000 4a52b5ad0000 4210b5ad0842 39ceb5ad1084 318cb5ad18c6 294ab5ad2108 2108b5ad294a 18c6b5ad318c 1084b5ad39ce 0842b5ad4210 0000b5ad4a52
+ffffad6b0000 f7bdad6b0000 ef7bad6b0000 e739ad6b0000 def7ad6b0000 d6b5ad6b0000 ce73ad6b0000 c631ad6b0000 bdefad6b0000 b5adad6b0000 ad6bad6b0000 a529ad6b0000 9ce7ad6b0000 94a5ad6b0000 8c63ad6b0000 8421ad6b0000 7bdead6b0000 739cad6b0000 6b5aad6b0000 6318ad6b0000 5ad6ad6b0000 5294ad6b0000 4a52ad6b0842 4210ad6b1084 39cead6b18c6 318cad6b2108 294aad6b294a 2108ad6b318c 18c6ad6b39ce 1084ad6b4210 0842ad6b4a52 0000ad6b5294
+ffffa5290000 f7bda5290000 ef7ba5290000 e739a5290000 def7a5290000 d6b5a5290000 ce73a5290000 c631a5290000 bdefa5290000 b5ada5290000 ad6ba5290000 a529a5290000 9ce7a5290000 94a5a5290000 8c63a5290000 8421a5290000 7bdea5290000 739ca5290000 6b5aa5290000 6318a5290000 5ad6a5290000 5294a5290842 4a52a5291084 4210a52918c6 39cea5292108 318ca529294a 294aa529318c 2108a52939ce 18c6a5294210 1084a5294a52 0842a5295294 0000a5295ad6
+ffff9ce70000 f7bd9ce70000 ef7b9ce70000 e7399ce70000 def79ce70000 d6b59ce70000 ce739ce70000 c6319ce70000 bdef9ce70000 b5ad9ce70000 ad6b9ce70000 a5299ce70000 9ce79ce70000 94a59ce70000 8c639ce70000 84219ce70000 7bde9ce70000 739c9ce70000 6b5a9ce70000 63189ce70000 5ad69ce70842 52949ce71084 4a529ce718c6 42109ce72108 39ce9ce7294a 318c9ce7318c 294a9ce739ce 21089ce74210 18c69ce74a52 10849ce75294 08429ce75ad6 00009ce76318
+ffff94a50000 f7bd94a50000 ef7b94a50000 e73994a50000 def794a50000 d6b594a50000 ce7394a50000 c63194a50000 bdef94a50000 b5ad94a50000 ad6b94a50000 a52994a50000 9ce794a50000 94a594a50000 8c6394a50000 842194a50000 7bde94a50000 739c94a50000 6b5a94a50000 631894a50842 5ad694a51084 529494a518c6 4a5294a52108 421094a5294a 39ce94a5318c 318c94a539ce 294a94a54210 210894a54a52 18c694a55294 108494a55ad6 084294a56318 000094a56b5a
+ffff8c630000 f7bd8c630000 ef7b8c630000 e7398c630000 def78c630000 d6b58c630000 ce738c630000 c6318c630000 bdef8c630000 b5ad8c630000 ad6b8c630000 a5298c630000 9ce78c630000 94a58c630000 8c638c630000 84218c630000 7bde8c630000 739c8c630000 6b5a8c630842 63188c631084 5ad68c6318c6 52948c632108 4a528c63294a 42108c63318c 39ce8c6339ce 318c8c634210 294a8c634a52 21088c635294 18c68c635ad6 10848c636318 08428c636b5a 00008c63739c
+ffff84210000 f7bd84210000 ef7b84210000 e73984210000 def784210000 d6b584210000 ce7384210000 c63184210000 bdef84210000 b5ad84210000 ad6b84210000 a52984210000 9ce784210000 94a584210000 8c6384210000 842184210000 7bde84210000 739c84210842 6b5a84211084 6318842118c6 5ad684212108 52948421294a 4a528421318c 4210842139ce 39ce84214210 318c84214a52 294a84215294 210884215ad6 18c684216318 108484216b5a 08428421739c 000084217bde
+ffff7bde0000 f7bd7bde0000 ef7b7bde0000 e7397bde0000 def77bde0000 d6b57bde0000 ce737bde0000 c6317bde0000 bdef7bde0000 b5ad7bde0000 ad6b7bde0000 a5297bde0000 9ce77bde0000 94a57bde0000 8c637bde0000 84217bde0000 7bde7bde0842 739c7bde1084 6b5a7bde18c6 63187bde2108 5ad67bde294a 52947bde318c 4a527bde39ce 42107bde4210 39ce7bde4a52 318c7bde5294 294a7bde5ad6 21087bde6318 18c67bde6b5a 10847bde739c 08427bde7bde 00007bde8421
+ffff739c0000 f7bd739c0000 ef7b739c0000 e739739c0000 def7739c0000 d6b5739c0000 ce73739c0000 c631739c0000 bdef739c0000 b5ad739c0000 ad6b739c0000 a529739c0000 9ce7739c0000 94a5739c0000 8c63739c0000 8421739c0842 7bde739c1084 739c739c18c6 6b5a739c2108 6318739c294a 5ad6739c318c 5294739c39ce 4a52739c4210 4210739c4a52 39ce739c5294 318c739c5ad6 294a739c6318 2108739c6b5a 18c6739c739c 1084739c7bde 0842739c8421 0000739c8c63
+ffff6b5a0000 f7bd6b5a0000 ef7b6b5a0000 e7396b5a0000 def76b5a0000 d6b56b5a0000 ce736b5a0000 c6316b5a0000 bdef6b5a0000 b5ad6b5a0000 ad6b6b5a0000 a5296b5a0000 9ce76b5a0000 94a56b5a0000 8c636b5a0842 84216b5a1084 7bde6b5a18c6 739c6b5a2108 6b5a6b5a294a 63186b5a318c 5ad66b5a39ce 52946b5a4210 4a526b5a4a52 42106b5a5294 39ce6b5a5ad6 318c6b5a6318 294a6b5a6b5a 21086b5a739c 18c66b5a7bde 10846b5a8421 08426b5a8c63 00006b5a94a5
+ffff63180000 f7bd63180000 ef7b63180000 e73963180000 def763180000 d6b563180000 ce7363180000 c63163180000 bdef63180000 b5ad63180000 ad6b63180000 a52963180000 9ce763180000 94a563180842 8c6363181084 8421631818c6 7bde63182108 739c6318294a 6b5a6318318c 6318631839ce 5ad663184210 529463184a52 4a5263185294 421063185ad6 39ce63186318 318c63186b5a 294a6318739c 210863187bde 18c663188421 108463188c63 0842631894a5 000063189ce7
+ffff5ad60000 f7bd5ad60000 ef7b5ad60000 e7395ad60000 def75ad60000 d6b55ad60000 ce735ad60000 c6315ad60000 bdef5ad60000 b5ad5ad60000 ad6b5ad60000 a5295ad60000 9ce75ad60842 94a55ad61084 8c635ad618c6 84215ad62108 7bde5ad6294a 739c5ad6318c 6b5a5ad639ce 63185ad64210 5ad65ad64a52 52945ad65294 4a525ad65ad6 42105ad66318 39ce5ad66b5a 318c5ad6739c 294a5ad67bde 21085ad68421 18c65ad68c63 10845ad694a5 08425ad69ce7 00005ad6a529
+ffff52940000 f7bd52940000 ef7b52940000 e73952940000 def752940000 d6b552940000 ce7352940000 c63152940000 bdef52940000 b5ad52940000 ad6b52940000 a52952940842 9ce752941084 94a5529418c6 8c6352942108 84215294294a 7bde5294318c 739c529439ce 6b5a52944210 631852944a52 5ad652945294 529452945ad6 4a5252946318 421052946b5a 39ce5294739c 318c52947bde 294a52948421 210852948c63 18c6529494a5 108452949ce7 08425294a529 00005294ad6b
+ffff4a520000 f7bd4a520000 ef7b4a520000 e7394a520000 def74a520000 d6b54a520000 ce734a520000 c6314a520000 bdef4a520000 b5ad4a520000 ad6b4a520842 a5294a521084 9ce74a5218c6 94a54a522108 8c634a52294a 84214a52318c 7bde4a5239ce 739c4a524210 6b5a4a524a52 63184a525294 5ad64a525ad6 52944a526318 4a524a526b5a 42104a52739c 39ce4a527bde 318c4a528421 294a4a528c63 21084a5294a5 18c64a529ce7 10844a52a529 08424a52ad6b 00004a52b5ad
+ffff42100000 f7bd42100000 ef7b42100000 e73942100000 def742100000 d6b542100000 ce7342100000 c63142100000 bdef42100000 b5ad42100842 ad6b42101084 a529421018c6 9ce742102108 94a54210294a 8c634210318c 8421421039ce 7bde42104210 739c42104a52 6b5a42105294 631842105ad6 5ad642106318 529442106b5a 4a524210739c 421042107bde 39ce42108421 318c42108c63 294a421094a5 210842109ce7 18c64210a529 10844210ad6b 08424210b5ad 00004210bdef
+ffff39ce0000 f7bd39ce0000 ef7b39ce0000 e73939ce0000 def739ce0000 d6b539ce0000 ce7339ce0000 c63139ce0000 bdef39ce0842 b5ad39ce1084 ad6b39ce18c6 a52939ce2108 9ce739ce294a 94a539ce318c 8c6339ce39ce 842139ce4210 7bde39ce4a52 739c39ce5294 6b5a39ce5ad6 631839ce6318 5ad639ce6b5a 529439ce739c 4a5239ce7bde 421039ce8421 39ce39ce8c63 318c39ce94a5 294a39ce9ce7 210839cea529 18c639cead6b 108439ceb5ad 084239cebdef 000039cec631
+ffff318c0000 f7bd318c0000 ef7b318c0000 e739318c0000 def7318c0000 d6b5318c0000 ce73318c0000 c631318c0842 bdef318c1084 b5ad318c18c6 ad6b318c2108 a529318c294a 9ce7318c318c 94a5318c39ce 8c63318c4210 8421318c4a52 7bde318c5294 739c318c5ad6 6b5a318c6318 6318318c6b5a 5ad6318c739c 5294318c7bde 4a52318c8421 4210318c8c63 39ce318c94a5 318c318c9ce7 294a318ca529 2108318cad6b 18c6318cb5ad 1084318cbdef 0842318cc631 0000318cce73
+ffff294a0000 f7bd294a0000 ef7b294a0000 e739294a0000 def7294a0000 d6b5294a0000 ce73294a0842 c631294a1084 bdef294a18c6 b5ad294a2108 ad6b294a294a a529294a318c 9ce7294a39ce 94a5294a4210 8c63294a4a52 8421294a5294 7bde294a5ad6 739c294a6318 6b5a294a6b5a 6318294a739c 5ad6294a7bde 5294294a8421 4a52294a8c63 4210294a94a5 39ce294a9ce7 318c294aa529 294a294aad6b 2108294ab5ad 18c6294abdef 1084294ac631 0842294ace73 0000294ad6b5
+ffff21080000 f7bd21080000 ef7b21080000 e73921080000 def721080000 d6b521080842 ce7321081084 c631210818c6 bdef21082108 b5ad2108294a ad6b2108318c a529210839ce 9ce721084210 94a521084a52 8c6321085294 842121085ad6 7bde21086318 739c21086b5a 6b5a2108739c 631821087bde 5ad621088421 529421088c63 4a52210894a5 421021089ce7 39ce2108a529 318c2108ad6b 294a2108b5ad 21082108bdef 18c62108c631 10842108ce73 08422108d6b5 00002108def7
+ffff18c60000 f7bd18c60000 ef7b18c60000 e73918c60000 def718c60842 d6b518c61084 ce7318c618c6 c63118c62108 bdef18c6294a b5ad18c6318c ad6b18c639ce a52918c64210 9ce718c64a52 94a518c65294 8c6318c65ad6 842118c66318 7bde18c66b5a 739c18c6739c 6b5a18c67bde 631818c68421 5ad618c68c63 529418c694a5 4a5218c69ce7 421018c6a529 39ce18c6ad6b 318c18c6b5ad 294a18c6bdef 210818c6c631 18c618c6ce73 108418c6d6b5 084218c6def7 000018c6e739
+ffff10840000 f7bd10840000 ef7b10840000 e73910840842 def710841084 d6b5108418c6 ce7310842108 c6311084294a bdef1084318c b5ad108439ce ad6b10844210 a52910844a52 9ce710845294 94a510845ad6 8c6310846318 842110846b5a 7bde1084739c 739c10847bde 6b5a10848421 631810848c63 5ad6108494a5 529410849ce7 4a521084a529 42101084ad6b 39ce1084b5ad 318c1084bdef 294a1084c631 21081084ce73 18c61084d6b5 10841084def7 08421084e739 00001084ef7b
+ffff08420000 f7bd08420000 ef7b08420842 e73908421084 def7084218c6 d6b508422108 ce730842294a c6310842318c bdef084239ce b5ad08424210 ad6b08424a52 a52908425294 9ce708425ad6 94a508426318 8c6308426b5a 84210842739c 7bde08427bde 739c08428421 6b5a08428c63 6318084294a5 5ad608429ce7 52940842a529 4a520842ad6b 42100842b5ad 39ce0842bdef 318c0842c631 294a0842ce73 21080842d6b5 18c60842def7 10840842e739 08420842ef7b 00000842f7bd
+ffff00000000 f7bd00000842 ef7b00001084 e739000018c6 def700002108 d6b50000294a ce730000318c c631000039ce bdef00004210 b5ad00004a52 ad6b00005294 a52900005ad6 9ce700006318 94a500006b5a 8c630000739c 842100007bde 7bde00008421 739c00008c63 6b5a000094a5 631800009ce7 5ad60000a529 52940000ad6b 4a520000b5ad 42100000bdef 39ce0000c631 318c0000ce73 294a0000d6b5 21080000def7 18c60000e739 10840000ef7b 08420000f7bd 00000000ffff
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p01.png b/libgo/go/image/png/testdata/pngsuite/basn3p01.png
new file mode 100644
index 000000000..a21db5977
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn3p01.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p01.sng b/libgo/go/image/png/testdata/pngsuite/basn3p01.sng
new file mode 100644
index 000000000..a8b3ce878
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn3p01.sng
@@ -0,0 +1,45 @@
+#SNG: from basn3p01.png
+IHDR {
+ width: 32; height: 32; bitdepth: 1;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (238,255, 34) # rgb = (0xee,0xff,0x22)
+ ( 34,102,255) # rgb = (0x22,0x66,0xff)
+}
+IMAGE {
+ pixels hex
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+0f0f0f0f
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+f0f0f0f0
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p02.png b/libgo/go/image/png/testdata/pngsuite/basn3p02.png
new file mode 100644
index 000000000..1d0ab6197
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn3p02.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p02.sng b/libgo/go/image/png/testdata/pngsuite/basn3p02.sng
new file mode 100644
index 000000000..f2321aa3d
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn3p02.sng
@@ -0,0 +1,50 @@
+#SNG: from basn3p02.png
+IHDR {
+ width: 32; height: 32; bitdepth: 2;
+ using color palette;
+}
+gAMA {1.0000}
+sBIT {
+ red: 1; green: 1; blue: 1;
+}
+PLTE {
+ ( 0,255, 0) # rgb = (0x00,0xff,0x00) green1
+ (255, 0, 0) # rgb = (0xff,0x00,0x00) red1
+ (255,255, 0) # rgb = (0xff,0xff,0x00) yellow1
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+}
+IMAGE {
+ pixels hex
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+ff55aa00ff55aa00
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+00ff55aa00ff55aa
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+aa00ff55aa00ff55
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+55aa00ff55aa00ff
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p04.png b/libgo/go/image/png/testdata/pngsuite/basn3p04.png
new file mode 100644
index 000000000..6dc6eac83
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn3p04.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p04.sng b/libgo/go/image/png/testdata/pngsuite/basn3p04.sng
new file mode 100644
index 000000000..e52885dba
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn3p04.sng
@@ -0,0 +1,61 @@
+#SNG: from basn3p04.png
+IHDR {
+ width: 32; height: 32; bitdepth: 4;
+ using color palette;
+}
+gAMA {1.0000}
+sBIT {
+ red: 4; green: 4; blue: 4;
+}
+PLTE {
+ ( 34, 0,255) # rgb = (0x22,0x00,0xff)
+ ( 0,255,255) # rgb = (0x00,0xff,0xff) cyan1
+ (136, 0,255) # rgb = (0x88,0x00,0xff)
+ ( 34,255, 0) # rgb = (0x22,0xff,0x00)
+ ( 0,153,255) # rgb = (0x00,0x99,0xff)
+ (255,102, 0) # rgb = (0xff,0x66,0x00)
+ (221, 0,255) # rgb = (0xdd,0x00,0xff)
+ (119,255, 0) # rgb = (0x77,0xff,0x00)
+ (255, 0, 0) # rgb = (0xff,0x00,0x00) red1
+ ( 0,255,153) # rgb = (0x00,0xff,0x99)
+ (221,255, 0) # rgb = (0xdd,0xff,0x00)
+ (255, 0,187) # rgb = (0xff,0x00,0xbb)
+ (255,187, 0) # rgb = (0xff,0xbb,0x00)
+ ( 0, 68,255) # rgb = (0x00,0x44,0xff)
+ ( 0,255, 68) # rgb = (0x00,0xff,0x44)
+}
+IMAGE {
+ pixels hex
+88885555ccccaaaa77773333eeee9999
+88885555ccccaaaa77773333eeee9999
+88885555ccccaaaa77773333eeee9999
+88885555ccccaaaa77773333eeee9999
+5555ccccaaaa77773333eeee99991111
+5555ccccaaaa77773333eeee99991111
+5555ccccaaaa77773333eeee99991111
+5555ccccaaaa77773333eeee99991111
+ccccaaaa77773333eeee999911114444
+ccccaaaa77773333eeee999911114444
+ccccaaaa77773333eeee999911114444
+ccccaaaa77773333eeee999911114444
+aaaa77773333eeee999911114444dddd
+aaaa77773333eeee999911114444dddd
+aaaa77773333eeee999911114444dddd
+aaaa77773333eeee999911114444dddd
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+77773333eeee999911114444dddd0000
+3333eeee999911114444dddd00002222
+3333eeee999911114444dddd00002222
+3333eeee999911114444dddd00002222
+3333eeee999911114444dddd00002222
+eeee999911114444dddd000022226666
+eeee999911114444dddd000022226666
+eeee999911114444dddd000022226666
+eeee999911114444dddd000022226666
+999911114444dddd000022226666bbbb
+999911114444dddd000022226666bbbb
+999911114444dddd000022226666bbbb
+999911114444dddd000022226666bbbb
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p08.png b/libgo/go/image/png/testdata/pngsuite/basn3p08.png
new file mode 100644
index 000000000..0e07f483c
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn3p08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p08.sng b/libgo/go/image/png/testdata/pngsuite/basn3p08.sng
new file mode 100644
index 000000000..0423bb21e
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn3p08.sng
@@ -0,0 +1,299 @@
+#SNG: from basn3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ ( 34, 68, 0) # rgb = (0x22,0x44,0x00)
+ (245,255,237) # rgb = (0xf5,0xff,0xed)
+ (119,255,119) # rgb = (0x77,0xff,0x77)
+ (203,255,255) # rgb = (0xcb,0xff,0xff)
+ ( 17, 10, 0) # rgb = (0x11,0x0a,0x00)
+ ( 58,119, 0) # rgb = (0x3a,0x77,0x00)
+ ( 34, 34,255) # rgb = (0x22,0x22,0xff)
+ (255, 17,255) # rgb = (0xff,0x11,0xff)
+ ( 17, 0, 0) # rgb = (0x11,0x00,0x00)
+ ( 34, 34, 0) # rgb = (0x22,0x22,0x00)
+ (255,172, 85) # rgb = (0xff,0xac,0x55)
+ (102,255,102) # rgb = (0x66,0xff,0x66)
+ (255,102,102) # rgb = (0xff,0x66,0x66)
+ (255, 1,255) # rgb = (0xff,0x01,0xff)
+ ( 34, 18, 0) # rgb = (0x22,0x12,0x00)
+ (220,255,255) # rgb = (0xdc,0xff,0xff)
+ (204,255,153) # rgb = (0xcc,0xff,0x99)
+ ( 68, 68,255) # rgb = (0x44,0x44,0xff)
+ ( 0, 85, 85) # rgb = (0x00,0x55,0x55)
+ ( 34, 0, 0) # rgb = (0x22,0x00,0x00)
+ (203,203,255) # rgb = (0xcb,0xcb,0xff)
+ ( 68, 68, 0) # rgb = (0x44,0x44,0x00)
+ ( 85,255, 85) # rgb = (0x55,0xff,0x55)
+ (203,203, 0) # rgb = (0xcb,0xcb,0x00)
+ ( 51, 26, 0) # rgb = (0x33,0x1a,0x00)
+ (255,236,220) # rgb = (0xff,0xec,0xdc)
+ (237,255,255) # rgb = (0xed,0xff,0xff)
+ (228,255,203) # rgb = (0xe4,0xff,0xcb)
+ (255,220,220) # rgb = (0xff,0xdc,0xdc)
+ ( 68,255, 68) # rgb = (0x44,0xff,0x44)
+ (102,102,255) # rgb = (0x66,0x66,0xff)
+ ( 51, 0, 0) # rgb = (0x33,0x00,0x00)
+ ( 68, 34, 0) # rgb = (0x44,0x22,0x00)
+ (237,237,255) # rgb = (0xed,0xed,0xff)
+ (102,102, 0) # rgb = (0x66,0x66,0x00)
+ (255,164, 68) # rgb = (0xff,0xa4,0x44)
+ (255,255,170) # rgb = (0xff,0xff,0xaa)
+ (237,237, 0) # rgb = (0xed,0xed,0x00)
+ ( 0,203,203) # rgb = (0x00,0xcb,0xcb)
+ (254,255,255) # rgb = (0xfe,0xff,0xff)
+ (253,255,254) # rgb = (0xfd,0xff,0xfe)
+ (255,255, 1) # rgb = (0xff,0xff,0x01)
+ ( 51,255, 51) # rgb = (0x33,0xff,0x33)
+ ( 85, 42, 0) # rgb = (0x55,0x2a,0x00)
+ ( 1, 1,255) # rgb = (0x01,0x01,0xff)
+ (136,136,255) # rgb = (0x88,0x88,0xff)
+ ( 0,170,170) # rgb = (0x00,0xaa,0xaa)
+ ( 1, 1, 0) # rgb = (0x01,0x01,0x00)
+ ( 68, 0, 0) # rgb = (0x44,0x00,0x00)
+ (136,136, 0) # rgb = (0x88,0x88,0x00)
+ (255,228,203) # rgb = (0xff,0xe4,0xcb)
+ (186, 91, 0) # rgb = (0xba,0x5b,0x00)
+ ( 34,255, 34) # rgb = (0x22,0xff,0x22)
+ (102, 50, 0) # rgb = (0x66,0x32,0x00)
+ (255,255,153) # rgb = (0xff,0xff,0x99)
+ (170,170,255) # rgb = (0xaa,0xaa,0xff)
+ ( 85, 0, 0) # rgb = (0x55,0x00,0x00)
+ (170,170, 0) # rgb = (0xaa,0xaa,0x00)
+ (203, 99, 0) # rgb = (0xcb,0x63,0x00)
+ ( 17,255, 17) # rgb = (0x11,0xff,0x11)
+ (212,255,170) # rgb = (0xd4,0xff,0xaa)
+ (119, 58, 0) # rgb = (0x77,0x3a,0x00)
+ (255, 68, 68) # rgb = (0xff,0x44,0x44)
+ (220,107, 0) # rgb = (0xdc,0x6b,0x00)
+ (102, 0, 0) # rgb = (0x66,0x00,0x00)
+ ( 1,255, 1) # rgb = (0x01,0xff,0x01)
+ (136, 66, 0) # rgb = (0x88,0x42,0x00)
+ (236,255,220) # rgb = (0xec,0xff,0xdc)
+ (107,220, 0) # rgb = (0x6b,0xdc,0x00)
+ (255,220,186) # rgb = (0xff,0xdc,0xba)
+ ( 0, 51, 51) # rgb = (0x00,0x33,0x33)
+ ( 0,237, 0) # rgb = (0x00,0xed,0x00)
+ (237,115, 0) # rgb = (0xed,0x73,0x00)
+ (255,255,136) # rgb = (0xff,0xff,0x88)
+ (153, 74, 0) # rgb = (0x99,0x4a,0x00)
+ ( 17,255,255) # rgb = (0x11,0xff,0xff)
+ (119, 0, 0) # rgb = (0x77,0x00,0x00)
+ (255,131, 1) # rgb = (0xff,0x83,0x01)
+ (255,186,186) # rgb = (0xff,0xba,0xba)
+ (254,123, 0) # rgb = (0xfe,0x7b,0x00)
+ (255,254,255) # rgb = (0xff,0xfe,0xff)
+ ( 0,203, 0) # rgb = (0x00,0xcb,0x00)
+ (255,153,153) # rgb = (0xff,0x99,0x99)
+ ( 34,255,255) # rgb = (0x22,0xff,0xff)
+ (136, 0, 0) # rgb = (0x88,0x00,0x00)
+ (255,255,119) # rgb = (0xff,0xff,0x77)
+ ( 0,136,136) # rgb = (0x00,0x88,0x88)
+ (255,220,255) # rgb = (0xff,0xdc,0xff)
+ ( 26, 51, 0) # rgb = (0x1a,0x33,0x00)
+ ( 0, 0,170) # rgb = (0x00,0x00,0xaa)
+ ( 51,255,255) # rgb = (0x33,0xff,0xff)
+ ( 0,153, 0) # rgb = (0x00,0x99,0x00)
+ (153, 0, 0) # rgb = (0x99,0x00,0x00)
+ ( 0, 0, 1) # rgb = (0x00,0x00,0x01)
+ ( 50,102, 0) # rgb = (0x32,0x66,0x00)
+ (255,186,255) # rgb = (0xff,0xba,0xff)
+ ( 68,255,255) # rgb = (0x44,0xff,0xff)
+ (255,170,255) # rgb = (0xff,0xaa,0xff)
+ ( 0,119, 0) # rgb = (0x00,0x77,0x00)
+ ( 0,254,254) # rgb = (0x00,0xfe,0xfe)
+ (170, 0, 0) # rgb = (0xaa,0x00,0x00)
+ ( 74,153, 0) # rgb = (0x4a,0x99,0x00)
+ (255,255,102) # rgb = (0xff,0xff,0x66)
+ (255, 34, 34) # rgb = (0xff,0x22,0x22)
+ ( 0, 0,153) # rgb = (0x00,0x00,0x99)
+ (139,255, 17) # rgb = (0x8b,0xff,0x11)
+ ( 85,255,255) # rgb = (0x55,0xff,0xff)
+ (255, 1, 1) # rgb = (0xff,0x01,0x01)
+ (255,136,255) # rgb = (0xff,0x88,0xff)
+ ( 0, 85, 0) # rgb = (0x00,0x55,0x00)
+ ( 0, 17, 17) # rgb = (0x00,0x11,0x11)
+ (255,255,254) # rgb = (0xff,0xff,0xfe)
+ (255,253,254) # rgb = (0xff,0xfd,0xfe)
+ (164,255, 68) # rgb = (0xa4,0xff,0x44)
+ (102,255,255) # rgb = (0x66,0xff,0xff)
+ (255,102,255) # rgb = (0xff,0x66,0xff)
+ ( 0, 51, 0) # rgb = (0x00,0x33,0x00)
+ (255,255, 85) # rgb = (0xff,0xff,0x55)
+ (255,119,119) # rgb = (0xff,0x77,0x77)
+ ( 0, 0,136) # rgb = (0x00,0x00,0x88)
+ (255, 68,255) # rgb = (0xff,0x44,0xff)
+ ( 0, 17, 0) # rgb = (0x00,0x11,0x00)
+ (119,255,255) # rgb = (0x77,0xff,0xff)
+ ( 0,102,102) # rgb = (0x00,0x66,0x66)
+ (255,255,237) # rgb = (0xff,0xff,0xed)
+ ( 0, 1, 0) # rgb = (0x00,0x01,0x00)
+ (255,245,237) # rgb = (0xff,0xf5,0xed)
+ ( 17, 17,255) # rgb = (0x11,0x11,0xff)
+ (255,255, 68) # rgb = (0xff,0xff,0x44)
+ (255, 34,255) # rgb = (0xff,0x22,0xff)
+ (255,237,237) # rgb = (0xff,0xed,0xed)
+ ( 17, 17, 0) # rgb = (0x11,0x11,0x00)
+ (136,255,255) # rgb = (0x88,0xff,0xff)
+ ( 0, 0,119) # rgb = (0x00,0x00,0x77)
+ (147,255, 34) # rgb = (0x93,0xff,0x22)
+ ( 0,220,220) # rgb = (0x00,0xdc,0xdc)
+ ( 51, 51,255) # rgb = (0x33,0x33,0xff)
+ (254, 0,254) # rgb = (0xfe,0x00,0xfe)
+ (186,186,255) # rgb = (0xba,0xba,0xff)
+ (153,255,255) # rgb = (0x99,0xff,0xff)
+ ( 51, 51, 0) # rgb = (0x33,0x33,0x00)
+ ( 99,203, 0) # rgb = (0x63,0xcb,0x00)
+ (186,186, 0) # rgb = (0xba,0xba,0x00)
+ (172,255, 85) # rgb = (0xac,0xff,0x55)
+ (255,255,220) # rgb = (0xff,0xff,0xdc)
+ (255,255, 51) # rgb = (0xff,0xff,0x33)
+ (123,254, 0) # rgb = (0x7b,0xfe,0x00)
+ (237, 0,237) # rgb = (0xed,0x00,0xed)
+ ( 85, 85,255) # rgb = (0x55,0x55,0xff)
+ (170,255,255) # rgb = (0xaa,0xff,0xff)
+ (220,220,255) # rgb = (0xdc,0xdc,0xff)
+ ( 85, 85, 0) # rgb = (0x55,0x55,0x00)
+ ( 0, 0,102) # rgb = (0x00,0x00,0x66)
+ (220,220, 0) # rgb = (0xdc,0xdc,0x00)
+ (220, 0,220) # rgb = (0xdc,0x00,0xdc)
+ (131,255, 1) # rgb = (0x83,0xff,0x01)
+ (119,119,255) # rgb = (0x77,0x77,0xff)
+ (254,254,255) # rgb = (0xfe,0xfe,0xff)
+ (255,255,203) # rgb = (0xff,0xff,0xcb)
+ (255, 85, 85) # rgb = (0xff,0x55,0x55)
+ (119,119, 0) # rgb = (0x77,0x77,0x00)
+ (254,254, 0) # rgb = (0xfe,0xfe,0x00)
+ (203, 0,203) # rgb = (0xcb,0x00,0xcb)
+ ( 0, 0,254) # rgb = (0x00,0x00,0xfe)
+ ( 1, 2, 0) # rgb = (0x01,0x02,0x00)
+ ( 1, 0, 0) # rgb = (0x01,0x00,0x00)
+ ( 18, 34, 0) # rgb = (0x12,0x22,0x00)
+ (255,255, 34) # rgb = (0xff,0xff,0x22)
+ ( 0, 68, 68) # rgb = (0x00,0x44,0x44)
+ (155,255, 51) # rgb = (0x9b,0xff,0x33)
+ (255,212,170) # rgb = (0xff,0xd4,0xaa)
+ ( 0, 0, 85) # rgb = (0x00,0x00,0x55)
+ (153,153,255) # rgb = (0x99,0x99,0xff)
+ (153,153, 0) # rgb = (0x99,0x99,0x00)
+ (186, 0,186) # rgb = (0xba,0x00,0xba)
+ ( 42, 85, 0) # rgb = (0x2a,0x55,0x00)
+ (255,203,203) # rgb = (0xff,0xcb,0xcb)
+ (180,255,102) # rgb = (0xb4,0xff,0x66)
+ (255,155, 51) # rgb = (0xff,0x9b,0x33)
+ (255,255,186) # rgb = (0xff,0xff,0xba)
+ (170, 0,170) # rgb = (0xaa,0x00,0xaa)
+ ( 66,136, 0) # rgb = (0x42,0x88,0x00)
+ ( 83,170, 0) # rgb = (0x53,0xaa,0x00)
+ (255,170,170) # rgb = (0xff,0xaa,0xaa)
+ ( 0, 0,237) # rgb = (0x00,0x00,0xed)
+ ( 0,186,186) # rgb = (0x00,0xba,0xba)
+ (255,255, 17) # rgb = (0xff,0xff,0x11)
+ ( 0,254, 0) # rgb = (0x00,0xfe,0x00)
+ ( 0, 0, 68) # rgb = (0x00,0x00,0x44)
+ ( 0,153,153) # rgb = (0x00,0x99,0x99)
+ (153, 0,153) # rgb = (0x99,0x00,0x99)
+ (255,204,153) # rgb = (0xff,0xcc,0x99)
+ (186, 0, 0) # rgb = (0xba,0x00,0x00)
+ (136, 0,136) # rgb = (0x88,0x00,0x88)
+ ( 0,220, 0) # rgb = (0x00,0xdc,0x00)
+ (255,147, 34) # rgb = (0xff,0x93,0x22)
+ ( 0, 0,220) # rgb = (0x00,0x00,0xdc)
+ (254,255,254) # rgb = (0xfe,0xff,0xfe)
+ (170, 83, 0) # rgb = (0xaa,0x53,0x00)
+ (119, 0,119) # rgb = (0x77,0x00,0x77)
+ ( 2, 1, 0) # rgb = (0x02,0x01,0x00)
+ (203, 0, 0) # rgb = (0xcb,0x00,0x00)
+ ( 0, 0, 51) # rgb = (0x00,0x00,0x33)
+ (255,237,255) # rgb = (0xff,0xed,0xff)
+ ( 0,186, 0) # rgb = (0x00,0xba,0x00)
+ (255, 51, 51) # rgb = (0xff,0x33,0x33)
+ (237,255,237) # rgb = (0xed,0xff,0xed)
+ (255,196,136) # rgb = (0xff,0xc4,0x88)
+ (188,255,119) # rgb = (0xbc,0xff,0x77)
+ ( 0,170, 0) # rgb = (0x00,0xaa,0x00)
+ (102, 0,102) # rgb = (0x66,0x00,0x66)
+ ( 0, 34, 34) # rgb = (0x00,0x22,0x22)
+ (220, 0, 0) # rgb = (0xdc,0x00,0x00)
+ (255,203,255) # rgb = (0xff,0xcb,0xff)
+ (220,255,220) # rgb = (0xdc,0xff,0xdc)
+ (255,139, 17) # rgb = (0xff,0x8b,0x11)
+ ( 0, 0,203) # rgb = (0x00,0x00,0xcb)
+ ( 0, 1, 1) # rgb = (0x00,0x01,0x01)
+ ( 85, 0, 85) # rgb = (0x55,0x00,0x55)
+ ( 0,136, 0) # rgb = (0x00,0x88,0x00)
+ ( 0, 0, 34) # rgb = (0x00,0x00,0x22)
+ ( 1,255,255) # rgb = (0x01,0xff,0xff)
+ (203,255,203) # rgb = (0xcb,0xff,0xcb)
+ (237, 0, 0) # rgb = (0xed,0x00,0x00)
+ (255,136,136) # rgb = (0xff,0x88,0x88)
+ ( 68, 0, 68) # rgb = (0x44,0x00,0x44)
+ ( 91,186, 0) # rgb = (0x5b,0xba,0x00)
+ (255,188,119) # rgb = (0xff,0xbc,0x77)
+ (255,153,255) # rgb = (0xff,0x99,0xff)
+ ( 0,102, 0) # rgb = (0x00,0x66,0x00)
+ (186,255,186) # rgb = (0xba,0xff,0xba)
+ ( 0,119,119) # rgb = (0x00,0x77,0x77)
+ (115,237, 0) # rgb = (0x73,0xed,0x00)
+ (254, 0, 0) # rgb = (0xfe,0x00,0x00)
+ ( 51, 0, 51) # rgb = (0x33,0x00,0x33)
+ ( 0, 0,186) # rgb = (0x00,0x00,0xba)
+ (255,119,255) # rgb = (0xff,0x77,0xff)
+ ( 0, 68, 0) # rgb = (0x00,0x44,0x00)
+ (170,255,170) # rgb = (0xaa,0xff,0xaa)
+ (255,254,254) # rgb = (0xff,0xfe,0xfe)
+ ( 0, 0, 17) # rgb = (0x00,0x00,0x11)
+ ( 34, 0, 34) # rgb = (0x22,0x00,0x22)
+ (196,255,136) # rgb = (0xc4,0xff,0x88)
+ ( 0,237,237) # rgb = (0x00,0xed,0xed)
+ (153,255,153) # rgb = (0x99,0xff,0x99)
+ (255, 85,255) # rgb = (0xff,0x55,0xff)
+ ( 0, 34, 0) # rgb = (0x00,0x22,0x00)
+ (255,180,102) # rgb = (0xff,0xb4,0x66)
+ ( 17, 0, 17) # rgb = (0x11,0x00,0x11)
+ ( 10, 17, 0) # rgb = (0x0a,0x11,0x00)
+ (255, 17, 17) # rgb = (0xff,0x11,0x11)
+ (220,255,186) # rgb = (0xdc,0xff,0xba)
+ (186,255,255) # rgb = (0xba,0xff,0xff)
+ (136,255,136) # rgb = (0x88,0xff,0x88)
+ ( 1, 0, 1) # rgb = (0x01,0x00,0x01)
+ (255, 51,255) # rgb = (0xff,0x33,0xff)
+}
+IMAGE {
+ pixels hex
+a5a5a5a5a4a4a4a42f2f2f2fc8c8c8c87d7d7d7dd9d9d9d95d5d5d5dfefefefe
+080808080404040483838383f9f9f9f9797979796e6e6e6ef0f0f0f0f8f8f8f8
+131313130e0e0e0e09090909a6a6a6a6f6f6f6f6d3d3d3d3dcdcdcdcf1f1f1f1
+1f1f1f1f181818188c8c8c8c585858587474747446464646cacacacaeaeaeaea
+30303030202020201515151500000000ededededa8a8a8a8bcbcbcbce1e1e1e1
+383838382b2b2b2b97979797afafafaf6d6d6d6d12121212ababababdadadada
+4040404035353535222222225e5e5e5ee5e5e5e57b7b7b7b98989898d2d2d2d2
+4c4c4c4c3d3d3d3da0a0a0a00505050562626262e7e7e7e785858585c7c7c7c7
+545454544242424231313131b5b5b5b5dbdbdbdb5656565677777777c1c1c1c1
+5c5c5c5c4a4a4a4aadadadad656565655b5b5b5bbdbdbdbd68686868bebebebe
+64646464c6c6c6c639393939b6b6b6b6d1d1d1d12e2e2e2e59595959b4b4b4b4
+c0c0c0c0333333338e8e8e8ee2e2e2e2ccccccccb9b9b9b9ebebebebaeaeaeae
+c9c9c9c93a3a3a3a171717178d8d8d8d5151515126262626d8d8d8d8a2a2a2a2
+d4d4d4d43f3f3f3f9999999944444444c2c2c2c287878787c4c4c4c49a9a9a9a
+dfdfdfdf4848484825252525e8e8e8e847474747f3f3f3f3b8b8b8b893939393
+e9e9e9e94f4f4f4fa1a1a1a192929292bbbbbbbb63636363a3a3a3a389898989
+6b6b6b6b4d4d4d4d292929299b9b9b9b41414141dddddddd2c2c2c2c0d0d0d0d
+fafafafad7d7d7d7babababa696969693b3b3b3b4b4b4b4b7f7f7f7f07070707
+67676767c3c3c3c3a7a7a7a78686868634343434535353530606060681818181
+cdcdcdcdb2b2b2b291919191a9a9a9a92a2a2a2a5a5a5a5a88888888ffffffff
+3e3e3e3e2323232380808080717171711d1d1d1d606060601111111178787878
+9f9f9f9f0a0a0a0a757575758f8f8f8f161616166a6a6a6a94949494f5f5f5f5
+0c0c0c0cf7f7f7f766666666b1b1b1b10b0b0b0b727272721e1e1e1e73737373
+76767676e3e3e3e355555555d0d0d0d0020202027a7a7a7a9c9c9c9cecececec
+e0e0e0e0cfcfcfcf49494949f2f2f2f2fdfdfdfd848484842d2d2d2d6c6c6c6c
+52525252bfbfbfbf3636363610101010f4f4f4f48b8b8b8bacacacace4e4e4e4
+b7b7b7b7aaaaaaaa242424243c3c3c3ceeeeeeee959595953737373761616161
+4e4e4e4e45454545b3b3b3b3fbfbfbfbe6e6e6e6fcfcfcfc8a8a8a8a5f5f5f5f
+b0b0b0b0323232329e9e9e9e1b1b1b1bdededede0303030314141414d5d5d5d5
+1c1c1c1c191919199090909043434343d6d6d6d60f0f0f0f9696969657575757
+828282827e7e7e7e7c7c7c7c01010101cececece1a1a1a1a21212121cbcbcbcb
+efefefef707070706f6f6f6f28282828c5c5c5c5272727279d9d9d9d50505050
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn4a08.png b/libgo/go/image/png/testdata/pngsuite/basn4a08.png
new file mode 100644
index 000000000..3bb0dd06b
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn4a08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn4a08.sng b/libgo/go/image/png/testdata/pngsuite/basn4a08.sng
new file mode 100644
index 000000000..b760382a0
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn4a08.sng
@@ -0,0 +1,41 @@
+#SNG: from basn4a08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale alpha;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ff00 ff08 ff10 ff18 ff20 ff29 ff31 ff39 ff41 ff4a ff52 ff5a ff62 ff6a ff73 ff7b ff83 ff8b ff94 ff9c ffa4 ffac ffb4 ffbd ffc5 ffcd ffd5 ffde ffe6 ffee fff6 ffff
+f600 f608 f610 f618 f620 f629 f631 f639 f641 f64a f652 f65a f662 f66a f673 f67b f683 f68b f694 f69c f6a4 f6ac f6b4 f6bd f6c5 f6cd f6d5 f6de f6e6 f6ee f6f6 f6ff
+ee00 ee08 ee10 ee18 ee20 ee29 ee31 ee39 ee41 ee4a ee52 ee5a ee62 ee6a ee73 ee7b ee83 ee8b ee94 ee9c eea4 eeac eeb4 eebd eec5 eecd eed5 eede eee6 eeee eef6 eeff
+e600 e608 e610 e618 e620 e629 e631 e639 e641 e64a e652 e65a e662 e66a e673 e67b e683 e68b e694 e69c e6a4 e6ac e6b4 e6bd e6c5 e6cd e6d5 e6de e6e6 e6ee e6f6 e6ff
+de00 de08 de10 de18 de20 de29 de31 de39 de41 de4a de52 de5a de62 de6a de73 de7b de83 de8b de94 de9c dea4 deac deb4 debd dec5 decd ded5 dede dee6 deee def6 deff
+d500 d508 d510 d518 d520 d529 d531 d539 d541 d54a d552 d55a d562 d56a d573 d57b d583 d58b d594 d59c d5a4 d5ac d5b4 d5bd d5c5 d5cd d5d5 d5de d5e6 d5ee d5f6 d5ff
+cd00 cd08 cd10 cd18 cd20 cd29 cd31 cd39 cd41 cd4a cd52 cd5a cd62 cd6a cd73 cd7b cd83 cd8b cd94 cd9c cda4 cdac cdb4 cdbd cdc5 cdcd cdd5 cdde cde6 cdee cdf6 cdff
+c500 c508 c510 c518 c520 c529 c531 c539 c541 c54a c552 c55a c562 c56a c573 c57b c583 c58b c594 c59c c5a4 c5ac c5b4 c5bd c5c5 c5cd c5d5 c5de c5e6 c5ee c5f6 c5ff
+bd00 bd08 bd10 bd18 bd20 bd29 bd31 bd39 bd41 bd4a bd52 bd5a bd62 bd6a bd73 bd7b bd83 bd8b bd94 bd9c bda4 bdac bdb4 bdbd bdc5 bdcd bdd5 bdde bde6 bdee bdf6 bdff
+b400 b408 b410 b418 b420 b429 b431 b439 b441 b44a b452 b45a b462 b46a b473 b47b b483 b48b b494 b49c b4a4 b4ac b4b4 b4bd b4c5 b4cd b4d5 b4de b4e6 b4ee b4f6 b4ff
+ac00 ac08 ac10 ac18 ac20 ac29 ac31 ac39 ac41 ac4a ac52 ac5a ac62 ac6a ac73 ac7b ac83 ac8b ac94 ac9c aca4 acac acb4 acbd acc5 accd acd5 acde ace6 acee acf6 acff
+a400 a408 a410 a418 a420 a429 a431 a439 a441 a44a a452 a45a a462 a46a a473 a47b a483 a48b a494 a49c a4a4 a4ac a4b4 a4bd a4c5 a4cd a4d5 a4de a4e6 a4ee a4f6 a4ff
+9c00 9c08 9c10 9c18 9c20 9c29 9c31 9c39 9c41 9c4a 9c52 9c5a 9c62 9c6a 9c73 9c7b 9c83 9c8b 9c94 9c9c 9ca4 9cac 9cb4 9cbd 9cc5 9ccd 9cd5 9cde 9ce6 9cee 9cf6 9cff
+9400 9408 9410 9418 9420 9429 9431 9439 9441 944a 9452 945a 9462 946a 9473 947b 9483 948b 9494 949c 94a4 94ac 94b4 94bd 94c5 94cd 94d5 94de 94e6 94ee 94f6 94ff
+8b00 8b08 8b10 8b18 8b20 8b29 8b31 8b39 8b41 8b4a 8b52 8b5a 8b62 8b6a 8b73 8b7b 8b83 8b8b 8b94 8b9c 8ba4 8bac 8bb4 8bbd 8bc5 8bcd 8bd5 8bde 8be6 8bee 8bf6 8bff
+8300 8308 8310 8318 8320 8329 8331 8339 8341 834a 8352 835a 8362 836a 8373 837b 8383 838b 8394 839c 83a4 83ac 83b4 83bd 83c5 83cd 83d5 83de 83e6 83ee 83f6 83ff
+7b00 7b08 7b10 7b18 7b20 7b29 7b31 7b39 7b41 7b4a 7b52 7b5a 7b62 7b6a 7b73 7b7b 7b83 7b8b 7b94 7b9c 7ba4 7bac 7bb4 7bbd 7bc5 7bcd 7bd5 7bde 7be6 7bee 7bf6 7bff
+7300 7308 7310 7318 7320 7329 7331 7339 7341 734a 7352 735a 7362 736a 7373 737b 7383 738b 7394 739c 73a4 73ac 73b4 73bd 73c5 73cd 73d5 73de 73e6 73ee 73f6 73ff
+6a00 6a08 6a10 6a18 6a20 6a29 6a31 6a39 6a41 6a4a 6a52 6a5a 6a62 6a6a 6a73 6a7b 6a83 6a8b 6a94 6a9c 6aa4 6aac 6ab4 6abd 6ac5 6acd 6ad5 6ade 6ae6 6aee 6af6 6aff
+6200 6208 6210 6218 6220 6229 6231 6239 6241 624a 6252 625a 6262 626a 6273 627b 6283 628b 6294 629c 62a4 62ac 62b4 62bd 62c5 62cd 62d5 62de 62e6 62ee 62f6 62ff
+5a00 5a08 5a10 5a18 5a20 5a29 5a31 5a39 5a41 5a4a 5a52 5a5a 5a62 5a6a 5a73 5a7b 5a83 5a8b 5a94 5a9c 5aa4 5aac 5ab4 5abd 5ac5 5acd 5ad5 5ade 5ae6 5aee 5af6 5aff
+5200 5208 5210 5218 5220 5229 5231 5239 5241 524a 5252 525a 5262 526a 5273 527b 5283 528b 5294 529c 52a4 52ac 52b4 52bd 52c5 52cd 52d5 52de 52e6 52ee 52f6 52ff
+4a00 4a08 4a10 4a18 4a20 4a29 4a31 4a39 4a41 4a4a 4a52 4a5a 4a62 4a6a 4a73 4a7b 4a83 4a8b 4a94 4a9c 4aa4 4aac 4ab4 4abd 4ac5 4acd 4ad5 4ade 4ae6 4aee 4af6 4aff
+4100 4108 4110 4118 4120 4129 4131 4139 4141 414a 4152 415a 4162 416a 4173 417b 4183 418b 4194 419c 41a4 41ac 41b4 41bd 41c5 41cd 41d5 41de 41e6 41ee 41f6 41ff
+3900 3908 3910 3918 3920 3929 3931 3939 3941 394a 3952 395a 3962 396a 3973 397b 3983 398b 3994 399c 39a4 39ac 39b4 39bd 39c5 39cd 39d5 39de 39e6 39ee 39f6 39ff
+3100 3108 3110 3118 3120 3129 3131 3139 3141 314a 3152 315a 3162 316a 3173 317b 3183 318b 3194 319c 31a4 31ac 31b4 31bd 31c5 31cd 31d5 31de 31e6 31ee 31f6 31ff
+2900 2908 2910 2918 2920 2929 2931 2939 2941 294a 2952 295a 2962 296a 2973 297b 2983 298b 2994 299c 29a4 29ac 29b4 29bd 29c5 29cd 29d5 29de 29e6 29ee 29f6 29ff
+2000 2008 2010 2018 2020 2029 2031 2039 2041 204a 2052 205a 2062 206a 2073 207b 2083 208b 2094 209c 20a4 20ac 20b4 20bd 20c5 20cd 20d5 20de 20e6 20ee 20f6 20ff
+1800 1808 1810 1818 1820 1829 1831 1839 1841 184a 1852 185a 1862 186a 1873 187b 1883 188b 1894 189c 18a4 18ac 18b4 18bd 18c5 18cd 18d5 18de 18e6 18ee 18f6 18ff
+1000 1008 1010 1018 1020 1029 1031 1039 1041 104a 1052 105a 1062 106a 1073 107b 1083 108b 1094 109c 10a4 10ac 10b4 10bd 10c5 10cd 10d5 10de 10e6 10ee 10f6 10ff
+0800 0808 0810 0818 0820 0829 0831 0839 0841 084a 0852 085a 0862 086a 0873 087b 0883 088b 0894 089c 08a4 08ac 08b4 08bd 08c5 08cd 08d5 08de 08e6 08ee 08f6 08ff
+0000 0008 0010 0018 0020 0029 0031 0039 0041 004a 0052 005a 0062 006a 0073 007b 0083 008b 0094 009c 00a4 00ac 00b4 00bd 00c5 00cd 00d5 00de 00e6 00ee 00f6 00ff
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn4a16.png b/libgo/go/image/png/testdata/pngsuite/basn4a16.png
new file mode 100644
index 000000000..6dbee9fbd
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn4a16.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn4a16.sng b/libgo/go/image/png/testdata/pngsuite/basn4a16.sng
new file mode 100644
index 000000000..d3b9b4722
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn4a16.sng
@@ -0,0 +1,41 @@
+#SNG: from basn4a16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using grayscale alpha;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+00000000 10840000 21080000 318c0000 42100000 52940000 63180000 739c0000 84200000 94a40000 a5280000 b5ac0000 c6300000 d6b40000 e7380000 f7bc0000 f7bc0000 e7380000 d6b40000 c6300000 b5ac0000 a5280000 94a40000 84200000 739c0000 63180000 52940000 42100000 318c0000 21080000 10840000 00000000
+10840000 00001085 11a71085 234f1085 34f61085 469e1085 58461085 69ed1085 7b951085 8d3d1085 9ee41085 b08c1085 c2341085 d3db1085 e5831085 f72b1085 f72b1085 e5831085 d3db1085 c2341085 b08c1085 9ee41085 8d3d1085 7b951085 69ed1085 58461085 469e1085 34f61085 234f1085 11a71085 00001085 10840000
+21080000 11a71085 00002109 12f62109 25ec2109 38e32109 4bd92109 5ed02109 71c62109 84bd2109 97b32109 aaa92109 bda02109 d0962109 e38d2109 f6832109 f6832109 e38d2109 d0962109 bda02109 aaa92109 97b32109 84bd2109 71c62109 5ed02109 4bd92109 38e32109 25ec2109 12f62109 00002109 11a71085 21080000
+318c0000 234f1085 12f62109 0000318d 147a318d 28f5318d 3d70318d 51eb318d 6665318d 7ae0318d 8f5b318d a3d6318d b851318d cccb318d e146318d f5c1318d f5c1318d e146318d cccb318d b851318d a3d6318d 8f5b318d 7ae0318d 6665318d 51eb318d 3d70318d 28f5318d 147a318d 0000318d 12f62109 234f1085 318c0000
+42100000 34f61085 25ec2109 147a318d 00004211 16424211 2c854211 42c84211 590a4211 6f4d4211 85904211 9bd24211 b2154211 c8584211 de9a4211 f4dd4211 f4dd4211 de9a4211 c8584211 b2154211 9bd24211 85904211 6f4d4211 590a4211 42c84211 2c854211 16424211 00004211 147a318d 25ec2109 34f61085 42100000
+52940000 469e1085 38e32109 28f5318d 16424211 00005295 18615295 30c25295 49245295 61855295 79e75295 92485295 aaa95295 c30b5295 db6c5295 f3ce5295 f3ce5295 db6c5295 c30b5295 aaa95295 92485295 79e75295 61855295 49245295 30c25295 18615295 00005295 16424211 28f5318d 38e32109 469e1085 52940000
+63180000 58461085 4bd92109 3d70318d 2c854211 18615295 00006319 1af26319 35e46319 50d76319 6bc96319 86bc6319 a1ae6319 bca06319 d7936319 f2856319 f2856319 d7936319 bca06319 a1ae6319 86bc6319 6bc96319 50d76319 35e46319 1af26319 00006319 18615295 2c854211 3d70318d 4bd92109 58461085 63180000
+739c0000 69ed1085 5ed02109 51eb318d 42c84211 30c25295 1af26319 0000739d 1e1d739d 3c3b739d 5a59739d 7877739d 9695739d b4b3739d d2d1739d f0ef739d f0ef739d d2d1739d b4b3739d 9695739d 7877739d 5a59739d 3c3b739d 1e1d739d 0000739d 1af26319 30c25295 42c84211 51eb318d 5ed02109 69ed1085 739c0000
+84200000 7b951085 71c62109 6665318d 590a4211 49245295 35e46319 1e1d739d 00008421 22218421 44438421 66658421 88878421 aaa98421 cccb8421 eeed8421 eeed8421 cccb8421 aaa98421 88878421 66658421 44438421 22218421 00008421 1e1d739d 35e46319 49245295 590a4211 6665318d 71c62109 7b951085 84200000
+94a40000 8d3d1085 84bd2109 7ae0318d 6f4d4211 61855295 50d76319 3c3b739d 22218421 000094a5 276294a5 4ec494a5 762694a5 9d8994a5 c4eb94a5 ec4d94a5 ec4d94a5 c4eb94a5 9d8994a5 762694a5 4ec494a5 276294a5 000094a5 22218421 3c3b739d 50d76319 61855295 6f4d4211 7ae0318d 84bd2109 8d3d1085 94a40000
+a5280000 9ee41085 97b32109 8f5b318d 85904211 79e75295 6bc96319 5a59739d 44438421 276294a5 0000a529 2e8ba529 5d16a529 8ba2a529 ba2da529 e8b9a529 e8b9a529 ba2da529 8ba2a529 5d16a529 2e8ba529 0000a529 276294a5 44438421 5a59739d 6bc96319 79e75295 85904211 8f5b318d 97b32109 9ee41085 a5280000
+b5ac0000 b08c1085 aaa92109 a3d6318d 9bd24211 92485295 86bc6319 7877739d 66658421 4ec494a5 2e8ba529 0000b5ad 38e3b5ad 71c6b5ad aaa9b5ad e38db5ad e38db5ad aaa9b5ad 71c6b5ad 38e3b5ad 0000b5ad 2e8ba529 4ec494a5 66658421 7877739d 86bc6319 92485295 9bd24211 a3d6318d aaa92109 b08c1085 b5ac0000
+c6300000 c2341085 bda02109 b851318d b2154211 aaa95295 a1ae6319 9695739d 88878421 762694a5 5d16a529 38e3b5ad 0000c631 4924c631 9248c631 db6cc631 db6cc631 9248c631 4924c631 0000c631 38e3b5ad 5d16a529 762694a5 88878421 9695739d a1ae6319 aaa95295 b2154211 b851318d bda02109 c2341085 c6300000
+d6b40000 d3db1085 d0962109 cccb318d c8584211 c30b5295 bca06319 b4b3739d aaa98421 9d8994a5 8ba2a529 71c6b5ad 4924c631 0000d6b5 6665d6b5 cccbd6b5 cccbd6b5 6665d6b5 0000d6b5 4924c631 71c6b5ad 8ba2a529 9d8994a5 aaa98421 b4b3739d bca06319 c30b5295 c8584211 cccb318d d0962109 d3db1085 d6b40000
+e7380000 e5831085 e38d2109 e146318d de9a4211 db6c5295 d7936319 d2d1739d cccb8421 c4eb94a5 ba2da529 aaa9b5ad 9248c631 6665d6b5 0000e739 aaa9e739 aaa9e739 0000e739 6665d6b5 9248c631 aaa9b5ad ba2da529 c4eb94a5 cccb8421 d2d1739d d7936319 db6c5295 de9a4211 e146318d e38d2109 e5831085 e7380000
+f7bc0000 f72b1085 f6832109 f5c1318d f4dd4211 f3ce5295 f2856319 f0ef739d eeed8421 ec4d94a5 e8b9a529 e38db5ad db6cc631 cccbd6b5 aaa9e739 0000f7bd 0000f7bd aaa9e739 cccbd6b5 db6cc631 e38db5ad e8b9a529 ec4d94a5 eeed8421 f0ef739d f2856319 f3ce5295 f4dd4211 f5c1318d f6832109 f72b1085 f7bc0000
+f7bc0000 f72b1085 f6832109 f5c1318d f4dd4211 f3ce5295 f2856319 f0ef739d eeed8421 ec4d94a5 e8b9a529 e38db5ad db6cc631 cccbd6b5 aaa9e739 0000f7bd 0000f7bd aaa9e739 cccbd6b5 db6cc631 e38db5ad e8b9a529 ec4d94a5 eeed8421 f0ef739d f2856319 f3ce5295 f4dd4211 f5c1318d f6832109 f72b1085 f7bc0000
+e7380000 e5831085 e38d2109 e146318d de9a4211 db6c5295 d7936319 d2d1739d cccb8421 c4eb94a5 ba2da529 aaa9b5ad 9248c631 6665d6b5 0000e739 aaa9e739 aaa9e739 0000e739 6665d6b5 9248c631 aaa9b5ad ba2da529 c4eb94a5 cccb8421 d2d1739d d7936319 db6c5295 de9a4211 e146318d e38d2109 e5831085 e7380000
+d6b40000 d3db1085 d0962109 cccb318d c8584211 c30b5295 bca06319 b4b3739d aaa98421 9d8994a5 8ba2a529 71c6b5ad 4924c631 0000d6b5 6665d6b5 cccbd6b5 cccbd6b5 6665d6b5 0000d6b5 4924c631 71c6b5ad 8ba2a529 9d8994a5 aaa98421 b4b3739d bca06319 c30b5295 c8584211 cccb318d d0962109 d3db1085 d6b40000
+c6300000 c2341085 bda02109 b851318d b2154211 aaa95295 a1ae6319 9695739d 88878421 762694a5 5d16a529 38e3b5ad 0000c631 4924c631 9248c631 db6cc631 db6cc631 9248c631 4924c631 0000c631 38e3b5ad 5d16a529 762694a5 88878421 9695739d a1ae6319 aaa95295 b2154211 b851318d bda02109 c2341085 c6300000
+b5ac0000 b08c1085 aaa92109 a3d6318d 9bd24211 92485295 86bc6319 7877739d 66658421 4ec494a5 2e8ba529 0000b5ad 38e3b5ad 71c6b5ad aaa9b5ad e38db5ad e38db5ad aaa9b5ad 71c6b5ad 38e3b5ad 0000b5ad 2e8ba529 4ec494a5 66658421 7877739d 86bc6319 92485295 9bd24211 a3d6318d aaa92109 b08c1085 b5ac0000
+a5280000 9ee41085 97b32109 8f5b318d 85904211 79e75295 6bc96319 5a59739d 44438421 276294a5 0000a529 2e8ba529 5d16a529 8ba2a529 ba2da529 e8b9a529 e8b9a529 ba2da529 8ba2a529 5d16a529 2e8ba529 0000a529 276294a5 44438421 5a59739d 6bc96319 79e75295 85904211 8f5b318d 97b32109 9ee41085 a5280000
+94a40000 8d3d1085 84bd2109 7ae0318d 6f4d4211 61855295 50d76319 3c3b739d 22218421 000094a5 276294a5 4ec494a5 762694a5 9d8994a5 c4eb94a5 ec4d94a5 ec4d94a5 c4eb94a5 9d8994a5 762694a5 4ec494a5 276294a5 000094a5 22218421 3c3b739d 50d76319 61855295 6f4d4211 7ae0318d 84bd2109 8d3d1085 94a40000
+84200000 7b951085 71c62109 6665318d 590a4211 49245295 35e46319 1e1d739d 00008421 22218421 44438421 66658421 88878421 aaa98421 cccb8421 eeed8421 eeed8421 cccb8421 aaa98421 88878421 66658421 44438421 22218421 00008421 1e1d739d 35e46319 49245295 590a4211 6665318d 71c62109 7b951085 84200000
+739c0000 69ed1085 5ed02109 51eb318d 42c84211 30c25295 1af26319 0000739d 1e1d739d 3c3b739d 5a59739d 7877739d 9695739d b4b3739d d2d1739d f0ef739d f0ef739d d2d1739d b4b3739d 9695739d 7877739d 5a59739d 3c3b739d 1e1d739d 0000739d 1af26319 30c25295 42c84211 51eb318d 5ed02109 69ed1085 739c0000
+63180000 58461085 4bd92109 3d70318d 2c854211 18615295 00006319 1af26319 35e46319 50d76319 6bc96319 86bc6319 a1ae6319 bca06319 d7936319 f2856319 f2856319 d7936319 bca06319 a1ae6319 86bc6319 6bc96319 50d76319 35e46319 1af26319 00006319 18615295 2c854211 3d70318d 4bd92109 58461085 63180000
+52940000 469e1085 38e32109 28f5318d 16424211 00005295 18615295 30c25295 49245295 61855295 79e75295 92485295 aaa95295 c30b5295 db6c5295 f3ce5295 f3ce5295 db6c5295 c30b5295 aaa95295 92485295 79e75295 61855295 49245295 30c25295 18615295 00005295 16424211 28f5318d 38e32109 469e1085 52940000
+42100000 34f61085 25ec2109 147a318d 00004211 16424211 2c854211 42c84211 590a4211 6f4d4211 85904211 9bd24211 b2154211 c8584211 de9a4211 f4dd4211 f4dd4211 de9a4211 c8584211 b2154211 9bd24211 85904211 6f4d4211 590a4211 42c84211 2c854211 16424211 00004211 147a318d 25ec2109 34f61085 42100000
+318c0000 234f1085 12f62109 0000318d 147a318d 28f5318d 3d70318d 51eb318d 6665318d 7ae0318d 8f5b318d a3d6318d b851318d cccb318d e146318d f5c1318d f5c1318d e146318d cccb318d b851318d a3d6318d 8f5b318d 7ae0318d 6665318d 51eb318d 3d70318d 28f5318d 147a318d 0000318d 12f62109 234f1085 318c0000
+21080000 11a71085 00002109 12f62109 25ec2109 38e32109 4bd92109 5ed02109 71c62109 84bd2109 97b32109 aaa92109 bda02109 d0962109 e38d2109 f6832109 f6832109 e38d2109 d0962109 bda02109 aaa92109 97b32109 84bd2109 71c62109 5ed02109 4bd92109 38e32109 25ec2109 12f62109 00002109 11a71085 21080000
+10840000 00001085 11a71085 234f1085 34f61085 469e1085 58461085 69ed1085 7b951085 8d3d1085 9ee41085 b08c1085 c2341085 d3db1085 e5831085 f72b1085 f72b1085 e5831085 d3db1085 c2341085 b08c1085 9ee41085 8d3d1085 7b951085 69ed1085 58461085 469e1085 34f61085 234f1085 11a71085 00001085 10840000
+00000000 10840000 21080000 318c0000 42100000 52940000 63180000 739c0000 84200000 94a40000 a5280000 b5ac0000 c6300000 d6b40000 e7380000 f7bc0000 f7bc0000 e7380000 d6b40000 c6300000 b5ac0000 a5280000 94a40000 84200000 739c0000 63180000 52940000 42100000 318c0000 21080000 10840000 00000000
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn6a08.png b/libgo/go/image/png/testdata/pngsuite/basn6a08.png
new file mode 100644
index 000000000..610623085
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn6a08.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn6a08.sng b/libgo/go/image/png/testdata/pngsuite/basn6a08.sng
new file mode 100644
index 000000000..c1e0bf475
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn6a08.sng
@@ -0,0 +1,41 @@
+#SNG: from basn6a08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color alpha;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ff000800 ff000808 ff000810 ff000818 ff000820 ff000829 ff000831 ff000839 ff000841 ff00084a ff000852 ff00085a ff000862 ff00086a ff000873 ff00087b ff000883 ff00088b ff000894 ff00089c ff0008a4 ff0008ac ff0008b4 ff0008bd ff0008c5 ff0008cd ff0008d5 ff0008de ff0008e6 ff0008ee ff0008f6 ff0008ff
+ff1f0800 ff1f0808 ff1f0810 ff1f0818 ff1f0820 ff1f0829 ff1f0831 ff1f0839 ff1f0841 ff1f084a ff1f0852 ff1f085a ff1f0862 ff1f086a ff1f0873 ff1f087b ff1f0883 ff1f088b ff1f0894 ff1f089c ff1f08a4 ff1f08ac ff1f08b4 ff1f08bd ff1f08c5 ff1f08cd ff1f08d5 ff1f08de ff1f08e6 ff1f08ee ff1f08f6 ff1f08ff
+ff3f0800 ff3f0808 ff3f0810 ff3f0818 ff3f0820 ff3f0829 ff3f0831 ff3f0839 ff3f0841 ff3f084a ff3f0852 ff3f085a ff3f0862 ff3f086a ff3f0873 ff3f087b ff3f0883 ff3f088b ff3f0894 ff3f089c ff3f08a4 ff3f08ac ff3f08b4 ff3f08bd ff3f08c5 ff3f08cd ff3f08d5 ff3f08de ff3f08e6 ff3f08ee ff3f08f6 ff3f08ff
+ff5f0800 ff5f0808 ff5f0810 ff5f0818 ff5f0820 ff5f0829 ff5f0831 ff5f0839 ff5f0841 ff5f084a ff5f0852 ff5f085a ff5f0862 ff5f086a ff5f0873 ff5f087b ff5f0883 ff5f088b ff5f0894 ff5f089c ff5f08a4 ff5f08ac ff5f08b4 ff5f08bd ff5f08c5 ff5f08cd ff5f08d5 ff5f08de ff5f08e6 ff5f08ee ff5f08f6 ff5f08ff
+ff7f0700 ff7f0708 ff7f0710 ff7f0718 ff7f0720 ff7f0729 ff7f0731 ff7f0739 ff7f0741 ff7f074a ff7f0752 ff7f075a ff7f0762 ff7f076a ff7f0773 ff7f077b ff7f0783 ff7f078b ff7f0794 ff7f079c ff7f07a4 ff7f07ac ff7f07b4 ff7f07bd ff7f07c5 ff7f07cd ff7f07d5 ff7f07de ff7f07e6 ff7f07ee ff7f07f6 ff7f07ff
+ff9f0700 ff9f0708 ff9f0710 ff9f0718 ff9f0720 ff9f0729 ff9f0731 ff9f0739 ff9f0741 ff9f074a ff9f0752 ff9f075a ff9f0762 ff9f076a ff9f0773 ff9f077b ff9f0783 ff9f078b ff9f0794 ff9f079c ff9f07a4 ff9f07ac ff9f07b4 ff9f07bd ff9f07c5 ff9f07cd ff9f07d5 ff9f07de ff9f07e6 ff9f07ee ff9f07f6 ff9f07ff
+ffbf0700 ffbf0708 ffbf0710 ffbf0718 ffbf0720 ffbf0729 ffbf0731 ffbf0739 ffbf0741 ffbf074a ffbf0752 ffbf075a ffbf0762 ffbf076a ffbf0773 ffbf077b ffbf0783 ffbf078b ffbf0794 ffbf079c ffbf07a4 ffbf07ac ffbf07b4 ffbf07bd ffbf07c5 ffbf07cd ffbf07d5 ffbf07de ffbf07e6 ffbf07ee ffbf07f6 ffbf07ff
+ffdf0700 ffdf0708 ffdf0710 ffdf0718 ffdf0720 ffdf0729 ffdf0731 ffdf0739 ffdf0741 ffdf074a ffdf0752 ffdf075a ffdf0762 ffdf076a ffdf0773 ffdf077b ffdf0783 ffdf078b ffdf0794 ffdf079c ffdf07a4 ffdf07ac ffdf07b4 ffdf07bd ffdf07c5 ffdf07cd ffdf07d5 ffdf07de ffdf07e6 ffdf07ee ffdf07f6 ffdf07ff
+ffff0600 ffff0608 ffff0610 ffff0618 ffff0620 ffff0629 ffff0631 ffff0639 ffff0641 ffff064a ffff0652 ffff065a ffff0662 ffff066a ffff0673 ffff067b ffff0683 ffff068b ffff0694 ffff069c ffff06a4 ffff06ac ffff06b4 ffff06bd ffff06c5 ffff06cd ffff06d5 ffff06de ffff06e6 ffff06ee ffff06f6 ffff06ff
+e0ff0600 e0ff0608 e0ff0610 e0ff0618 e0ff0620 e0ff0629 e0ff0631 e0ff0639 e0ff0641 e0ff064a e0ff0652 e0ff065a e0ff0662 e0ff066a e0ff0673 e0ff067b e0ff0683 e0ff068b e0ff0694 e0ff069c e0ff06a4 e0ff06ac e0ff06b4 e0ff06bd e0ff06c5 e0ff06cd e0ff06d5 e0ff06de e0ff06e6 e0ff06ee e0ff06f6 e0ff06ff
+c0ff0600 c0ff0608 c0ff0610 c0ff0618 c0ff0620 c0ff0629 c0ff0631 c0ff0639 c0ff0641 c0ff064a c0ff0652 c0ff065a c0ff0662 c0ff066a c0ff0673 c0ff067b c0ff0683 c0ff068b c0ff0694 c0ff069c c0ff06a4 c0ff06ac c0ff06b4 c0ff06bd c0ff06c5 c0ff06cd c0ff06d5 c0ff06de c0ff06e6 c0ff06ee c0ff06f6 c0ff06ff
+a0ff0500 a0ff0508 a0ff0510 a0ff0518 a0ff0520 a0ff0529 a0ff0531 a0ff0539 a0ff0541 a0ff054a a0ff0552 a0ff055a a0ff0562 a0ff056a a0ff0573 a0ff057b a0ff0583 a0ff058b a0ff0594 a0ff059c a0ff05a4 a0ff05ac a0ff05b4 a0ff05bd a0ff05c5 a0ff05cd a0ff05d5 a0ff05de a0ff05e6 a0ff05ee a0ff05f6 a0ff05ff
+80ff0500 80ff0508 80ff0510 80ff0518 80ff0520 80ff0529 80ff0531 80ff0539 80ff0541 80ff054a 80ff0552 80ff055a 80ff0562 80ff056a 80ff0573 80ff057b 80ff0583 80ff058b 80ff0594 80ff059c 80ff05a4 80ff05ac 80ff05b4 80ff05bd 80ff05c5 80ff05cd 80ff05d5 80ff05de 80ff05e6 80ff05ee 80ff05f6 80ff05ff
+60ff0500 60ff0508 60ff0510 60ff0518 60ff0520 60ff0529 60ff0531 60ff0539 60ff0541 60ff054a 60ff0552 60ff055a 60ff0562 60ff056a 60ff0573 60ff057b 60ff0583 60ff058b 60ff0594 60ff059c 60ff05a4 60ff05ac 60ff05b4 60ff05bd 60ff05c5 60ff05cd 60ff05d5 60ff05de 60ff05e6 60ff05ee 60ff05f6 60ff05ff
+40ff0500 40ff0508 40ff0510 40ff0518 40ff0520 40ff0529 40ff0531 40ff0539 40ff0541 40ff054a 40ff0552 40ff055a 40ff0562 40ff056a 40ff0573 40ff057b 40ff0583 40ff058b 40ff0594 40ff059c 40ff05a4 40ff05ac 40ff05b4 40ff05bd 40ff05c5 40ff05cd 40ff05d5 40ff05de 40ff05e6 40ff05ee 40ff05f6 40ff05ff
+20ff0400 20ff0408 20ff0410 20ff0418 20ff0420 20ff0429 20ff0431 20ff0439 20ff0441 20ff044a 20ff0452 20ff045a 20ff0462 20ff046a 20ff0473 20ff047b 20ff0483 20ff048b 20ff0494 20ff049c 20ff04a4 20ff04ac 20ff04b4 20ff04bd 20ff04c5 20ff04cd 20ff04d5 20ff04de 20ff04e6 20ff04ee 20ff04f6 20ff04ff
+04ff0000 04ff0008 04ff0010 04ff0018 04ff0020 04ff0029 04ff0031 04ff0039 04ff0041 04ff004a 04ff0052 04ff005a 04ff0062 04ff006a 04ff0073 04ff007b 04ff0083 04ff008b 04ff0094 04ff009c 04ff00a4 04ff00ac 04ff00b4 04ff00bd 04ff00c5 04ff00cd 04ff00d5 04ff00de 04ff00e6 04ff00ee 04ff00f6 04ff00ff
+04ff1f00 04ff1f08 04ff1f10 04ff1f18 04ff1f20 04ff1f29 04ff1f31 04ff1f39 04ff1f41 04ff1f4a 04ff1f52 04ff1f5a 04ff1f62 04ff1f6a 04ff1f73 04ff1f7b 04ff1f83 04ff1f8b 04ff1f94 04ff1f9c 04ff1fa4 04ff1fac 04ff1fb4 04ff1fbd 04ff1fc5 04ff1fcd 04ff1fd5 04ff1fde 04ff1fe6 04ff1fee 04ff1ff6 04ff1fff
+03ff3f00 03ff3f08 03ff3f10 03ff3f18 03ff3f20 03ff3f29 03ff3f31 03ff3f39 03ff3f41 03ff3f4a 03ff3f52 03ff3f5a 03ff3f62 03ff3f6a 03ff3f73 03ff3f7b 03ff3f83 03ff3f8b 03ff3f94 03ff3f9c 03ff3fa4 03ff3fac 03ff3fb4 03ff3fbd 03ff3fc5 03ff3fcd 03ff3fd5 03ff3fde 03ff3fe6 03ff3fee 03ff3ff6 03ff3fff
+03ff5f00 03ff5f08 03ff5f10 03ff5f18 03ff5f20 03ff5f29 03ff5f31 03ff5f39 03ff5f41 03ff5f4a 03ff5f52 03ff5f5a 03ff5f62 03ff5f6a 03ff5f73 03ff5f7b 03ff5f83 03ff5f8b 03ff5f94 03ff5f9c 03ff5fa4 03ff5fac 03ff5fb4 03ff5fbd 03ff5fc5 03ff5fcd 03ff5fd5 03ff5fde 03ff5fe6 03ff5fee 03ff5ff6 03ff5fff
+03ff7f00 03ff7f08 03ff7f10 03ff7f18 03ff7f20 03ff7f29 03ff7f31 03ff7f39 03ff7f41 03ff7f4a 03ff7f52 03ff7f5a 03ff7f62 03ff7f6a 03ff7f73 03ff7f7b 03ff7f83 03ff7f8b 03ff7f94 03ff7f9c 03ff7fa4 03ff7fac 03ff7fb4 03ff7fbd 03ff7fc5 03ff7fcd 03ff7fd5 03ff7fde 03ff7fe6 03ff7fee 03ff7ff6 03ff7fff
+03ff9f00 03ff9f08 03ff9f10 03ff9f18 03ff9f20 03ff9f29 03ff9f31 03ff9f39 03ff9f41 03ff9f4a 03ff9f52 03ff9f5a 03ff9f62 03ff9f6a 03ff9f73 03ff9f7b 03ff9f83 03ff9f8b 03ff9f94 03ff9f9c 03ff9fa4 03ff9fac 03ff9fb4 03ff9fbd 03ff9fc5 03ff9fcd 03ff9fd5 03ff9fde 03ff9fe6 03ff9fee 03ff9ff6 03ff9fff
+02ffbf00 02ffbf08 02ffbf10 02ffbf18 02ffbf20 02ffbf29 02ffbf31 02ffbf39 02ffbf41 02ffbf4a 02ffbf52 02ffbf5a 02ffbf62 02ffbf6a 02ffbf73 02ffbf7b 02ffbf83 02ffbf8b 02ffbf94 02ffbf9c 02ffbfa4 02ffbfac 02ffbfb4 02ffbfbd 02ffbfc5 02ffbfcd 02ffbfd5 02ffbfde 02ffbfe6 02ffbfee 02ffbff6 02ffbfff
+02ffdf00 02ffdf08 02ffdf10 02ffdf18 02ffdf20 02ffdf29 02ffdf31 02ffdf39 02ffdf41 02ffdf4a 02ffdf52 02ffdf5a 02ffdf62 02ffdf6a 02ffdf73 02ffdf7b 02ffdf83 02ffdf8b 02ffdf94 02ffdf9c 02ffdfa4 02ffdfac 02ffdfb4 02ffdfbd 02ffdfc5 02ffdfcd 02ffdfd5 02ffdfde 02ffdfe6 02ffdfee 02ffdff6 02ffdfff
+02ffff00 02ffff08 02ffff10 02ffff18 02ffff20 02ffff29 02ffff31 02ffff39 02ffff41 02ffff4a 02ffff52 02ffff5a 02ffff62 02ffff6a 02ffff73 02ffff7b 02ffff83 02ffff8b 02ffff94 02ffff9c 02ffffa4 02ffffac 02ffffb4 02ffffbd 02ffffc5 02ffffcd 02ffffd5 02ffffde 02ffffe6 02ffffee 02fffff6 02ffffff
+01e0ff00 01e0ff08 01e0ff10 01e0ff18 01e0ff20 01e0ff29 01e0ff31 01e0ff39 01e0ff41 01e0ff4a 01e0ff52 01e0ff5a 01e0ff62 01e0ff6a 01e0ff73 01e0ff7b 01e0ff83 01e0ff8b 01e0ff94 01e0ff9c 01e0ffa4 01e0ffac 01e0ffb4 01e0ffbd 01e0ffc5 01e0ffcd 01e0ffd5 01e0ffde 01e0ffe6 01e0ffee 01e0fff6 01e0ffff
+01c0ff00 01c0ff08 01c0ff10 01c0ff18 01c0ff20 01c0ff29 01c0ff31 01c0ff39 01c0ff41 01c0ff4a 01c0ff52 01c0ff5a 01c0ff62 01c0ff6a 01c0ff73 01c0ff7b 01c0ff83 01c0ff8b 01c0ff94 01c0ff9c 01c0ffa4 01c0ffac 01c0ffb4 01c0ffbd 01c0ffc5 01c0ffcd 01c0ffd5 01c0ffde 01c0ffe6 01c0ffee 01c0fff6 01c0ffff
+01a0ff00 01a0ff08 01a0ff10 01a0ff18 01a0ff20 01a0ff29 01a0ff31 01a0ff39 01a0ff41 01a0ff4a 01a0ff52 01a0ff5a 01a0ff62 01a0ff6a 01a0ff73 01a0ff7b 01a0ff83 01a0ff8b 01a0ff94 01a0ff9c 01a0ffa4 01a0ffac 01a0ffb4 01a0ffbd 01a0ffc5 01a0ffcd 01a0ffd5 01a0ffde 01a0ffe6 01a0ffee 01a0fff6 01a0ffff
+0180ff00 0180ff08 0180ff10 0180ff18 0180ff20 0180ff29 0180ff31 0180ff39 0180ff41 0180ff4a 0180ff52 0180ff5a 0180ff62 0180ff6a 0180ff73 0180ff7b 0180ff83 0180ff8b 0180ff94 0180ff9c 0180ffa4 0180ffac 0180ffb4 0180ffbd 0180ffc5 0180ffcd 0180ffd5 0180ffde 0180ffe6 0180ffee 0180fff6 0180ffff
+0060ff00 0060ff08 0060ff10 0060ff18 0060ff20 0060ff29 0060ff31 0060ff39 0060ff41 0060ff4a 0060ff52 0060ff5a 0060ff62 0060ff6a 0060ff73 0060ff7b 0060ff83 0060ff8b 0060ff94 0060ff9c 0060ffa4 0060ffac 0060ffb4 0060ffbd 0060ffc5 0060ffcd 0060ffd5 0060ffde 0060ffe6 0060ffee 0060fff6 0060ffff
+0040ff00 0040ff08 0040ff10 0040ff18 0040ff20 0040ff29 0040ff31 0040ff39 0040ff41 0040ff4a 0040ff52 0040ff5a 0040ff62 0040ff6a 0040ff73 0040ff7b 0040ff83 0040ff8b 0040ff94 0040ff9c 0040ffa4 0040ffac 0040ffb4 0040ffbd 0040ffc5 0040ffcd 0040ffd5 0040ffde 0040ffe6 0040ffee 0040fff6 0040ffff
+0020ff00 0020ff08 0020ff10 0020ff18 0020ff20 0020ff29 0020ff31 0020ff39 0020ff41 0020ff4a 0020ff52 0020ff5a 0020ff62 0020ff6a 0020ff73 0020ff7b 0020ff83 0020ff8b 0020ff94 0020ff9c 0020ffa4 0020ffac 0020ffb4 0020ffbd 0020ffc5 0020ffcd 0020ffd5 0020ffde 0020ffe6 0020ffee 0020fff6 0020ffff
+}
diff --git a/libgo/go/image/png/testdata/pngsuite/basn6a16.png b/libgo/go/image/png/testdata/pngsuite/basn6a16.png
new file mode 100644
index 000000000..a9bf3cb46
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn6a16.png
Binary files differ
diff --git a/libgo/go/image/png/testdata/pngsuite/basn6a16.sng b/libgo/go/image/png/testdata/pngsuite/basn6a16.sng
new file mode 100644
index 000000000..13c70a4d5
--- /dev/null
+++ b/libgo/go/image/png/testdata/pngsuite/basn6a16.sng
@@ -0,0 +1,41 @@
+#SNG: from basn6a16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using color alpha;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+ffffffff00000000 f7bcffff00000000 ef7affff00000000 e738ffff00000000 def6ffff00000000 d6b4ffff00000000 ce72ffff00000000 c630ffff00000000 bdeeffff00000000 b5acffff00000000 ad6affff00000000 a528ffff00000000 9ce6ffff00000000 94a4ffff00000000 8c62ffff00000000 8420ffff00000000 7bdeffff00000000 739cffff00000000 6b5affff00000000 6318ffff00000000 5ad6ffff00000000 5294ffff00000000 4a52ffff00000000 4210ffff00000000 39ceffff00000000 318cffff00000000 294affff00000000 2108ffff00000000 18c6ffff00000000 1084ffff00000000 0842ffff00000000 0000ffff00000000
+fffff7bc00000000 ffffffff00001085 f72bffff00001085 ee57ffff00001085 e583ffff00001085 dcafffff00001085 d3dbffff00001085 cb08ffff00001085 c234ffff00001085 b960ffff00001085 b08cffff00001085 a7b8ffff00001085 9ee4ffff00001085 9611ffff00001085 8d3dffff00001085 8469ffff00001085 7b95ffff00001085 72c1ffff00001085 69edffff00001085 611affff00001085 5846ffff00001085 4f72ffff00001085 469effff00001085 3dcaffff00001085 34f6ffff00001085 2c23ffff00001085 234fffff00001085 1a7bffff00001085 11a7ffff00001085 08d3ffff00001085 0000ffff00001085 0000f7bc08420000
+ffffef7a00000000 fffff72b00001085 ffffffff00002109 f683ffff00002109 ed08ffff00002109 e38dffff00002109 da12ffff00002109 d096ffff00002109 c71bffff00002109 bda0ffff00002109 b425ffff00002109 aaa9ffff00002109 a12effff00002109 97b3ffff00002109 8e38ffff00002109 84bdffff00002109 7b41ffff00002109 71c6ffff00002109 684bffff00002109 5ed0ffff00002109 5554ffff00002109 4bd9ffff00002109 425effff00002109 38e3ffff00002109 2f68ffff00002109 25ecffff00002109 1c71ffff00002109 12f6ffff00002109 097bffff00002109 0000ffff00002109 0000f72b08d31085 0000ef7a10840000
+ffffe73800000000 ffffee5700001085 fffff68300002109 ffffffff0000318d f5c1ffff0000318d eb84ffff0000318d e146ffff0000318d d709ffff0000318d ccccffff0000318d c28effff0000318d b851ffff0000318d ae13ffff0000318d a3d6ffff0000318d 9998ffff0000318d 8f5bffff0000318d 851effff0000318d 7ae0ffff0000318d 70a3ffff0000318d 6665ffff0000318d 5c28ffff0000318d 51ebffff0000318d 47adffff0000318d 3d70ffff0000318d 3332ffff0000318d 28f5ffff0000318d 1eb8ffff0000318d 147affff0000318d 0a3dffff0000318d 0000ffff0000318d 0000f683097b2109 0000ee5711a71085 0000e73818c60000
+ffffdef600000000 ffffe58300001085 ffffed0800002109 fffff5c10000318d ffffffff00004211 f4ddffff00004211 e9bcffff00004211 de9affff00004211 d379ffff00004211 c858ffff00004211 bd36ffff00004211 b215ffff00004211 a6f4ffff00004211 9bd2ffff00004211 90b1ffff00004211 8590ffff00004211 7a6effff00004211 6f4dffff00004211 642cffff00004211 590affff00004211 4de9ffff00004211 42c8ffff00004211 37a6ffff00004211 2c85ffff00004211 2164ffff00004211 1642ffff00004211 0b21ffff00004211 0000ffff00004211 0000f5c10a3d318d 0000ed0812f62109 0000e5831a7b1085 0000def621080000
+ffffd6b400000000 ffffdcaf00001085 ffffe38d00002109 ffffeb840000318d fffff4dd00004211 ffffffff00005295 f3ceffff00005295 e79dffff00005295 db6cffff00005295 cf3cffff00005295 c30bffff00005295 b6daffff00005295 aaa9ffff00005295 9e79ffff00005295 9248ffff00005295 8617ffff00005295 79e7ffff00005295 6db6ffff00005295 6185ffff00005295 5554ffff00005295 4924ffff00005295 3cf3ffff00005295 30c2ffff00005295 2492ffff00005295 1861ffff00005295 0c30ffff00005295 0000ffff00005295 0000f4dd0b214211 0000eb84147a318d 0000e38d1c712109 0000dcaf234f1085 0000d6b4294a0000
+ffffce7200000000 ffffd3db00001085 ffffda1200002109 ffffe1460000318d ffffe9bc00004211 fffff3ce00005295 ffffffff00006319 f285ffff00006319 e50cffff00006319 d793ffff00006319 ca1affff00006319 bca0ffff00006319 af27ffff00006319 a1aeffff00006319 9435ffff00006319 86bcffff00006319 7942ffff00006319 6bc9ffff00006319 5e50ffff00006319 50d7ffff00006319 435effff00006319 35e4ffff00006319 286bffff00006319 1af2ffff00006319 0d79ffff00006319 0000ffff00006319 0000f3ce0c305295 0000e9bc16424211 0000e1461eb8318d 0000da1225ec2109 0000d3db2c231085 0000ce72318c0000
+ffffc63000000000 ffffcb0800001085 ffffd09600002109 ffffd7090000318d ffffde9a00004211 ffffe79d00005295 fffff28500006319 ffffffff0000739d f0f0ffff0000739d e1e1ffff0000739d d2d2ffff0000739d c3c3ffff0000739d b4b3ffff0000739d a5a4ffff0000739d 9695ffff0000739d 8786ffff0000739d 7877ffff0000739d 6968ffff0000739d 5a59ffff0000739d 4b4affff0000739d 3c3bffff0000739d 2d2cffff0000739d 1e1dffff0000739d 0f0effff0000739d 0000ffff0000739d 0000f2850d796319 0000e79d18615295 0000de9a21644211 0000d70928f5318d 0000d0962f682109 0000cb0834f61085 0000c63039ce0000
+ffffbdee00000000 ffffc23400001085 ffffc71b00002109 ffffcccc0000318d ffffd37900004211 ffffdb6c00005295 ffffe50c00006319 fffff0f00000739d ffffffff00008421 eeeeffff00008421 ddddffff00008421 ccccffff00008421 bbbaffff00008421 aaa9ffff00008421 9998ffff00008421 8887ffff00008421 7776ffff00008421 6665ffff00008421 5554ffff00008421 4443ffff00008421 3332ffff00008421 2221ffff00008421 1110ffff00008421 0000ffff00008421 0000f0f00f0e739d 0000e50c1af26319 0000db6c24925295 0000d3792c854211 0000cccc3332318d 0000c71b38e32109 0000c2343dca1085 0000bdee42100000
+ffffb5ac00000000 ffffb96000001085 ffffbda000002109 ffffc28e0000318d ffffc85800004211 ffffcf3c00005295 ffffd79300006319 ffffe1e10000739d ffffeeee00008421 ffffffff000094a5 ec4dffff000094a5 d89cffff000094a5 c4ebffff000094a5 b13affff000094a5 9d89ffff000094a5 89d8ffff000094a5 7626ffff000094a5 6275ffff000094a5 4ec4ffff000094a5 3b13ffff000094a5 2762ffff000094a5 13b1ffff000094a5 0000ffff000094a5 0000eeee11108421 0000e1e11e1d739d 0000d793286b6319 0000cf3c30c25295 0000c85837a64211 0000c28e3d70318d 0000bda0425e2109 0000b960469e1085 0000b5ac4a520000
+ffffad6a00000000 ffffb08c00001085 ffffb42500002109 ffffb8510000318d ffffbd3600004211 ffffc30b00005295 ffffca1a00006319 ffffd2d20000739d ffffdddd00008421 ffffec4d000094a5 ffffffff0000a529 e8b9ffff0000a529 d173ffff0000a529 ba2dffff0000a529 a2e8ffff0000a529 8ba2ffff0000a529 745cffff0000a529 5d16ffff0000a529 45d1ffff0000a529 2e8bffff0000a529 1745ffff0000a529 0000ffff0000a529 0000ec4d13b194a5 0000dddd22218421 0000d2d22d2c739d 0000ca1a35e46319 0000c30b3cf35295 0000bd3642c84211 0000b85147ad318d 0000b4254bd92109 0000b08c4f721085 0000ad6a52940000
+ffffa52800000000 ffffa7b800001085 ffffaaa900002109 ffffae130000318d ffffb21500004211 ffffb6da00005295 ffffbca000006319 ffffc3c30000739d ffffcccc00008421 ffffd89c000094a5 ffffe8b90000a529 ffffffff0000b5ad e38dffff0000b5ad c71bffff0000b5ad aaa9ffff0000b5ad 8e38ffff0000b5ad 71c6ffff0000b5ad 5554ffff0000b5ad 38e3ffff0000b5ad 1c71ffff0000b5ad 0000ffff0000b5ad 0000e8b91745a529 0000d89c276294a5 0000cccc33328421 0000c3c33c3b739d 0000bca0435e6319 0000b6da49245295 0000b2154de94211 0000ae1351eb318d 0000aaa955542109 0000a7b858461085 0000a5285ad60000
+ffff9ce600000000 ffff9ee400001085 ffffa12e00002109 ffffa3d60000318d ffffa6f400004211 ffffaaa900005295 ffffaf2700006319 ffffb4b30000739d ffffbbba00008421 ffffc4eb000094a5 ffffd1730000a529 ffffe38d0000b5ad ffffffff0000c631 db6cffff0000c631 b6daffff0000c631 9248ffff0000c631 6db6ffff0000c631 4924ffff0000c631 2492ffff0000c631 0000ffff0000c631 0000e38d1c71b5ad 0000d1732e8ba529 0000c4eb3b1394a5 0000bbba44438421 0000b4b34b4a739d 0000af2750d76319 0000aaa955545295 0000a6f4590a4211 0000a3d65c28318d 0000a12e5ed02109 00009ee4611a1085 00009ce663180000
+ffff94a400000000 ffff961100001085 ffff97b300002109 ffff99980000318d ffff9bd200004211 ffff9e7900005295 ffffa1ae00006319 ffffa5a40000739d ffffaaa900008421 ffffb13a000094a5 ffffba2d0000a529 ffffc71b0000b5ad ffffdb6c0000c631 ffffffff0000d6b5 ccccffff0000d6b5 9998ffff0000d6b5 6665ffff0000d6b5 3332ffff0000d6b5 0000ffff0000d6b5 0000db6c2492c631 0000c71b38e3b5ad 0000ba2d45d1a529 0000b13a4ec494a5 0000aaa955548421 0000a5a45a59739d 0000a1ae5e506319 00009e7961855295 00009bd2642c4211 000099986665318d 000097b3684b2109 0000961169ed1085 000094a46b5a0000
+ffff8c6200000000 ffff8d3d00001085 ffff8e3800002109 ffff8f5b0000318d ffff90b100004211 ffff924800005295 ffff943500006319 ffff96950000739d ffff999800008421 ffff9d89000094a5 ffffa2e80000a529 ffffaaa90000b5ad ffffb6da0000c631 ffffcccc0000d6b5 ffffffff0000e739 aaa9ffff0000e739 5554ffff0000e739 0000ffff0000e739 0000cccc3332d6b5 0000b6da4924c631 0000aaa95554b5ad 0000a2e85d16a529 00009d89627594a5 0000999866658421 000096956968739d 000094356bc96319 000092486db65295 000090b16f4d4211 00008f5b70a3318d 00008e3871c62109 00008d3d72c11085 00008c62739c0000
+ffff842000000000 ffff846900001085 ffff84bd00002109 ffff851e0000318d ffff859000004211 ffff861700005295 ffff86bc00006319 ffff87860000739d ffff888700008421 ffff89d8000094a5 ffff8ba20000a529 ffff8e380000b5ad ffff92480000c631 ffff99980000d6b5 ffffaaa90000e739 ffffffff0000f7bd 0000ffff0000f7bd 0000aaa95554e739 000099986665d6b5 000092486db6c631 00008e3871c6b5ad 00008ba2745ca529 000089d8762694a5 0000888777768421 000087867877739d 000086bc79426319 0000861779e75295 000085907a6e4211 0000851e7ae0318d 000084bd7b412109 000084697b951085 000084207bde0000
+ffff7bde00000000 ffff7b9500001085 ffff7b4100002109 ffff7ae00000318d ffff7a6e00004211 ffff79e700005295 ffff794200006319 ffff78770000739d ffff777600008421 ffff7626000094a5 ffff745c0000a529 ffff71c60000b5ad ffff6db60000c631 ffff66650000d6b5 ffff55540000e739 ffff00000000f7bd 00000000fffff7bd 00005554aaa9e739 000066659998d6b5 00006db69248c631 000071c68e38b5ad 0000745c8ba2a529 0000762689d894a5 0000777688878421 000078778786739d 0000794286bc6319 000079e786175295 00007a6e85904211 00007ae0851e318d 00007b4184bd2109 00007b9584691085 00007bde84200000
+ffff739c00000000 ffff72c100001085 ffff71c600002109 ffff70a30000318d ffff6f4d00004211 ffff6db600005295 ffff6bc900006319 ffff69680000739d ffff666500008421 ffff6275000094a5 ffff5d160000a529 ffff55540000b5ad ffff49240000c631 ffff33320000d6b5 ffff00000000e739 aaa900005554e739 55540000aaa9e739 00000000ffffe739 00003332ccccd6b5 00004924b6dac631 00005554aaa9b5ad 00005d16a2e8a529 000062759d8994a5 0000666599988421 000069689695739d 00006bc994356319 00006db692485295 00006f4d90b14211 000070a38f5b318d 000071c68e382109 000072c18d3d1085 0000739c8c620000
+ffff6b5a00000000 ffff69ed00001085 ffff684b00002109 ffff66650000318d ffff642c00004211 ffff618500005295 ffff5e5000006319 ffff5a590000739d ffff555400008421 ffff4ec4000094a5 ffff45d10000a529 ffff38e30000b5ad ffff24920000c631 ffff00000000d6b5 cccc00003332d6b5 999800006665d6b5 666500009998d6b5 33320000ccccd6b5 00000000ffffd6b5 00002492db6cc631 000038e3c71bb5ad 000045d1ba2da529 00004ec4b13a94a5 00005554aaa98421 00005a59a5a4739d 00005e50a1ae6319 000061859e795295 0000642c9bd24211 000066659998318d 0000684b97b32109 000069ed96111085 00006b5a94a40000
+ffff631800000000 ffff611a00001085 ffff5ed000002109 ffff5c280000318d ffff590a00004211 ffff555400005295 ffff50d700006319 ffff4b4a0000739d ffff444300008421 ffff3b13000094a5 ffff2e8b0000a529 ffff1c710000b5ad ffff00000000c631 db6c00002492c631 b6da00004924c631 924800006db6c631 6db600009248c631 49240000b6dac631 24920000db6cc631 00000000ffffc631 00001c71e38db5ad 00002e8bd173a529 00003b13c4eb94a5 00004443bbba8421 00004b4ab4b3739d 000050d7af276319 00005554aaa95295 0000590aa6f44211 00005c28a3d6318d 00005ed0a12e2109 0000611a9ee41085 000063189ce60000
+ffff5ad600000000 ffff584600001085 ffff555400002109 ffff51eb0000318d ffff4de900004211 ffff492400005295 ffff435e00006319 ffff3c3b0000739d ffff333200008421 ffff2762000094a5 ffff17450000a529 ffff00000000b5ad e38d00001c71b5ad c71b000038e3b5ad aaa900005554b5ad 8e38000071c6b5ad 71c600008e38b5ad 55540000aaa9b5ad 38e30000c71bb5ad 1c710000e38db5ad 00000000ffffb5ad 00001745e8b9a529 00002762d89c94a5 00003332cccc8421 00003c3bc3c3739d 0000435ebca06319 00004924b6da5295 00004de9b2154211 000051ebae13318d 00005554aaa92109 00005846a7b81085 00005ad6a5280000
+ffff529400000000 ffff4f7200001085 ffff4bd900002109 ffff47ad0000318d ffff42c800004211 ffff3cf300005295 ffff35e400006319 ffff2d2c0000739d ffff222100008421 ffff13b1000094a5 ffff00000000a529 e8b900001745a529 d17300002e8ba529 ba2d000045d1a529 a2e800005d16a529 8ba20000745ca529 745c00008ba2a529 5d160000a2e8a529 45d10000ba2da529 2e8b0000d173a529 17450000e8b9a529 00000000ffffa529 000013b1ec4d94a5 00002221dddd8421 00002d2cd2d2739d 000035e4ca1a6319 00003cf3c30b5295 000042c8bd364211 000047adb851318d 00004bd9b4252109 00004f72b08c1085 00005294ad6a0000
+ffff4a5200000000 ffff469e00001085 ffff425e00002109 ffff3d700000318d ffff37a600004211 ffff30c200005295 ffff286b00006319 ffff1e1d0000739d ffff111000008421 ffff0000000094a5 ec4d000013b194a5 d89c0000276294a5 c4eb00003b1394a5 b13a00004ec494a5 9d890000627594a5 89d80000762694a5 7626000089d894a5 627500009d8994a5 4ec40000b13a94a5 3b130000c4eb94a5 27620000d89c94a5 13b10000ec4d94a5 00000000ffff94a5 00001110eeee8421 00001e1de1e1739d 0000286bd7936319 000030c2cf3c5295 000037a6c8584211 00003d70c28e318d 0000425ebda02109 0000469eb9601085 00004a52b5ac0000
+ffff421000000000 ffff3dca00001085 ffff38e300002109 ffff33320000318d ffff2c8500004211 ffff249200005295 ffff1af200006319 ffff0f0e0000739d ffff000000008421 eeee000011108421 dddd000022218421 cccc000033328421 bbba000044438421 aaa9000055548421 9998000066658421 8887000077768421 7776000088878421 6665000099988421 55540000aaa98421 44430000bbba8421 33320000cccc8421 22210000dddd8421 11100000eeee8421 00000000ffff8421 00000f0ef0f0739d 00001af2e50c6319 00002492db6c5295 00002c85d3794211 00003332cccc318d 000038e3c71b2109 00003dcac2341085 00004210bdee0000
+ffff39ce00000000 ffff34f600001085 ffff2f6800002109 ffff28f50000318d ffff216400004211 ffff186100005295 ffff0d7900006319 ffff00000000739d f0f000000f0e739d e1e100001e1d739d d2d200002d2c739d c3c300003c3b739d b4b300004b4a739d a5a400005a59739d 969500006968739d 878600007877739d 787700008786739d 696800009695739d 5a590000a5a4739d 4b4a0000b4b3739d 3c3b0000c3c3739d 2d2c0000d2d2739d 1e1d0000e1e1739d 0f0e0000f0f0739d 00000000ffff739d 00000d79f2856319 00001861e79d5295 00002164de9a4211 000028f5d709318d 00002f68d0962109 000034f6cb081085 000039cec6300000
+ffff318c00000000 ffff2c2300001085 ffff25ec00002109 ffff1eb80000318d ffff164200004211 ffff0c3000005295 ffff000000006319 f28500000d796319 e50c00001af26319 d7930000286b6319 ca1a000035e46319 bca00000435e6319 af27000050d76319 a1ae00005e506319 943500006bc96319 86bc000079426319 7942000086bc6319 6bc9000094356319 5e500000a1ae6319 50d70000af276319 435e0000bca06319 35e40000ca1a6319 286b0000d7936319 1af20000e50c6319 0d790000f2856319 00000000ffff6319 00000c30f3ce5295 00001642e9bc4211 00001eb8e146318d 000025ecda122109 00002c23d3db1085 0000318cce720000
+ffff294a00000000 ffff234f00001085 ffff1c7100002109 ffff147a0000318d ffff0b2100004211 ffff000000005295 f3ce00000c305295 e79d000018615295 db6c000024925295 cf3c000030c25295 c30b00003cf35295 b6da000049245295 aaa9000055545295 9e79000061855295 924800006db65295 8617000079e75295 79e7000086175295 6db6000092485295 618500009e795295 55540000aaa95295 49240000b6da5295 3cf30000c30b5295 30c20000cf3c5295 24920000db6c5295 18610000e79d5295 0c300000f3ce5295 00000000ffff5295 00000b21f4dd4211 0000147aeb84318d 00001c71e38d2109 0000234fdcaf1085 0000294ad6b40000
+ffff210800000000 ffff1a7b00001085 ffff12f600002109 ffff0a3d0000318d ffff000000004211 f4dd00000b214211 e9bc000016424211 de9a000021644211 d37900002c854211 c858000037a64211 bd36000042c84211 b21500004de94211 a6f40000590a4211 9bd20000642c4211 90b100006f4d4211 859000007a6e4211 7a6e000085904211 6f4d000090b14211 642c00009bd24211 590a0000a6f44211 4de90000b2154211 42c80000bd364211 37a60000c8584211 2c850000d3794211 21640000de9a4211 16420000e9bc4211 0b210000f4dd4211 00000000ffff4211 00000a3df5c1318d 000012f6ed082109 00001a7be5831085 00002108def60000
+ffff18c600000000 ffff11a700001085 ffff097b00002109 ffff00000000318d f5c100000a3d318d eb840000147a318d e14600001eb8318d d709000028f5318d cccc00003332318d c28e00003d70318d b851000047ad318d ae13000051eb318d a3d600005c28318d 999800006665318d 8f5b000070a3318d 851e00007ae0318d 7ae00000851e318d 70a300008f5b318d 666500009998318d 5c280000a3d6318d 51eb0000ae13318d 47ad0000b851318d 3d700000c28e318d 33320000cccc318d 28f50000d709318d 1eb80000e146318d 147a0000eb84318d 0a3d0000f5c1318d 00000000ffff318d 0000097bf6832109 000011a7ee571085 000018c6e7380000
+ffff108400000000 ffff08d300001085 ffff000000002109 f6830000097b2109 ed08000012f62109 e38d00001c712109 da12000025ec2109 d09600002f682109 c71b000038e32109 bda00000425e2109 b42500004bd92109 aaa9000055542109 a12e00005ed02109 97b30000684b2109 8e38000071c62109 84bd00007b412109 7b41000084bd2109 71c600008e382109 684b000097b32109 5ed00000a12e2109 55540000aaa92109 4bd90000b4252109 425e0000bda02109 38e30000c71b2109 2f680000d0962109 25ec0000da122109 1c710000e38d2109 12f60000ed082109 097b0000f6832109 00000000ffff2109 000008d3f72b1085 00001084ef7a0000
+ffff084200000000 ffff000000001085 f72b000008d31085 ee57000011a71085 e58300001a7b1085 dcaf0000234f1085 d3db00002c231085 cb08000034f61085 c23400003dca1085 b9600000469e1085 b08c00004f721085 a7b8000058461085 9ee40000611a1085 9611000069ed1085 8d3d000072c11085 846900007b951085 7b95000084691085 72c100008d3d1085 69ed000096111085 611a00009ee41085 58460000a7b81085 4f720000b08c1085 469e0000b9601085 3dca0000c2341085 34f60000cb081085 2c230000d3db1085 234f0000dcaf1085 1a7b0000e5831085 11a70000ee571085 08d30000f72b1085 00000000ffff1085 00000842f7bc0000
+ffff000000000000 f7bc000008420000 ef7a000010840000 e738000018c60000 def6000021080000 d6b40000294a0000 ce720000318c0000 c630000039ce0000 bdee000042100000 b5ac00004a520000 ad6a000052940000 a52800005ad60000 9ce6000063180000 94a400006b5a0000 8c620000739c0000 842000007bde0000 7bde000084200000 739c00008c620000 6b5a000094a40000 631800009ce60000 5ad60000a5280000 52940000ad6a0000 4a520000b5ac0000 42100000bdee0000 39ce0000c6300000 318c0000ce720000 294a0000d6b40000 21080000def60000 18c60000e7380000 10840000ef7a0000 08420000f7bc0000 00000000ffff0000
+}
diff --git a/libgo/go/image/png/writer.go b/libgo/go/image/png/writer.go
new file mode 100644
index 000000000..081d06bf5
--- /dev/null
+++ b/libgo/go/image/png/writer.go
@@ -0,0 +1,437 @@
+// 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 png
+
+import (
+ "bufio"
+ "compress/zlib"
+ "hash/crc32"
+ "image"
+ "io"
+ "os"
+ "strconv"
+)
+
+type encoder struct {
+ w io.Writer
+ m image.Image
+ cb int
+ err os.Error
+ header [8]byte
+ footer [4]byte
+ tmp [3 * 256]byte
+}
+
+// Big-endian.
+func writeUint32(b []uint8, u uint32) {
+ b[0] = uint8(u >> 24)
+ b[1] = uint8(u >> 16)
+ b[2] = uint8(u >> 8)
+ b[3] = uint8(u >> 0)
+}
+
+type opaquer interface {
+ Opaque() bool
+}
+
+// Returns whether or not the image is fully opaque.
+func opaque(m image.Image) bool {
+ if o, ok := m.(opaquer); ok {
+ return o.Opaque()
+ }
+ b := m.Bounds()
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ _, _, _, a := m.At(x, y).RGBA()
+ if a != 0xffff {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// The absolute value of a byte interpreted as a signed int8.
+func abs8(d uint8) int {
+ if d < 128 {
+ return int(d)
+ }
+ return 256 - int(d)
+}
+
+func (e *encoder) writeChunk(b []byte, name string) {
+ if e.err != nil {
+ return
+ }
+ n := uint32(len(b))
+ if int(n) != len(b) {
+ e.err = UnsupportedError(name + " chunk is too large: " + strconv.Itoa(len(b)))
+ return
+ }
+ writeUint32(e.header[0:4], n)
+ e.header[4] = name[0]
+ e.header[5] = name[1]
+ e.header[6] = name[2]
+ e.header[7] = name[3]
+ crc := crc32.NewIEEE()
+ crc.Write(e.header[4:8])
+ crc.Write(b)
+ writeUint32(e.footer[0:4], crc.Sum32())
+
+ _, e.err = e.w.Write(e.header[0:8])
+ if e.err != nil {
+ return
+ }
+ _, e.err = e.w.Write(b)
+ if e.err != nil {
+ return
+ }
+ _, e.err = e.w.Write(e.footer[0:4])
+}
+
+func (e *encoder) writeIHDR() {
+ b := e.m.Bounds()
+ writeUint32(e.tmp[0:4], uint32(b.Dx()))
+ writeUint32(e.tmp[4:8], uint32(b.Dy()))
+ // Set bit depth and color type.
+ switch e.cb {
+ case cbG8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctGrayscale
+ case cbTC8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctTrueColor
+ case cbP8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctPaletted
+ case cbTCA8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctTrueColorAlpha
+ case cbG16:
+ e.tmp[8] = 16
+ e.tmp[9] = ctGrayscale
+ case cbTC16:
+ e.tmp[8] = 16
+ e.tmp[9] = ctTrueColor
+ case cbTCA16:
+ e.tmp[8] = 16
+ e.tmp[9] = ctTrueColorAlpha
+ }
+ e.tmp[10] = 0 // default compression method
+ e.tmp[11] = 0 // default filter method
+ e.tmp[12] = 0 // non-interlaced
+ e.writeChunk(e.tmp[0:13], "IHDR")
+}
+
+func (e *encoder) writePLTE(p image.PalettedColorModel) {
+ if len(p) < 1 || len(p) > 256 {
+ e.err = FormatError("bad palette length: " + strconv.Itoa(len(p)))
+ return
+ }
+ for i := 0; i < len(p); i++ {
+ r, g, b, a := p[i].RGBA()
+ if a != 0xffff {
+ e.err = UnsupportedError("non-opaque palette color")
+ return
+ }
+ e.tmp[3*i+0] = uint8(r >> 8)
+ e.tmp[3*i+1] = uint8(g >> 8)
+ e.tmp[3*i+2] = uint8(b >> 8)
+ }
+ e.writeChunk(e.tmp[0:3*len(p)], "PLTE")
+}
+
+// An encoder is an io.Writer that satisfies writes by writing PNG IDAT chunks,
+// including an 8-byte header and 4-byte CRC checksum per Write call. Such calls
+// should be relatively infrequent, since writeIDATs uses a bufio.Writer.
+//
+// This method should only be called from writeIDATs (via writeImage).
+// No other code should treat an encoder as an io.Writer.
+//
+// Note that, because the zlib Reader may involve an io.Pipe, e.Write calls may
+// occur on a separate go-routine than the e.writeIDATs call, and care should be
+// taken that e's state (such as its tmp buffer) is not modified concurrently.
+func (e *encoder) Write(b []byte) (int, os.Error) {
+ e.writeChunk(b, "IDAT")
+ if e.err != nil {
+ return 0, e.err
+ }
+ return len(b), nil
+}
+
+// Chooses the filter to use for encoding the current row, and applies it.
+// The return value is the index of the filter and also of the row in cr that has had it applied.
+func filter(cr [][]byte, pr []byte, bpp int) int {
+ // We try all five filter types, and pick the one that minimizes the sum of absolute differences.
+ // This is the same heuristic that libpng uses, although the filters are attempted in order of
+ // estimated most likely to be minimal (ftUp, ftPaeth, ftNone, ftSub, ftAverage), rather than
+ // in their enumeration order (ftNone, ftSub, ftUp, ftAverage, ftPaeth).
+ cdat0 := cr[0][1:]
+ cdat1 := cr[1][1:]
+ cdat2 := cr[2][1:]
+ cdat3 := cr[3][1:]
+ cdat4 := cr[4][1:]
+ pdat := pr[1:]
+ n := len(cdat0)
+
+ // The up filter.
+ sum := 0
+ for i := 0; i < n; i++ {
+ cdat2[i] = cdat0[i] - pdat[i]
+ sum += abs8(cdat2[i])
+ }
+ best := sum
+ filter := ftUp
+
+ // The Paeth filter.
+ sum = 0
+ for i := 0; i < bpp; i++ {
+ cdat4[i] = cdat0[i] - paeth(0, pdat[i], 0)
+ sum += abs8(cdat4[i])
+ }
+ for i := bpp; i < n; i++ {
+ cdat4[i] = cdat0[i] - paeth(cdat0[i-bpp], pdat[i], pdat[i-bpp])
+ sum += abs8(cdat4[i])
+ if sum >= best {
+ break
+ }
+ }
+ if sum < best {
+ best = sum
+ filter = ftPaeth
+ }
+
+ // The none filter.
+ sum = 0
+ for i := 0; i < n; i++ {
+ sum += abs8(cdat0[i])
+ if sum >= best {
+ break
+ }
+ }
+ if sum < best {
+ best = sum
+ filter = ftNone
+ }
+
+ // The sub filter.
+ sum = 0
+ for i := 0; i < bpp; i++ {
+ cdat1[i] = cdat0[i]
+ sum += abs8(cdat1[i])
+ }
+ for i := bpp; i < n; i++ {
+ cdat1[i] = cdat0[i] - cdat0[i-bpp]
+ sum += abs8(cdat1[i])
+ if sum >= best {
+ break
+ }
+ }
+ if sum < best {
+ best = sum
+ filter = ftSub
+ }
+
+ // The average filter.
+ sum = 0
+ for i := 0; i < bpp; i++ {
+ cdat3[i] = cdat0[i] - pdat[i]/2
+ sum += abs8(cdat3[i])
+ }
+ for i := bpp; i < n; i++ {
+ cdat3[i] = cdat0[i] - uint8((int(cdat0[i-bpp])+int(pdat[i]))/2)
+ sum += abs8(cdat3[i])
+ if sum >= best {
+ break
+ }
+ }
+ if sum < best {
+ best = sum
+ filter = ftAverage
+ }
+
+ return filter
+}
+
+func writeImage(w io.Writer, m image.Image, cb int) os.Error {
+ zw, err := zlib.NewWriter(w)
+ if err != nil {
+ return err
+ }
+ defer zw.Close()
+
+ bpp := 0 // Bytes per pixel.
+ var paletted *image.Paletted
+ switch cb {
+ case cbG8:
+ bpp = 1
+ case cbTC8:
+ bpp = 3
+ case cbP8:
+ bpp = 1
+ paletted = m.(*image.Paletted)
+ case cbTCA8:
+ bpp = 4
+ case cbTC16:
+ bpp = 6
+ case cbTCA16:
+ bpp = 8
+ case cbG16:
+ bpp = 2
+ }
+ // cr[*] and pr are the bytes for the current and previous row.
+ // cr[0] is unfiltered (or equivalently, filtered with the ftNone filter).
+ // cr[ft], for non-zero filter types ft, are buffers for transforming cr[0] under the
+ // other PNG filter types. These buffers are allocated once and re-used for each row.
+ // The +1 is for the per-row filter type, which is at cr[*][0].
+ b := m.Bounds()
+ var cr [nFilter][]uint8
+ for i := 0; i < len(cr); i++ {
+ cr[i] = make([]uint8, 1+bpp*b.Dx())
+ cr[i][0] = uint8(i)
+ }
+ pr := make([]uint8, 1+bpp*b.Dx())
+
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ // Convert from colors to bytes.
+ switch cb {
+ case cbG8:
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c := image.GrayColorModel.Convert(m.At(x, y)).(image.GrayColor)
+ cr[0][x+1] = c.Y
+ }
+ case cbTC8:
+ for x := b.Min.X; x < b.Max.X; x++ {
+ // We have previously verified that the alpha value is fully opaque.
+ r, g, b, _ := m.At(x, y).RGBA()
+ cr[0][3*x+1] = uint8(r >> 8)
+ cr[0][3*x+2] = uint8(g >> 8)
+ cr[0][3*x+3] = uint8(b >> 8)
+ }
+ case cbP8:
+ rowOffset := y * paletted.Stride
+ copy(cr[0][b.Min.X+1:], paletted.Pix[rowOffset+b.Min.X:rowOffset+b.Max.X])
+ case cbTCA8:
+ // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c := image.NRGBAColorModel.Convert(m.At(x, y)).(image.NRGBAColor)
+ cr[0][4*x+1] = c.R
+ cr[0][4*x+2] = c.G
+ cr[0][4*x+3] = c.B
+ cr[0][4*x+4] = c.A
+ }
+ case cbG16:
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c := image.Gray16ColorModel.Convert(m.At(x, y)).(image.Gray16Color)
+ cr[0][2*x+1] = uint8(c.Y >> 8)
+ cr[0][2*x+2] = uint8(c.Y)
+ }
+ case cbTC16:
+ for x := b.Min.X; x < b.Max.X; x++ {
+ // We have previously verified that the alpha value is fully opaque.
+ r, g, b, _ := m.At(x, y).RGBA()
+ cr[0][6*x+1] = uint8(r >> 8)
+ cr[0][6*x+2] = uint8(r)
+ cr[0][6*x+3] = uint8(g >> 8)
+ cr[0][6*x+4] = uint8(g)
+ cr[0][6*x+5] = uint8(b >> 8)
+ cr[0][6*x+6] = uint8(b)
+ }
+ case cbTCA16:
+ // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c := image.NRGBA64ColorModel.Convert(m.At(x, y)).(image.NRGBA64Color)
+ cr[0][8*x+1] = uint8(c.R >> 8)
+ cr[0][8*x+2] = uint8(c.R)
+ cr[0][8*x+3] = uint8(c.G >> 8)
+ cr[0][8*x+4] = uint8(c.G)
+ cr[0][8*x+5] = uint8(c.B >> 8)
+ cr[0][8*x+6] = uint8(c.B)
+ cr[0][8*x+7] = uint8(c.A >> 8)
+ cr[0][8*x+8] = uint8(c.A)
+ }
+ }
+
+ // Apply the filter.
+ f := filter(cr[0:nFilter], pr, bpp)
+
+ // Write the compressed bytes.
+ _, err = zw.Write(cr[f])
+ if err != nil {
+ return err
+ }
+
+ // The current row for y is the previous row for y+1.
+ pr, cr[0] = cr[0], pr
+ }
+ return nil
+}
+
+// Write the actual image data to one or more IDAT chunks.
+func (e *encoder) writeIDATs() {
+ if e.err != nil {
+ return
+ }
+ var bw *bufio.Writer
+ bw, e.err = bufio.NewWriterSize(e, 1<<15)
+ if e.err != nil {
+ return
+ }
+ e.err = writeImage(bw, e.m, e.cb)
+ if e.err != nil {
+ return
+ }
+ e.err = bw.Flush()
+}
+
+func (e *encoder) writeIEND() { e.writeChunk(e.tmp[0:0], "IEND") }
+
+// Encode writes the Image m to w in PNG format. Any Image may be encoded, but
+// images that are not image.NRGBA might be encoded lossily.
+func Encode(w io.Writer, m image.Image) os.Error {
+ // Obviously, negative widths and heights are invalid. Furthermore, the PNG
+ // spec section 11.2.2 says that zero is invalid. Excessively large images are
+ // also rejected.
+ mw, mh := int64(m.Bounds().Dx()), int64(m.Bounds().Dy())
+ if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 {
+ return FormatError("invalid image size: " + strconv.Itoa64(mw) + "x" + strconv.Itoa64(mw))
+ }
+
+ var e encoder
+ e.w = w
+ e.m = m
+ pal, _ := m.(*image.Paletted)
+ if pal != nil {
+ e.cb = cbP8
+ } else {
+ switch m.ColorModel() {
+ case image.GrayColorModel:
+ e.cb = cbG8
+ case image.Gray16ColorModel:
+ e.cb = cbG16
+ case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel:
+ if opaque(m) {
+ e.cb = cbTC8
+ } else {
+ e.cb = cbTCA8
+ }
+ default:
+ if opaque(m) {
+ e.cb = cbTC16
+ } else {
+ e.cb = cbTCA16
+ }
+ }
+ }
+
+ _, e.err = io.WriteString(w, pngHeader)
+ e.writeIHDR()
+ if pal != nil {
+ e.writePLTE(pal.Palette)
+ }
+ e.writeIDATs()
+ e.writeIEND()
+ return e.err
+}
diff --git a/libgo/go/image/png/writer_test.go b/libgo/go/image/png/writer_test.go
new file mode 100644
index 000000000..f218a5564
--- /dev/null
+++ b/libgo/go/image/png/writer_test.go
@@ -0,0 +1,86 @@
+// 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 png
+
+import (
+ "bytes"
+ "fmt"
+ "image"
+ "io"
+ "os"
+ "testing"
+)
+
+func diff(m0, m1 image.Image) os.Error {
+ b0, b1 := m0.Bounds(), m1.Bounds()
+ if !b0.Eq(b1) {
+ return fmt.Errorf("dimensions differ: %v vs %v", b0, b1)
+ }
+ for y := b0.Min.Y; y < b0.Max.Y; y++ {
+ for x := b0.Min.X; x < b0.Max.X; x++ {
+ r0, g0, b0, a0 := m0.At(x, y).RGBA()
+ r1, g1, b1, a1 := m1.At(x, y).RGBA()
+ if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
+ return fmt.Errorf("colors differ at (%d, %d): %v vs %v", x, y, m0.At(x, y), m1.At(x, y))
+ }
+ }
+ }
+ return nil
+}
+
+func TestWriter(t *testing.T) {
+ // The filenames variable is declared in reader_test.go.
+ for _, fn := range filenames {
+ qfn := "testdata/pngsuite/" + fn + ".png"
+ // Read the image.
+ m0, err := readPng(qfn)
+ if err != nil {
+ t.Error(fn, err)
+ continue
+ }
+ // Read the image again, and push it through a pipe that encodes at the write end, and decodes at the read end.
+ pr, pw := io.Pipe()
+ defer pr.Close()
+ go func() {
+ defer pw.Close()
+ m1, err := readPng(qfn)
+ if err != nil {
+ t.Error(fn, err)
+ return
+ }
+ err = Encode(pw, m1)
+ if err != nil {
+ t.Error(fn, err)
+ return
+ }
+ }()
+ m2, err := Decode(pr)
+ if err != nil {
+ t.Error(fn, err)
+ continue
+ }
+ // Compare the two.
+ err = diff(m0, m2)
+ if err != nil {
+ t.Error(fn, err)
+ continue
+ }
+ }
+}
+
+func BenchmarkEncodePaletted(b *testing.B) {
+ b.StopTimer()
+ img := image.NewPaletted(640, 480,
+ []image.Color{
+ image.RGBAColor{0, 0, 0, 255},
+ image.RGBAColor{255, 255, 255, 255},
+ })
+ b.StartTimer()
+ buffer := new(bytes.Buffer)
+ for i := 0; i < b.N; i++ {
+ buffer.Reset()
+ Encode(buffer, img)
+ }
+}
diff --git a/libgo/go/index/suffixarray/qsufsort.go b/libgo/go/index/suffixarray/qsufsort.go
new file mode 100644
index 000000000..0e6894a8b
--- /dev/null
+++ b/libgo/go/index/suffixarray/qsufsort.go
@@ -0,0 +1,164 @@
+// 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 algorithm is based on "Faster Suffix Sorting"
+// by N. Jesper Larsson and Kunihiko Sadakane
+// paper: http://www.larsson.dogma.net/ssrev-tr.pdf
+// code: http://www.larsson.dogma.net/qsufsort.c
+
+// This algorithm computes the suffix array sa by computing its inverse.
+// Consecutive groups of suffixes in sa are labeled as sorted groups or
+// unsorted groups. For a given pass of the sorter, all suffixes are ordered
+// up to their first h characters, and sa is h-ordered. Suffixes in their
+// final positions and unambiguouly sorted in h-order are in a sorted group.
+// Consecutive groups of suffixes with identical first h characters are an
+// unsorted group. In each pass of the algorithm, unsorted groups are sorted
+// according to the group number of their following suffix.
+
+// In the implementation, if sa[i] is negative, it indicates that i is
+// the first element of a sorted group of length -sa[i], and can be skipped.
+// An unsorted group sa[i:k] is given the group number of the index of its
+// last element, k-1. The group numbers are stored in the inverse slice (inv),
+// and when all groups are sorted, this slice is the inverse suffix array.
+
+package suffixarray
+
+import "sort"
+
+func qsufsort(data []byte) []int {
+ // initial sorting by first byte of suffix
+ sa := sortedByFirstByte(data)
+ if len(sa) < 2 {
+ return sa
+ }
+ // initialize the group lookup table
+ // this becomes the inverse of the suffix array when all groups are sorted
+ inv := initGroups(sa, data)
+
+ // the index starts 1-ordered
+ sufSortable := &suffixSortable{sa, inv, 1}
+
+ for sa[0] > -len(sa) { // until all suffixes are one big sorted group
+ // The suffixes are h-ordered, make them 2*h-ordered
+ pi := 0 // pi is first position of first group
+ sl := 0 // sl is negated length of sorted groups
+ for pi < len(sa) {
+ if s := sa[pi]; s < 0 { // if pi starts sorted group
+ pi -= s // skip over sorted group
+ sl += s // add negated length to sl
+ } else { // if pi starts unsorted group
+ if sl != 0 {
+ sa[pi+sl] = sl // combine sorted groups before pi
+ sl = 0
+ }
+ pk := inv[s] + 1 // pk-1 is last position of unsorted group
+ sufSortable.sa = sa[pi:pk]
+ sort.Sort(sufSortable)
+ sufSortable.updateGroups(pi)
+ pi = pk // next group
+ }
+ }
+ if sl != 0 { // if the array ends with a sorted group
+ sa[pi+sl] = sl // combine sorted groups at end of sa
+ }
+
+ sufSortable.h *= 2 // double sorted depth
+ }
+
+ for i := range sa { // reconstruct suffix array from inverse
+ sa[inv[i]] = i
+ }
+ return sa
+}
+
+
+func sortedByFirstByte(data []byte) []int {
+ // total byte counts
+ var count [256]int
+ for _, b := range data {
+ count[b]++
+ }
+ // make count[b] equal index of first occurence of b in sorted array
+ sum := 0
+ for b := range count {
+ count[b], sum = sum, count[b]+sum
+ }
+ // iterate through bytes, placing index into the correct spot in sa
+ sa := make([]int, len(data))
+ for i, b := range data {
+ sa[count[b]] = i
+ count[b]++
+ }
+ return sa
+}
+
+
+func initGroups(sa []int, data []byte) []int {
+ // label contiguous same-letter groups with the same group number
+ inv := make([]int, len(data))
+ prevGroup := len(sa) - 1
+ groupByte := data[sa[prevGroup]]
+ for i := len(sa) - 1; i >= 0; i-- {
+ if b := data[sa[i]]; b < groupByte {
+ if prevGroup == i+1 {
+ sa[i+1] = -1
+ }
+ groupByte = b
+ prevGroup = i
+ }
+ inv[sa[i]] = prevGroup
+ if prevGroup == 0 {
+ sa[0] = -1
+ }
+ }
+ // Separate out the final suffix to the start of its group.
+ // This is necessary to ensure the suffix "a" is before "aba"
+ // when using a potentially unstable sort.
+ lastByte := data[len(data)-1]
+ s := -1
+ for i := range sa {
+ if sa[i] >= 0 {
+ if data[sa[i]] == lastByte && s == -1 {
+ s = i
+ }
+ if sa[i] == len(sa)-1 {
+ sa[i], sa[s] = sa[s], sa[i]
+ inv[sa[s]] = s
+ sa[s] = -1 // mark it as an isolated sorted group
+ break
+ }
+ }
+ }
+ return inv
+}
+
+
+type suffixSortable struct {
+ sa []int
+ inv []int
+ h int
+}
+
+func (x *suffixSortable) Len() int { return len(x.sa) }
+func (x *suffixSortable) Less(i, j int) bool { return x.inv[x.sa[i]+x.h] < x.inv[x.sa[j]+x.h] }
+func (x *suffixSortable) Swap(i, j int) { x.sa[i], x.sa[j] = x.sa[j], x.sa[i] }
+
+
+func (x *suffixSortable) updateGroups(offset int) {
+ prev := len(x.sa) - 1
+ group := x.inv[x.sa[prev]+x.h]
+ for i := prev; i >= 0; i-- {
+ if g := x.inv[x.sa[i]+x.h]; g < group {
+ if prev == i+1 { // previous group had size 1 and is thus sorted
+ x.sa[i+1] = -1
+ }
+ group = g
+ prev = i
+ }
+ x.inv[x.sa[i]] = prev + offset
+ if prev == 0 { // first group has size 1 and is thus sorted
+ x.sa[0] = -1
+ }
+ }
+}
diff --git a/libgo/go/index/suffixarray/suffixarray.go b/libgo/go/index/suffixarray/suffixarray.go
new file mode 100644
index 000000000..628e000e1
--- /dev/null
+++ b/libgo/go/index/suffixarray/suffixarray.go
@@ -0,0 +1,182 @@
+// 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.
+
+// The suffixarray package implements substring search in logarithmic time
+// using an in-memory suffix array.
+//
+// Example use:
+//
+// // create index for some data
+// index := suffixarray.New(data)
+//
+// // lookup byte slice s
+// offsets1 := index.Lookup(s, -1) // the list of all indices where s occurs in data
+// offsets2 := index.Lookup(s, 3) // the list of at most 3 indices where s occurs in data
+//
+package suffixarray
+
+import (
+ "bytes"
+ "regexp"
+ "sort"
+)
+
+
+// Index implements a suffix array for fast substring search.
+type Index struct {
+ data []byte
+ sa []int // suffix array for data
+}
+
+
+// New creates a new Index for data.
+// Index creation time is O(N*log(N)) for N = len(data).
+func New(data []byte) *Index {
+ return &Index{data, qsufsort(data)}
+}
+
+
+// Bytes returns the data over which the index was created.
+// It must not be modified.
+//
+func (x *Index) Bytes() []byte {
+ return x.data
+}
+
+
+func (x *Index) at(i int) []byte {
+ return x.data[x.sa[i]:]
+}
+
+
+func (x *Index) search(s []byte) int {
+ return sort.Search(len(x.sa), func(i int) bool { return bytes.Compare(x.at(i), s) >= 0 })
+}
+
+
+// Lookup returns an unsorted list of at most n indices where the byte string s
+// occurs in the indexed data. If n < 0, all occurrences are returned.
+// The result is nil if s is empty, s is not found, or n == 0.
+// Lookup time is O((log(N) + len(result))*len(s)) where N is the
+// size of the indexed data.
+//
+func (x *Index) Lookup(s []byte, n int) (result []int) {
+ if len(s) > 0 && n != 0 {
+ // find matching suffix index i
+ i := x.search(s)
+ // x.at(i-1) < s <= x.at(i)
+
+ // collect the following suffixes with matching prefixes
+ for (n < 0 || len(result) < n) && i < len(x.sa) && bytes.HasPrefix(x.at(i), s) {
+ result = append(result, x.sa[i])
+ i++
+ }
+ }
+ return
+}
+
+
+// FindAllIndex returns a sorted list of non-overlapping matches of the
+// regular expression r, where a match is a pair of indices specifying
+// the matched slice of x.Bytes(). If n < 0, all matches are returned
+// in successive order. Otherwise, at most n matches are returned and
+// they may not be successive. The result is nil if there are no matches,
+// or if n == 0.
+//
+func (x *Index) FindAllIndex(r *regexp.Regexp, n int) (result [][]int) {
+ // a non-empty literal prefix is used to determine possible
+ // match start indices with Lookup
+ prefix, complete := r.LiteralPrefix()
+ lit := []byte(prefix)
+
+ // worst-case scenario: no literal prefix
+ if prefix == "" {
+ return r.FindAllIndex(x.data, n)
+ }
+
+ // if regexp is a literal just use Lookup and convert its
+ // result into match pairs
+ if complete {
+ // Lookup returns indices that may belong to overlapping matches.
+ // After eliminating them, we may end up with fewer than n matches.
+ // If we don't have enough at the end, redo the search with an
+ // increased value n1, but only if Lookup returned all the requested
+ // indices in the first place (if it returned fewer than that then
+ // there cannot be more).
+ for n1 := n; ; n1 += 2 * (n - len(result)) /* overflow ok */ {
+ indices := x.Lookup(lit, n1)
+ if len(indices) == 0 {
+ return
+ }
+ sort.SortInts(indices)
+ pairs := make([]int, 2*len(indices))
+ result = make([][]int, len(indices))
+ count := 0
+ prev := 0
+ for _, i := range indices {
+ if count == n {
+ break
+ }
+ // ignore indices leading to overlapping matches
+ if prev <= i {
+ j := 2 * count
+ pairs[j+0] = i
+ pairs[j+1] = i + len(lit)
+ result[count] = pairs[j : j+2]
+ count++
+ prev = i + len(lit)
+ }
+ }
+ result = result[0:count]
+ if len(result) >= n || len(indices) != n1 {
+ // found all matches or there's no chance to find more
+ // (n and n1 can be negative)
+ break
+ }
+ }
+ if len(result) == 0 {
+ result = nil
+ }
+ return
+ }
+
+ // regexp has a non-empty literal prefix; Lookup(lit) computes
+ // the indices of possible complete matches; use these as starting
+ // points for anchored searches
+ // (regexp "^" matches beginning of input, not beginning of line)
+ r = regexp.MustCompile("^" + r.String()) // compiles because r compiled
+
+ // same comment about Lookup applies here as in the loop above
+ for n1 := n; ; n1 += 2 * (n - len(result)) /* overflow ok */ {
+ indices := x.Lookup(lit, n1)
+ if len(indices) == 0 {
+ return
+ }
+ sort.SortInts(indices)
+ result = result[0:0]
+ prev := 0
+ for _, i := range indices {
+ if len(result) == n {
+ break
+ }
+ m := r.FindIndex(x.data[i:]) // anchored search - will not run off
+ // ignore indices leading to overlapping matches
+ if m != nil && prev <= i {
+ m[0] = i // correct m
+ m[1] += i
+ result = append(result, m)
+ prev = m[1]
+ }
+ }
+ if len(result) >= n || len(indices) != n1 {
+ // found all matches or there's no chance to find more
+ // (n and n1 can be negative)
+ break
+ }
+ }
+ if len(result) == 0 {
+ result = nil
+ }
+ return
+}
diff --git a/libgo/go/index/suffixarray/suffixarray_test.go b/libgo/go/index/suffixarray/suffixarray_test.go
new file mode 100644
index 000000000..b3486a96d
--- /dev/null
+++ b/libgo/go/index/suffixarray/suffixarray_test.go
@@ -0,0 +1,234 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package suffixarray
+
+import (
+ "bytes"
+ "container/vector"
+ "regexp"
+ "sort"
+ "strings"
+ "testing"
+)
+
+
+type testCase struct {
+ name string // name of test case
+ source string // source to index
+ patterns []string // patterns to lookup
+}
+
+
+var testCases = []testCase{
+ {
+ "empty string",
+ "",
+ []string{
+ "",
+ "foo",
+ "(foo)",
+ ".*",
+ "a*",
+ },
+ },
+
+ {
+ "all a's",
+ "aaaaaaaaaa", // 10 a's
+ []string{
+ "",
+ "a",
+ "aa",
+ "aaa",
+ "aaaa",
+ "aaaaa",
+ "aaaaaa",
+ "aaaaaaa",
+ "aaaaaaaa",
+ "aaaaaaaaa",
+ "aaaaaaaaaa",
+ "aaaaaaaaaaa", // 11 a's
+ ".",
+ ".*",
+ "a+",
+ "aa+",
+ "aaaa[b]?",
+ "aaa*",
+ },
+ },
+
+ {
+ "abc",
+ "abc",
+ []string{
+ "a",
+ "b",
+ "c",
+ "ab",
+ "bc",
+ "abc",
+ "a.c",
+ "a(b|c)",
+ "abc?",
+ },
+ },
+
+ {
+ "barbara*3",
+ "barbarabarbarabarbara",
+ []string{
+ "a",
+ "bar",
+ "rab",
+ "arab",
+ "barbar",
+ "bara?bar",
+ },
+ },
+
+ {
+ "typing drill",
+ "Now is the time for all good men to come to the aid of their country.",
+ []string{
+ "Now",
+ "the time",
+ "to come the aid",
+ "is the time for all good men to come to the aid of their",
+ "to (come|the)?",
+ },
+ },
+}
+
+
+// find all occurrences of s in source; report at most n occurences
+func find(src, s string, n int) []int {
+ var res vector.IntVector
+ if s != "" && n != 0 {
+ // find at most n occurrences of s in src
+ for i := -1; n < 0 || len(res) < n; {
+ j := strings.Index(src[i+1:], s)
+ if j < 0 {
+ break
+ }
+ i += j + 1
+ res.Push(i)
+ }
+ }
+ return res
+}
+
+
+func testLookup(t *testing.T, tc *testCase, x *Index, s string, n int) {
+ res := x.Lookup([]byte(s), n)
+ exp := find(tc.source, s, n)
+
+ // check that the lengths match
+ if len(res) != len(exp) {
+ t.Errorf("test %q, lookup %q (n = %d): expected %d results; got %d", tc.name, s, n, len(exp), len(res))
+ }
+
+ // if n >= 0 the number of results is limited --- unless n >= all results,
+ // we may obtain different positions from the Index and from find (because
+ // Index may not find the results in the same order as find) => in general
+ // we cannot simply check that the res and exp lists are equal
+
+ // check that each result is in fact a correct match and there are no duplicates
+ sort.SortInts(res)
+ for i, r := range res {
+ if r < 0 || len(tc.source) <= r {
+ t.Errorf("test %q, lookup %q, result %d (n = %d): index %d out of range [0, %d[", tc.name, s, i, n, r, len(tc.source))
+ } else if !strings.HasPrefix(tc.source[r:], s) {
+ t.Errorf("test %q, lookup %q, result %d (n = %d): index %d not a match", tc.name, s, i, n, r)
+ }
+ if i > 0 && res[i-1] == r {
+ t.Errorf("test %q, lookup %q, result %d (n = %d): found duplicate index %d", tc.name, s, i, n, r)
+ }
+ }
+
+ if n < 0 {
+ // all results computed - sorted res and exp must be equal
+ for i, r := range res {
+ e := exp[i]
+ if r != e {
+ t.Errorf("test %q, lookup %q, result %d: expected index %d; got %d", tc.name, s, i, e, r)
+ }
+ }
+ }
+}
+
+
+func testFindAllIndex(t *testing.T, tc *testCase, x *Index, rx *regexp.Regexp, n int) {
+ res := x.FindAllIndex(rx, n)
+ exp := rx.FindAllStringIndex(tc.source, n)
+
+ // check that the lengths match
+ if len(res) != len(exp) {
+ t.Errorf("test %q, FindAllIndex %q (n = %d): expected %d results; got %d", tc.name, rx, n, len(exp), len(res))
+ }
+
+ // if n >= 0 the number of results is limited --- unless n >= all results,
+ // we may obtain different positions from the Index and from regexp (because
+ // Index may not find the results in the same order as regexp) => in general
+ // we cannot simply check that the res and exp lists are equal
+
+ // check that each result is in fact a correct match and the result is sorted
+ for i, r := range res {
+ if r[0] < 0 || r[0] > r[1] || len(tc.source) < r[1] {
+ t.Errorf("test %q, FindAllIndex %q, result %d (n == %d): illegal match [%d, %d]", tc.name, rx, i, n, r[0], r[1])
+ } else if !rx.MatchString(tc.source[r[0]:r[1]]) {
+ t.Errorf("test %q, FindAllIndex %q, result %d (n = %d): [%d, %d] not a match", tc.name, rx, i, n, r[0], r[1])
+ }
+ }
+
+ if n < 0 {
+ // all results computed - sorted res and exp must be equal
+ for i, r := range res {
+ e := exp[i]
+ if r[0] != e[0] || r[1] != e[1] {
+ t.Errorf("test %q, FindAllIndex %q, result %d: expected match [%d, %d]; got [%d, %d]",
+ tc.name, rx, i, e[0], e[1], r[0], r[1])
+ }
+ }
+ }
+}
+
+
+func testLookups(t *testing.T, tc *testCase, x *Index, n int) {
+ for _, pat := range tc.patterns {
+ testLookup(t, tc, x, pat, n)
+ if rx, err := regexp.Compile(pat); err == nil {
+ testFindAllIndex(t, tc, x, rx, n)
+ }
+ }
+}
+
+
+// index is used to hide the sort.Interface
+type index Index
+
+func (x *index) Len() int { return len(x.sa) }
+func (x *index) Less(i, j int) bool { return bytes.Compare(x.at(i), x.at(j)) < 0 }
+func (x *index) Swap(i, j int) { x.sa[i], x.sa[j] = x.sa[j], x.sa[i] }
+func (a *index) at(i int) []byte { return a.data[a.sa[i]:] }
+
+
+func testConstruction(t *testing.T, tc *testCase, x *Index) {
+ if !sort.IsSorted((*index)(x)) {
+ t.Errorf("testConstruction failed %s", tc.name)
+ }
+}
+
+
+func TestIndex(t *testing.T) {
+ for _, tc := range testCases {
+ x := New([]byte(tc.source))
+ testConstruction(t, &tc, x)
+ testLookups(t, &tc, x, 0)
+ testLookups(t, &tc, x, 1)
+ testLookups(t, &tc, x, 10)
+ testLookups(t, &tc, x, 2e9)
+ testLookups(t, &tc, x, -1)
+ }
+}
diff --git a/libgo/go/io/io.go b/libgo/go/io/io.go
new file mode 100644
index 000000000..1a6eca95a
--- /dev/null
+++ b/libgo/go/io/io.go
@@ -0,0 +1,369 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package provides basic interfaces to I/O primitives.
+// Its primary job is to wrap existing implementations of such primitives,
+// such as those in package os, into shared public interfaces that
+// abstract the functionality, plus some other related primitives.
+package io
+
+import "os"
+
+// Error represents an unexpected I/O behavior.
+type Error struct {
+ os.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"}
+
+// ErrShortBuffer means that a read required a longer buffer than was provided.
+var ErrShortBuffer os.Error = &Error{"short buffer"}
+
+// ErrUnexpectedEOF means that os.EOF was encountered in the
+// middle of reading a fixed-size block or data structure.
+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.
+// If some data is available but not len(p) bytes, Read conventionally
+// returns what is available rather than block waiting for more.
+//
+// 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.
+type Reader interface {
+ Read(p []byte) (n int, err os.Error)
+}
+
+// Writer is the interface that wraps the basic Write method.
+//
+// Write writes len(p) bytes from p to the underlying data stream.
+// It returns the number of bytes written from p (0 <= n <= len(p))
+// and any error encountered that caused the write to stop early.
+// Write must return a non-nil error if it returns n < len(p).
+type Writer interface {
+ Write(p []byte) (n int, err os.Error)
+}
+
+// Closer is the interface that wraps the basic Close method.
+type Closer interface {
+ Close() os.Error
+}
+
+// Seeker is the interface that wraps the basic Seek method.
+//
+// Seek sets the offset for the next Read or Write to offset,
+// interpreted according to whence: 0 means relative to the origin of
+// the file, 1 means relative to the current offset, and 2 means
+// relative to the end. Seek returns the new offset and an Error, if
+// any.
+type Seeker interface {
+ Seek(offset int64, whence int) (ret int64, err os.Error)
+}
+
+// ReadWriter is the interface that groups the basic Read and Write methods.
+type ReadWriter interface {
+ Reader
+ Writer
+}
+
+// ReadCloser is the interface that groups the basic Read and Close methods.
+type ReadCloser interface {
+ Reader
+ Closer
+}
+
+// WriteCloser is the interface that groups the basic Write and Close methods.
+type WriteCloser interface {
+ Writer
+ Closer
+}
+
+// ReadWriteCloser is the interface that groups the basic Read, Write and Close methods.
+type ReadWriteCloser interface {
+ Reader
+ Writer
+ Closer
+}
+
+// ReadSeeker is the interface that groups the basic Read and Seek methods.
+type ReadSeeker interface {
+ Reader
+ Seeker
+}
+
+// WriteSeeker is the interface that groups the basic Write and Seek methods.
+type WriteSeeker interface {
+ Writer
+ Seeker
+}
+
+// ReadWriteSeeker is the interface that groups the basic Read, Write and Seek methods.
+type ReadWriteSeeker interface {
+ Reader
+ Writer
+ Seeker
+}
+
+// ReaderFrom is the interface that wraps the ReadFrom method.
+type ReaderFrom interface {
+ ReadFrom(r Reader) (n int64, err os.Error)
+}
+
+// WriterTo is the interface that wraps the WriteTo method.
+type WriterTo interface {
+ WriteTo(w Writer) (n int64, err os.Error)
+}
+
+// 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
+// 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.
+//
+// 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.
+type ReaderAt interface {
+ ReadAt(p []byte, off int64) (n int, err os.Error)
+}
+
+// WriterAt is the interface that wraps the basic WriteAt method.
+//
+// WriteAt writes len(p) bytes from p to the underlying data stream
+// at offset off. It returns the number of bytes written from p (0 <= n <= len(p))
+// and any error encountered that caused the write to stop early.
+// WriteAt must return a non-nil error if it returns n < len(p).
+type WriterAt interface {
+ WriteAt(p []byte, off int64) (n int, err os.Error)
+}
+
+// ReadByter is the interface that wraps the ReadByte method.
+//
+// ReadByte reads and returns the next byte from the input.
+// If no byte is available, err will be set.
+type ReadByter interface {
+ ReadByte() (c byte, err os.Error)
+}
+
+// WriteString writes the contents of the string s to w, which accepts an array of bytes.
+func WriteString(w Writer, s string) (n int, err os.Error) {
+ return w.Write([]byte(s))
+}
+
+// ReadAtLeast reads from r into buf until it has read at least min bytes.
+// It returns the number of bytes copied and an error if fewer bytes were read.
+// The error is os.EOF only if no bytes were read.
+// If an EOF happens after reading fewer than min bytes,
+// ReadAtLeast returns ErrUnexpectedEOF.
+// If min is greater than the length of buf, ReadAtLeast returns ErrShortBuffer.
+func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
+ if len(buf) < min {
+ return 0, ErrShortBuffer
+ }
+ for n < min {
+ nn, e := r.Read(buf[n:])
+ if nn > 0 {
+ n += nn
+ }
+ if e != nil {
+ if e == os.EOF && n > 0 {
+ e = ErrUnexpectedEOF
+ }
+ return n, e
+ }
+ }
+ return
+}
+
+// ReadFull reads exactly len(buf) bytes from r into buf.
+// It returns the number of bytes copied and an error if fewer bytes were read.
+// The error is os.EOF only if no bytes were read.
+// If an EOF happens after reading some but not all the bytes,
+// ReadFull returns ErrUnexpectedEOF.
+func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
+ return ReadAtLeast(r, buf, len(buf))
+}
+
+// Copyn copies n bytes (or until an error) from src to dst.
+// It returns the number of bytes copied and the error, if any.
+//
+// If dst implements the ReaderFrom interface,
+// the copy is implemented by calling dst.ReadFrom(src).
+func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
+ // If the writer has a ReadFrom method, use it to do the copy.
+ // Avoids a buffer allocation and a copy.
+ if rt, ok := dst.(ReaderFrom); ok {
+ written, err = rt.ReadFrom(LimitReader(src, n))
+ if written < n && err == nil {
+ // rt stopped early; must have been EOF.
+ err = os.EOF
+ }
+ return
+ }
+ buf := make([]byte, 32*1024)
+ for written < n {
+ l := len(buf)
+ if d := n - written; d < int64(l) {
+ l = int(d)
+ }
+ nr, er := src.Read(buf[0:l])
+ if nr > 0 {
+ nw, ew := dst.Write(buf[0:nr])
+ if nw > 0 {
+ written += int64(nw)
+ }
+ if ew != nil {
+ err = ew
+ break
+ }
+ if nr != nw {
+ err = ErrShortWrite
+ break
+ }
+ }
+ if er != nil {
+ err = er
+ break
+ }
+ }
+ return written, err
+}
+
+// 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.
+//
+// If dst implements the ReaderFrom interface,
+// the copy is implemented by calling dst.ReadFrom(src).
+// Otherwise, if src implements the WriterTo interface,
+// the copy is implemented by calling src.WriteTo(dst).
+func Copy(dst Writer, src Reader) (written int64, err os.Error) {
+ // If the writer has a ReadFrom method, use it to do the copy.
+ // Avoids an allocation and a copy.
+ if rt, ok := dst.(ReaderFrom); ok {
+ return rt.ReadFrom(src)
+ }
+ // Similarly, if the reader has a WriteTo method, use it to do the copy.
+ if wt, ok := src.(WriterTo); ok {
+ return wt.WriteTo(dst)
+ }
+ buf := make([]byte, 32*1024)
+ for {
+ nr, er := src.Read(buf)
+ if nr > 0 {
+ nw, ew := dst.Write(buf[0:nr])
+ if nw > 0 {
+ written += int64(nw)
+ }
+ if ew != nil {
+ err = ew
+ break
+ }
+ if nr != nw {
+ err = ErrShortWrite
+ break
+ }
+ }
+ if er == os.EOF {
+ break
+ }
+ if er != nil {
+ err = er
+ break
+ }
+ }
+ return written, err
+}
+
+// LimitReader returns a Reader that reads from r
+// but stops with os.EOF after n bytes.
+func LimitReader(r Reader, n int64) Reader { return &limitedReader{r, n} }
+
+type limitedReader struct {
+ r Reader
+ n int64
+}
+
+func (l *limitedReader) Read(p []byte) (n int, err os.Error) {
+ if l.n <= 0 {
+ return 0, os.EOF
+ }
+ if int64(len(p)) > l.n {
+ p = p[0:l.n]
+ }
+ n, err = l.r.Read(p)
+ l.n -= int64(n)
+ return
+}
+
+// NewSectionReader returns a SectionReader that reads from r
+// starting at offset off and stops with os.EOF after n bytes.
+func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader {
+ return &SectionReader{r, off, off, off + n}
+}
+
+// SectionReader implements Read, Seek, and ReadAt on a section
+// of an underlying ReaderAt.
+type SectionReader struct {
+ r ReaderAt
+ base int64
+ off int64
+ limit int64
+}
+
+func (s *SectionReader) Read(p []byte) (n int, err os.Error) {
+ if s.off >= s.limit {
+ return 0, os.EOF
+ }
+ if max := s.limit - s.off; int64(len(p)) > max {
+ p = p[0:max]
+ }
+ n, err = s.r.ReadAt(p, s.off)
+ s.off += int64(n)
+ return
+}
+
+func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err os.Error) {
+ switch whence {
+ default:
+ return 0, os.EINVAL
+ case 0:
+ offset += s.base
+ case 1:
+ offset += s.off
+ case 2:
+ offset += s.limit
+ }
+ if offset < s.base || offset > s.limit {
+ return 0, os.EINVAL
+ }
+ s.off = offset
+ return offset - s.base, nil
+}
+
+func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err os.Error) {
+ if off < 0 || off >= s.limit-s.base {
+ return 0, os.EOF
+ }
+ off += s.base
+ if max := s.limit - off; int64(len(p)) > max {
+ p = p[0:max]
+ }
+ return s.r.ReadAt(p, off)
+}
+
+// Size returns the size of the section in bytes.
+func (s *SectionReader) Size() int64 { return s.limit - s.base }
diff --git a/libgo/go/io/io_test.go b/libgo/go/io/io_test.go
new file mode 100644
index 000000000..4fcd85e69
--- /dev/null
+++ b/libgo/go/io/io_test.go
@@ -0,0 +1,156 @@
+// 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 io_test
+
+import (
+ "bytes"
+ . "io"
+ "os"
+ "strings"
+ "testing"
+)
+
+// An version of bytes.Buffer without ReadFrom and WriteTo
+type Buffer struct {
+ bytes.Buffer
+ ReaderFrom // conflicts with and hides bytes.Buffer's ReaderFrom.
+ WriterTo // conflicts with and hides bytes.Buffer's WriterTo.
+}
+
+// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy and Copyn.
+
+func TestCopy(t *testing.T) {
+ rb := new(Buffer)
+ wb := new(Buffer)
+ rb.WriteString("hello, world.")
+ Copy(wb, rb)
+ if wb.String() != "hello, world." {
+ t.Errorf("Copy did not work properly")
+ }
+}
+
+func TestCopyReadFrom(t *testing.T) {
+ rb := new(Buffer)
+ wb := new(bytes.Buffer) // implements ReadFrom.
+ rb.WriteString("hello, world.")
+ Copy(wb, rb)
+ if wb.String() != "hello, world." {
+ t.Errorf("Copy did not work properly")
+ }
+}
+
+func TestCopyWriteTo(t *testing.T) {
+ rb := new(bytes.Buffer) // implements WriteTo.
+ wb := new(Buffer)
+ rb.WriteString("hello, world.")
+ Copy(wb, rb)
+ if wb.String() != "hello, world." {
+ t.Errorf("Copy did not work properly")
+ }
+}
+
+func TestCopyn(t *testing.T) {
+ rb := new(Buffer)
+ wb := new(Buffer)
+ rb.WriteString("hello, world.")
+ Copyn(wb, rb, 5)
+ if wb.String() != "hello" {
+ t.Errorf("Copyn did not work properly")
+ }
+}
+
+func TestCopynReadFrom(t *testing.T) {
+ rb := new(Buffer)
+ wb := new(bytes.Buffer) // implements ReadFrom.
+ rb.WriteString("hello")
+ Copyn(wb, rb, 5)
+ if wb.String() != "hello" {
+ t.Errorf("Copyn did not work properly")
+ }
+}
+
+func TestCopynWriteTo(t *testing.T) {
+ rb := new(bytes.Buffer) // implements WriteTo.
+ wb := new(Buffer)
+ rb.WriteString("hello, world.")
+ Copyn(wb, rb, 5)
+ if wb.String() != "hello" {
+ t.Errorf("Copyn did not work properly")
+ }
+}
+
+type noReadFrom struct {
+ w Writer
+}
+
+func (w *noReadFrom) Write(p []byte) (n int, err os.Error) {
+ return w.w.Write(p)
+}
+
+func TestCopynEOF(t *testing.T) {
+ // Test that EOF behavior is the same regardless of whether
+ // argument to Copyn has ReadFrom.
+
+ b := new(bytes.Buffer)
+
+ n, err := Copyn(&noReadFrom{b}, strings.NewReader("foo"), 3)
+ if n != 3 || err != nil {
+ t.Errorf("Copyn(noReadFrom, foo, 3) = %d, %v; want 3, nil", n, err)
+ }
+
+ n, err = Copyn(&noReadFrom{b}, strings.NewReader("foo"), 4)
+ if n != 3 || err != os.EOF {
+ t.Errorf("Copyn(noReadFrom, foo, 4) = %d, %v; want 3, EOF", n, err)
+ }
+
+ n, err = Copyn(b, strings.NewReader("foo"), 3) // b has read from
+ if n != 3 || err != nil {
+ t.Errorf("Copyn(bytes.Buffer, foo, 3) = %d, %v; want 3, nil", n, err)
+ }
+
+ n, err = Copyn(b, strings.NewReader("foo"), 4) // b has read from
+ if n != 3 || err != os.EOF {
+ t.Errorf("Copyn(bytes.Buffer, foo, 4) = %d, %v; want 3, EOF", n, err)
+ }
+}
+
+func TestReadAtLeast(t *testing.T) {
+ var rb bytes.Buffer
+ rb.Write([]byte("0123"))
+ buf := make([]byte, 2)
+ n, err := ReadAtLeast(&rb, buf, 2)
+ if err != nil {
+ t.Error(err)
+ }
+ n, err = ReadAtLeast(&rb, buf, 4)
+ if err != ErrShortBuffer {
+ t.Errorf("expected ErrShortBuffer got %v", err)
+ }
+ if n != 0 {
+ t.Errorf("expected to have read 0 bytes, got %v", n)
+ }
+ n, err = ReadAtLeast(&rb, buf, 1)
+ if err != nil {
+ t.Error(err)
+ }
+ if n != 2 {
+ t.Errorf("expected to have read 2 bytes, got %v", n)
+ }
+ n, err = ReadAtLeast(&rb, buf, 2)
+ if err != os.EOF {
+ t.Errorf("expected EOF, got %v", err)
+ }
+ if n != 0 {
+ t.Errorf("expected to have read 0 bytes, got %v", n)
+ }
+ rb.Write([]byte("4"))
+ n, err = ReadAtLeast(&rb, buf, 2)
+ if err != ErrUnexpectedEOF {
+ t.Errorf("expected ErrUnexpectedEOF, got %v", err)
+ }
+ if n != 1 {
+ t.Errorf("expected to have read 1 bytes, got %v", n)
+ }
+}
diff --git a/libgo/go/io/ioutil/ioutil.go b/libgo/go/io/ioutil/ioutil.go
new file mode 100644
index 000000000..fb3fdcda1
--- /dev/null
+++ b/libgo/go/io/ioutil/ioutil.go
@@ -0,0 +1,90 @@
+// 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.
+
+// Utility functions.
+
+package ioutil
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "sort"
+)
+
+// ReadAll reads from r until an error or EOF and returns the data it read.
+func ReadAll(r io.Reader) ([]byte, os.Error) {
+ var buf bytes.Buffer
+ _, err := io.Copy(&buf, r)
+ return buf.Bytes(), err
+}
+
+// ReadFile reads the file named by filename and returns the contents.
+func ReadFile(filename string) ([]byte, os.Error) {
+ f, err := os.Open(filename, os.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ // It's a good but not certain bet that FileInfo will tell us exactly how much to
+ // read, so let's try it but be prepared for the answer to be wrong.
+ fi, err := f.Stat()
+ var n int64
+ if err == nil && fi.Size < 2e9 { // Don't preallocate a huge buffer, just in case.
+ n = fi.Size
+ }
+ // Add a little extra in case Size is zero, and to avoid another allocation after
+ // Read has filled the buffer.
+ n += bytes.MinRead
+ // Pre-allocate the correct size of buffer, then set its size to zero. The
+ // Buffer will read into the allocated space cheaply. If the size was wrong,
+ // we'll either waste some space off the end or reallocate as needed, but
+ // in the overwhelmingly common case we'll get it just right.
+ buf := bytes.NewBuffer(make([]byte, 0, n))
+ _, err = buf.ReadFrom(f)
+ return buf.Bytes(), err
+}
+
+// WriteFile writes data to a file named by filename.
+// If the file does not exist, WriteFile creates it with permissions perm;
+// otherwise WriteFile truncates it before writing.
+func WriteFile(filename string, data []byte, perm uint32) os.Error {
+ f, err := os.Open(filename, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, perm)
+ if err != nil {
+ return err
+ }
+ n, err := f.Write(data)
+ f.Close()
+ if err == nil && n < len(data) {
+ err = io.ErrShortWrite
+ }
+ return err
+}
+
+// A dirList implements sort.Interface.
+type fileInfoList []*os.FileInfo
+
+func (f fileInfoList) Len() int { return len(f) }
+func (f fileInfoList) Less(i, j int) bool { return f[i].Name < f[j].Name }
+func (f fileInfoList) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
+
+// ReadDir reads the directory named by dirname and returns
+// a list of sorted directory entries.
+func ReadDir(dirname string) ([]*os.FileInfo, os.Error) {
+ f, err := os.Open(dirname, os.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ list, err := f.Readdir(-1)
+ f.Close()
+ if err != nil {
+ return nil, err
+ }
+ fi := make(fileInfoList, len(list))
+ for i := range list {
+ fi[i] = &list[i]
+ }
+ sort.Sort(fi)
+ return fi, nil
+}
diff --git a/libgo/go/io/ioutil/ioutil_test.go b/libgo/go/io/ioutil/ioutil_test.go
new file mode 100644
index 000000000..150ee6d63
--- /dev/null
+++ b/libgo/go/io/ioutil/ioutil_test.go
@@ -0,0 +1,92 @@
+// 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 ioutil_test
+
+import (
+ . "io/ioutil"
+ "os"
+ "testing"
+)
+
+func checkSize(t *testing.T, path string, size int64) {
+ dir, err := os.Stat(path)
+ if err != nil {
+ t.Fatalf("Stat %q (looking for size %d): %s", path, size, err)
+ }
+ if dir.Size != size {
+ t.Errorf("Stat %q: size %d want %d", path, dir.Size, size)
+ }
+}
+
+func TestReadFile(t *testing.T) {
+ filename := "rumpelstilzchen"
+ contents, err := ReadFile(filename)
+ if err == nil {
+ t.Fatalf("ReadFile %s: error expected, none found", filename)
+ }
+
+ filename = "ioutil_test.go"
+ contents, err = ReadFile(filename)
+ if err != nil {
+ t.Fatalf("ReadFile %s: %v", filename, err)
+ }
+
+ checkSize(t, filename, int64(len(contents)))
+}
+
+func TestWriteFile(t *testing.T) {
+ filename := "_test/rumpelstilzchen"
+ data := "Programming today is a race between software engineers striving to " +
+ "build bigger and better idiot-proof programs, and the Universe trying " +
+ "to produce bigger and better idiots. So far, the Universe is winning."
+
+ if err := WriteFile(filename, []byte(data), 0644); err != nil {
+ t.Fatalf("WriteFile %s: %v", filename, err)
+ }
+
+ contents, err := ReadFile(filename)
+ if err != nil {
+ t.Fatalf("ReadFile %s: %v", filename, err)
+ }
+
+ if string(contents) != data {
+ t.Fatalf("contents = %q\nexpected = %q", string(contents), data)
+ }
+
+ // cleanup
+ os.Remove(filename) // ignore error
+}
+
+
+func TestReadDir(t *testing.T) {
+ dirname := "rumpelstilzchen"
+ _, err := ReadDir(dirname)
+ if err == nil {
+ t.Fatalf("ReadDir %s: error expected, none found", dirname)
+ }
+
+ dirname = "."
+ list, err := ReadDir(dirname)
+ if err != nil {
+ t.Fatalf("ReadDir %s: %v", dirname, err)
+ }
+
+ foundTest := false
+ foundTestDir := false
+ for _, dir := range list {
+ switch {
+ case dir.IsRegular() && dir.Name == "ioutil_test.go":
+ foundTest = true
+ case dir.IsDirectory() && dir.Name == "_test":
+ foundTestDir = true
+ }
+ }
+ if !foundTest {
+ t.Fatalf("ReadDir %s: test file not found", dirname)
+ }
+ if !foundTestDir {
+ t.Fatalf("ReadDir %s: _test directory not found", dirname)
+ }
+}
diff --git a/libgo/go/io/ioutil/tempfile.go b/libgo/go/io/ioutil/tempfile.go
new file mode 100644
index 000000000..114eca2b5
--- /dev/null
+++ b/libgo/go/io/ioutil/tempfile.go
@@ -0,0 +1,60 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ioutil
+
+import (
+ "os"
+ "strconv"
+)
+
+// Random number state, accessed without lock; racy but harmless.
+// We generate random temporary file names so that there's a good
+// chance the file doesn't exist yet - keeps the number of tries in
+// TempFile to a minimum.
+var rand uint32
+
+func reseed() uint32 {
+ sec, nsec, _ := os.Time()
+ return uint32(sec*1e9 + nsec + int64(os.Getpid()))
+}
+
+func nextSuffix() string {
+ r := rand
+ if r == 0 {
+ r = reseed()
+ }
+ r = r*1664525 + 1013904223 // constants from Numerical Recipes
+ rand = r
+ return strconv.Itoa(int(1e9 + r%1e9))[1:]
+}
+
+// TempFile creates a new temporary file in the directory dir
+// with a name beginning with prefix, opens the file for reading
+// and writing, and returns the resulting *os.File.
+// If dir is the empty string, TempFile uses the default directory
+// for temporary files (see os.TempDir).
+// Multiple programs calling TempFile simultaneously
+// will not choose the same file. The caller can use f.Name()
+// to find the name of the file. It is the caller's responsibility to
+// remove the file when no longer needed.
+func TempFile(dir, prefix string) (f *os.File, err os.Error) {
+ if dir == "" {
+ dir = os.TempDir()
+ }
+
+ nconflict := 0
+ for i := 0; i < 10000; i++ {
+ name := dir + "/" + prefix + nextSuffix()
+ f, err = os.Open(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
+ if pe, ok := err.(*os.PathError); ok && pe.Error == os.EEXIST {
+ if nconflict++; nconflict > 10 {
+ rand = reseed()
+ }
+ continue
+ }
+ break
+ }
+ return
+}
diff --git a/libgo/go/io/ioutil/tempfile_test.go b/libgo/go/io/ioutil/tempfile_test.go
new file mode 100644
index 000000000..d949a86cf
--- /dev/null
+++ b/libgo/go/io/ioutil/tempfile_test.go
@@ -0,0 +1,33 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ioutil_test
+
+import (
+ . "io/ioutil"
+ "os"
+ "regexp"
+ "testing"
+)
+
+func TestTempFile(t *testing.T) {
+ f, err := TempFile("/_not_exists_", "foo")
+ if f != nil || err == nil {
+ t.Errorf("TempFile(`/_not_exists_`, `foo`) = %v, %v", f, err)
+ }
+
+ dir := os.TempDir()
+ f, err = TempFile(dir, "ioutil_test")
+ if f == nil || err != nil {
+ t.Errorf("TempFile(dir, `ioutil_test`) = %v, %v", f, err)
+ }
+ if f != nil {
+ re := regexp.MustCompile("^" + regexp.QuoteMeta(dir) + "/ioutil_test[0-9]+$")
+ if !re.MatchString(f.Name()) {
+ t.Errorf("TempFile(`"+dir+"`, `ioutil_test`) created bad name %s", f.Name())
+ }
+ os.Remove(f.Name())
+ }
+ f.Close()
+}
diff --git a/libgo/go/io/multi.go b/libgo/go/io/multi.go
new file mode 100644
index 000000000..88e4f1b76
--- /dev/null
+++ b/libgo/go/io/multi.go
@@ -0,0 +1,60 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io
+
+import "os"
+
+type multiReader struct {
+ readers []Reader
+}
+
+func (mr *multiReader) Read(p []byte) (n int, err os.Error) {
+ for len(mr.readers) > 0 {
+ n, err = mr.readers[0].Read(p)
+ if n > 0 || err != os.EOF {
+ if err == os.EOF {
+ // This shouldn't happen.
+ // Well-behaved Readers should never
+ // return non-zero bytes read with an
+ // EOF. But if so, we clean it.
+ err = nil
+ }
+ return
+ }
+ mr.readers = mr.readers[1:]
+ }
+ return 0, os.EOF
+}
+
+// MultiReader returns a Reader that's the logical concatenation of
+// the provided input readers. They're read sequentially. Once all
+// inputs are drained, Read will return os.EOF.
+func MultiReader(readers ...Reader) Reader {
+ return &multiReader{readers}
+}
+
+type multiWriter struct {
+ writers []Writer
+}
+
+func (t *multiWriter) Write(p []byte) (n int, err os.Error) {
+ for _, w := range t.writers {
+ n, err = w.Write(p)
+ if err != nil {
+ return
+ }
+ if n != len(p) {
+ err = ErrShortWrite
+ return
+ }
+ }
+ return len(p), nil
+}
+
+// MultiWriter creates a writer that duplicates its writes to all the
+// provided writers, similar to the Unix tee(1) command.
+func MultiWriter(writers ...Writer) Writer {
+ return &multiWriter{writers}
+}
diff --git a/libgo/go/io/multi_test.go b/libgo/go/io/multi_test.go
new file mode 100644
index 000000000..3ecb7c75d
--- /dev/null
+++ b/libgo/go/io/multi_test.go
@@ -0,0 +1,88 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io_test
+
+import (
+ . "io"
+ "bytes"
+ "crypto/sha1"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+)
+
+func TestMultiReader(t *testing.T) {
+ var mr Reader
+ var buf []byte
+ nread := 0
+ withFooBar := func(tests func()) {
+ r1 := strings.NewReader("foo ")
+ r2 := strings.NewReader("bar")
+ mr = MultiReader(r1, r2)
+ buf = make([]byte, 20)
+ tests()
+ }
+ expectRead := func(size int, expected string, eerr os.Error) {
+ nread++
+ n, gerr := mr.Read(buf[0:size])
+ if n != len(expected) {
+ t.Errorf("#%d, expected %d bytes; got %d",
+ nread, len(expected), n)
+ }
+ got := string(buf[0:n])
+ if got != expected {
+ t.Errorf("#%d, expected %q; got %q",
+ nread, expected, got)
+ }
+ if gerr != eerr {
+ t.Errorf("#%d, expected error %v; got %v",
+ nread, eerr, gerr)
+ }
+ buf = buf[n:]
+ }
+ withFooBar(func() {
+ expectRead(2, "fo", nil)
+ expectRead(5, "o ", nil)
+ expectRead(5, "bar", nil)
+ expectRead(5, "", os.EOF)
+ })
+ withFooBar(func() {
+ expectRead(4, "foo ", nil)
+ expectRead(1, "b", nil)
+ expectRead(3, "ar", nil)
+ expectRead(1, "", os.EOF)
+ })
+ withFooBar(func() {
+ expectRead(5, "foo ", nil)
+ })
+}
+
+func TestMultiWriter(t *testing.T) {
+ sha1 := sha1.New()
+ sink := new(bytes.Buffer)
+ mw := MultiWriter(sha1, sink)
+
+ sourceString := "My input text."
+ source := strings.NewReader(sourceString)
+ written, err := Copy(mw, source)
+
+ if written != int64(len(sourceString)) {
+ t.Errorf("short write of %d, not %d", written, len(sourceString))
+ }
+
+ if err != nil {
+ t.Errorf("unexpected error: %v", err)
+ }
+
+ sha1hex := fmt.Sprintf("%x", sha1.Sum())
+ if sha1hex != "01cb303fa8c30a64123067c5aa6284ba7ec2d31b" {
+ t.Error("incorrect sha1 value")
+ }
+
+ if sink.String() != sourceString {
+ t.Errorf("expected %q; got %q", sourceString, sink.String())
+ }
+}
diff --git a/libgo/go/io/pipe.go b/libgo/go/io/pipe.go
new file mode 100644
index 000000000..df76418b9
--- /dev/null
+++ b/libgo/go/io/pipe.go
@@ -0,0 +1,305 @@
+// 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.
+
+// Pipe adapter to connect code expecting an io.Reader
+// with code expecting an io.Writer.
+
+package io
+
+import (
+ "os"
+ "runtime"
+ "sync"
+)
+
+type pipeResult struct {
+ n int
+ err os.Error
+}
+
+// Shared pipe structure.
+type pipe struct {
+ // Reader sends on cr1, receives on cr2.
+ // Writer does the same on cw1, cw2.
+ r1, w1 chan []byte
+ r2, w2 chan pipeResult
+
+ rclose chan os.Error // read close; error to return to writers
+ wclose chan os.Error // write close; error to return to readers
+
+ done chan int // read or write half is done
+}
+
+func (p *pipe) run() {
+ var (
+ rb []byte // pending Read
+ wb []byte // pending Write
+ wn int // amount written so far from wb
+ rerr os.Error // if read end is closed, error to send to writers
+ werr os.Error // if write end is closed, error to send to readers
+ r1 chan []byte // p.cr1 or nil depending on whether Read is ok
+ w1 chan []byte // p.cw1 or nil depending on whether Write is ok
+ ndone int
+ )
+
+ // Read and Write are enabled at the start.
+ r1 = p.r1
+ w1 = p.w1
+
+ for {
+ select {
+ case <-p.done:
+ if ndone++; ndone == 2 {
+ // both reader and writer are gone
+ // close out any existing i/o
+ if r1 == nil {
+ p.r2 <- pipeResult{0, os.EINVAL}
+ }
+ if w1 == nil {
+ p.w2 <- pipeResult{0, os.EINVAL}
+ }
+ return
+ }
+ continue
+ case rerr = <-p.rclose:
+ if w1 == nil {
+ // finish pending Write
+ p.w2 <- pipeResult{wn, rerr}
+ wn = 0
+ w1 = p.w1 // allow another Write
+ }
+ if r1 == nil {
+ // Close of read side during Read.
+ // finish pending Read with os.EINVAL.
+ p.r2 <- pipeResult{0, os.EINVAL}
+ r1 = p.r1 // allow another Read
+ }
+ continue
+ case werr = <-p.wclose:
+ if r1 == nil {
+ // finish pending Read
+ p.r2 <- pipeResult{0, werr}
+ r1 = p.r1 // allow another Read
+ }
+ if w1 == nil {
+ // Close of write side during Write.
+ // finish pending Write with os.EINVAL.
+ p.w2 <- pipeResult{wn, os.EINVAL}
+ wn = 0
+ w1 = p.w1 // allow another Write
+ }
+ continue
+ case rb = <-r1:
+ if werr != nil {
+ // write end is closed
+ p.r2 <- pipeResult{0, werr}
+ continue
+ }
+ if rerr != nil {
+ // read end is closed
+ p.r2 <- pipeResult{0, os.EINVAL}
+ continue
+ }
+ r1 = nil // disable Read until this one is done
+ case wb = <-w1:
+ if rerr != nil {
+ // read end is closed
+ p.w2 <- pipeResult{0, rerr}
+ continue
+ }
+ if werr != nil {
+ // write end is closed
+ p.w2 <- pipeResult{0, os.EINVAL}
+ continue
+ }
+ w1 = nil // disable Write until this one is done
+ }
+
+ if r1 == nil && w1 == nil {
+ // Have rb and wb. Execute.
+ n := copy(rb, wb)
+ wn += n
+ wb = wb[n:]
+
+ // Finish Read.
+ p.r2 <- pipeResult{n, nil}
+ r1 = p.r1 // allow another Read
+
+ // Maybe finish Write.
+ if len(wb) == 0 {
+ p.w2 <- pipeResult{wn, nil}
+ wn = 0
+ w1 = p.w1 // allow another Write
+ }
+ }
+ }
+}
+
+// Read/write halves of the pipe.
+// They are separate structures for two reasons:
+// 1. If one end becomes garbage without being Closed,
+// its finalizer can Close so that the other end
+// does not hang indefinitely.
+// 2. Clients cannot use interface conversions on the
+// read end to find the Write method, and vice versa.
+
+type pipeHalf struct {
+ c1 chan []byte
+ c2 chan pipeResult
+ cclose chan os.Error
+ done chan int
+
+ lock sync.Mutex
+ closed bool
+
+ io sync.Mutex
+ ioclosed bool
+}
+
+func (p *pipeHalf) rw(data []byte) (n int, err os.Error) {
+ // Run i/o operation.
+ // Check ioclosed flag under lock to make sure we're still allowed to do i/o.
+ p.io.Lock()
+ if p.ioclosed {
+ p.io.Unlock()
+ return 0, os.EINVAL
+ }
+ p.io.Unlock()
+ p.c1 <- data
+ res := <-p.c2
+ return res.n, res.err
+}
+
+func (p *pipeHalf) close(err os.Error) os.Error {
+ // Close pipe half.
+ // Only first call to close does anything.
+ p.lock.Lock()
+ if p.closed {
+ p.lock.Unlock()
+ return os.EINVAL
+ }
+ p.closed = true
+ p.lock.Unlock()
+
+ // First, send the close notification.
+ p.cclose <- err
+
+ // Runner is now responding to rw operations
+ // with os.EINVAL. Cut off future rw operations
+ // by setting ioclosed flag.
+ p.io.Lock()
+ p.ioclosed = true
+ p.io.Unlock()
+
+ // With ioclosed set, there will be no more rw operations
+ // working on the channels.
+ // Tell the runner we won't be bothering it anymore.
+ p.done <- 1
+
+ // Successfully torn down; can disable finalizer.
+ runtime.SetFinalizer(p, nil)
+
+ return nil
+}
+
+func (p *pipeHalf) finalizer() {
+ p.close(os.EINVAL)
+}
+
+
+// A PipeReader is the read half of a pipe.
+type PipeReader struct {
+ pipeHalf
+}
+
+// Read implements the standard Read interface:
+// it reads data from the pipe, blocking until a writer
+// arrives or the write end is closed.
+// If the write end is closed with an error, that error is
+// returned as err; otherwise err is nil.
+func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
+ return r.rw(data)
+}
+
+// Close closes the reader; subsequent writes to the
+// write half of the pipe will return the error os.EPIPE.
+func (r *PipeReader) Close() os.Error {
+ return r.CloseWithError(nil)
+}
+
+// CloseWithError closes the reader; subsequent writes
+// to the write half of the pipe will return the error err.
+func (r *PipeReader) CloseWithError(err os.Error) os.Error {
+ if err == nil {
+ err = os.EPIPE
+ }
+ return r.close(err)
+}
+
+// A PipeWriter is the write half of a pipe.
+type PipeWriter struct {
+ pipeHalf
+}
+
+// Write implements the standard Write interface:
+// it writes data to the pipe, blocking until readers
+// have consumed all the data or the read end is closed.
+// If the read end is closed with an error, that err is
+// returned as err; otherwise err is os.EPIPE.
+func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
+ return w.rw(data)
+}
+
+// Close closes the writer; subsequent reads from the
+// read half of the pipe will return no bytes and os.EOF.
+func (w *PipeWriter) Close() os.Error {
+ return w.CloseWithError(nil)
+}
+
+// CloseWithError closes the writer; subsequent reads from the
+// read half of the pipe will return no bytes and the error err.
+func (w *PipeWriter) CloseWithError(err os.Error) os.Error {
+ if err == nil {
+ err = os.EOF
+ }
+ return w.close(err)
+}
+
+// Pipe creates a synchronous in-memory pipe.
+// It can be used to connect code expecting an io.Reader
+// with code expecting an io.Writer.
+// Reads on one end are matched with writes on the other,
+// copying data directly between the two; there is no internal buffering.
+func Pipe() (*PipeReader, *PipeWriter) {
+ p := &pipe{
+ r1: make(chan []byte),
+ r2: make(chan pipeResult),
+ w1: make(chan []byte),
+ w2: make(chan pipeResult),
+ rclose: make(chan os.Error),
+ wclose: make(chan os.Error),
+ done: make(chan int),
+ }
+ go p.run()
+
+ // NOTE: Cannot use composite literal here:
+ // pipeHalf{c1: p.cr1, c2: p.cr2, cclose: p.crclose, cdone: p.cdone}
+ // because this implicitly copies the pipeHalf, which copies the inner mutex.
+
+ r := new(PipeReader)
+ r.c1 = p.r1
+ r.c2 = p.r2
+ r.cclose = p.rclose
+ r.done = p.done
+ runtime.SetFinalizer(r, (*PipeReader).finalizer)
+
+ w := new(PipeWriter)
+ w.c1 = p.w1
+ w.c2 = p.w2
+ w.cclose = p.wclose
+ w.done = p.done
+ runtime.SetFinalizer(w, (*PipeWriter).finalizer)
+
+ return r, w
+}
diff --git a/libgo/go/io/pipe_test.go b/libgo/go/io/pipe_test.go
new file mode 100644
index 000000000..bd4b94f0a
--- /dev/null
+++ b/libgo/go/io/pipe_test.go
@@ -0,0 +1,271 @@
+// 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 io_test
+
+import (
+ "fmt"
+ . "io"
+ "os"
+ "testing"
+ "time"
+)
+
+func checkWrite(t *testing.T, w Writer, data []byte, c chan int) {
+ n, err := w.Write(data)
+ if err != nil {
+ t.Errorf("write: %v", err)
+ }
+ if n != len(data) {
+ t.Errorf("short write: %d != %d", n, len(data))
+ }
+ c <- 0
+}
+
+// Test a single read/write pair.
+func TestPipe1(t *testing.T) {
+ c := make(chan int)
+ r, w := Pipe()
+ var buf = make([]byte, 64)
+ go checkWrite(t, w, []byte("hello, world"), c)
+ n, err := r.Read(buf)
+ if err != nil {
+ t.Errorf("read: %v", err)
+ } else if n != 12 || string(buf[0:12]) != "hello, world" {
+ t.Errorf("bad read: got %q", buf[0:n])
+ }
+ <-c
+ r.Close()
+ w.Close()
+}
+
+func reader(t *testing.T, r Reader, c chan int) {
+ var buf = make([]byte, 64)
+ for {
+ n, err := r.Read(buf)
+ if err == os.EOF {
+ c <- 0
+ break
+ }
+ if err != nil {
+ t.Errorf("read: %v", err)
+ }
+ c <- n
+ }
+}
+
+// Test a sequence of read/write pairs.
+func TestPipe2(t *testing.T) {
+ c := make(chan int)
+ r, w := Pipe()
+ go reader(t, r, c)
+ var buf = make([]byte, 64)
+ for i := 0; i < 5; i++ {
+ p := buf[0 : 5+i*10]
+ n, err := w.Write(p)
+ if n != len(p) {
+ t.Errorf("wrote %d, got %d", len(p), n)
+ }
+ if err != nil {
+ t.Errorf("write: %v", err)
+ }
+ nn := <-c
+ if nn != n {
+ t.Errorf("wrote %d, read got %d", n, nn)
+ }
+ }
+ w.Close()
+ nn := <-c
+ if nn != 0 {
+ t.Errorf("final read got %d", nn)
+ }
+}
+
+type pipeReturn struct {
+ n int
+ err os.Error
+}
+
+// Test a large write that requires multiple reads to satisfy.
+func writer(w WriteCloser, buf []byte, c chan pipeReturn) {
+ n, err := w.Write(buf)
+ w.Close()
+ c <- pipeReturn{n, err}
+}
+
+func TestPipe3(t *testing.T) {
+ c := make(chan pipeReturn)
+ r, w := Pipe()
+ var wdat = make([]byte, 128)
+ for i := 0; i < len(wdat); i++ {
+ wdat[i] = byte(i)
+ }
+ go writer(w, wdat, c)
+ var rdat = make([]byte, 1024)
+ tot := 0
+ for n := 1; n <= 256; n *= 2 {
+ nn, err := r.Read(rdat[tot : tot+n])
+ if err != nil && err != os.EOF {
+ t.Fatalf("read: %v", err)
+ }
+
+ // only final two reads should be short - 1 byte, then 0
+ expect := n
+ if n == 128 {
+ expect = 1
+ } else if n == 256 {
+ expect = 0
+ if err != os.EOF {
+ t.Fatalf("read at end: %v", err)
+ }
+ }
+ if nn != expect {
+ t.Fatalf("read %d, expected %d, got %d", n, expect, nn)
+ }
+ tot += nn
+ }
+ pr := <-c
+ if pr.n != 128 || pr.err != nil {
+ t.Fatalf("write 128: %d, %v", pr.n, pr.err)
+ }
+ if tot != 128 {
+ t.Fatalf("total read %d != 128", tot)
+ }
+ for i := 0; i < 128; i++ {
+ if rdat[i] != byte(i) {
+ t.Fatalf("rdat[%d] = %d", i, rdat[i])
+ }
+ }
+}
+
+// Test read after/before writer close.
+
+type closer interface {
+ CloseWithError(os.Error) os.Error
+ Close() os.Error
+}
+
+type pipeTest struct {
+ async bool
+ err os.Error
+ closeWithError bool
+}
+
+func (p pipeTest) String() string {
+ return fmt.Sprintf("async=%v err=%v closeWithError=%v", p.async, p.err, p.closeWithError)
+}
+
+var pipeTests = []pipeTest{
+ {true, nil, false},
+ {true, nil, true},
+ {true, ErrShortWrite, true},
+ {false, nil, false},
+ {false, nil, true},
+ {false, ErrShortWrite, true},
+}
+
+func delayClose(t *testing.T, cl closer, ch chan int, tt pipeTest) {
+ time.Sleep(1e6) // 1 ms
+ var err os.Error
+ if tt.closeWithError {
+ err = cl.CloseWithError(tt.err)
+ } else {
+ err = cl.Close()
+ }
+ if err != nil {
+ t.Errorf("delayClose: %v", err)
+ }
+ ch <- 0
+}
+
+func TestPipeReadClose(t *testing.T) {
+ for _, tt := range pipeTests {
+ c := make(chan int, 1)
+ r, w := Pipe()
+ if tt.async {
+ go delayClose(t, w, c, tt)
+ } else {
+ delayClose(t, w, c, tt)
+ }
+ var buf = make([]byte, 64)
+ n, err := r.Read(buf)
+ <-c
+ want := tt.err
+ if want == nil {
+ want = os.EOF
+ }
+ if err != want {
+ t.Errorf("read from closed pipe: %v want %v", err, want)
+ }
+ if n != 0 {
+ t.Errorf("read on closed pipe returned %d", n)
+ }
+ if err = r.Close(); err != nil {
+ t.Errorf("r.Close: %v", err)
+ }
+ }
+}
+
+// Test close on Read side during Read.
+func TestPipeReadClose2(t *testing.T) {
+ c := make(chan int, 1)
+ r, _ := Pipe()
+ go delayClose(t, r, c, pipeTest{})
+ n, err := r.Read(make([]byte, 64))
+ <-c
+ if n != 0 || err != os.EINVAL {
+ t.Errorf("read from closed pipe: %v, %v want %v, %v", n, err, 0, os.EINVAL)
+ }
+}
+
+// Test write after/before reader close.
+
+func TestPipeWriteClose(t *testing.T) {
+ for _, tt := range pipeTests {
+ c := make(chan int, 1)
+ r, w := Pipe()
+ if tt.async {
+ go delayClose(t, r, c, tt)
+ } else {
+ delayClose(t, r, c, tt)
+ }
+ n, err := WriteString(w, "hello, world")
+ <-c
+ expect := tt.err
+ if expect == nil {
+ expect = os.EPIPE
+ }
+ if err != expect {
+ t.Errorf("write on closed pipe: %v want %v", err, expect)
+ }
+ if n != 0 {
+ t.Errorf("write on closed pipe returned %d", n)
+ }
+ if err = w.Close(); err != nil {
+ t.Errorf("w.Close: %v", err)
+ }
+ }
+}
+
+func TestWriteEmpty(t *testing.T) {
+ r, w := Pipe()
+ go func() {
+ w.Write([]byte{})
+ w.Close()
+ }()
+ var b [2]byte
+ ReadFull(r, b[0:2])
+ r.Close()
+}
+
+func TestWriteNil(t *testing.T) {
+ r, w := Pipe()
+ go func() {
+ w.Write(nil)
+ w.Close()
+ }()
+ var b [2]byte
+ ReadFull(r, b[0:2])
+ r.Close()
+}
diff --git a/libgo/go/json/decode.go b/libgo/go/json/decode.go
new file mode 100644
index 000000000..ff91dd83c
--- /dev/null
+++ b/libgo/go/json/decode.go
@@ -0,0 +1,861 @@
+// 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.
+
+// Represents JSON data structure using native Go types: booleans, floats,
+// strings, arrays, and maps.
+
+package json
+
+import (
+ "container/vector"
+ "os"
+ "reflect"
+ "runtime"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf16"
+ "utf8"
+)
+
+// Unmarshal parses the JSON-encoded data and stores the result
+// in the value pointed to by v.
+//
+// Unmarshal traverses the value v recursively.
+// If an encountered value implements the Unmarshaler interface,
+// Unmarshal calls its UnmarshalJSON method with a well-formed
+// JSON encoding.
+//
+// Otherwise, Unmarshal uses the inverse of the encodings that
+// Marshal uses, allocating maps, slices, and pointers as necessary,
+// with the following additional rules:
+//
+// To unmarshal a JSON value into a nil interface value, the
+// type stored in the interface value is one of:
+//
+// bool, for JSON booleans
+// float64, for JSON numbers
+// string, for JSON strings
+// []interface{}, for JSON arrays
+// map[string]interface{}, for JSON objects
+// nil for JSON null
+//
+// If a JSON value is not appropriate for a given target type,
+// or if a JSON number overflows the target type, Unmarshal
+// skips that field and completes the unmarshalling as best it can.
+// If no more serious errors are encountered, Unmarshal returns
+// an UnmarshalTypeError describing the earliest such error.
+//
+func Unmarshal(data []byte, v interface{}) os.Error {
+ d := new(decodeState).init(data)
+
+ // Quick check for well-formedness.
+ // Avoids filling out half a data structure
+ // before discovering a JSON syntax error.
+ err := checkValid(data, &d.scan)
+ if err != nil {
+ return err
+ }
+
+ return d.unmarshal(v)
+}
+
+// Unmarshaler is the interface implemented by objects
+// that can unmarshal a JSON description of themselves.
+// The input can be assumed to be a valid JSON object
+// encoding. UnmarshalJSON must copy the JSON data
+// if it wishes to retain the data after returning.
+type Unmarshaler interface {
+ UnmarshalJSON([]byte) os.Error
+}
+
+
+// An UnmarshalTypeError describes a JSON value that was
+// not appropriate for a value of a specific Go type.
+type UnmarshalTypeError struct {
+ Value string // description of JSON value - "bool", "array", "number -5"
+ Type reflect.Type // type of Go value it could not be assigned to
+}
+
+func (e *UnmarshalTypeError) String() string {
+ return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
+}
+
+// An UnmarshalFieldError describes a JSON object key that
+// led to an unexported (and therefore unwritable) struct field.
+type UnmarshalFieldError struct {
+ Key string
+ Type *reflect.StructType
+ Field reflect.StructField
+}
+
+func (e *UnmarshalFieldError) String() string {
+ return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
+}
+
+// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
+// (The argument to Unmarshal must be a non-nil pointer.)
+type InvalidUnmarshalError struct {
+ Type reflect.Type
+}
+
+func (e *InvalidUnmarshalError) String() string {
+ if e.Type == nil {
+ return "json: Unmarshal(nil)"
+ }
+
+ if _, ok := e.Type.(*reflect.PtrType); !ok {
+ return "json: Unmarshal(non-pointer " + e.Type.String() + ")"
+ }
+ return "json: Unmarshal(nil " + e.Type.String() + ")"
+}
+
+func (d *decodeState) unmarshal(v interface{}) (err os.Error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ err = r.(os.Error)
+ }
+ }()
+
+ rv := reflect.NewValue(v)
+ pv, ok := rv.(*reflect.PtrValue)
+ if !ok || pv.IsNil() {
+ return &InvalidUnmarshalError{reflect.Typeof(v)}
+ }
+
+ d.scan.reset()
+ // We decode rv not pv.Elem because the Unmarshaler interface
+ // test must be applied at the top level of the value.
+ d.value(rv)
+ return d.savedError
+}
+
+// decodeState represents the state while decoding a JSON value.
+type decodeState struct {
+ data []byte
+ off int // read offset in data
+ scan scanner
+ nextscan scanner // for calls to nextValue
+ savedError os.Error
+}
+
+// errPhase is used for errors that should not happen unless
+// there is a bug in the JSON decoder or something is editing
+// the data slice while the decoder executes.
+var errPhase = os.NewError("JSON decoder out of sync - data changing underfoot?")
+
+func (d *decodeState) init(data []byte) *decodeState {
+ d.data = data
+ d.off = 0
+ d.savedError = nil
+ return d
+}
+
+// error aborts the decoding by panicking with err.
+func (d *decodeState) error(err os.Error) {
+ panic(err)
+}
+
+// saveError saves the first err it is called with,
+// for reporting at the end of the unmarshal.
+func (d *decodeState) saveError(err os.Error) {
+ if d.savedError == nil {
+ d.savedError = err
+ }
+}
+
+// next cuts off and returns the next full JSON value in d.data[d.off:].
+// The next value is known to be an object or array, not a literal.
+func (d *decodeState) next() []byte {
+ c := d.data[d.off]
+ item, rest, err := nextValue(d.data[d.off:], &d.nextscan)
+ if err != nil {
+ d.error(err)
+ }
+ d.off = len(d.data) - len(rest)
+
+ // Our scanner has seen the opening brace/bracket
+ // and thinks we're still in the middle of the object.
+ // invent a closing brace/bracket to get it out.
+ if c == '{' {
+ d.scan.step(&d.scan, '}')
+ } else {
+ d.scan.step(&d.scan, ']')
+ }
+
+ return item
+}
+
+// scanWhile processes bytes in d.data[d.off:] until it
+// receives a scan code not equal to op.
+// It updates d.off and returns the new scan code.
+func (d *decodeState) scanWhile(op int) int {
+ var newOp int
+ for {
+ if d.off >= len(d.data) {
+ newOp = d.scan.eof()
+ d.off = len(d.data) + 1 // mark processed EOF with len+1
+ } else {
+ c := int(d.data[d.off])
+ d.off++
+ newOp = d.scan.step(&d.scan, c)
+ }
+ if newOp != op {
+ break
+ }
+ }
+ return newOp
+}
+
+// value decodes a JSON value from d.data[d.off:] into the value.
+// it updates d.off to point past the decoded value.
+func (d *decodeState) value(v reflect.Value) {
+ if v == nil {
+ _, rest, err := nextValue(d.data[d.off:], &d.nextscan)
+ if err != nil {
+ d.error(err)
+ }
+ d.off = len(d.data) - len(rest)
+
+ // d.scan thinks we're still at the beginning of the item.
+ // Feed in an empty string - the shortest, simplest value -
+ // so that it knows we got to the end of the value.
+ if d.scan.step == stateRedo {
+ panic("redo")
+ }
+ d.scan.step(&d.scan, '"')
+ d.scan.step(&d.scan, '"')
+ return
+ }
+
+ switch op := d.scanWhile(scanSkipSpace); op {
+ default:
+ d.error(errPhase)
+
+ case scanBeginArray:
+ d.array(v)
+
+ case scanBeginObject:
+ d.object(v)
+
+ case scanBeginLiteral:
+ d.literal(v)
+ }
+}
+
+// indirect walks down v allocating pointers as needed,
+// until it gets to a non-pointer.
+// if it encounters an Unmarshaler, indirect stops and returns that.
+// if wantptr is true, indirect stops at the last pointer.
+func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, reflect.Value) {
+ for {
+ var isUnmarshaler bool
+ if v.Type().NumMethod() > 0 {
+ // Remember that this is an unmarshaler,
+ // but wait to return it until after allocating
+ // the pointer (if necessary).
+ _, isUnmarshaler = v.Interface().(Unmarshaler)
+ }
+
+ if iv, ok := v.(*reflect.InterfaceValue); ok && !iv.IsNil() {
+ v = iv.Elem()
+ continue
+ }
+ pv, ok := v.(*reflect.PtrValue)
+ if !ok {
+ break
+ }
+ _, isptrptr := pv.Elem().(*reflect.PtrValue)
+ if !isptrptr && wantptr && !isUnmarshaler {
+ return nil, pv
+ }
+ if pv.IsNil() {
+ pv.PointTo(reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem()))
+ }
+ if isUnmarshaler {
+ // Using v.Interface().(Unmarshaler)
+ // here means that we have to use a pointer
+ // as the struct field. We cannot use a value inside
+ // a pointer to a struct, because in that case
+ // v.Interface() is the value (x.f) not the pointer (&x.f).
+ // This is an unfortunate consequence of reflect.
+ // An alternative would be to look up the
+ // UnmarshalJSON method and return a FuncValue.
+ return v.Interface().(Unmarshaler), nil
+ }
+ v = pv.Elem()
+ }
+ return nil, v
+}
+
+// array consumes an array from d.data[d.off-1:], decoding into the value v.
+// the first byte of the array ('[') has been read already.
+func (d *decodeState) array(v reflect.Value) {
+ // Check for unmarshaler.
+ unmarshaler, pv := d.indirect(v, false)
+ if unmarshaler != nil {
+ d.off--
+ err := unmarshaler.UnmarshalJSON(d.next())
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ // Decoding into nil interface? Switch to non-reflect code.
+ iv, ok := v.(*reflect.InterfaceValue)
+ if ok {
+ iv.Set(reflect.NewValue(d.arrayInterface()))
+ return
+ }
+
+ // Check type of target.
+ av, ok := v.(reflect.ArrayOrSliceValue)
+ if !ok {
+ d.saveError(&UnmarshalTypeError{"array", v.Type()})
+ d.off--
+ d.next()
+ return
+ }
+
+ sv, _ := v.(*reflect.SliceValue)
+
+ i := 0
+ for {
+ // Look ahead for ] - can only happen on first iteration.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+
+ // Back up so d.value can have the byte we just read.
+ d.off--
+ d.scan.undo(op)
+
+ // Get element of array, growing if necessary.
+ if i >= av.Cap() && sv != nil {
+ newcap := sv.Cap() + sv.Cap()/2
+ if newcap < 4 {
+ newcap = 4
+ }
+ newv := reflect.MakeSlice(sv.Type().(*reflect.SliceType), sv.Len(), newcap)
+ reflect.Copy(newv, sv)
+ sv.Set(newv)
+ }
+ if i >= av.Len() && sv != nil {
+ // Must be slice; gave up on array during i >= av.Cap().
+ sv.SetLen(i + 1)
+ }
+
+ // Decode into element.
+ if i < av.Len() {
+ d.value(av.Elem(i))
+ } else {
+ // Ran out of fixed array: skip.
+ d.value(nil)
+ }
+ i++
+
+ // Next token must be , or ].
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+ if op != scanArrayValue {
+ d.error(errPhase)
+ }
+ }
+ if i < av.Len() {
+ if sv == nil {
+ // Array. Zero the rest.
+ z := reflect.MakeZero(av.Type().(*reflect.ArrayType).Elem())
+ for ; i < av.Len(); i++ {
+ av.Elem(i).SetValue(z)
+ }
+ } else {
+ sv.SetLen(i)
+ }
+ }
+}
+
+// matchName returns true if key should be written to a field named name.
+func matchName(key, name string) bool {
+ return strings.ToLower(key) == strings.ToLower(name)
+}
+
+// object consumes an object from d.data[d.off-1:], decoding into the value v.
+// the first byte of the object ('{') has been read already.
+func (d *decodeState) object(v reflect.Value) {
+ // Check for unmarshaler.
+ unmarshaler, pv := d.indirect(v, false)
+ if unmarshaler != nil {
+ d.off--
+ err := unmarshaler.UnmarshalJSON(d.next())
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ // Decoding into nil interface? Switch to non-reflect code.
+ iv, ok := v.(*reflect.InterfaceValue)
+ if ok {
+ iv.Set(reflect.NewValue(d.objectInterface()))
+ return
+ }
+
+ // Check type of target: struct or map[string]T
+ var (
+ mv *reflect.MapValue
+ sv *reflect.StructValue
+ )
+ switch v := v.(type) {
+ case *reflect.MapValue:
+ // map must have string type
+ t := v.Type().(*reflect.MapType)
+ if t.Key() != reflect.Typeof("") {
+ d.saveError(&UnmarshalTypeError{"object", v.Type()})
+ break
+ }
+ mv = v
+ if mv.IsNil() {
+ mv.SetValue(reflect.MakeMap(t))
+ }
+ case *reflect.StructValue:
+ sv = v
+ default:
+ d.saveError(&UnmarshalTypeError{"object", v.Type()})
+ }
+
+ if mv == nil && sv == nil {
+ d.off--
+ d.next() // skip over { } in input
+ return
+ }
+
+ for {
+ // Read opening " of string key or closing }.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ // closing } - can only happen on first iteration.
+ break
+ }
+ if op != scanBeginLiteral {
+ d.error(errPhase)
+ }
+
+ // Read string key.
+ start := d.off - 1
+ op = d.scanWhile(scanContinue)
+ item := d.data[start : d.off-1]
+ key, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+
+ // Figure out field corresponding to key.
+ var subv reflect.Value
+ if mv != nil {
+ subv = reflect.MakeZero(mv.Type().(*reflect.MapType).Elem())
+ } else {
+ var f reflect.StructField
+ var ok bool
+ // First try for field with that tag.
+ st := sv.Type().(*reflect.StructType)
+ for i := 0; i < sv.NumField(); i++ {
+ f = st.Field(i)
+ if f.Tag == key {
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ // Second, exact match.
+ f, ok = st.FieldByName(key)
+ }
+ if !ok {
+ // Third, case-insensitive match.
+ f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
+ }
+
+ // Extract value; name must be exported.
+ if ok {
+ if f.PkgPath != "" {
+ d.saveError(&UnmarshalFieldError{key, st, f})
+ } else {
+ subv = sv.FieldByIndex(f.Index)
+ }
+ }
+ }
+
+ // Read : before value.
+ if op == scanSkipSpace {
+ op = d.scanWhile(scanSkipSpace)
+ }
+ if op != scanObjectKey {
+ d.error(errPhase)
+ }
+
+ // Read value.
+ d.value(subv)
+
+ // Write value back to map;
+ // if using struct, subv points into struct already.
+ if mv != nil {
+ mv.SetElem(reflect.NewValue(key), subv)
+ }
+
+ // Next token must be , or }.
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ break
+ }
+ if op != scanObjectValue {
+ d.error(errPhase)
+ }
+ }
+}
+
+// literal consumes a literal from d.data[d.off-1:], decoding into the value v.
+// The first byte of the literal has been read already
+// (that's how the caller knows it's a literal).
+func (d *decodeState) literal(v reflect.Value) {
+ // All bytes inside literal return scanContinue op code.
+ start := d.off - 1
+ op := d.scanWhile(scanContinue)
+
+ // Scan read one byte too far; back up.
+ d.off--
+ d.scan.undo(op)
+ item := d.data[start:d.off]
+
+ // Check for unmarshaler.
+ wantptr := item[0] == 'n' // null
+ unmarshaler, pv := d.indirect(v, wantptr)
+ if unmarshaler != nil {
+ err := unmarshaler.UnmarshalJSON(item)
+ if err != nil {
+ d.error(err)
+ }
+ return
+ }
+ v = pv
+
+ switch c := item[0]; c {
+ case 'n': // null
+ switch v.(type) {
+ default:
+ d.saveError(&UnmarshalTypeError{"null", v.Type()})
+ case *reflect.InterfaceValue, *reflect.PtrValue, *reflect.MapValue:
+ v.SetValue(nil)
+ }
+
+ case 't', 'f': // true, false
+ value := c == 't'
+ switch v := v.(type) {
+ default:
+ d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+ case *reflect.BoolValue:
+ v.Set(value)
+ case *reflect.InterfaceValue:
+ v.Set(reflect.NewValue(value))
+ }
+
+ case '"': // string
+ s, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+ switch v := v.(type) {
+ default:
+ d.saveError(&UnmarshalTypeError{"string", v.Type()})
+ case *reflect.StringValue:
+ v.Set(s)
+ case *reflect.InterfaceValue:
+ v.Set(reflect.NewValue(s))
+ }
+
+ default: // number
+ if c != '-' && (c < '0' || c > '9') {
+ d.error(errPhase)
+ }
+ s := string(item)
+ switch v := v.(type) {
+ default:
+ d.error(&UnmarshalTypeError{"number", v.Type()})
+ case *reflect.InterfaceValue:
+ n, err := strconv.Atof64(s)
+ if err != nil {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.Set(reflect.NewValue(n))
+
+ case *reflect.IntValue:
+ n, err := strconv.Atoi64(s)
+ if err != nil || v.Overflow(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.Set(n)
+
+ case *reflect.UintValue:
+ n, err := strconv.Atoui64(s)
+ if err != nil || v.Overflow(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.Set(n)
+
+ case *reflect.FloatValue:
+ n, err := strconv.AtofN(s, v.Type().Bits())
+ if err != nil || v.Overflow(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ break
+ }
+ v.Set(n)
+ }
+ }
+}
+
+// The xxxInterface routines build up a value to be stored
+// in an empty interface. They are not strictly necessary,
+// but they avoid the weight of reflection in this common case.
+
+// valueInterface is like value but returns interface{}
+func (d *decodeState) valueInterface() interface{} {
+ switch d.scanWhile(scanSkipSpace) {
+ default:
+ d.error(errPhase)
+ case scanBeginArray:
+ return d.arrayInterface()
+ case scanBeginObject:
+ return d.objectInterface()
+ case scanBeginLiteral:
+ return d.literalInterface()
+ }
+ panic("unreachable")
+}
+
+// arrayInterface is like array but returns []interface{}.
+func (d *decodeState) arrayInterface() []interface{} {
+ var v vector.Vector
+ for {
+ // Look ahead for ] - can only happen on first iteration.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+
+ // Back up so d.value can have the byte we just read.
+ d.off--
+ d.scan.undo(op)
+
+ v.Push(d.valueInterface())
+
+ // Next token must be , or ].
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndArray {
+ break
+ }
+ if op != scanArrayValue {
+ d.error(errPhase)
+ }
+ }
+ return v
+}
+
+// objectInterface is like object but returns map[string]interface{}.
+func (d *decodeState) objectInterface() map[string]interface{} {
+ m := make(map[string]interface{})
+ for {
+ // Read opening " of string key or closing }.
+ op := d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ // closing } - can only happen on first iteration.
+ break
+ }
+ if op != scanBeginLiteral {
+ d.error(errPhase)
+ }
+
+ // Read string key.
+ start := d.off - 1
+ op = d.scanWhile(scanContinue)
+ item := d.data[start : d.off-1]
+ key, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+
+ // Read : before value.
+ if op == scanSkipSpace {
+ op = d.scanWhile(scanSkipSpace)
+ }
+ if op != scanObjectKey {
+ d.error(errPhase)
+ }
+
+ // Read value.
+ m[key] = d.valueInterface()
+
+ // Next token must be , or }.
+ op = d.scanWhile(scanSkipSpace)
+ if op == scanEndObject {
+ break
+ }
+ if op != scanObjectValue {
+ d.error(errPhase)
+ }
+ }
+ return m
+}
+
+
+// literalInterface is like literal but returns an interface value.
+func (d *decodeState) literalInterface() interface{} {
+ // All bytes inside literal return scanContinue op code.
+ start := d.off - 1
+ op := d.scanWhile(scanContinue)
+
+ // Scan read one byte too far; back up.
+ d.off--
+ d.scan.undo(op)
+ item := d.data[start:d.off]
+
+ switch c := item[0]; c {
+ case 'n': // null
+ return nil
+
+ case 't', 'f': // true, false
+ return c == 't'
+
+ case '"': // string
+ s, ok := unquote(item)
+ if !ok {
+ d.error(errPhase)
+ }
+ return s
+
+ default: // number
+ if c != '-' && (c < '0' || c > '9') {
+ d.error(errPhase)
+ }
+ n, err := strconv.Atof64(string(item))
+ if err != nil {
+ d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.Typeof(0.0)})
+ }
+ return n
+ }
+ panic("unreachable")
+}
+
+// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
+// or it returns -1.
+func getu4(s []byte) int {
+ if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
+ return -1
+ }
+ rune, err := strconv.Btoui64(string(s[2:6]), 16)
+ if err != nil {
+ return -1
+ }
+ return int(rune)
+}
+
+// unquote converts a quoted JSON string literal s into an actual string t.
+// The rules are different than for Go, so cannot use strconv.Unquote.
+func unquote(s []byte) (t string, ok bool) {
+ if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
+ return
+ }
+ b := make([]byte, len(s)+2*utf8.UTFMax)
+ w := 0
+ for r := 1; r < len(s)-1; {
+ // Out of room? Can only happen if s is full of
+ // malformed UTF-8 and we're replacing each
+ // byte with RuneError.
+ if w >= len(b)-2*utf8.UTFMax {
+ nb := make([]byte, (len(b)+utf8.UTFMax)*2)
+ copy(nb, b[0:w])
+ b = nb
+ }
+ switch c := s[r]; {
+ case c == '\\':
+ r++
+ if r >= len(s)-1 {
+ return
+ }
+ switch s[r] {
+ default:
+ return
+ case '"', '\\', '/', '\'':
+ b[w] = s[r]
+ r++
+ w++
+ case 'b':
+ b[w] = '\b'
+ r++
+ w++
+ case 'f':
+ b[w] = '\f'
+ r++
+ w++
+ case 'n':
+ b[w] = '\n'
+ r++
+ w++
+ case 'r':
+ b[w] = '\r'
+ r++
+ w++
+ case 't':
+ b[w] = '\t'
+ r++
+ w++
+ case 'u':
+ r--
+ rune := getu4(s[r:])
+ if rune < 0 {
+ return
+ }
+ r += 6
+ if utf16.IsSurrogate(rune) {
+ rune1 := getu4(s[r:])
+ if dec := utf16.DecodeRune(rune, rune1); dec != unicode.ReplacementChar {
+ // A valid pair; consume.
+ r += 6
+ w += utf8.EncodeRune(b[w:], dec)
+ break
+ }
+ // Invalid surrogate; fall back to replacement rune.
+ rune = unicode.ReplacementChar
+ }
+ w += utf8.EncodeRune(b[w:], rune)
+ }
+
+ // Quote, control characters are invalid.
+ case c == '"', c < ' ':
+ return
+
+ // ASCII
+ case c < utf8.RuneSelf:
+ b[w] = c
+ r++
+ w++
+
+ // Coerce to well-formed UTF-8.
+ default:
+ rune, size := utf8.DecodeRune(s[r:])
+ r += size
+ w += utf8.EncodeRune(b[w:], rune)
+ }
+ }
+ return string(b[0:w]), true
+}
diff --git a/libgo/go/json/decode_test.go b/libgo/go/json/decode_test.go
new file mode 100644
index 000000000..9cb27af41
--- /dev/null
+++ b/libgo/go/json/decode_test.go
@@ -0,0 +1,517 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+ "bytes"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type T struct {
+ X string
+ Y int
+}
+
+type tx struct {
+ x int
+}
+
+var txType = reflect.Typeof((*tx)(nil)).(*reflect.PtrType).Elem().(*reflect.StructType)
+
+// A type that can unmarshal itself.
+
+type unmarshaler struct {
+ T bool
+}
+
+func (u *unmarshaler) UnmarshalJSON(b []byte) os.Error {
+ *u = unmarshaler{true} // All we need to see that UnmarshalJson is called.
+ return nil
+}
+
+var (
+ um0, um1 unmarshaler // target2 of unmarshaling
+ ump = &um1
+ umtrue = unmarshaler{true}
+)
+
+
+type unmarshalTest struct {
+ in string
+ ptr interface{}
+ out interface{}
+ err os.Error
+}
+
+var unmarshalTests = []unmarshalTest{
+ // basic types
+ {`true`, new(bool), true, nil},
+ {`1`, new(int), 1, nil},
+ {`1.2`, new(float64), 1.2, nil},
+ {`-5`, new(int16), int16(-5), nil},
+ {`"a\u1234"`, new(string), "a\u1234", nil},
+ {`"http:\/\/"`, new(string), "http://", nil},
+ {`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil},
+ {`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil},
+ {"null", new(interface{}), nil, nil},
+ {`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.Typeof("")}},
+ {`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
+
+ // syntax errors
+ {`{"X": "foo", "Y"}`, nil, nil, SyntaxError("invalid character '}' after object key")},
+
+ // composite tests
+ {allValueIndent, new(All), allValue, nil},
+ {allValueCompact, new(All), allValue, nil},
+ {allValueIndent, new(*All), &allValue, nil},
+ {allValueCompact, new(*All), &allValue, nil},
+ {pallValueIndent, new(All), pallValue, nil},
+ {pallValueCompact, new(All), pallValue, nil},
+ {pallValueIndent, new(*All), &pallValue, nil},
+ {pallValueCompact, new(*All), &pallValue, nil},
+
+ // unmarshal interface test
+ {`{"T":false}`, &um0, umtrue, nil}, // use "false" so test will fail if custom unmarshaler is not called
+ {`{"T":false}`, &ump, &umtrue, nil},
+}
+
+func TestMarshal(t *testing.T) {
+ b, err := Marshal(allValue)
+ if err != nil {
+ t.Fatalf("Marshal allValue: %v", err)
+ }
+ if string(b) != allValueCompact {
+ t.Errorf("Marshal allValueCompact")
+ diff(t, b, []byte(allValueCompact))
+ return
+ }
+
+ b, err = Marshal(pallValue)
+ if err != nil {
+ t.Fatalf("Marshal pallValue: %v", err)
+ }
+ if string(b) != pallValueCompact {
+ t.Errorf("Marshal pallValueCompact")
+ diff(t, b, []byte(pallValueCompact))
+ return
+ }
+}
+
+func TestMarshalBadUTF8(t *testing.T) {
+ s := "hello\xffworld"
+ b, err := Marshal(s)
+ if err == nil {
+ t.Fatal("Marshal bad UTF8: no error")
+ }
+ if len(b) != 0 {
+ t.Fatal("Marshal returned data")
+ }
+ if _, ok := err.(*InvalidUTF8Error); !ok {
+ t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err, err)
+ }
+}
+
+func TestUnmarshal(t *testing.T) {
+ var scan scanner
+ for i, tt := range unmarshalTests {
+ in := []byte(tt.in)
+ if err := checkValid(in, &scan); err != nil {
+ if !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("#%d: checkValid: %v", i, err)
+ continue
+ }
+ }
+ if tt.ptr == nil {
+ continue
+ }
+ // v = new(right-type)
+ v := reflect.NewValue(tt.ptr).(*reflect.PtrValue)
+ v.PointTo(reflect.MakeZero(v.Type().(*reflect.PtrType).Elem()))
+ if err := Unmarshal([]byte(in), v.Interface()); !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("#%d: %v want %v", i, err, tt.err)
+ continue
+ }
+ if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
+ t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
+ data, _ := Marshal(v.Elem().Interface())
+ println(string(data))
+ data, _ = Marshal(tt.out)
+ println(string(data))
+ return
+ continue
+ }
+ }
+}
+
+func TestUnmarshalMarshal(t *testing.T) {
+ var v interface{}
+ if err := Unmarshal(jsonBig, &v); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ b, err := Marshal(v)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ if bytes.Compare(jsonBig, b) != 0 {
+ t.Errorf("Marshal jsonBig")
+ diff(t, b, jsonBig)
+ return
+ }
+}
+
+type Xint struct {
+ X int
+}
+
+func TestUnmarshalInterface(t *testing.T) {
+ var xint Xint
+ var i interface{} = &xint
+ if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if xint.X != 1 {
+ t.Fatalf("Did not write to xint")
+ }
+}
+
+func TestUnmarshalPtrPtr(t *testing.T) {
+ var xint Xint
+ pxint := &xint
+ if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if xint.X != 1 {
+ t.Fatalf("Did not write to xint")
+ }
+}
+
+func TestHTMLEscape(t *testing.T) {
+ b, err := MarshalForHTML("foobarbaz<>&quux")
+ if err != nil {
+ t.Fatalf("MarshalForHTML error: %v", err)
+ }
+ if !bytes.Equal(b, []byte(`"foobarbaz\u003c\u003e\u0026quux"`)) {
+ t.Fatalf("Unexpected encoding of \"<>&\": %s", b)
+ }
+}
+
+func noSpace(c int) int {
+ if isSpace(c) {
+ return -1
+ }
+ return c
+}
+
+type All struct {
+ Bool bool
+ Int int
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint uint
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ Uintptr uintptr
+ Float32 float32
+ Float64 float64
+
+ Foo string "bar"
+
+ PBool *bool
+ PInt *int
+ PInt8 *int8
+ PInt16 *int16
+ PInt32 *int32
+ PInt64 *int64
+ PUint *uint
+ PUint8 *uint8
+ PUint16 *uint16
+ PUint32 *uint32
+ PUint64 *uint64
+ PUintptr *uintptr
+ PFloat32 *float32
+ PFloat64 *float64
+
+ String string
+ PString *string
+
+ Map map[string]Small
+ MapP map[string]*Small
+ PMap *map[string]Small
+ PMapP *map[string]*Small
+
+ EmptyMap map[string]Small
+ NilMap map[string]Small
+
+ Slice []Small
+ SliceP []*Small
+ PSlice *[]Small
+ PSliceP *[]*Small
+
+ EmptySlice []Small
+ NilSlice []Small
+
+ StringSlice []string
+ ByteSlice []byte
+
+ Small Small
+ PSmall *Small
+ PPSmall **Small
+
+ Interface interface{}
+ PInterface *interface{}
+
+ unexported int
+}
+
+type Small struct {
+ Tag string
+}
+
+var allValue = All{
+ Bool: true,
+ Int: 2,
+ Int8: 3,
+ Int16: 4,
+ Int32: 5,
+ Int64: 6,
+ Uint: 7,
+ Uint8: 8,
+ Uint16: 9,
+ Uint32: 10,
+ Uint64: 11,
+ Uintptr: 12,
+ Float32: 14.1,
+ Float64: 15.1,
+ Foo: "foo",
+ String: "16",
+ Map: map[string]Small{
+ "17": {Tag: "tag17"},
+ "18": {Tag: "tag18"},
+ },
+ MapP: map[string]*Small{
+ "19": &Small{Tag: "tag19"},
+ "20": nil,
+ },
+ EmptyMap: map[string]Small{},
+ Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}},
+ SliceP: []*Small{&Small{Tag: "tag22"}, nil, &Small{Tag: "tag23"}},
+ EmptySlice: []Small{},
+ StringSlice: []string{"str24", "str25", "str26"},
+ ByteSlice: []byte{27, 28, 29},
+ Small: Small{Tag: "tag30"},
+ PSmall: &Small{Tag: "tag31"},
+ Interface: 5.2,
+}
+
+var pallValue = All{
+ PBool: &allValue.Bool,
+ PInt: &allValue.Int,
+ PInt8: &allValue.Int8,
+ PInt16: &allValue.Int16,
+ PInt32: &allValue.Int32,
+ PInt64: &allValue.Int64,
+ PUint: &allValue.Uint,
+ PUint8: &allValue.Uint8,
+ PUint16: &allValue.Uint16,
+ PUint32: &allValue.Uint32,
+ PUint64: &allValue.Uint64,
+ PUintptr: &allValue.Uintptr,
+ PFloat32: &allValue.Float32,
+ PFloat64: &allValue.Float64,
+ PString: &allValue.String,
+ PMap: &allValue.Map,
+ PMapP: &allValue.MapP,
+ PSlice: &allValue.Slice,
+ PSliceP: &allValue.SliceP,
+ PPSmall: &allValue.PSmall,
+ PInterface: &allValue.Interface,
+}
+
+var allValueIndent = `{
+ "Bool": true,
+ "Int": 2,
+ "Int8": 3,
+ "Int16": 4,
+ "Int32": 5,
+ "Int64": 6,
+ "Uint": 7,
+ "Uint8": 8,
+ "Uint16": 9,
+ "Uint32": 10,
+ "Uint64": 11,
+ "Uintptr": 12,
+ "Float32": 14.1,
+ "Float64": 15.1,
+ "bar": "foo",
+ "PBool": null,
+ "PInt": null,
+ "PInt8": null,
+ "PInt16": null,
+ "PInt32": null,
+ "PInt64": null,
+ "PUint": null,
+ "PUint8": null,
+ "PUint16": null,
+ "PUint32": null,
+ "PUint64": null,
+ "PUintptr": null,
+ "PFloat32": null,
+ "PFloat64": null,
+ "String": "16",
+ "PString": null,
+ "Map": {
+ "17": {
+ "Tag": "tag17"
+ },
+ "18": {
+ "Tag": "tag18"
+ }
+ },
+ "MapP": {
+ "19": {
+ "Tag": "tag19"
+ },
+ "20": null
+ },
+ "PMap": null,
+ "PMapP": null,
+ "EmptyMap": {},
+ "NilMap": null,
+ "Slice": [
+ {
+ "Tag": "tag20"
+ },
+ {
+ "Tag": "tag21"
+ }
+ ],
+ "SliceP": [
+ {
+ "Tag": "tag22"
+ },
+ null,
+ {
+ "Tag": "tag23"
+ }
+ ],
+ "PSlice": null,
+ "PSliceP": null,
+ "EmptySlice": [],
+ "NilSlice": [],
+ "StringSlice": [
+ "str24",
+ "str25",
+ "str26"
+ ],
+ "ByteSlice": [
+ 27,
+ 28,
+ 29
+ ],
+ "Small": {
+ "Tag": "tag30"
+ },
+ "PSmall": {
+ "Tag": "tag31"
+ },
+ "PPSmall": null,
+ "Interface": 5.2,
+ "PInterface": null
+}`
+
+var allValueCompact = strings.Map(noSpace, allValueIndent)
+
+var pallValueIndent = `{
+ "Bool": false,
+ "Int": 0,
+ "Int8": 0,
+ "Int16": 0,
+ "Int32": 0,
+ "Int64": 0,
+ "Uint": 0,
+ "Uint8": 0,
+ "Uint16": 0,
+ "Uint32": 0,
+ "Uint64": 0,
+ "Uintptr": 0,
+ "Float32": 0,
+ "Float64": 0,
+ "bar": "",
+ "PBool": true,
+ "PInt": 2,
+ "PInt8": 3,
+ "PInt16": 4,
+ "PInt32": 5,
+ "PInt64": 6,
+ "PUint": 7,
+ "PUint8": 8,
+ "PUint16": 9,
+ "PUint32": 10,
+ "PUint64": 11,
+ "PUintptr": 12,
+ "PFloat32": 14.1,
+ "PFloat64": 15.1,
+ "String": "",
+ "PString": "16",
+ "Map": null,
+ "MapP": null,
+ "PMap": {
+ "17": {
+ "Tag": "tag17"
+ },
+ "18": {
+ "Tag": "tag18"
+ }
+ },
+ "PMapP": {
+ "19": {
+ "Tag": "tag19"
+ },
+ "20": null
+ },
+ "EmptyMap": null,
+ "NilMap": null,
+ "Slice": [],
+ "SliceP": [],
+ "PSlice": [
+ {
+ "Tag": "tag20"
+ },
+ {
+ "Tag": "tag21"
+ }
+ ],
+ "PSliceP": [
+ {
+ "Tag": "tag22"
+ },
+ null,
+ {
+ "Tag": "tag23"
+ }
+ ],
+ "EmptySlice": [],
+ "NilSlice": [],
+ "StringSlice": [],
+ "ByteSlice": [],
+ "Small": {
+ "Tag": ""
+ },
+ "PSmall": null,
+ "PPSmall": {
+ "Tag": "tag31"
+ },
+ "Interface": null,
+ "PInterface": 5.2
+}`
+
+var pallValueCompact = strings.Map(noSpace, pallValueIndent)
diff --git a/libgo/go/json/encode.go b/libgo/go/json/encode.go
new file mode 100644
index 000000000..759b49dbe
--- /dev/null
+++ b/libgo/go/json/encode.go
@@ -0,0 +1,332 @@
+// 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.
+
+// The json package implements encoding and decoding of JSON objects as
+// defined in RFC 4627.
+package json
+
+import (
+ "os"
+ "bytes"
+ "reflect"
+ "runtime"
+ "sort"
+ "strconv"
+ "utf8"
+)
+
+// Marshal returns the JSON encoding of v.
+//
+// Marshal traverses the value v recursively.
+// If an encountered value implements the Marshaler interface,
+// Marshal calls its MarshalJSON method to produce JSON.
+//
+// Otherwise, Marshal uses the following type-dependent default encodings:
+//
+// Boolean values encode as JSON booleans.
+//
+// Floating point and integer values encode as JSON numbers.
+//
+// String values encode as JSON strings, with each invalid UTF-8 sequence
+// replaced by the encoding of the Unicode replacement character U+FFFD.
+//
+// Array and slice values encode as JSON arrays.
+//
+// Struct values encode as JSON objects. Each struct field becomes
+// a member of the object. By default the object's key name is the
+// struct field name converted to lower case. If the struct field
+// has a tag, that tag will be used as the name instead.
+// Only exported fields will be encoded.
+//
+// Map values encode as JSON objects.
+// The map's key type must be string; the object keys are used directly
+// as map keys.
+//
+// Pointer values encode as the value pointed to.
+// A nil pointer encodes as the null JSON object.
+//
+// Interface values encode as the value contained in the interface.
+// A nil interface value encodes as the null JSON object.
+//
+// Channel, complex, and function values cannot be encoded in JSON.
+// Attempting to encode such a value causes Marshal to return
+// an InvalidTypeError.
+//
+// JSON cannot represent cyclic data structures and Marshal does not
+// handle them. Passing cyclic structures to Marshal will result in
+// an infinite recursion.
+//
+func Marshal(v interface{}) ([]byte, os.Error) {
+ e := &encodeState{}
+ err := e.marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ return e.Bytes(), nil
+}
+
+// MarshalIndent is like Marshal but applies Indent to format the output.
+func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
+ b, err := Marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ var buf bytes.Buffer
+ err = Indent(&buf, b, prefix, indent)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// MarshalForHTML is like Marshal but applies HTMLEscape to the output.
+func MarshalForHTML(v interface{}) ([]byte, os.Error) {
+ b, err := Marshal(v)
+ if err != nil {
+ return nil, err
+ }
+ var buf bytes.Buffer
+ HTMLEscape(&buf, b)
+ return buf.Bytes(), nil
+}
+
+// HTMLEscape appends to dst the JSON-encoded src with <, >, and &
+// characters inside string literals changed to \u003c, \u003e, \u0026
+// so that the JSON will be safe to embed inside HTML <script> tags.
+// For historical reasons, web browsers don't honor standard HTML
+// escaping within <script> tags, so an alternative JSON encoding must
+// be used.
+func HTMLEscape(dst *bytes.Buffer, src []byte) {
+ // < > & can only appear in string literals,
+ // so just scan the string one byte at a time.
+ start := 0
+ for i, c := range src {
+ if c == '<' || c == '>' || c == '&' {
+ if start < i {
+ dst.Write(src[start:i])
+ }
+ dst.WriteString(`\u00`)
+ dst.WriteByte(hex[c>>4])
+ dst.WriteByte(hex[c&0xF])
+ start = i + 1
+ }
+ }
+ if start < len(src) {
+ dst.Write(src[start:])
+ }
+}
+
+// Marshaler is the interface implemented by objects that
+// can marshal themselves into valid JSON.
+type Marshaler interface {
+ MarshalJSON() ([]byte, os.Error)
+}
+
+type UnsupportedTypeError struct {
+ Type reflect.Type
+}
+
+func (e *UnsupportedTypeError) String() string {
+ return "json: unsupported type: " + e.Type.String()
+}
+
+type InvalidUTF8Error struct {
+ S string
+}
+
+func (e *InvalidUTF8Error) String() string {
+ return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
+}
+
+type MarshalerError struct {
+ Type reflect.Type
+ Error os.Error
+}
+
+func (e *MarshalerError) String() string {
+ return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Error.String()
+}
+
+type interfaceOrPtrValue interface {
+ IsNil() bool
+ Elem() reflect.Value
+}
+
+var hex = "0123456789abcdef"
+
+// An encodeState encodes JSON into a bytes.Buffer.
+type encodeState struct {
+ bytes.Buffer // accumulated output
+}
+
+func (e *encodeState) marshal(v interface{}) (err os.Error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ err = r.(os.Error)
+ }
+ }()
+ e.reflectValue(reflect.NewValue(v))
+ return nil
+}
+
+func (e *encodeState) error(err os.Error) {
+ panic(err)
+}
+
+func (e *encodeState) reflectValue(v reflect.Value) {
+ if v == nil {
+ e.WriteString("null")
+ return
+ }
+
+ if j, ok := v.Interface().(Marshaler); ok {
+ b, err := j.MarshalJSON()
+ if err == nil {
+ // copy JSON into buffer, checking validity.
+ err = Compact(&e.Buffer, b)
+ }
+ if err != nil {
+ e.error(&MarshalerError{v.Type(), err})
+ }
+ return
+ }
+
+ switch v := v.(type) {
+ case *reflect.BoolValue:
+ x := v.Get()
+ if x {
+ e.WriteString("true")
+ } else {
+ e.WriteString("false")
+ }
+
+ case *reflect.IntValue:
+ e.WriteString(strconv.Itoa64(v.Get()))
+
+ case *reflect.UintValue:
+ e.WriteString(strconv.Uitoa64(v.Get()))
+
+ case *reflect.FloatValue:
+ e.WriteString(strconv.FtoaN(v.Get(), 'g', -1, v.Type().Bits()))
+
+ case *reflect.StringValue:
+ e.string(v.Get())
+
+ case *reflect.StructValue:
+ e.WriteByte('{')
+ t := v.Type().(*reflect.StructType)
+ n := v.NumField()
+ first := true
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+ if f.PkgPath != "" {
+ continue
+ }
+ if first {
+ first = false
+ } else {
+ e.WriteByte(',')
+ }
+ if f.Tag != "" {
+ e.string(f.Tag)
+ } else {
+ e.string(f.Name)
+ }
+ e.WriteByte(':')
+ e.reflectValue(v.Field(i))
+ }
+ e.WriteByte('}')
+
+ case *reflect.MapValue:
+ if _, ok := v.Type().(*reflect.MapType).Key().(*reflect.StringType); !ok {
+ e.error(&UnsupportedTypeError{v.Type()})
+ }
+ if v.IsNil() {
+ e.WriteString("null")
+ break
+ }
+ e.WriteByte('{')
+ var sv stringValues = v.Keys()
+ sort.Sort(sv)
+ for i, k := range sv {
+ if i > 0 {
+ e.WriteByte(',')
+ }
+ e.string(k.(*reflect.StringValue).Get())
+ e.WriteByte(':')
+ e.reflectValue(v.Elem(k))
+ }
+ e.WriteByte('}')
+
+ case reflect.ArrayOrSliceValue:
+ e.WriteByte('[')
+ n := v.Len()
+ for i := 0; i < n; i++ {
+ if i > 0 {
+ e.WriteByte(',')
+ }
+ e.reflectValue(v.Elem(i))
+ }
+ e.WriteByte(']')
+
+ case interfaceOrPtrValue:
+ if v.IsNil() {
+ e.WriteString("null")
+ return
+ }
+ e.reflectValue(v.Elem())
+
+ default:
+ e.error(&UnsupportedTypeError{v.Type()})
+ }
+ return
+}
+
+// stringValues is a slice of reflect.Value holding *reflect.StringValue.
+// It implements the methods to sort by string.
+type stringValues []reflect.Value
+
+func (sv stringValues) Len() int { return len(sv) }
+func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
+func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
+func (sv stringValues) get(i int) string { return sv[i].(*reflect.StringValue).Get() }
+
+func (e *encodeState) string(s string) {
+ e.WriteByte('"')
+ start := 0
+ for i := 0; i < len(s); {
+ if b := s[i]; b < utf8.RuneSelf {
+ if 0x20 <= b && b != '\\' && b != '"' {
+ i++
+ continue
+ }
+ if start < i {
+ e.WriteString(s[start:i])
+ }
+ if b == '\\' || b == '"' {
+ e.WriteByte('\\')
+ e.WriteByte(b)
+ } else {
+ e.WriteString(`\u00`)
+ e.WriteByte(hex[b>>4])
+ e.WriteByte(hex[b&0xF])
+ }
+ i++
+ start = i
+ continue
+ }
+ c, size := utf8.DecodeRuneInString(s[i:])
+ if c == utf8.RuneError && size == 1 {
+ e.error(&InvalidUTF8Error{s})
+ }
+ i += size
+ }
+ if start < len(s) {
+ e.WriteString(s[start:])
+ }
+ e.WriteByte('"')
+}
diff --git a/libgo/go/json/indent.go b/libgo/go/json/indent.go
new file mode 100644
index 000000000..000da42f6
--- /dev/null
+++ b/libgo/go/json/indent.go
@@ -0,0 +1,116 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+ "bytes"
+ "os"
+)
+
+// Compact appends to dst the JSON-encoded src with
+// insignificant space characters elided.
+func Compact(dst *bytes.Buffer, src []byte) os.Error {
+ origLen := dst.Len()
+ var scan scanner
+ scan.reset()
+ start := 0
+ for i, c := range src {
+ v := scan.step(&scan, int(c))
+ if v >= scanSkipSpace {
+ if v == scanError {
+ break
+ }
+ if start < i {
+ dst.Write(src[start:i])
+ }
+ start = i + 1
+ }
+ }
+ if scan.eof() == scanError {
+ dst.Truncate(origLen)
+ return scan.err
+ }
+ if start < len(src) {
+ dst.Write(src[start:])
+ }
+ return nil
+}
+
+func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
+ dst.WriteByte('\n')
+ dst.WriteString(prefix)
+ for i := 0; i < depth; i++ {
+ dst.WriteString(indent)
+ }
+}
+
+// Indent appends to dst an indented form of the JSON-encoded src.
+// Each element in a JSON object or array begins on a new,
+// indented line beginning with prefix followed by one or more
+// copies of indent according to the indentation nesting.
+// The data appended to dst has no trailing newline, to make it easier
+// to embed inside other formatted JSON data.
+func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) os.Error {
+ origLen := dst.Len()
+ var scan scanner
+ scan.reset()
+ needIndent := false
+ depth := 0
+ for _, c := range src {
+ v := scan.step(&scan, int(c))
+ if v == scanSkipSpace {
+ continue
+ }
+ if v == scanError {
+ break
+ }
+ if needIndent && v != scanEndObject && v != scanEndArray {
+ needIndent = false
+ depth++
+ newline(dst, prefix, indent, depth)
+ }
+
+ // Emit semantically uninteresting bytes
+ // (in particular, punctuation in strings) unmodified.
+ if v == scanContinue {
+ dst.WriteByte(c)
+ continue
+ }
+
+ // Add spacing around real punctuation.
+ switch c {
+ case '{', '[':
+ // delay indent so that empty object and array are formatted as {} and [].
+ needIndent = true
+ dst.WriteByte(c)
+
+ case ',':
+ dst.WriteByte(c)
+ newline(dst, prefix, indent, depth)
+
+ case ':':
+ dst.WriteByte(c)
+ dst.WriteByte(' ')
+
+ case '}', ']':
+ if needIndent {
+ // suppress indent in empty object/array
+ needIndent = false
+ } else {
+ depth--
+ newline(dst, prefix, indent, depth)
+ }
+ dst.WriteByte(c)
+
+ default:
+ dst.WriteByte(c)
+ }
+ }
+ if scan.eof() == scanError {
+ dst.Truncate(origLen)
+ return scan.err
+ }
+ return nil
+}
diff --git a/libgo/go/json/scanner.go b/libgo/go/json/scanner.go
new file mode 100644
index 000000000..112c8f9c3
--- /dev/null
+++ b/libgo/go/json/scanner.go
@@ -0,0 +1,618 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+// JSON value parser state machine.
+// Just about at the limit of what is reasonable to write by hand.
+// Some parts are a bit tedious, but overall it nicely factors out the
+// otherwise common code from the multiple scanning functions
+// in this package (Compact, Indent, checkValid, nextValue, etc).
+//
+// This file starts with two simple examples using the scanner
+// before diving into the scanner itself.
+
+import (
+ "os"
+ "strconv"
+)
+
+// checkValid verifies that data is valid JSON-encoded data.
+// scan is passed in for use by checkValid to avoid an allocation.
+func checkValid(data []byte, scan *scanner) os.Error {
+ scan.reset()
+ for _, c := range data {
+ if scan.step(scan, int(c)) == scanError {
+ return scan.err
+ }
+ }
+ if scan.eof() == scanError {
+ return scan.err
+ }
+ return nil
+}
+
+// nextValue splits data after the next whole JSON value,
+// returning that value and the bytes that follow it as separate slices.
+// scan is passed in for use by nextValue to avoid an allocation.
+func nextValue(data []byte, scan *scanner) (value, rest []byte, err os.Error) {
+ scan.reset()
+ for i, c := range data {
+ v := scan.step(scan, int(c))
+ if v >= scanEnd {
+ switch v {
+ case scanError:
+ return nil, nil, scan.err
+ case scanEnd:
+ return data[0:i], data[i:], nil
+ }
+ }
+ }
+ if scan.eof() == scanError {
+ return nil, nil, scan.err
+ }
+ return data, nil, nil
+}
+
+// A SyntaxError is a description of a JSON syntax error.
+type SyntaxError string
+
+func (e SyntaxError) String() string { return string(e) }
+
+
+// A scanner is a JSON scanning state machine.
+// Callers call scan.reset() and then pass bytes in one at a time
+// by calling scan.step(&scan, c) for each byte.
+// The return value, referred to as an opcode, tells the
+// caller about significant parsing events like beginning
+// and ending literals, objects, and arrays, so that the
+// caller can follow along if it wishes.
+// The return value scanEnd indicates that a single top-level
+// JSON value has been completed, *before* the byte that
+// just got passed in. (The indication must be delayed in order
+// to recognize the end of numbers: is 123 a whole value or
+// the beginning of 12345e+6?).
+type scanner struct {
+ // The step is a func to be called to execute the next transition.
+ // Also tried using an integer constant and a single func
+ // with a switch, but using the func directly was 10% faster
+ // on a 64-bit Mac Mini, and it's nicer to read.
+ step func(*scanner, int) int
+
+ // Stack of what we're in the middle of - array values, object keys, object values.
+ parseState []int
+
+ // Error that happened, if any.
+ err os.Error
+
+ // 1-byte redo (see undo method)
+ redoCode int
+ redoState func(*scanner, int) int
+}
+
+// These values are returned by the state transition functions
+// assigned to scanner.state and the method scanner.eof.
+// They give details about the current state of the scan that
+// callers might be interested to know about.
+// It is okay to ignore the return value of any particular
+// call to scanner.state: if one call returns scanError,
+// every subsequent call will return scanError too.
+const (
+ // Continue.
+ scanContinue = iota // uninteresting byte
+ scanBeginLiteral // end implied by next result != scanContinue
+ scanBeginObject // begin object
+ scanObjectKey // just finished object key (string)
+ scanObjectValue // just finished non-last object value
+ scanEndObject // end object (implies scanObjectValue if possible)
+ scanBeginArray // begin array
+ scanArrayValue // just finished array value
+ scanEndArray // end array (implies scanArrayValue if possible)
+ scanSkipSpace // space byte; can skip; known to be last "continue" result
+
+ // Stop.
+ scanEnd // top-level value ended *before* this byte; known to be first "stop" result
+ scanError // hit an error, scanner.err.
+)
+
+// These values are stored in the parseState stack.
+// They give the current state of a composite value
+// being scanned. If the parser is inside a nested value
+// the parseState describes the nested state, outermost at entry 0.
+const (
+ parseObjectKey = iota // parsing object key (before colon)
+ parseObjectValue // parsing object value (after colon)
+ parseArrayValue // parsing array value
+)
+
+// reset prepares the scanner for use.
+// It must be called before calling s.step.
+func (s *scanner) reset() {
+ s.step = stateBeginValue
+ s.parseState = s.parseState[0:0]
+ s.err = nil
+}
+
+// eof tells the scanner that the end of input has been reached.
+// It returns a scan status just as s.step does.
+func (s *scanner) eof() int {
+ if s.err != nil {
+ return scanError
+ }
+ if s.step == stateEndTop {
+ return scanEnd
+ }
+ s.step(s, ' ')
+ if s.step == stateEndTop {
+ return scanEnd
+ }
+ if s.err == nil {
+ s.err = SyntaxError("unexpected end of JSON input")
+ }
+ return scanError
+}
+
+// pushParseState pushes a new parse state p onto the parse stack.
+func (s *scanner) pushParseState(p int) {
+ s.parseState = append(s.parseState, p)
+}
+
+// popParseState pops a parse state (already obtained) off the stack
+// and updates s.step accordingly.
+func (s *scanner) popParseState() {
+ n := len(s.parseState) - 1
+ s.parseState = s.parseState[0:n]
+ if n == 0 {
+ s.step = stateEndTop
+ } else {
+ s.step = stateEndValue
+ }
+}
+
+func isSpace(c int) bool {
+ return c == ' ' || c == '\t' || c == '\r' || c == '\n'
+}
+
+// NOTE(rsc): The various instances of
+//
+// if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+//
+// below should all be if c <= ' ' && isSpace(c), but inlining
+// the checks makes a significant difference (>10%) in tight loops
+// such as nextValue. These should be rewritten with the clearer
+// function call once 6g knows to inline the call.
+
+// stateBeginValueOrEmpty is the state after reading `[`.
+func stateBeginValueOrEmpty(s *scanner, c int) int {
+ if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ return scanSkipSpace
+ }
+ if c == ']' {
+ return stateEndValue(s, c)
+ }
+ return stateBeginValue(s, c)
+}
+
+// stateBeginValue is the state at the beginning of the input.
+func stateBeginValue(s *scanner, c int) int {
+ if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ return scanSkipSpace
+ }
+ switch c {
+ case '{':
+ s.step = stateBeginStringOrEmpty
+ s.pushParseState(parseObjectKey)
+ return scanBeginObject
+ case '[':
+ s.step = stateBeginValueOrEmpty
+ s.pushParseState(parseArrayValue)
+ return scanBeginArray
+ case '"':
+ s.step = stateInString
+ return scanBeginLiteral
+ case '-':
+ s.step = stateNeg
+ return scanBeginLiteral
+ case '0': // beginning of 0.123
+ s.step = state0
+ return scanBeginLiteral
+ case 't': // beginning of true
+ s.step = stateT
+ return scanBeginLiteral
+ case 'f': // beginning of false
+ s.step = stateF
+ return scanBeginLiteral
+ case 'n': // beginning of null
+ s.step = stateN
+ return scanBeginLiteral
+ }
+ if '1' <= c && c <= '9' { // beginning of 1234.5
+ s.step = state1
+ return scanBeginLiteral
+ }
+ return s.error(c, "looking for beginning of value")
+}
+
+// stateBeginStringOrEmpty is the state after reading `{`.
+func stateBeginStringOrEmpty(s *scanner, c int) int {
+ if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ return scanSkipSpace
+ }
+ if c == '}' {
+ n := len(s.parseState)
+ s.parseState[n-1] = parseObjectValue
+ return stateEndValue(s, c)
+ }
+ return stateBeginString(s, c)
+}
+
+// stateBeginString is the state after reading `{"key": value,`.
+func stateBeginString(s *scanner, c int) int {
+ if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ return scanSkipSpace
+ }
+ if c == '"' {
+ s.step = stateInString
+ return scanBeginLiteral
+ }
+ return s.error(c, "looking for beginning of object key string")
+}
+
+// stateEndValue is the state after completing a value,
+// such as after reading `{}` or `true` or `["x"`.
+func stateEndValue(s *scanner, c int) int {
+ n := len(s.parseState)
+ if n == 0 {
+ // Completed top-level before the current byte.
+ s.step = stateEndTop
+ return stateEndTop(s, c)
+ }
+ if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ s.step = stateEndValue
+ return scanSkipSpace
+ }
+ ps := s.parseState[n-1]
+ switch ps {
+ case parseObjectKey:
+ if c == ':' {
+ s.parseState[n-1] = parseObjectValue
+ s.step = stateBeginValue
+ return scanObjectKey
+ }
+ return s.error(c, "after object key")
+ case parseObjectValue:
+ if c == ',' {
+ s.parseState[n-1] = parseObjectKey
+ s.step = stateBeginString
+ return scanObjectValue
+ }
+ if c == '}' {
+ s.popParseState()
+ return scanEndObject
+ }
+ return s.error(c, "after object key:value pair")
+ case parseArrayValue:
+ if c == ',' {
+ s.step = stateBeginValue
+ return scanArrayValue
+ }
+ if c == ']' {
+ s.popParseState()
+ return scanEndArray
+ }
+ return s.error(c, "after array element")
+ }
+ return s.error(c, "")
+}
+
+// stateEndTop is the state after finishing the top-level value,
+// such as after reading `{}` or `[1,2,3]`.
+// Only space characters should be seen now.
+func stateEndTop(s *scanner, c int) int {
+ if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
+ // Complain about non-space byte on next call.
+ s.error(c, "after top-level value")
+ }
+ return scanEnd
+}
+
+// stateInString is the state after reading `"`.
+func stateInString(s *scanner, c int) int {
+ if c == '"' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ if c == '\\' {
+ s.step = stateInStringEsc
+ return scanContinue
+ }
+ if c < 0x20 {
+ return s.error(c, "in string literal")
+ }
+ return scanContinue
+}
+
+// stateInStringEsc is the state after reading `"\` during a quoted string.
+func stateInStringEsc(s *scanner, c int) int {
+ switch c {
+ case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
+ s.step = stateInString
+ return scanContinue
+ }
+ if c == 'u' {
+ s.step = stateInStringEscU
+ return scanContinue
+ }
+ return s.error(c, "in string escape code")
+}
+
+// stateInStringEscU is the state after reading `"\u` during a quoted string.
+func stateInStringEscU(s *scanner, c int) int {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInStringEscU1
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU1 is the state after reading `"\u1` during a quoted string.
+func stateInStringEscU1(s *scanner, c int) int {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInStringEscU12
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU12 is the state after reading `"\u12` during a quoted string.
+func stateInStringEscU12(s *scanner, c int) int {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInStringEscU123
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU123 is the state after reading `"\u123` during a quoted string.
+func stateInStringEscU123(s *scanner, c int) int {
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ s.step = stateInString
+ return scanContinue
+ }
+ // numbers
+ return s.error(c, "in \\u hexadecimal character escape")
+}
+
+// stateInStringEscU123 is the state after reading `-` during a number.
+func stateNeg(s *scanner, c int) int {
+ if c == '0' {
+ s.step = state0
+ return scanContinue
+ }
+ if '1' <= c && c <= '9' {
+ s.step = state1
+ return scanContinue
+ }
+ return s.error(c, "in numeric literal")
+}
+
+// state1 is the state after reading a non-zero integer during a number,
+// such as after reading `1` or `100` but not `0`.
+func state1(s *scanner, c int) int {
+ if '0' <= c && c <= '9' {
+ s.step = state1
+ return scanContinue
+ }
+ return state0(s, c)
+}
+
+// state0 is the state after reading `0` during a number.
+func state0(s *scanner, c int) int {
+ if c == '.' {
+ s.step = stateDot
+ return scanContinue
+ }
+ if c == 'e' {
+ s.step = stateE
+ return scanContinue
+ }
+ return stateEndValue(s, c)
+}
+
+// stateDot is the state after reading the integer and decimal point in a number,
+// such as after reading `1.`.
+func stateDot(s *scanner, c int) int {
+ if '0' <= c && c <= '9' {
+ s.step = stateDot0
+ return scanContinue
+ }
+ return s.error(c, "after decimal point in numeric literal")
+}
+
+// stateDot0 is the state after reading the integer, decimal point, and subsequent
+// digits of a number, such as after reading `3.14`.
+func stateDot0(s *scanner, c int) int {
+ if '0' <= c && c <= '9' {
+ s.step = stateDot0
+ return scanContinue
+ }
+ if c == 'e' {
+ s.step = stateE
+ return scanContinue
+ }
+ return stateEndValue(s, c)
+}
+
+// stateE is the state after reading the mantissa and e in a number,
+// such as after reading `314e` or `0.314e`.
+func stateE(s *scanner, c int) int {
+ if c == '+' {
+ s.step = stateESign
+ return scanContinue
+ }
+ if c == '-' {
+ s.step = stateESign
+ return scanContinue
+ }
+ return stateESign(s, c)
+}
+
+// stateESign is the state after reading the mantissa, e, and sign in a number,
+// such as after reading `314e-` or `0.314e+`.
+func stateESign(s *scanner, c int) int {
+ if '0' <= c && c <= '9' {
+ s.step = stateE0
+ return scanContinue
+ }
+ return s.error(c, "in exponent of numeric literal")
+}
+
+// stateE0 is the state after reading the mantissa, e, optional sign,
+// and at least one digit of the exponent in a number,
+// such as after reading `314e-2` or `0.314e+1` or `3.14e0`.
+func stateE0(s *scanner, c int) int {
+ if '0' <= c && c <= '9' {
+ s.step = stateE0
+ return scanContinue
+ }
+ return stateEndValue(s, c)
+}
+
+// stateT is the state after reading `t`.
+func stateT(s *scanner, c int) int {
+ if c == 'r' {
+ s.step = stateTr
+ return scanContinue
+ }
+ return s.error(c, "in literal true (expecting 'r')")
+}
+
+// stateTr is the state after reading `tr`.
+func stateTr(s *scanner, c int) int {
+ if c == 'u' {
+ s.step = stateTru
+ return scanContinue
+ }
+ return s.error(c, "in literal true (expecting 'u')")
+}
+
+// stateTru is the state after reading `tru`.
+func stateTru(s *scanner, c int) int {
+ if c == 'e' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ return s.error(c, "in literal true (expecting 'e')")
+}
+
+// stateF is the state after reading `f`.
+func stateF(s *scanner, c int) int {
+ if c == 'a' {
+ s.step = stateFa
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 'a')")
+}
+
+// stateFa is the state after reading `fa`.
+func stateFa(s *scanner, c int) int {
+ if c == 'l' {
+ s.step = stateFal
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 'l')")
+}
+
+// stateFal is the state after reading `fal`.
+func stateFal(s *scanner, c int) int {
+ if c == 's' {
+ s.step = stateFals
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 's')")
+}
+
+// stateFals is the state after reading `fals`.
+func stateFals(s *scanner, c int) int {
+ if c == 'e' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ return s.error(c, "in literal false (expecting 'e')")
+}
+
+// stateN is the state after reading `n`.
+func stateN(s *scanner, c int) int {
+ if c == 'u' {
+ s.step = stateNu
+ return scanContinue
+ }
+ return s.error(c, "in literal null (expecting 'u')")
+}
+
+// stateNu is the state after reading `nu`.
+func stateNu(s *scanner, c int) int {
+ if c == 'l' {
+ s.step = stateNul
+ return scanContinue
+ }
+ return s.error(c, "in literal null (expecting 'l')")
+}
+
+// stateNul is the state after reading `nul`.
+func stateNul(s *scanner, c int) int {
+ if c == 'l' {
+ s.step = stateEndValue
+ return scanContinue
+ }
+ return s.error(c, "in literal null (expecting 'l')")
+}
+
+// stateError is the state after reaching a syntax error,
+// such as after reading `[1}` or `5.1.2`.
+func stateError(s *scanner, c int) int {
+ return scanError
+}
+
+// error records an error and switches to the error state.
+func (s *scanner) error(c int, context string) int {
+ s.step = stateError
+ s.err = SyntaxError("invalid character " + quoteChar(c) + " " + context)
+ return scanError
+}
+
+// quoteChar formats c as a quoted character literal
+func quoteChar(c int) string {
+ // special cases - different from quoted strings
+ if c == '\'' {
+ return `'\''`
+ }
+ if c == '"' {
+ return `'"'`
+ }
+
+ // use quoted string with different quotation marks
+ s := strconv.Quote(string(c))
+ return "'" + s[1:len(s)-1] + "'"
+}
+
+// undo causes the scanner to return scanCode from the next state transition.
+// This gives callers a simple 1-byte undo mechanism.
+func (s *scanner) undo(scanCode int) {
+ if s.step == stateRedo {
+ panic("invalid use of scanner")
+ }
+ s.redoCode = scanCode
+ s.redoState = s.step
+ s.step = stateRedo
+}
+
+// stateRedo helps implement the scanner's 1-byte undo.
+func stateRedo(s *scanner, c int) int {
+ s.step = s.redoState
+ return s.redoCode
+}
diff --git a/libgo/go/json/scanner_test.go b/libgo/go/json/scanner_test.go
new file mode 100644
index 000000000..2dc8ff87f
--- /dev/null
+++ b/libgo/go/json/scanner_test.go
@@ -0,0 +1,260 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+ "bytes"
+ "math"
+ "rand"
+ "testing"
+)
+
+// Tests of simple examples.
+
+type example struct {
+ compact string
+ indent string
+}
+
+var examples = []example{
+ {`1`, `1`},
+ {`{}`, `{}`},
+ {`[]`, `[]`},
+ {`{"":2}`, "{\n\t\"\": 2\n}"},
+ {`[3]`, "[\n\t3\n]"},
+ {`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"},
+ {`{"x":1}`, "{\n\t\"x\": 1\n}"},
+ {ex1, ex1i},
+}
+
+var ex1 = `[true,false,null,"x",1,1.5,0,-5e+2]`
+
+var ex1i = `[
+ true,
+ false,
+ null,
+ "x",
+ 1,
+ 1.5,
+ 0,
+ -5e+2
+]`
+
+func TestCompact(t *testing.T) {
+ var buf bytes.Buffer
+ for _, tt := range examples {
+ buf.Reset()
+ if err := Compact(&buf, []byte(tt.compact)); err != nil {
+ t.Errorf("Compact(%#q): %v", tt.compact, err)
+ } else if s := buf.String(); s != tt.compact {
+ t.Errorf("Compact(%#q) = %#q, want original", tt.compact, s)
+ }
+
+ buf.Reset()
+ if err := Compact(&buf, []byte(tt.indent)); err != nil {
+ t.Errorf("Compact(%#q): %v", tt.indent, err)
+ continue
+ } else if s := buf.String(); s != tt.compact {
+ t.Errorf("Compact(%#q) = %#q, want %#q", tt.indent, s, tt.compact)
+ }
+ }
+}
+
+func TestIndent(t *testing.T) {
+ var buf bytes.Buffer
+ for _, tt := range examples {
+ buf.Reset()
+ if err := Indent(&buf, []byte(tt.indent), "", "\t"); err != nil {
+ t.Errorf("Indent(%#q): %v", tt.indent, err)
+ } else if s := buf.String(); s != tt.indent {
+ t.Errorf("Indent(%#q) = %#q, want original", tt.indent, s)
+ }
+
+ buf.Reset()
+ if err := Indent(&buf, []byte(tt.compact), "", "\t"); err != nil {
+ t.Errorf("Indent(%#q): %v", tt.compact, err)
+ continue
+ } else if s := buf.String(); s != tt.indent {
+ t.Errorf("Indent(%#q) = %#q, want %#q", tt.compact, s, tt.indent)
+ }
+ }
+}
+
+// Tests of a large random structure.
+
+func TestCompactBig(t *testing.T) {
+ var buf bytes.Buffer
+ if err := Compact(&buf, jsonBig); err != nil {
+ t.Fatalf("Compact: %v", err)
+ }
+ b := buf.Bytes()
+ if bytes.Compare(b, jsonBig) != 0 {
+ t.Error("Compact(jsonBig) != jsonBig")
+ diff(t, b, jsonBig)
+ return
+ }
+}
+
+func TestIndentBig(t *testing.T) {
+ var buf bytes.Buffer
+ if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
+ t.Fatalf("Indent1: %v", err)
+ }
+ b := buf.Bytes()
+ if len(b) == len(jsonBig) {
+ // jsonBig is compact (no unnecessary spaces);
+ // indenting should make it bigger
+ t.Fatalf("Indent(jsonBig) did not get bigger")
+ }
+
+ // should be idempotent
+ var buf1 bytes.Buffer
+ if err := Indent(&buf1, b, "", "\t"); err != nil {
+ t.Fatalf("Indent2: %v", err)
+ }
+ b1 := buf1.Bytes()
+ if bytes.Compare(b1, b) != 0 {
+ t.Error("Indent(Indent(jsonBig)) != Indent(jsonBig)")
+ diff(t, b1, b)
+ return
+ }
+
+ // should get back to original
+ buf1.Reset()
+ if err := Compact(&buf1, b); err != nil {
+ t.Fatalf("Compact: %v", err)
+ }
+ b1 = buf1.Bytes()
+ if bytes.Compare(b1, jsonBig) != 0 {
+ t.Error("Compact(Indent(jsonBig)) != jsonBig")
+ diff(t, b1, jsonBig)
+ return
+ }
+}
+
+func TestNextValueBig(t *testing.T) {
+ var scan scanner
+ item, rest, err := nextValue(jsonBig, &scan)
+ if err != nil {
+ t.Fatalf("nextValue: %s", err)
+ }
+ if len(item) != len(jsonBig) || &item[0] != &jsonBig[0] {
+ t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
+ }
+ if len(rest) != 0 {
+ t.Errorf("invalid rest: %d", len(rest))
+ }
+
+ item, rest, err = nextValue(append(jsonBig, []byte("HELLO WORLD")...), &scan)
+ if err != nil {
+ t.Fatalf("nextValue extra: %s", err)
+ }
+ if len(item) != len(jsonBig) {
+ t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
+ }
+ if string(rest) != "HELLO WORLD" {
+ t.Errorf("invalid rest: %d", len(rest))
+ }
+}
+
+func BenchmarkSkipValue(b *testing.B) {
+ var scan scanner
+ for i := 0; i < b.N; i++ {
+ nextValue(jsonBig, &scan)
+ }
+ b.SetBytes(int64(len(jsonBig)))
+}
+
+func diff(t *testing.T, a, b []byte) {
+ for i := 0; ; i++ {
+ if i >= len(a) || i >= len(b) || a[i] != b[i] {
+ j := i - 10
+ if j < 0 {
+ j = 0
+ }
+ t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:]))
+ return
+ }
+ }
+}
+
+func trim(b []byte) []byte {
+ if len(b) > 20 {
+ return b[0:20]
+ }
+ return b
+}
+
+// Generate a random JSON object.
+
+var jsonBig []byte
+
+func init() {
+ b, err := Marshal(genValue(10000))
+ if err != nil {
+ panic(err)
+ }
+ jsonBig = b
+}
+
+func genValue(n int) interface{} {
+ if n > 1 {
+ switch rand.Intn(2) {
+ case 0:
+ return genArray(n)
+ case 1:
+ return genMap(n)
+ }
+ }
+ switch rand.Intn(3) {
+ case 0:
+ return rand.Intn(2) == 0
+ case 1:
+ return rand.NormFloat64()
+ case 2:
+ return genString(30)
+ }
+ panic("unreachable")
+}
+
+func genString(stddev float64) string {
+ n := int(math.Fabs(rand.NormFloat64()*stddev + stddev/2))
+ c := make([]int, n)
+ for i := range c {
+ f := math.Fabs(rand.NormFloat64()*64 + 32)
+ if f > 0x10ffff {
+ f = 0x10ffff
+ }
+ c[i] = int(f)
+ }
+ return string(c)
+}
+
+func genArray(n int) []interface{} {
+ f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
+ if f > n {
+ f = n
+ }
+ x := make([]interface{}, int(f))
+ for i := range x {
+ x[i] = genValue(((i+1)*n)/f - (i*n)/f)
+ }
+ return x
+}
+
+func genMap(n int) map[string]interface{} {
+ f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
+ if f > n {
+ f = n
+ }
+ if n > 0 && f == 0 {
+ f = 1
+ }
+ x := make(map[string]interface{})
+ for i := 0; i < f; i++ {
+ x[genString(10)] = genValue(((i+1)*n)/f - (i*n)/f)
+ }
+ return x
+}
diff --git a/libgo/go/json/stream.go b/libgo/go/json/stream.go
new file mode 100644
index 000000000..cb9b16559
--- /dev/null
+++ b/libgo/go/json/stream.go
@@ -0,0 +1,184 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+ "io"
+ "os"
+)
+
+// A Decoder reads and decodes JSON objects from an input stream.
+type Decoder struct {
+ r io.Reader
+ buf []byte
+ d decodeState
+ scan scanner
+ err os.Error
+}
+
+// NewDecoder returns a new decoder that reads from r.
+func NewDecoder(r io.Reader) *Decoder {
+ return &Decoder{r: r}
+}
+
+// Decode reads the next JSON-encoded value from the
+// connection and stores it in the value pointed to by v.
+//
+// See the documentation for Unmarshal for details about
+// the conversion of JSON into a Go value.
+func (dec *Decoder) Decode(v interface{}) os.Error {
+ if dec.err != nil {
+ return dec.err
+ }
+
+ n, err := dec.readValue()
+ if err != nil {
+ return err
+ }
+
+ // Don't save err from unmarshal into dec.err:
+ // the connection is still usable since we read a complete JSON
+ // object from it before the error happened.
+ dec.d.init(dec.buf[0:n])
+ err = dec.d.unmarshal(v)
+
+ // Slide rest of data down.
+ rest := copy(dec.buf, dec.buf[n:])
+ dec.buf = dec.buf[0:rest]
+
+ return err
+}
+
+// readValue reads a JSON value into dec.buf.
+// It returns the length of the encoding.
+func (dec *Decoder) readValue() (int, os.Error) {
+ dec.scan.reset()
+
+ scanp := 0
+ var err os.Error
+Input:
+ for {
+ // Look in the buffer for a new value.
+ for i, c := range dec.buf[scanp:] {
+ v := dec.scan.step(&dec.scan, int(c))
+ if v == scanEnd {
+ scanp += i
+ break Input
+ }
+ // scanEnd is delayed one byte.
+ // We might block trying to get that byte from src,
+ // so instead invent a space byte.
+ if v == scanEndObject && dec.scan.step(&dec.scan, ' ') == scanEnd {
+ scanp += i + 1
+ break Input
+ }
+ if v == scanError {
+ dec.err = dec.scan.err
+ return 0, dec.scan.err
+ }
+ }
+ scanp = len(dec.buf)
+
+ // Did the last read have an error?
+ // Delayed until now to allow buffer scan.
+ if err != nil {
+ if err == os.EOF {
+ if dec.scan.step(&dec.scan, ' ') == scanEnd {
+ break Input
+ }
+ if nonSpace(dec.buf) {
+ err = io.ErrUnexpectedEOF
+ }
+ }
+ dec.err = err
+ return 0, err
+ }
+
+ // Make room to read more into the buffer.
+ const minRead = 512
+ if cap(dec.buf)-len(dec.buf) < minRead {
+ newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead)
+ copy(newBuf, dec.buf)
+ dec.buf = newBuf
+ }
+
+ // Read. Delay error for next iteration (after scan).
+ var n int
+ n, err = dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
+ dec.buf = dec.buf[0 : len(dec.buf)+n]
+ }
+ return scanp, nil
+}
+
+func nonSpace(b []byte) bool {
+ for _, c := range b {
+ if !isSpace(int(c)) {
+ return true
+ }
+ }
+ return false
+}
+
+// An Encoder writes JSON objects to an output stream.
+type Encoder struct {
+ w io.Writer
+ e encodeState
+ err os.Error
+}
+
+// NewEncoder returns a new encoder that writes to w.
+func NewEncoder(w io.Writer) *Encoder {
+ return &Encoder{w: w}
+}
+
+// Encode writes the JSON encoding of v to the connection.
+//
+// See the documentation for Marshal for details about the
+// conversion of Go values to JSON.
+func (enc *Encoder) Encode(v interface{}) os.Error {
+ if enc.err != nil {
+ return enc.err
+ }
+ enc.e.Reset()
+ err := enc.e.marshal(v)
+ if err != nil {
+ return err
+ }
+
+ // Terminate each value with a newline.
+ // This makes the output look a little nicer
+ // when debugging, and some kind of space
+ // is required if the encoded value was a number,
+ // so that the reader knows there aren't more
+ // digits coming.
+ enc.e.WriteByte('\n')
+
+ if _, err = enc.w.Write(enc.e.Bytes()); err != nil {
+ enc.err = err
+ }
+ return err
+}
+
+// RawMessage is a raw encoded JSON object.
+// It implements Marshaler and Unmarshaler and can
+// be used to delay JSON decoding or precompute a JSON encoding.
+type RawMessage []byte
+
+// MarshalJSON returns *m as the JSON encoding of m.
+func (m *RawMessage) MarshalJSON() ([]byte, os.Error) {
+ return *m, nil
+}
+
+// UnmarshalJSON sets *m to a copy of data.
+func (m *RawMessage) UnmarshalJSON(data []byte) os.Error {
+ if m == nil {
+ return os.NewError("json.RawMessage: UnmarshalJSON on nil pointer")
+ }
+ *m = append((*m)[0:0], data...)
+ return nil
+}
+
+var _ Marshaler = (*RawMessage)(nil)
+var _ Unmarshaler = (*RawMessage)(nil)
diff --git a/libgo/go/json/stream_test.go b/libgo/go/json/stream_test.go
new file mode 100644
index 000000000..6ddaed9fe
--- /dev/null
+++ b/libgo/go/json/stream_test.go
@@ -0,0 +1,122 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+)
+
+// Test values for the stream test.
+// One of each JSON kind.
+var streamTest = []interface{}{
+ 0.1,
+ "hello",
+ nil,
+ true,
+ false,
+ []interface{}{"a", "b", "c"},
+ map[string]interface{}{"K": "Kelvin", "ß": "long s"},
+ 3.14, // another value to make sure something can follow map
+}
+
+var streamEncoded = `0.1
+"hello"
+null
+true
+false
+["a","b","c"]
+{"ß":"long s","K":"Kelvin"}
+3.14
+`
+
+func TestEncoder(t *testing.T) {
+ for i := 0; i <= len(streamTest); i++ {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ for j, v := range streamTest[0:i] {
+ if err := enc.Encode(v); err != nil {
+ t.Fatalf("encode #%d: %v", j, err)
+ }
+ }
+ if have, want := buf.String(), nlines(streamEncoded, i); have != want {
+ t.Errorf("encoding %d items: mismatch", i)
+ diff(t, []byte(have), []byte(want))
+ break
+ }
+ }
+}
+
+func TestDecoder(t *testing.T) {
+ for i := 0; i <= len(streamTest); i++ {
+ // Use stream without newlines as input,
+ // just to stress the decoder even more.
+ // Our test input does not include back-to-back numbers.
+ // Otherwise stripping the newlines would
+ // merge two adjacent JSON values.
+ var buf bytes.Buffer
+ for _, c := range nlines(streamEncoded, i) {
+ if c != '\n' {
+ buf.WriteRune(c)
+ }
+ }
+ out := make([]interface{}, i)
+ dec := NewDecoder(&buf)
+ for j := range out {
+ if err := dec.Decode(&out[j]); err != nil {
+ t.Fatalf("decode #%d/%d: %v", j, i, err)
+ }
+ }
+ if !reflect.DeepEqual(out, streamTest[0:i]) {
+ t.Errorf("decoding %d items: mismatch", i)
+ for j := range out {
+ if !reflect.DeepEqual(out[j], streamTest[j]) {
+ t.Errorf("#%d: have %v want %v", j, out[j], streamTest[j])
+ }
+ }
+ break
+ }
+ }
+}
+
+func nlines(s string, n int) string {
+ if n <= 0 {
+ return ""
+ }
+ for i, c := range s {
+ if c == '\n' {
+ if n--; n == 0 {
+ return s[0 : i+1]
+ }
+ }
+ }
+ return s
+}
+
+func TestRawMessage(t *testing.T) {
+ // TODO(rsc): Should not need the * in *RawMessage
+ var data struct {
+ X float64
+ Id *RawMessage
+ Y float32
+ }
+ const raw = `["\u0056",null]`
+ const msg = `{"X":0.1,"Id":["\u0056",null],"Y":0.2}`
+ err := Unmarshal([]byte(msg), &data)
+ if err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if string([]byte(*data.Id)) != raw {
+ t.Fatalf("Raw mismatch: have %#q want %#q", []byte(*data.Id), raw)
+ }
+ b, err := Marshal(&data)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ if string(b) != msg {
+ t.Fatalf("Marshal: have %#q want %#q", b, msg)
+ }
+}
diff --git a/libgo/go/log/log.go b/libgo/go/log/log.go
new file mode 100644
index 000000000..d34af9e5e
--- /dev/null
+++ b/libgo/go/log/log.go
@@ -0,0 +1,278 @@
+// 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.
+
+// Simple logging package. It defines a type, Logger, with methods
+// for formatting output. It also has a predefined 'standard' Logger
+// accessible through helper functions Print[f|ln], Exit[f|ln], and
+// Panic[f|ln], which are easier to use than creating a Logger manually.
+// That logger writes to standard error and prints the date and time
+// of each logged message.
+// The Exit functions call os.Exit(1) after writing the log message.
+// The Panic functions call panic after writing the log message.
+package log
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "runtime"
+ "os"
+ "time"
+ "sync"
+)
+
+// These flags define which text to prefix to each log entry generated by the Logger.
+const (
+ // Bits or'ed together to control what's printed. There is no control over the
+ // order they appear (the order listed here) or the format they present (as
+ // described in the comments). A colon appears after these items:
+ // 2009/0123 01:23:23.123123 /a/b/c/d.go:23: message
+ Ldate = 1 << iota // the date: 2009/0123
+ Ltime // the time: 01:23:23
+ Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
+ Llongfile // full file name and line number: /a/b/c/d.go:23
+ Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
+)
+
+// A Logger represents an active logging object that generates lines of
+// output to an io.Writer. Each logging operation makes a single call to
+// the Writer's Write method. A Logger can be used simultaneously from
+// multiple goroutines; it guarantees to serialize access to the Writer.
+type Logger struct {
+ mu sync.Mutex // ensures atomic writes
+ out io.Writer // destination for output
+ prefix string // prefix to write at beginning of each line
+ flag int // properties
+}
+
+// New creates a new Logger. The out variable sets the
+// destination to which log data will be written.
+// The prefix appears at the beginning of each generated log line.
+// The flag argument defines the logging properties.
+func New(out io.Writer, prefix string, flag int) *Logger {
+ return &Logger{out: out, prefix: prefix, flag: flag}
+}
+
+var std = New(os.Stderr, "", Ldate|Ltime)
+
+// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
+// Knows the buffer has capacity.
+func itoa(buf *bytes.Buffer, i int, wid int) {
+ var u uint = uint(i)
+ if u == 0 && wid <= 1 {
+ buf.WriteByte('0')
+ return
+ }
+
+ // Assemble decimal in reverse order.
+ var b [32]byte
+ bp := len(b)
+ for ; u > 0 || wid > 0; u /= 10 {
+ bp--
+ wid--
+ b[bp] = byte(u%10) + '0'
+ }
+
+ // avoid slicing b to avoid an allocation.
+ for bp < len(b) {
+ buf.WriteByte(b[bp])
+ bp++
+ }
+}
+
+func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) {
+ buf.WriteString(l.prefix)
+ if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
+ t := time.SecondsToLocalTime(ns / 1e9)
+ if l.flag&Ldate != 0 {
+ itoa(buf, int(t.Year), 4)
+ buf.WriteByte('/')
+ itoa(buf, int(t.Month), 2)
+ buf.WriteByte('/')
+ itoa(buf, int(t.Day), 2)
+ buf.WriteByte(' ')
+ }
+ if l.flag&(Ltime|Lmicroseconds) != 0 {
+ itoa(buf, int(t.Hour), 2)
+ buf.WriteByte(':')
+ itoa(buf, int(t.Minute), 2)
+ buf.WriteByte(':')
+ itoa(buf, int(t.Second), 2)
+ if l.flag&Lmicroseconds != 0 {
+ buf.WriteByte('.')
+ itoa(buf, int(ns%1e9)/1e3, 6)
+ }
+ buf.WriteByte(' ')
+ }
+ }
+ if l.flag&(Lshortfile|Llongfile) != 0 {
+ _, file, line, ok := runtime.Caller(calldepth)
+ if ok {
+ if l.flag&Lshortfile != 0 {
+ short := file
+ for i := len(file) - 1; i > 0; i-- {
+ if file[i] == '/' {
+ short = file[i+1:]
+ break
+ }
+ }
+ file = short
+ }
+ } else {
+ file = "???"
+ line = 0
+ }
+ buf.WriteString(file)
+ buf.WriteByte(':')
+ itoa(buf, line, -1)
+ buf.WriteString(": ")
+ }
+}
+
+// Output writes the output for a logging event. The string s contains
+// the text to print after the prefix specified by the flags of the
+// Logger. A newline is appended if the last character of s is not
+// already a newline. Calldepth is used to recover the PC and is
+// provided for generality, although at the moment on all pre-defined
+// paths it will be 2.
+func (l *Logger) Output(calldepth int, s string) os.Error {
+ now := time.Nanoseconds() // get this early.
+ buf := new(bytes.Buffer)
+ l.formatHeader(buf, now, calldepth+1)
+ buf.WriteString(s)
+ if len(s) > 0 && s[len(s)-1] != '\n' {
+ buf.WriteByte('\n')
+ }
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ _, err := l.out.Write(buf.Bytes())
+ return err
+}
+
+// Printf calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Printf.
+func (l *Logger) Printf(format string, v ...interface{}) {
+ l.Output(2, fmt.Sprintf(format, v...))
+}
+
+// Print calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Print.
+func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }
+
+// Println calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Println.
+func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }
+
+// Exit is equivalent to l.Print() followed by a call to os.Exit(1).
+func (l *Logger) Exit(v ...interface{}) {
+ l.Output(2, fmt.Sprint(v...))
+ os.Exit(1)
+}
+
+// Exitf is equivalent to l.Printf() followed by a call to os.Exit(1).
+func (l *Logger) Exitf(format string, v ...interface{}) {
+ l.Output(2, fmt.Sprintf(format, v...))
+ os.Exit(1)
+}
+
+// Exitln is equivalent to l.Println() followed by a call to os.Exit(1).
+func (l *Logger) Exitln(v ...interface{}) {
+ l.Output(2, fmt.Sprintln(v...))
+ os.Exit(1)
+}
+
+// Panic is equivalent to l.Print() followed by a call to panic().
+func (l *Logger) Panic(v ...interface{}) {
+ s := fmt.Sprint(v...)
+ l.Output(2, s)
+ panic(s)
+}
+
+// Panicf is equivalent to l.Printf() followed by a call to panic().
+func (l *Logger) Panicf(format string, v ...interface{}) {
+ s := fmt.Sprintf(format, v...)
+ l.Output(2, s)
+ panic(s)
+}
+
+// Panicln is equivalent to l.Println() followed by a call to panic().
+func (l *Logger) Panicln(v ...interface{}) {
+ s := fmt.Sprintln(v...)
+ l.Output(2, s)
+ panic(s)
+}
+
+// SetOutput sets the output destination for the standard logger.
+func SetOutput(w io.Writer) {
+ std.out = w
+}
+
+// SetFlags sets the output flags for the standard logger.
+func SetFlags(flag int) {
+ std.flag = flag
+}
+
+// SetPrefix sets the output prefix for the standard logger.
+func SetPrefix(prefix string) {
+ std.prefix = prefix
+}
+
+// These functions write to the standard logger.
+
+// Print calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Print.
+func Print(v ...interface{}) {
+ std.Output(2, fmt.Sprint(v...))
+}
+
+// Printf calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Printf.
+func Printf(format string, v ...interface{}) {
+ std.Output(2, fmt.Sprintf(format, v...))
+}
+
+// Println calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Println.
+func Println(v ...interface{}) {
+ std.Output(2, fmt.Sprintln(v...))
+}
+
+// Exit is equivalent to Print() followed by a call to os.Exit(1).
+func Exit(v ...interface{}) {
+ std.Output(2, fmt.Sprint(v...))
+ os.Exit(1)
+}
+
+// Exitf is equivalent to Printf() followed by a call to os.Exit(1).
+func Exitf(format string, v ...interface{}) {
+ std.Output(2, fmt.Sprintf(format, v...))
+ os.Exit(1)
+}
+
+// Exitln is equivalent to Println() followed by a call to os.Exit(1).
+func Exitln(v ...interface{}) {
+ std.Output(2, fmt.Sprintln(v...))
+ os.Exit(1)
+}
+
+// Panic is equivalent to Print() followed by a call to panic().
+func Panic(v ...interface{}) {
+ s := fmt.Sprint(v...)
+ std.Output(2, s)
+ panic(s)
+}
+
+// Panicf is equivalent to Printf() followed by a call to panic().
+func Panicf(format string, v ...interface{}) {
+ s := fmt.Sprintf(format, v...)
+ std.Output(2, s)
+ panic(s)
+}
+
+// Panicln is equivalent to Println() followed by a call to panic().
+func Panicln(v ...interface{}) {
+ s := fmt.Sprintln(v...)
+ std.Output(2, s)
+ panic(s)
+}
diff --git a/libgo/go/log/log_test.go b/libgo/go/log/log_test.go
new file mode 100644
index 000000000..bd4d1a9c5
--- /dev/null
+++ b/libgo/go/log/log_test.go
@@ -0,0 +1,86 @@
+// 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 log
+
+// These tests are too simple.
+
+import (
+ "bytes"
+ "os"
+ "regexp"
+ "testing"
+)
+
+const (
+ Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
+ Rtime = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
+ Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
+ Rline = `[0-9]+:` // must update if the calls to l.Printf / l.Print below move
+ Rlongfile = `.*/[A-Za-z0-9_\-]+\.go:|\?\?\?:` + Rline
+ Rshortfile = `[A-Za-z0-9_\-]+\.go:|\?\?\?:` + Rline
+)
+
+type tester struct {
+ flag int
+ prefix string
+ pattern string // regexp that log output must match; we add ^ and expected_text$ always
+}
+
+var tests = []tester{
+ // individual pieces:
+ {0, "", ""},
+ {0, "XXX", "XXX"},
+ {Ldate, "", Rdate + " "},
+ {Ltime, "", Rtime + " "},
+ {Ltime | Lmicroseconds, "", Rtime + Rmicroseconds + " "},
+ {Lmicroseconds, "", Rtime + Rmicroseconds + " "}, // microsec implies time
+ {Llongfile, "", Rlongfile + " "},
+ {Lshortfile, "", Rshortfile + " "},
+ {Llongfile | Lshortfile, "", Rshortfile + " "}, // shortfile overrides longfile
+ // everything at once:
+ {Ldate | Ltime | Lmicroseconds | Llongfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rlongfile + " "},
+ {Ldate | Ltime | Lmicroseconds | Lshortfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rshortfile + " "},
+}
+
+// Test using Println("hello", 23, "world") or using Printf("hello %d world", 23)
+func testPrint(t *testing.T, flag int, prefix string, pattern string, useFormat bool) {
+ buf := new(bytes.Buffer)
+ SetOutput(buf)
+ SetFlags(flag)
+ SetPrefix(prefix)
+ if useFormat {
+ Printf("hello %d world", 23)
+ } else {
+ Println("hello", 23, "world")
+ }
+ line := buf.String()
+ line = line[0 : len(line)-1]
+ pattern = "^" + pattern + "hello 23 world$"
+ matched, err4 := regexp.MatchString(pattern, line)
+ if err4 != nil {
+ t.Fatal("pattern did not compile:", err4)
+ }
+ if !matched {
+ t.Errorf("log output should match %q is %q", pattern, line)
+ }
+ SetOutput(os.Stderr)
+}
+
+func TestAll(t *testing.T) {
+ for _, testcase := range tests {
+ testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, false)
+ testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, true)
+ }
+}
+
+func TestOutput(t *testing.T) {
+ const testString = "test"
+ var b bytes.Buffer
+ l := New(&b, "", 0)
+ l.Println(testString)
+ if expect := testString + "\n"; b.String() != expect {
+ t.Errorf("log output should match %q is %q", expect, b.String())
+ }
+}
diff --git a/libgo/go/math/acosh.go b/libgo/go/math/acosh.go
new file mode 100644
index 000000000..d8067c065
--- /dev/null
+++ b/libgo/go/math/acosh.go
@@ -0,0 +1,62 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_acosh.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// __ieee754_acosh(x)
+// Method :
+// Based on
+// acosh(x) = log [ x + sqrt(x*x-1) ]
+// we have
+// acosh(x) := log(x)+ln2, if x is large; else
+// acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+// acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+//
+// Special cases:
+// acosh(x) is NaN with signal if x<1.
+// acosh(NaN) is NaN without signal.
+//
+
+// Acosh(x) calculates the inverse hyperbolic cosine of x.
+//
+// Special cases are:
+// Acosh(x) = NaN if x < 1
+// Acosh(NaN) = NaN
+func Acosh(x float64) float64 {
+ const (
+ Ln2 = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF
+ Large = 1 << 28 // 2**28
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN
+ // when compiler does it for us
+ // first case is special case
+ switch {
+ case x < 1 || x != x: // x < 1 || IsNaN(x):
+ return NaN()
+ case x == 1:
+ return 0
+ case x >= Large:
+ return Log(x) + Ln2 // x > 2**28
+ case x > 2:
+ return Log(2*x - 1/(x+Sqrt(x*x-1))) // 2**28 > x > 2
+ }
+ t := x - 1
+ return Log1p(t + Sqrt(2*t+t*t)) // 2 >= x > 1
+}
diff --git a/libgo/go/math/all_test.go b/libgo/go/math/all_test.go
new file mode 100644
index 000000000..d2a7d411e
--- /dev/null
+++ b/libgo/go/math/all_test.go
@@ -0,0 +1,2737 @@
+// 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 math_test
+
+import (
+ "fmt"
+ . "math"
+ "runtime"
+ "testing"
+)
+
+var vf = []float64{
+ 4.9790119248836735e+00,
+ 7.7388724745781045e+00,
+ -2.7688005719200159e-01,
+ -5.0106036182710749e+00,
+ 9.6362937071984173e+00,
+ 2.9263772392439646e+00,
+ 5.2290834314593066e+00,
+ 2.7279399104360102e+00,
+ 1.8253080916808550e+00,
+ -8.6859247685756013e+00,
+}
+// The expected results below were computed by the high precision calculators
+// at http://keisan.casio.com/. More exact input values (array vf[], above)
+// were obtained by printing them with "%.26f". The answers were calculated
+// to 26 digits (by using the "Digit number" drop-down control of each
+// calculator).
+var acos = []float64{
+ 1.0496193546107222142571536e+00,
+ 6.8584012813664425171660692e-01,
+ 1.5984878714577160325521819e+00,
+ 2.0956199361475859327461799e+00,
+ 2.7053008467824138592616927e-01,
+ 1.2738121680361776018155625e+00,
+ 1.0205369421140629186287407e+00,
+ 1.2945003481781246062157835e+00,
+ 1.3872364345374451433846657e+00,
+ 2.6231510803970463967294145e+00,
+}
+var acosh = []float64{
+ 2.4743347004159012494457618e+00,
+ 2.8576385344292769649802701e+00,
+ 7.2796961502981066190593175e-01,
+ 2.4796794418831451156471977e+00,
+ 3.0552020742306061857212962e+00,
+ 2.044238592688586588942468e+00,
+ 2.5158701513104513595766636e+00,
+ 1.99050839282411638174299e+00,
+ 1.6988625798424034227205445e+00,
+ 2.9611454842470387925531875e+00,
+}
+var asin = []float64{
+ 5.2117697218417440497416805e-01,
+ 8.8495619865825236751471477e-01,
+ -02.769154466281941332086016e-02,
+ -5.2482360935268931351485822e-01,
+ 1.3002662421166552333051524e+00,
+ 2.9698415875871901741575922e-01,
+ 5.5025938468083370060258102e-01,
+ 2.7629597861677201301553823e-01,
+ 1.83559892257451475846656e-01,
+ -1.0523547536021497774980928e+00,
+}
+var asinh = []float64{
+ 2.3083139124923523427628243e+00,
+ 2.743551594301593620039021e+00,
+ -2.7345908534880091229413487e-01,
+ -2.3145157644718338650499085e+00,
+ 2.9613652154015058521951083e+00,
+ 1.7949041616585821933067568e+00,
+ 2.3564032905983506405561554e+00,
+ 1.7287118790768438878045346e+00,
+ 1.3626658083714826013073193e+00,
+ -2.8581483626513914445234004e+00,
+}
+var atan = []float64{
+ 1.372590262129621651920085e+00,
+ 1.442290609645298083020664e+00,
+ -2.7011324359471758245192595e-01,
+ -1.3738077684543379452781531e+00,
+ 1.4673921193587666049154681e+00,
+ 1.2415173565870168649117764e+00,
+ 1.3818396865615168979966498e+00,
+ 1.2194305844639670701091426e+00,
+ 1.0696031952318783760193244e+00,
+ -1.4561721938838084990898679e+00,
+}
+var atanh = []float64{
+ 5.4651163712251938116878204e-01,
+ 1.0299474112843111224914709e+00,
+ -2.7695084420740135145234906e-02,
+ -5.5072096119207195480202529e-01,
+ 1.9943940993171843235906642e+00,
+ 3.01448604578089708203017e-01,
+ 5.8033427206942188834370595e-01,
+ 2.7987997499441511013958297e-01,
+ 1.8459947964298794318714228e-01,
+ -1.3273186910532645867272502e+00,
+}
+var atan2 = []float64{
+ 1.1088291730037004444527075e+00,
+ 9.1218183188715804018797795e-01,
+ 1.5984772603216203736068915e+00,
+ 2.0352918654092086637227327e+00,
+ 8.0391819139044720267356014e-01,
+ 1.2861075249894661588866752e+00,
+ 1.0889904479131695712182587e+00,
+ 1.3044821793397925293797357e+00,
+ 1.3902530903455392306872261e+00,
+ 2.2859857424479142655411058e+00,
+}
+var cbrt = []float64{
+ 1.7075799841925094446722675e+00,
+ 1.9779982212970353936691498e+00,
+ -6.5177429017779910853339447e-01,
+ -1.7111838886544019873338113e+00,
+ 2.1279920909827937423960472e+00,
+ 1.4303536770460741452312367e+00,
+ 1.7357021059106154902341052e+00,
+ 1.3972633462554328350552916e+00,
+ 1.2221149580905388454977636e+00,
+ -2.0556003730500069110343596e+00,
+}
+var ceil = []float64{
+ 5.0000000000000000e+00,
+ 8.0000000000000000e+00,
+ 0.0000000000000000e+00,
+ -5.0000000000000000e+00,
+ 1.0000000000000000e+01,
+ 3.0000000000000000e+00,
+ 6.0000000000000000e+00,
+ 3.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ -8.0000000000000000e+00,
+}
+var copysign = []float64{
+ -4.9790119248836735e+00,
+ -7.7388724745781045e+00,
+ -2.7688005719200159e-01,
+ -5.0106036182710749e+00,
+ -9.6362937071984173e+00,
+ -2.9263772392439646e+00,
+ -5.2290834314593066e+00,
+ -2.7279399104360102e+00,
+ -1.8253080916808550e+00,
+ -8.6859247685756013e+00,
+}
+var cos = []float64{
+ 2.634752140995199110787593e-01,
+ 1.148551260848219865642039e-01,
+ 9.6191297325640768154550453e-01,
+ 2.938141150061714816890637e-01,
+ -9.777138189897924126294461e-01,
+ -9.7693041344303219127199518e-01,
+ 4.940088096948647263961162e-01,
+ -9.1565869021018925545016502e-01,
+ -2.517729313893103197176091e-01,
+ -7.39241351595676573201918e-01,
+}
+var cosh = []float64{
+ 7.2668796942212842775517446e+01,
+ 1.1479413465659254502011135e+03,
+ 1.0385767908766418550935495e+00,
+ 7.5000957789658051428857788e+01,
+ 7.655246669605357888468613e+03,
+ 9.3567491758321272072888257e+00,
+ 9.331351599270605471131735e+01,
+ 7.6833430994624643209296404e+00,
+ 3.1829371625150718153881164e+00,
+ 2.9595059261916188501640911e+03,
+}
+var erf = []float64{
+ 5.1865354817738701906913566e-01,
+ 7.2623875834137295116929844e-01,
+ -3.123458688281309990629839e-02,
+ -5.2143121110253302920437013e-01,
+ 8.2704742671312902508629582e-01,
+ 3.2101767558376376743993945e-01,
+ 5.403990312223245516066252e-01,
+ 3.0034702916738588551174831e-01,
+ 2.0369924417882241241559589e-01,
+ -7.8069386968009226729944677e-01,
+}
+var erfc = []float64{
+ 4.8134645182261298093086434e-01,
+ 2.7376124165862704883070156e-01,
+ 1.0312345868828130999062984e+00,
+ 1.5214312111025330292043701e+00,
+ 1.7295257328687097491370418e-01,
+ 6.7898232441623623256006055e-01,
+ 4.596009687776754483933748e-01,
+ 6.9965297083261411448825169e-01,
+ 7.9630075582117758758440411e-01,
+ 1.7806938696800922672994468e+00,
+}
+var exp = []float64{
+ 1.4533071302642137507696589e+02,
+ 2.2958822575694449002537581e+03,
+ 7.5814542574851666582042306e-01,
+ 6.6668778421791005061482264e-03,
+ 1.5310493273896033740861206e+04,
+ 1.8659907517999328638667732e+01,
+ 1.8662167355098714543942057e+02,
+ 1.5301332413189378961665788e+01,
+ 6.2047063430646876349125085e+00,
+ 1.6894712385826521111610438e-04,
+}
+var expm1 = []float64{
+ 5.105047796122957327384770212e-02,
+ 8.046199708567344080562675439e-02,
+ -2.764970978891639815187418703e-03,
+ -4.8871434888875355394330300273e-02,
+ 1.0115864277221467777117227494e-01,
+ 2.969616407795910726014621657e-02,
+ 5.368214487944892300914037972e-02,
+ 2.765488851131274068067445335e-02,
+ 1.842068661871398836913874273e-02,
+ -8.3193870863553801814961137573e-02,
+}
+var exp2 = []float64{
+ 3.1537839463286288034313104e+01,
+ 2.1361549283756232296144849e+02,
+ 8.2537402562185562902577219e-01,
+ 3.1021158628740294833424229e-02,
+ 7.9581744110252191462569661e+02,
+ 7.6019905892596359262696423e+00,
+ 3.7506882048388096973183084e+01,
+ 6.6250893439173561733216375e+00,
+ 3.5438267900243941544605339e+00,
+ 2.4281533133513300984289196e-03,
+}
+var fabs = []float64{
+ 4.9790119248836735e+00,
+ 7.7388724745781045e+00,
+ 2.7688005719200159e-01,
+ 5.0106036182710749e+00,
+ 9.6362937071984173e+00,
+ 2.9263772392439646e+00,
+ 5.2290834314593066e+00,
+ 2.7279399104360102e+00,
+ 1.8253080916808550e+00,
+ 8.6859247685756013e+00,
+}
+var fdim = []float64{
+ 4.9790119248836735e+00,
+ 7.7388724745781045e+00,
+ 0.0000000000000000e+00,
+ 0.0000000000000000e+00,
+ 9.6362937071984173e+00,
+ 2.9263772392439646e+00,
+ 5.2290834314593066e+00,
+ 2.7279399104360102e+00,
+ 1.8253080916808550e+00,
+ 0.0000000000000000e+00,
+}
+var floor = []float64{
+ 4.0000000000000000e+00,
+ 7.0000000000000000e+00,
+ -1.0000000000000000e+00,
+ -6.0000000000000000e+00,
+ 9.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 5.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 1.0000000000000000e+00,
+ -9.0000000000000000e+00,
+}
+var fmod = []float64{
+ 4.197615023265299782906368e-02,
+ 2.261127525421895434476482e+00,
+ 3.231794108794261433104108e-02,
+ 4.989396381728925078391512e+00,
+ 3.637062928015826201999516e-01,
+ 1.220868282268106064236690e+00,
+ 4.770916568540693347699744e+00,
+ 1.816180268691969246219742e+00,
+ 8.734595415957246977711748e-01,
+ 1.314075231424398637614104e+00,
+}
+
+type fi struct {
+ f float64
+ i int
+}
+
+var frexp = []fi{
+ {6.2237649061045918750e-01, 3},
+ {9.6735905932226306250e-01, 3},
+ {-5.5376011438400318000e-01, -1},
+ {-6.2632545228388436250e-01, 3},
+ {6.02268356699901081250e-01, 4},
+ {7.3159430981099115000e-01, 2},
+ {6.5363542893241332500e-01, 3},
+ {6.8198497760900255000e-01, 2},
+ {9.1265404584042750000e-01, 1},
+ {-5.4287029803597508250e-01, 4},
+}
+var gamma = []float64{
+ 2.3254348370739963835386613898e+01,
+ 2.991153837155317076427529816e+03,
+ -4.561154336726758060575129109e+00,
+ 7.719403468842639065959210984e-01,
+ 1.6111876618855418534325755566e+05,
+ 1.8706575145216421164173224946e+00,
+ 3.4082787447257502836734201635e+01,
+ 1.579733951448952054898583387e+00,
+ 9.3834586598354592860187267089e-01,
+ -2.093995902923148389186189429e-05,
+}
+var j0 = []float64{
+ -1.8444682230601672018219338e-01,
+ 2.27353668906331975435892e-01,
+ 9.809259936157051116270273e-01,
+ -1.741170131426226587841181e-01,
+ -2.1389448451144143352039069e-01,
+ -2.340905848928038763337414e-01,
+ -1.0029099691890912094586326e-01,
+ -1.5466726714884328135358907e-01,
+ 3.252650187653420388714693e-01,
+ -8.72218484409407250005360235e-03,
+}
+var j1 = []float64{
+ -3.251526395295203422162967e-01,
+ 1.893581711430515718062564e-01,
+ -1.3711761352467242914491514e-01,
+ 3.287486536269617297529617e-01,
+ 1.3133899188830978473849215e-01,
+ 3.660243417832986825301766e-01,
+ -3.4436769271848174665420672e-01,
+ 4.329481396640773768835036e-01,
+ 5.8181350531954794639333955e-01,
+ -2.7030574577733036112996607e-01,
+}
+var j2 = []float64{
+ 5.3837518920137802565192769e-02,
+ -1.7841678003393207281244667e-01,
+ 9.521746934916464142495821e-03,
+ 4.28958355470987397983072e-02,
+ 2.4115371837854494725492872e-01,
+ 4.842458532394520316844449e-01,
+ -3.142145220618633390125946e-02,
+ 4.720849184745124761189957e-01,
+ 3.122312022520957042957497e-01,
+ 7.096213118930231185707277e-02,
+}
+var jM3 = []float64{
+ -3.684042080996403091021151e-01,
+ 2.8157665936340887268092661e-01,
+ 4.401005480841948348343589e-04,
+ 3.629926999056814081597135e-01,
+ 3.123672198825455192489266e-02,
+ -2.958805510589623607540455e-01,
+ -3.2033177696533233403289416e-01,
+ -2.592737332129663376736604e-01,
+ -1.0241334641061485092351251e-01,
+ -2.3762660886100206491674503e-01,
+}
+var lgamma = []fi{
+ {3.146492141244545774319734e+00, 1},
+ {8.003414490659126375852113e+00, 1},
+ {1.517575735509779707488106e+00, -1},
+ {-2.588480028182145853558748e-01, 1},
+ {1.1989897050205555002007985e+01, 1},
+ {6.262899811091257519386906e-01, 1},
+ {3.5287924899091566764846037e+00, 1},
+ {4.5725644770161182299423372e-01, 1},
+ {-6.363667087767961257654854e-02, 1},
+ {-1.077385130910300066425564e+01, -1},
+}
+var log = []float64{
+ 1.605231462693062999102599e+00,
+ 2.0462560018708770653153909e+00,
+ -1.2841708730962657801275038e+00,
+ 1.6115563905281545116286206e+00,
+ 2.2655365644872016636317461e+00,
+ 1.0737652208918379856272735e+00,
+ 1.6542360106073546632707956e+00,
+ 1.0035467127723465801264487e+00,
+ 6.0174879014578057187016475e-01,
+ 2.161703872847352815363655e+00,
+}
+var logb = []float64{
+ 2.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ -2.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 3.0000000000000000e+00,
+ 1.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 1.0000000000000000e+00,
+ 0.0000000000000000e+00,
+ 3.0000000000000000e+00,
+}
+var log10 = []float64{
+ 6.9714316642508290997617083e-01,
+ 8.886776901739320576279124e-01,
+ -5.5770832400658929815908236e-01,
+ 6.998900476822994346229723e-01,
+ 9.8391002850684232013281033e-01,
+ 4.6633031029295153334285302e-01,
+ 7.1842557117242328821552533e-01,
+ 4.3583479968917773161304553e-01,
+ 2.6133617905227038228626834e-01,
+ 9.3881606348649405716214241e-01,
+}
+var log1p = []float64{
+ 4.8590257759797794104158205e-02,
+ 7.4540265965225865330849141e-02,
+ -2.7726407903942672823234024e-03,
+ -5.1404917651627649094953380e-02,
+ 9.1998280672258624681335010e-02,
+ 2.8843762576593352865894824e-02,
+ 5.0969534581863707268992645e-02,
+ 2.6913947602193238458458594e-02,
+ 1.8088493239630770262045333e-02,
+ -9.0865245631588989681559268e-02,
+}
+var log2 = []float64{
+ 2.3158594707062190618898251e+00,
+ 2.9521233862883917703341018e+00,
+ -1.8526669502700329984917062e+00,
+ 2.3249844127278861543568029e+00,
+ 3.268478366538305087466309e+00,
+ 1.5491157592596970278166492e+00,
+ 2.3865580889631732407886495e+00,
+ 1.447811865817085365540347e+00,
+ 8.6813999540425116282815557e-01,
+ 3.118679457227342224364709e+00,
+}
+var modf = [][2]float64{
+ {4.0000000000000000e+00, 9.7901192488367350108546816e-01},
+ {7.0000000000000000e+00, 7.3887247457810456552351752e-01},
+ {0.0000000000000000e+00, -2.7688005719200159404635997e-01},
+ {-5.0000000000000000e+00, -1.060361827107492160848778e-02},
+ {9.0000000000000000e+00, 6.3629370719841737980004837e-01},
+ {2.0000000000000000e+00, 9.2637723924396464525443662e-01},
+ {5.0000000000000000e+00, 2.2908343145930665230025625e-01},
+ {2.0000000000000000e+00, 7.2793991043601025126008608e-01},
+ {1.0000000000000000e+00, 8.2530809168085506044576505e-01},
+ {-8.0000000000000000e+00, -6.8592476857560136238589621e-01},
+}
+var nextafter = []float64{
+ 4.97901192488367438926388786e+00,
+ 7.73887247457810545370193722e+00,
+ -2.7688005719200153853520874e-01,
+ -5.01060361827107403343006808e+00,
+ 9.63629370719841915615688777e+00,
+ 2.92637723924396508934364647e+00,
+ 5.22908343145930754047867595e+00,
+ 2.72793991043601069534929593e+00,
+ 1.82530809168085528249036997e+00,
+ -8.68592476857559958602905681e+00,
+}
+var pow = []float64{
+ 9.5282232631648411840742957e+04,
+ 5.4811599352999901232411871e+07,
+ 5.2859121715894396531132279e-01,
+ 9.7587991957286474464259698e-06,
+ 4.328064329346044846740467e+09,
+ 8.4406761805034547437659092e+02,
+ 1.6946633276191194947742146e+05,
+ 5.3449040147551939075312879e+02,
+ 6.688182138451414936380374e+01,
+ 2.0609869004248742886827439e-09,
+}
+var remainder = []float64{
+ 4.197615023265299782906368e-02,
+ 2.261127525421895434476482e+00,
+ 3.231794108794261433104108e-02,
+ -2.120723654214984321697556e-02,
+ 3.637062928015826201999516e-01,
+ 1.220868282268106064236690e+00,
+ -4.581668629186133046005125e-01,
+ -9.117596417440410050403443e-01,
+ 8.734595415957246977711748e-01,
+ 1.314075231424398637614104e+00,
+}
+var signbit = []bool{
+ false,
+ false,
+ true,
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+}
+var sin = []float64{
+ -9.6466616586009283766724726e-01,
+ 9.9338225271646545763467022e-01,
+ -2.7335587039794393342449301e-01,
+ 9.5586257685042792878173752e-01,
+ -2.099421066779969164496634e-01,
+ 2.135578780799860532750616e-01,
+ -8.694568971167362743327708e-01,
+ 4.019566681155577786649878e-01,
+ 9.6778633541687993721617774e-01,
+ -6.734405869050344734943028e-01,
+}
+var sinh = []float64{
+ 7.2661916084208532301448439e+01,
+ 1.1479409110035194500526446e+03,
+ -2.8043136512812518927312641e-01,
+ -7.499429091181587232835164e+01,
+ 7.6552466042906758523925934e+03,
+ 9.3031583421672014313789064e+00,
+ 9.330815755828109072810322e+01,
+ 7.6179893137269146407361477e+00,
+ 3.021769180549615819524392e+00,
+ -2.95950575724449499189888e+03,
+}
+var sqrt = []float64{
+ 2.2313699659365484748756904e+00,
+ 2.7818829009464263511285458e+00,
+ 5.2619393496314796848143251e-01,
+ 2.2384377628763938724244104e+00,
+ 3.1042380236055381099288487e+00,
+ 1.7106657298385224403917771e+00,
+ 2.286718922705479046148059e+00,
+ 1.6516476350711159636222979e+00,
+ 1.3510396336454586262419247e+00,
+ 2.9471892997524949215723329e+00,
+}
+var tan = []float64{
+ -3.661316565040227801781974e+00,
+ 8.64900232648597589369854e+00,
+ -2.8417941955033612725238097e-01,
+ 3.253290185974728640827156e+00,
+ 2.147275640380293804770778e-01,
+ -2.18600910711067004921551e-01,
+ -1.760002817872367935518928e+00,
+ -4.389808914752818126249079e-01,
+ -3.843885560201130679995041e+00,
+ 9.10988793377685105753416e-01,
+}
+var tanh = []float64{
+ 9.9990531206936338549262119e-01,
+ 9.9999962057085294197613294e-01,
+ -2.7001505097318677233756845e-01,
+ -9.9991110943061718603541401e-01,
+ 9.9999999146798465745022007e-01,
+ 9.9427249436125236705001048e-01,
+ 9.9994257600983138572705076e-01,
+ 9.9149409509772875982054701e-01,
+ 9.4936501296239685514466577e-01,
+ -9.9999994291374030946055701e-01,
+}
+var trunc = []float64{
+ 4.0000000000000000e+00,
+ 7.0000000000000000e+00,
+ -0.0000000000000000e+00,
+ -5.0000000000000000e+00,
+ 9.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 5.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 1.0000000000000000e+00,
+ -8.0000000000000000e+00,
+}
+var y0 = []float64{
+ -3.053399153780788357534855e-01,
+ 1.7437227649515231515503649e-01,
+ -8.6221781263678836910392572e-01,
+ -3.100664880987498407872839e-01,
+ 1.422200649300982280645377e-01,
+ 4.000004067997901144239363e-01,
+ -3.3340749753099352392332536e-01,
+ 4.5399790746668954555205502e-01,
+ 4.8290004112497761007536522e-01,
+ 2.7036697826604756229601611e-01,
+}
+var y1 = []float64{
+ 0.15494213737457922210218611,
+ -0.2165955142081145245075746,
+ -2.4644949631241895201032829,
+ 0.1442740489541836405154505,
+ 0.2215379960518984777080163,
+ 0.3038800915160754150565448,
+ 0.0691107642452362383808547,
+ 0.2380116417809914424860165,
+ -0.20849492979459761009678934,
+ 0.0242503179793232308250804,
+}
+var y2 = []float64{
+ 0.3675780219390303613394936,
+ -0.23034826393250119879267257,
+ -16.939677983817727205631397,
+ 0.367653980523052152867791,
+ -0.0962401471767804440353136,
+ -0.1923169356184851105200523,
+ 0.35984072054267882391843766,
+ -0.2794987252299739821654982,
+ -0.7113490692587462579757954,
+ -0.2647831587821263302087457,
+}
+var yM3 = []float64{
+ -0.14035984421094849100895341,
+ -0.097535139617792072703973,
+ 242.25775994555580176377379,
+ -0.1492267014802818619511046,
+ 0.26148702629155918694500469,
+ 0.56675383593895176530394248,
+ -0.206150264009006981070575,
+ 0.64784284687568332737963658,
+ 1.3503631555901938037008443,
+ 0.1461869756579956803341844,
+}
+
+// arguments and expected results for special cases
+var vfacosSC = []float64{
+ -Pi,
+ 1,
+ Pi,
+ NaN(),
+}
+var acosSC = []float64{
+ NaN(),
+ 0,
+ NaN(),
+ NaN(),
+}
+
+var vfacoshSC = []float64{
+ Inf(-1),
+ 0.5,
+ 1,
+ Inf(1),
+ NaN(),
+}
+var acoshSC = []float64{
+ NaN(),
+ NaN(),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfasinSC = []float64{
+ -Pi,
+ Copysign(0, -1),
+ 0,
+ Pi,
+ NaN(),
+}
+var asinSC = []float64{
+ NaN(),
+ Copysign(0, -1),
+ 0,
+ NaN(),
+ NaN(),
+}
+
+var vfasinhSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var asinhSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfatanSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var atanSC = []float64{
+ -Pi / 2,
+ Copysign(0, -1),
+ 0,
+ Pi / 2,
+ NaN(),
+}
+
+var vfatanhSC = []float64{
+ Inf(-1),
+ -Pi,
+ -1,
+ Copysign(0, -1),
+ 0,
+ 1,
+ Pi,
+ Inf(1),
+ NaN(),
+}
+var atanhSC = []float64{
+ NaN(),
+ NaN(),
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+ NaN(),
+ NaN(),
+}
+var vfatan2SC = [][2]float64{
+ {Inf(-1), Inf(-1)},
+ {Inf(-1), -Pi},
+ {Inf(-1), 0},
+ {Inf(-1), +Pi},
+ {Inf(-1), Inf(1)},
+ {Inf(-1), NaN()},
+ {-Pi, Inf(-1)},
+ {-Pi, 0},
+ {-Pi, Inf(1)},
+ {-Pi, NaN()},
+ {Copysign(0, -1), Inf(-1)},
+ {Copysign(0, -1), -Pi},
+ {Copysign(0, -1), Copysign(0, -1)},
+ {Copysign(0, -1), 0},
+ {Copysign(0, -1), +Pi},
+ {Copysign(0, -1), Inf(1)},
+ {Copysign(0, -1), NaN()},
+ {0, Inf(-1)},
+ {0, -Pi},
+ {0, Copysign(0, -1)},
+ {0, 0},
+ {0, +Pi},
+ {0, Inf(1)},
+ {0, NaN()},
+ {+Pi, Inf(-1)},
+ {+Pi, 0},
+ {+Pi, Inf(1)},
+ {+Pi, NaN()},
+ {Inf(1), Inf(-1)},
+ {Inf(1), -Pi},
+ {Inf(1), 0},
+ {Inf(1), +Pi},
+ {Inf(1), Inf(1)},
+ {Inf(1), NaN()},
+ {NaN(), NaN()},
+}
+var atan2SC = []float64{
+ -3 * Pi / 4, // atan2(-Inf, -Inf)
+ -Pi / 2, // atan2(-Inf, -Pi)
+ -Pi / 2, // atan2(-Inf, +0)
+ -Pi / 2, // atan2(-Inf, +Pi)
+ -Pi / 4, // atan2(-Inf, +Inf)
+ NaN(), // atan2(-Inf, NaN)
+ -Pi, // atan2(-Pi, -Inf)
+ -Pi / 2, // atan2(-Pi, +0)
+ Copysign(0, -1), // atan2(-Pi, Inf)
+ NaN(), // atan2(-Pi, NaN)
+ -Pi, // atan2(-0, -Inf)
+ -Pi, // atan2(-0, -Pi)
+ -Pi, // atan2(-0, -0)
+ Copysign(0, -1), // atan2(-0, +0)
+ Copysign(0, -1), // atan2(-0, +Pi)
+ Copysign(0, -1), // atan2(-0, +Inf)
+ NaN(), // atan2(-0, NaN)
+ Pi, // atan2(+0, -Inf)
+ Pi, // atan2(+0, -Pi)
+ Pi, // atan2(+0, -0)
+ 0, // atan2(+0, +0)
+ 0, // atan2(+0, +Pi)
+ 0, // atan2(+0, +Inf)
+ NaN(), // atan2(+0, NaN)
+ Pi, // atan2(+Pi, -Inf)
+ Pi / 2, // atan2(+Pi, +0)
+ 0, // atan2(+Pi, +Inf)
+ NaN(), // atan2(+Pi, NaN)
+ 3 * Pi / 4, // atan2(+Inf, -Inf)
+ Pi / 2, // atan2(+Inf, -Pi)
+ Pi / 2, // atan2(+Inf, +0)
+ Pi / 2, // atan2(+Inf, +Pi)
+ Pi / 4, // atan2(+Inf, +Inf)
+ NaN(), // atan2(+Inf, NaN)
+ NaN(), // atan2(NaN, NaN)
+}
+
+var vfcbrtSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var cbrtSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfceilSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var ceilSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfcopysignSC = []float64{
+ Inf(-1),
+ Inf(1),
+ NaN(),
+}
+var copysignSC = []float64{
+ Inf(-1),
+ Inf(-1),
+ NaN(),
+}
+
+var vfcosSC = []float64{
+ Inf(-1),
+ Inf(1),
+ NaN(),
+}
+var cosSC = []float64{
+ NaN(),
+ NaN(),
+ NaN(),
+}
+
+var vfcoshSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var coshSC = []float64{
+ Inf(1),
+ 1,
+ 1,
+ Inf(1),
+ NaN(),
+}
+
+var vferfSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var erfSC = []float64{
+ -1,
+ Copysign(0, -1),
+ 0,
+ 1,
+ NaN(),
+}
+
+var vferfcSC = []float64{
+ Inf(-1),
+ Inf(1),
+ NaN(),
+}
+var erfcSC = []float64{
+ 2,
+ 0,
+ NaN(),
+}
+
+var vfexpSC = []float64{
+ Inf(-1),
+ -2000,
+ 2000,
+ Inf(1),
+ NaN(),
+}
+var expSC = []float64{
+ 0,
+ 0,
+ Inf(1),
+ Inf(1),
+ NaN(),
+}
+
+var vfexpm1SC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var expm1SC = []float64{
+ -1,
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vffabsSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var fabsSC = []float64{
+ Inf(1),
+ 0,
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vffmodSC = [][2]float64{
+ {Inf(-1), Inf(-1)},
+ {Inf(-1), -Pi},
+ {Inf(-1), 0},
+ {Inf(-1), Pi},
+ {Inf(-1), Inf(1)},
+ {Inf(-1), NaN()},
+ {-Pi, Inf(-1)},
+ {-Pi, 0},
+ {-Pi, Inf(1)},
+ {-Pi, NaN()},
+ {Copysign(0, -1), Inf(-1)},
+ {Copysign(0, -1), 0},
+ {Copysign(0, -1), Inf(1)},
+ {Copysign(0, -1), NaN()},
+ {0, Inf(-1)},
+ {0, 0},
+ {0, Inf(1)},
+ {0, NaN()},
+ {Pi, Inf(-1)},
+ {Pi, 0},
+ {Pi, Inf(1)},
+ {Pi, NaN()},
+ {Inf(1), Inf(-1)},
+ {Inf(1), -Pi},
+ {Inf(1), 0},
+ {Inf(1), Pi},
+ {Inf(1), Inf(1)},
+ {Inf(1), NaN()},
+ {NaN(), Inf(-1)},
+ {NaN(), -Pi},
+ {NaN(), 0},
+ {NaN(), Pi},
+ {NaN(), Inf(1)},
+ {NaN(), NaN()},
+}
+var fmodSC = []float64{
+ NaN(), // fmod(-Inf, -Inf)
+ NaN(), // fmod(-Inf, -Pi)
+ NaN(), // fmod(-Inf, 0)
+ NaN(), // fmod(-Inf, Pi)
+ NaN(), // fmod(-Inf, +Inf)
+ NaN(), // fmod(-Inf, NaN)
+ -Pi, // fmod(-Pi, -Inf)
+ NaN(), // fmod(-Pi, 0)
+ -Pi, // fmod(-Pi, +Inf)
+ NaN(), // fmod(-Pi, NaN)
+ Copysign(0, -1), // fmod(-0, -Inf)
+ NaN(), // fmod(-0, 0)
+ Copysign(0, -1), // fmod(-0, Inf)
+ NaN(), // fmod(-0, NaN)
+ 0, // fmod(0, -Inf)
+ NaN(), // fmod(0, 0)
+ 0, // fmod(0, +Inf)
+ NaN(), // fmod(0, NaN)
+ Pi, // fmod(Pi, -Inf)
+ NaN(), // fmod(Pi, 0)
+ Pi, // fmod(Pi, +Inf)
+ NaN(), // fmod(Pi, NaN)
+ NaN(), // fmod(+Inf, -Inf)
+ NaN(), // fmod(+Inf, -Pi)
+ NaN(), // fmod(+Inf, 0)
+ NaN(), // fmod(+Inf, Pi)
+ NaN(), // fmod(+Inf, +Inf)
+ NaN(), // fmod(+Inf, NaN)
+ NaN(), // fmod(NaN, -Inf)
+ NaN(), // fmod(NaN, -Pi)
+ NaN(), // fmod(NaN, 0)
+ NaN(), // fmod(NaN, Pi)
+ NaN(), // fmod(NaN, +Inf)
+ NaN(), // fmod(NaN, NaN)
+}
+
+var vffrexpSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var frexpSC = []fi{
+ {Inf(-1), 0},
+ {Copysign(0, -1), 0},
+ {0, 0},
+ {Inf(1), 0},
+ {NaN(), 0},
+}
+
+var vfgammaSC = []float64{
+ Inf(-1),
+ -3,
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var gammaSC = []float64{
+ Inf(-1),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ NaN(),
+}
+
+var vfhypotSC = [][2]float64{
+ {Inf(-1), Inf(-1)},
+ {Inf(-1), 0},
+ {Inf(-1), Inf(1)},
+ {Inf(-1), NaN()},
+ {Copysign(0, -1), Copysign(0, -1)},
+ {Copysign(0, -1), 0},
+ {0, Copysign(0, -1)},
+ {0, 0}, // +0, +0
+ {0, Inf(-1)},
+ {0, Inf(1)},
+ {0, NaN()},
+ {Inf(1), Inf(-1)},
+ {Inf(1), 0},
+ {Inf(1), Inf(1)},
+ {Inf(1), NaN()},
+ {NaN(), Inf(-1)},
+ {NaN(), 0},
+ {NaN(), Inf(1)},
+ {NaN(), NaN()},
+}
+var hypotSC = []float64{
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ 0,
+ 0,
+ 0,
+ 0,
+ Inf(1),
+ Inf(1),
+ NaN(),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ NaN(),
+ Inf(1),
+ NaN(),
+}
+
+var vfilogbSC = []float64{
+ Inf(-1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var ilogbSC = []int{
+ MaxInt32,
+ MinInt32,
+ MaxInt32,
+ MaxInt32,
+}
+
+var vfj0SC = []float64{
+ Inf(-1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var j0SC = []float64{
+ 0,
+ 1,
+ 0,
+ NaN(),
+}
+var j1SC = []float64{
+ 0,
+ 0,
+ 0,
+ NaN(),
+}
+var j2SC = []float64{
+ 0,
+ 0,
+ 0,
+ NaN(),
+}
+var jM3SC = []float64{
+ 0,
+ 0,
+ 0,
+ NaN(),
+}
+
+var vfldexpSC = []fi{
+ {0, 0},
+ {0, -1075},
+ {0, 1024},
+ {Copysign(0, -1), 0},
+ {Copysign(0, -1), -1075},
+ {Copysign(0, -1), 1024},
+ {Inf(1), 0},
+ {Inf(1), -1024},
+ {Inf(-1), 0},
+ {Inf(-1), -1024},
+ {NaN(), -1024},
+}
+var ldexpSC = []float64{
+ 0,
+ 0,
+ 0,
+ Copysign(0, -1),
+ Copysign(0, -1),
+ Copysign(0, -1),
+ Inf(1),
+ Inf(1),
+ Inf(-1),
+ Inf(-1),
+ NaN(),
+}
+
+var vflgammaSC = []float64{
+ Inf(-1),
+ -3,
+ 0,
+ 1,
+ 2,
+ Inf(1),
+ NaN(),
+}
+var lgammaSC = []fi{
+ {Inf(-1), 1},
+ {Inf(1), 1},
+ {Inf(1), 1},
+ {0, 1},
+ {0, 1},
+ {Inf(1), 1},
+ {NaN(), 1},
+}
+
+var vflogSC = []float64{
+ Inf(-1),
+ -Pi,
+ Copysign(0, -1),
+ 0,
+ 1,
+ Inf(1),
+ NaN(),
+}
+var logSC = []float64{
+ NaN(),
+ NaN(),
+ Inf(-1),
+ Inf(-1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vflogbSC = []float64{
+ Inf(-1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var logbSC = []float64{
+ Inf(1),
+ Inf(-1),
+ Inf(1),
+ NaN(),
+}
+
+var vflog1pSC = []float64{
+ Inf(-1),
+ -Pi,
+ -1,
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var log1pSC = []float64{
+ NaN(),
+ NaN(),
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfmodfSC = []float64{
+ Inf(-1),
+ Inf(1),
+ NaN(),
+}
+var modfSC = [][2]float64{
+ {Inf(-1), NaN()}, // [2]float64{Copysign(0, -1), Inf(-1)},
+ {Inf(1), NaN()}, // [2]float64{0, Inf(1)},
+ {NaN(), NaN()},
+}
+
+var vfnextafterSC = [][2]float64{
+ {0, NaN()},
+ {NaN(), 0},
+ {NaN(), NaN()},
+}
+var nextafterSC = []float64{
+ NaN(),
+ NaN(),
+ NaN(),
+}
+
+var vfpowSC = [][2]float64{
+ {Inf(-1), -Pi},
+ {Inf(-1), -3},
+ {Inf(-1), Copysign(0, -1)},
+ {Inf(-1), 0},
+ {Inf(-1), 1},
+ {Inf(-1), 3},
+ {Inf(-1), Pi},
+ {Inf(-1), NaN()},
+
+ {-Pi, Inf(-1)},
+ {-Pi, -Pi},
+ {-Pi, Copysign(0, -1)},
+ {-Pi, 0},
+ {-Pi, 1},
+ {-Pi, Pi},
+ {-Pi, Inf(1)},
+ {-Pi, NaN()},
+
+ {-1, Inf(-1)},
+ {-1, Inf(1)},
+ {-1, NaN()},
+ {-1 / 2, Inf(-1)},
+ {-1 / 2, Inf(1)},
+ {Copysign(0, -1), Inf(-1)},
+ {Copysign(0, -1), -Pi},
+ {Copysign(0, -1), -3},
+ {Copysign(0, -1), 3},
+ {Copysign(0, -1), Pi},
+ {Copysign(0, -1), Inf(1)},
+
+ {0, Inf(-1)},
+ {0, -Pi},
+ {0, -3},
+ {0, Copysign(0, -1)},
+ {0, 0},
+ {0, 3},
+ {0, Pi},
+ {0, Inf(1)},
+ {0, NaN()},
+
+ {1 / 2, Inf(-1)},
+ {1 / 2, Inf(1)},
+ {1, Inf(-1)},
+ {1, Inf(1)},
+ {1, NaN()},
+
+ {Pi, Inf(-1)},
+ {Pi, Copysign(0, -1)},
+ {Pi, 0},
+ {Pi, 1},
+ {Pi, Inf(1)},
+ {Pi, NaN()},
+ {Inf(1), -Pi},
+ {Inf(1), Copysign(0, -1)},
+ {Inf(1), 0},
+ {Inf(1), 1},
+ {Inf(1), Pi},
+ {Inf(1), NaN()},
+ {NaN(), -Pi},
+ {NaN(), Copysign(0, -1)},
+ {NaN(), 0},
+ {NaN(), 1},
+ {NaN(), Pi},
+ {NaN(), NaN()},
+}
+var powSC = []float64{
+ 0, // pow(-Inf, -Pi)
+ Copysign(0, -1), // pow(-Inf, -3)
+ 1, // pow(-Inf, -0)
+ 1, // pow(-Inf, +0)
+ Inf(-1), // pow(-Inf, 1)
+ Inf(-1), // pow(-Inf, 3)
+ Inf(1), // pow(-Inf, Pi)
+ NaN(), // pow(-Inf, NaN)
+ 0, // pow(-Pi, -Inf)
+ NaN(), // pow(-Pi, -Pi)
+ 1, // pow(-Pi, -0)
+ 1, // pow(-Pi, +0)
+ -Pi, // pow(-Pi, 1)
+ NaN(), // pow(-Pi, Pi)
+ Inf(1), // pow(-Pi, +Inf)
+ NaN(), // pow(-Pi, NaN)
+ 1, // pow(-1, -Inf) IEEE 754-2008
+ 1, // pow(-1, +Inf) IEEE 754-2008
+ NaN(), // pow(-1, NaN)
+ Inf(1), // pow(-1/2, -Inf)
+ 0, // pow(-1/2, +Inf)
+ Inf(1), // pow(-0, -Inf)
+ Inf(1), // pow(-0, -Pi)
+ Inf(-1), // pow(-0, -3) IEEE 754-2008
+ Copysign(0, -1), // pow(-0, 3) IEEE 754-2008
+ 0, // pow(-0, +Pi)
+ 0, // pow(-0, +Inf)
+ Inf(1), // pow(+0, -Inf)
+ Inf(1), // pow(+0, -Pi)
+ Inf(1), // pow(+0, -3)
+ 1, // pow(+0, -0)
+ 1, // pow(+0, +0)
+ 0, // pow(+0, 3)
+ 0, // pow(+0, +Pi)
+ 0, // pow(+0, +Inf)
+ NaN(), // pow(+0, NaN)
+ Inf(1), // pow(1/2, -Inf)
+ 0, // pow(1/2, +Inf)
+ 1, // pow(1, -Inf) IEEE 754-2008
+ 1, // pow(1, +Inf) IEEE 754-2008
+ 1, // pow(1, NaN) IEEE 754-2008
+ 0, // pow(+Pi, -Inf)
+ 1, // pow(+Pi, -0)
+ 1, // pow(+Pi, +0)
+ Pi, // pow(+Pi, 1)
+ Inf(1), // pow(+Pi, +Inf)
+ NaN(), // pow(+Pi, NaN)
+ 0, // pow(+Inf, -Pi)
+ 1, // pow(+Inf, -0)
+ 1, // pow(+Inf, +0)
+ Inf(1), // pow(+Inf, 1)
+ Inf(1), // pow(+Inf, Pi)
+ NaN(), // pow(+Inf, NaN)
+ NaN(), // pow(NaN, -Pi)
+ 1, // pow(NaN, -0)
+ 1, // pow(NaN, +0)
+ NaN(), // pow(NaN, 1)
+ NaN(), // pow(NaN, +Pi)
+ NaN(), // pow(NaN, NaN)
+}
+
+var vfsignbitSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var signbitSC = []bool{
+ true,
+ true,
+ false,
+ false,
+ false,
+}
+
+var vfsinSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var sinSC = []float64{
+ NaN(),
+ Copysign(0, -1),
+ 0,
+ NaN(),
+ NaN(),
+}
+
+var vfsinhSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var sinhSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vfsqrtSC = []float64{
+ Inf(-1),
+ -Pi,
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var sqrtSC = []float64{
+ NaN(),
+ NaN(),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+
+var vftanhSC = []float64{
+ Inf(-1),
+ Copysign(0, -1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var tanhSC = []float64{
+ -1,
+ Copysign(0, -1),
+ 0,
+ 1,
+ NaN(),
+}
+
+var vfy0SC = []float64{
+ Inf(-1),
+ 0,
+ Inf(1),
+ NaN(),
+}
+var y0SC = []float64{
+ NaN(),
+ Inf(-1),
+ 0,
+ NaN(),
+}
+var y1SC = []float64{
+ NaN(),
+ Inf(-1),
+ 0,
+ NaN(),
+}
+var y2SC = []float64{
+ NaN(),
+ Inf(-1),
+ 0,
+ NaN(),
+}
+var yM3SC = []float64{
+ NaN(),
+ Inf(1),
+ 0,
+ NaN(),
+}
+
+// arguments and expected results for boundary cases
+const (
+ SmallestNormalFloat64 = 2.2250738585072014e-308 // 2**-1022
+ LargestSubnormalFloat64 = SmallestNormalFloat64 - SmallestNonzeroFloat64
+)
+
+var vffrexpBC = []float64{
+ SmallestNormalFloat64,
+ LargestSubnormalFloat64,
+ SmallestNonzeroFloat64,
+ MaxFloat64,
+ -SmallestNormalFloat64,
+ -LargestSubnormalFloat64,
+ -SmallestNonzeroFloat64,
+ -MaxFloat64,
+}
+var frexpBC = []fi{
+ {0.5, -1021},
+ {0.99999999999999978, -1022},
+ {0.5, -1073},
+ {0.99999999999999989, 1024},
+ {-0.5, -1021},
+ {-0.99999999999999978, -1022},
+ {-0.5, -1073},
+ {-0.99999999999999989, 1024},
+}
+
+var vfldexpBC = []fi{
+ {SmallestNormalFloat64, -52},
+ {LargestSubnormalFloat64, -51},
+ {SmallestNonzeroFloat64, 1074},
+ {MaxFloat64, -(1023 + 1074)},
+ {1, -1075},
+ {-1, -1075},
+ {1, 1024},
+ {-1, 1024},
+}
+var ldexpBC = []float64{
+ SmallestNonzeroFloat64,
+ 1e-323, // 2**-1073
+ 1,
+ 1e-323, // 2**-1073
+ 0,
+ Copysign(0, -1),
+ Inf(1),
+ Inf(-1),
+}
+
+var logbBC = []float64{
+ -1022,
+ -1023,
+ -1074,
+ 1023,
+ -1022,
+ -1023,
+ -1074,
+ 1023,
+}
+
+func tolerance(a, b, e float64) bool {
+ d := a - b
+ if d < 0 {
+ d = -d
+ }
+
+ if a != 0 {
+ e = e * a
+ if e < 0 {
+ e = -e
+ }
+ }
+ return d < e
+}
+func kindaclose(a, b float64) bool { return tolerance(a, b, 1e-8) }
+func close(a, b float64) bool { return tolerance(a, b, 1e-14) }
+func veryclose(a, b float64) bool { return tolerance(a, b, 4e-16) }
+func soclose(a, b, e float64) bool { return tolerance(a, b, e) }
+func alike(a, b float64) bool {
+ switch {
+ case IsNaN(a) && IsNaN(b):
+ return true
+ case a == b:
+ return Signbit(a) == Signbit(b)
+ }
+ return false
+}
+
+func TestAcos(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 10
+ if f := Acos(a); !close(acos[i], f) {
+ t.Errorf("Acos(%g) = %g, want %g", a, f, acos[i])
+ }
+ }
+ for i := 0; i < len(vfacosSC); i++ {
+ if f := Acos(vfacosSC[i]); !alike(acosSC[i], f) {
+ t.Errorf("Acos(%g) = %g, want %g", vfacosSC[i], f, acosSC[i])
+ }
+ }
+}
+
+func TestAcosh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := 1 + Fabs(vf[i])
+ if f := Acosh(a); !veryclose(acosh[i], f) {
+ t.Errorf("Acosh(%g) = %g, want %g", a, f, acosh[i])
+ }
+ }
+ for i := 0; i < len(vfacoshSC); i++ {
+ if f := Acosh(vfacoshSC[i]); !alike(acoshSC[i], f) {
+ t.Errorf("Acosh(%g) = %g, want %g", vfacoshSC[i], f, acoshSC[i])
+ }
+ }
+}
+
+func TestAsin(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 10
+ if f := Asin(a); !veryclose(asin[i], f) {
+ t.Errorf("Asin(%g) = %g, want %g", a, f, asin[i])
+ }
+ }
+ for i := 0; i < len(vfasinSC); i++ {
+ if f := Asin(vfasinSC[i]); !alike(asinSC[i], f) {
+ t.Errorf("Asin(%g) = %g, want %g", vfasinSC[i], f, asinSC[i])
+ }
+ }
+}
+
+func TestAsinh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Asinh(vf[i]); !veryclose(asinh[i], f) {
+ t.Errorf("Asinh(%g) = %g, want %g", vf[i], f, asinh[i])
+ }
+ }
+ for i := 0; i < len(vfasinhSC); i++ {
+ if f := Asinh(vfasinhSC[i]); !alike(asinhSC[i], f) {
+ t.Errorf("Asinh(%g) = %g, want %g", vfasinhSC[i], f, asinhSC[i])
+ }
+ }
+}
+
+func TestAtan(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Atan(vf[i]); !veryclose(atan[i], f) {
+ t.Errorf("Atan(%g) = %g, want %g", vf[i], f, atan[i])
+ }
+ }
+ for i := 0; i < len(vfatanSC); i++ {
+ if f := Atan(vfatanSC[i]); !alike(atanSC[i], f) {
+ t.Errorf("Atan(%g) = %g, want %g", vfatanSC[i], f, atanSC[i])
+ }
+ }
+}
+
+func TestAtanh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 10
+ if f := Atanh(a); !veryclose(atanh[i], f) {
+ t.Errorf("Atanh(%g) = %g, want %g", a, f, atanh[i])
+ }
+ }
+ for i := 0; i < len(vfatanhSC); i++ {
+ if f := Atanh(vfatanhSC[i]); !alike(atanhSC[i], f) {
+ t.Errorf("Atanh(%g) = %g, want %g", vfatanhSC[i], f, atanhSC[i])
+ }
+ }
+}
+
+func TestAtan2(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Atan2(10, vf[i]); !veryclose(atan2[i], f) {
+ t.Errorf("Atan2(10, %g) = %g, want %g", vf[i], f, atan2[i])
+ }
+ }
+ for i := 0; i < len(vfatan2SC); i++ {
+ if f := Atan2(vfatan2SC[i][0], vfatan2SC[i][1]); !alike(atan2SC[i], f) {
+ t.Errorf("Atan2(%g, %g) = %g, want %g", vfatan2SC[i][0], vfatan2SC[i][1], f, atan2SC[i])
+ }
+ }
+}
+
+func TestCbrt(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Cbrt(vf[i]); !veryclose(cbrt[i], f) {
+ t.Errorf("Cbrt(%g) = %g, want %g", vf[i], f, cbrt[i])
+ }
+ }
+ for i := 0; i < len(vfcbrtSC); i++ {
+ if f := Cbrt(vfcbrtSC[i]); !alike(cbrtSC[i], f) {
+ t.Errorf("Cbrt(%g) = %g, want %g", vfcbrtSC[i], f, cbrtSC[i])
+ }
+ }
+}
+
+func TestCeil(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Ceil(vf[i]); ceil[i] != f {
+ t.Errorf("Ceil(%g) = %g, want %g", vf[i], f, ceil[i])
+ }
+ }
+ for i := 0; i < len(vfceilSC); i++ {
+ if f := Ceil(vfceilSC[i]); !alike(ceilSC[i], f) {
+ t.Errorf("Ceil(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
+ }
+ }
+}
+
+func TestCopysign(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Copysign(vf[i], -1); copysign[i] != f {
+ t.Errorf("Copysign(%g, -1) = %g, want %g", vf[i], f, copysign[i])
+ }
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := Copysign(vf[i], 1); -copysign[i] != f {
+ t.Errorf("Copysign(%g, 1) = %g, want %g", vf[i], f, -copysign[i])
+ }
+ }
+ for i := 0; i < len(vfcopysignSC); i++ {
+ if f := Copysign(vfcopysignSC[i], -1); !alike(copysignSC[i], f) {
+ t.Errorf("Copysign(%g, -1) = %g, want %g", vfcopysignSC[i], f, copysignSC[i])
+ }
+ }
+}
+
+func TestCos(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Cos(vf[i]); !close(cos[i], f) {
+ t.Errorf("Cos(%g) = %g, want %g", vf[i], f, cos[i])
+ }
+ }
+ for i := 0; i < len(vfcosSC); i++ {
+ if f := Cos(vfcosSC[i]); !alike(cosSC[i], f) {
+ t.Errorf("Cos(%g) = %g, want %g", vfcosSC[i], f, cosSC[i])
+ }
+ }
+}
+
+func TestCosh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Cosh(vf[i]); !close(cosh[i], f) {
+ t.Errorf("Cosh(%g) = %g, want %g", vf[i], f, cosh[i])
+ }
+ }
+ for i := 0; i < len(vfcoshSC); i++ {
+ if f := Cosh(vfcoshSC[i]); !alike(coshSC[i], f) {
+ t.Errorf("Cosh(%g) = %g, want %g", vfcoshSC[i], f, coshSC[i])
+ }
+ }
+}
+
+func TestErf(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 10
+ if f := Erf(a); !veryclose(erf[i], f) {
+ t.Errorf("Erf(%g) = %g, want %g", a, f, erf[i])
+ }
+ }
+ for i := 0; i < len(vferfSC); i++ {
+ if f := Erf(vferfSC[i]); !alike(erfSC[i], f) {
+ t.Errorf("Erf(%g) = %g, want %g", vferfSC[i], f, erfSC[i])
+ }
+ }
+}
+
+func TestErfc(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 10
+ if f := Erfc(a); !veryclose(erfc[i], f) {
+ t.Errorf("Erfc(%g) = %g, want %g", a, f, erfc[i])
+ }
+ }
+ for i := 0; i < len(vferfcSC); i++ {
+ if f := Erfc(vferfcSC[i]); !alike(erfcSC[i], f) {
+ t.Errorf("Erfc(%g) = %g, want %g", vferfcSC[i], f, erfcSC[i])
+ }
+ }
+}
+
+func TestExp(t *testing.T) {
+ testExp(t, Exp, "Exp")
+ testExp(t, ExpGo, "ExpGo")
+}
+
+func testExp(t *testing.T, Exp func(float64) float64, name string) {
+ for i := 0; i < len(vf); i++ {
+ if f := Exp(vf[i]); !close(exp[i], f) {
+ t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp[i])
+ }
+ }
+ for i := 0; i < len(vfexpSC); i++ {
+ if f := Exp(vfexpSC[i]); !alike(expSC[i], f) {
+ t.Errorf("%s(%g) = %g, want %g", name, vfexpSC[i], f, expSC[i])
+ }
+ }
+}
+
+func TestExpm1(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 100
+ if f := Expm1(a); !veryclose(expm1[i], f) {
+ t.Errorf("Expm1(%g) = %g, want %g", a, f, expm1[i])
+ }
+ }
+ for i := 0; i < len(vfexpm1SC); i++ {
+ if f := Expm1(vfexpm1SC[i]); !alike(expm1SC[i], f) {
+ t.Errorf("Expm1(%g) = %g, want %g", vfexpm1SC[i], f, expm1SC[i])
+ }
+ }
+}
+
+func TestExp2(t *testing.T) {
+ testExp2(t, Exp2, "Exp2")
+ testExp2(t, Exp2Go, "Exp2Go")
+}
+
+func testExp2(t *testing.T, Exp2 func(float64) float64, name string) {
+ for i := 0; i < len(vf); i++ {
+ if f := Exp2(vf[i]); !close(exp2[i], f) {
+ t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp2[i])
+ }
+ }
+ for i := 0; i < len(vfexpSC); i++ {
+ if f := Exp2(vfexpSC[i]); !alike(expSC[i], f) {
+ t.Errorf("%s(%g) = %g, want %g", name, vfexpSC[i], f, expSC[i])
+ }
+ }
+ for n := -1074; n < 1024; n++ {
+ f := Exp2(float64(n))
+ vf := Ldexp(1, n)
+ if f != vf {
+ t.Errorf("%s(%d) = %g, want %g", name, n, f, vf)
+ }
+ }
+}
+
+func TestFabs(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Fabs(vf[i]); fabs[i] != f {
+ t.Errorf("Fabs(%g) = %g, want %g", vf[i], f, fabs[i])
+ }
+ }
+ for i := 0; i < len(vffabsSC); i++ {
+ if f := Fabs(vffabsSC[i]); !alike(fabsSC[i], f) {
+ t.Errorf("Fabs(%g) = %g, want %g", vffabsSC[i], f, fabsSC[i])
+ }
+ }
+}
+
+func TestFdim(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Fdim(vf[i], 0); fdim[i] != f {
+ t.Errorf("Fdim(%g, %g) = %g, want %g", vf[i], 0.0, f, fdim[i])
+ }
+ }
+}
+
+func TestFloor(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Floor(vf[i]); floor[i] != f {
+ t.Errorf("Floor(%g) = %g, want %g", vf[i], f, floor[i])
+ }
+ }
+ for i := 0; i < len(vfceilSC); i++ {
+ if f := Floor(vfceilSC[i]); !alike(ceilSC[i], f) {
+ t.Errorf("Floor(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
+ }
+ }
+}
+
+func TestFmax(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Fmax(vf[i], ceil[i]); ceil[i] != f {
+ t.Errorf("Fmax(%g, %g) = %g, want %g", vf[i], ceil[i], f, ceil[i])
+ }
+ }
+}
+
+func TestFmin(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Fmin(vf[i], floor[i]); floor[i] != f {
+ t.Errorf("Fmin(%g, %g) = %g, want %g", vf[i], floor[i], f, floor[i])
+ }
+ }
+}
+
+func TestFmod(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Fmod(10, vf[i]); fmod[i] != f {
+ t.Errorf("Fmod(10, %g) = %g, want %g", vf[i], f, fmod[i])
+ }
+ }
+ for i := 0; i < len(vffmodSC); i++ {
+ if f := Fmod(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) {
+ t.Errorf("Fmod(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
+ }
+ }
+}
+
+func TestFrexp(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f, j := Frexp(vf[i]); !veryclose(frexp[i].f, f) || frexp[i].i != j {
+ t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vf[i], f, j, frexp[i].f, frexp[i].i)
+ }
+ }
+ for i := 0; i < len(vffrexpSC); i++ {
+ if f, j := Frexp(vffrexpSC[i]); !alike(frexpSC[i].f, f) || frexpSC[i].i != j {
+ t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vffrexpSC[i], f, j, frexpSC[i].f, frexpSC[i].i)
+ }
+ }
+ for i := 0; i < len(vffrexpBC); i++ {
+ if f, j := Frexp(vffrexpBC[i]); !alike(frexpBC[i].f, f) || frexpBC[i].i != j {
+ t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vffrexpBC[i], f, j, frexpBC[i].f, frexpBC[i].i)
+ }
+ }
+}
+
+func TestGamma(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Gamma(vf[i]); !close(gamma[i], f) {
+ t.Errorf("Gamma(%g) = %g, want %g", vf[i], f, gamma[i])
+ }
+ }
+ for i := 0; i < len(vfgammaSC); i++ {
+ if f := Gamma(vfgammaSC[i]); !alike(gammaSC[i], f) {
+ t.Errorf("Gamma(%g) = %g, want %g", vfgammaSC[i], f, gammaSC[i])
+ }
+ }
+}
+
+func TestHypot(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(1e200 * tanh[i] * Sqrt(2))
+ if f := Hypot(1e200*tanh[i], 1e200*tanh[i]); !veryclose(a, f) {
+ t.Errorf("Hypot(%g, %g) = %g, want %g", 1e200*tanh[i], 1e200*tanh[i], f, a)
+ }
+ }
+ for i := 0; i < len(vfhypotSC); i++ {
+ if f := Hypot(vfhypotSC[i][0], vfhypotSC[i][1]); !alike(hypotSC[i], f) {
+ t.Errorf("Hypot(%g, %g) = %g, want %g", vfhypotSC[i][0], vfhypotSC[i][1], f, hypotSC[i])
+ }
+ }
+}
+
+func TestIlogb(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := frexp[i].i - 1 // adjust because fr in the interval [½, 1)
+ if e := Ilogb(vf[i]); a != e {
+ t.Errorf("Ilogb(%g) = %d, want %d", vf[i], e, a)
+ }
+ }
+ for i := 0; i < len(vflogbSC); i++ {
+ if e := Ilogb(vflogbSC[i]); ilogbSC[i] != e {
+ t.Errorf("Ilogb(%g) = %d, want %d", vflogbSC[i], e, ilogbSC[i])
+ }
+ }
+ for i := 0; i < len(vffrexpBC); i++ {
+ if e := Ilogb(vffrexpBC[i]); int(logbBC[i]) != e {
+ t.Errorf("Ilogb(%g) = %d, want %d", vffrexpBC[i], e, int(logbBC[i]))
+ }
+ }
+}
+
+func TestJ0(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := J0(vf[i]); !soclose(j0[i], f, 4e-14) {
+ t.Errorf("J0(%g) = %g, want %g", vf[i], f, j0[i])
+ }
+ }
+ for i := 0; i < len(vfj0SC); i++ {
+ if f := J0(vfj0SC[i]); !alike(j0SC[i], f) {
+ t.Errorf("J0(%g) = %g, want %g", vfj0SC[i], f, j0SC[i])
+ }
+ }
+}
+
+func TestJ1(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := J1(vf[i]); !close(j1[i], f) {
+ t.Errorf("J1(%g) = %g, want %g", vf[i], f, j1[i])
+ }
+ }
+ for i := 0; i < len(vfj0SC); i++ {
+ if f := J1(vfj0SC[i]); !alike(j1SC[i], f) {
+ t.Errorf("J1(%g) = %g, want %g", vfj0SC[i], f, j1SC[i])
+ }
+ }
+}
+
+func TestJn(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Jn(2, vf[i]); !close(j2[i], f) {
+ t.Errorf("Jn(2, %g) = %g, want %g", vf[i], f, j2[i])
+ }
+ if f := Jn(-3, vf[i]); !close(jM3[i], f) {
+ t.Errorf("Jn(-3, %g) = %g, want %g", vf[i], f, jM3[i])
+ }
+ }
+ for i := 0; i < len(vfj0SC); i++ {
+ if f := Jn(2, vfj0SC[i]); !alike(j2SC[i], f) {
+ t.Errorf("Jn(2, %g) = %g, want %g", vfj0SC[i], f, j2SC[i])
+ }
+ if f := Jn(-3, vfj0SC[i]); !alike(jM3SC[i], f) {
+ t.Errorf("Jn(-3, %g) = %g, want %g", vfj0SC[i], f, jM3SC[i])
+ }
+ }
+}
+
+func TestLdexp(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Ldexp(frexp[i].f, frexp[i].i); !veryclose(vf[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", frexp[i].f, frexp[i].i, f, vf[i])
+ }
+ }
+ for i := 0; i < len(vffrexpSC); i++ {
+ if f := Ldexp(frexpSC[i].f, frexpSC[i].i); !alike(vffrexpSC[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", frexpSC[i].f, frexpSC[i].i, f, vffrexpSC[i])
+ }
+ }
+ for i := 0; i < len(vfldexpSC); i++ {
+ if f := Ldexp(vfldexpSC[i].f, vfldexpSC[i].i); !alike(ldexpSC[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", vfldexpSC[i].f, vfldexpSC[i].i, f, ldexpSC[i])
+ }
+ }
+ for i := 0; i < len(vffrexpBC); i++ {
+ if f := Ldexp(frexpBC[i].f, frexpBC[i].i); !alike(vffrexpBC[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", frexpBC[i].f, frexpBC[i].i, f, vffrexpBC[i])
+ }
+ }
+ for i := 0; i < len(vfldexpBC); i++ {
+ if f := Ldexp(vfldexpBC[i].f, vfldexpBC[i].i); !alike(ldexpBC[i], f) {
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", vfldexpBC[i].f, vfldexpBC[i].i, f, ldexpBC[i])
+ }
+ }
+}
+
+func TestLgamma(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f, s := Lgamma(vf[i]); !close(lgamma[i].f, f) || lgamma[i].i != s {
+ t.Errorf("Lgamma(%g) = %g, %d, want %g, %d", vf[i], f, s, lgamma[i].f, lgamma[i].i)
+ }
+ }
+ for i := 0; i < len(vflgammaSC); i++ {
+ if f, s := Lgamma(vflgammaSC[i]); !alike(lgammaSC[i].f, f) || lgammaSC[i].i != s {
+ t.Errorf("Lgamma(%g) = %g, %d, want %g, %d", vflgammaSC[i], f, s, lgammaSC[i].f, lgammaSC[i].i)
+ }
+ }
+}
+
+func TestLog(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Log(a); log[i] != f {
+ t.Errorf("Log(%g) = %g, want %g", a, f, log[i])
+ }
+ }
+ if f := Log(10); f != Ln10 {
+ t.Errorf("Log(%g) = %g, want %g", 10.0, f, Ln10)
+ }
+ for i := 0; i < len(vflogSC); i++ {
+ if f := Log(vflogSC[i]); !alike(logSC[i], f) {
+ t.Errorf("Log(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+ }
+ }
+}
+
+func TestLogb(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Logb(vf[i]); logb[i] != f {
+ t.Errorf("Logb(%g) = %g, want %g", vf[i], f, logb[i])
+ }
+ }
+ for i := 0; i < len(vflogbSC); i++ {
+ if f := Logb(vflogbSC[i]); !alike(logbSC[i], f) {
+ t.Errorf("Logb(%g) = %g, want %g", vflogbSC[i], f, logbSC[i])
+ }
+ }
+ for i := 0; i < len(vffrexpBC); i++ {
+ if e := Logb(vffrexpBC[i]); !alike(logbBC[i], e) {
+ t.Errorf("Ilogb(%g) = %g, want %g", vffrexpBC[i], e, logbBC[i])
+ }
+ }
+}
+
+func TestLog10(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Log10(a); !veryclose(log10[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", a, f, log10[i])
+ }
+ }
+ if f := Log10(E); f != Log10E {
+ t.Errorf("Log10(%g) = %g, want %g", E, f, Log10E)
+ }
+ for i := 0; i < len(vflogSC); i++ {
+ if f := Log10(vflogSC[i]); !alike(logSC[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+ }
+ }
+}
+
+func TestLog1p(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := vf[i] / 100
+ if f := Log1p(a); !veryclose(log1p[i], f) {
+ t.Errorf("Log1p(%g) = %g, want %g", a, f, log1p[i])
+ }
+ }
+ a := 9.0
+ if f := Log1p(a); f != Ln10 {
+ t.Errorf("Log1p(%g) = %g, want %g", a, f, Ln10)
+ }
+ for i := 0; i < len(vflogSC); i++ {
+ if f := Log1p(vflog1pSC[i]); !alike(log1pSC[i], f) {
+ t.Errorf("Log1p(%g) = %g, want %g", vflog1pSC[i], f, log1pSC[i])
+ }
+ }
+}
+
+func TestLog2(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Log2(a); !veryclose(log2[i], f) {
+ t.Errorf("Log2(%g) = %g, want %g", a, f, log2[i])
+ }
+ }
+ if f := Log2(E); f != Log2E {
+ t.Errorf("Log2(%g) = %g, want %g", E, f, Log2E)
+ }
+ for i := 0; i < len(vflogSC); i++ {
+ if f := Log2(vflogSC[i]); !alike(logSC[i], f) {
+ t.Errorf("Log2(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+ }
+ }
+}
+
+func TestModf(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f, g := Modf(vf[i]); !veryclose(modf[i][0], f) || !veryclose(modf[i][1], g) {
+ t.Errorf("Modf(%g) = %g, %g, want %g, %g", vf[i], f, g, modf[i][0], modf[i][1])
+ }
+ }
+ for i := 0; i < len(vfmodfSC); i++ {
+ if f, g := Modf(vfmodfSC[i]); !alike(modfSC[i][0], f) || !alike(modfSC[i][1], g) {
+ t.Errorf("Modf(%g) = %g, %g, want %g, %g", vfmodfSC[i], f, g, modfSC[i][0], modfSC[i][1])
+ }
+ }
+}
+
+func TestNextafter(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Nextafter(vf[i], 10); nextafter[i] != f {
+ t.Errorf("Nextafter(%g, %g) = %g want %g", vf[i], 10.0, f, nextafter[i])
+ }
+ }
+ for i := 0; i < len(vfmodfSC); i++ {
+ if f := Nextafter(vfnextafterSC[i][0], vfnextafterSC[i][1]); !alike(nextafterSC[i], f) {
+ t.Errorf("Nextafter(%g, %g) = %g want %g", vfnextafterSC[i][0], vfnextafterSC[i][1], f, nextafterSC[i])
+ }
+ }
+}
+
+func TestPow(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Pow(10, vf[i]); !close(pow[i], f) {
+ t.Errorf("Pow(10, %g) = %g, want %g", vf[i], f, pow[i])
+ }
+ }
+ for i := 0; i < len(vfpowSC); i++ {
+ if f := Pow(vfpowSC[i][0], vfpowSC[i][1]); !alike(powSC[i], f) {
+ t.Errorf("Pow(%g, %g) = %g, want %g", vfpowSC[i][0], vfpowSC[i][1], f, powSC[i])
+ }
+ }
+}
+
+func TestRemainder(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Remainder(10, vf[i]); remainder[i] != f {
+ t.Errorf("Remainder(10, %g) = %g, want %g", vf[i], f, remainder[i])
+ }
+ }
+ for i := 0; i < len(vffmodSC); i++ {
+ if f := Remainder(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) {
+ t.Errorf("Remainder(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
+ }
+ }
+}
+
+func TestSignbit(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Signbit(vf[i]); signbit[i] != f {
+ t.Errorf("Signbit(%g) = %t, want %t", vf[i], f, signbit[i])
+ }
+ }
+ for i := 0; i < len(vfsignbitSC); i++ {
+ if f := Signbit(vfsignbitSC[i]); signbitSC[i] != f {
+ t.Errorf("Signbit(%g) = %t, want %t", vfsignbitSC[i], f, signbitSC[i])
+ }
+ }
+}
+func TestSin(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Sin(vf[i]); !close(sin[i], f) {
+ t.Errorf("Sin(%g) = %g, want %g", vf[i], f, sin[i])
+ }
+ }
+ for i := 0; i < len(vfsinSC); i++ {
+ if f := Sin(vfsinSC[i]); !alike(sinSC[i], f) {
+ t.Errorf("Sin(%g) = %g, want %g", vfsinSC[i], f, sinSC[i])
+ }
+ }
+}
+
+func TestSincos(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if s, c := Sincos(vf[i]); !close(sin[i], s) || !close(cos[i], c) {
+ t.Errorf("Sincos(%g) = %g, %g want %g, %g", vf[i], s, c, sin[i], cos[i])
+ }
+ }
+}
+
+func TestSinh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Sinh(vf[i]); !close(sinh[i], f) {
+ t.Errorf("Sinh(%g) = %g, want %g", vf[i], f, sinh[i])
+ }
+ }
+ for i := 0; i < len(vfsinhSC); i++ {
+ if f := Sinh(vfsinhSC[i]); !alike(sinhSC[i], f) {
+ t.Errorf("Sinh(%g) = %g, want %g", vfsinhSC[i], f, sinhSC[i])
+ }
+ }
+}
+
+func TestSqrt(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := SqrtGo(a); sqrt[i] != f {
+ t.Errorf("SqrtGo(%g) = %g, want %g", a, f, sqrt[i])
+ }
+ a = Fabs(vf[i])
+ if f := Sqrt(a); sqrt[i] != f {
+ t.Errorf("Sqrt(%g) = %g, want %g", a, f, sqrt[i])
+ }
+ }
+ for i := 0; i < len(vfsqrtSC); i++ {
+ if f := SqrtGo(vfsqrtSC[i]); !alike(sqrtSC[i], f) {
+ t.Errorf("SqrtGo(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i])
+ }
+ if f := Sqrt(vfsqrtSC[i]); !alike(sqrtSC[i], f) {
+ t.Errorf("Sqrt(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i])
+ }
+ }
+}
+
+func TestTan(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Tan(vf[i]); !close(tan[i], f) {
+ t.Errorf("Tan(%g) = %g, want %g", vf[i], f, tan[i])
+ }
+ }
+ // same special cases as Sin
+ for i := 0; i < len(vfsinSC); i++ {
+ if f := Tan(vfsinSC[i]); !alike(sinSC[i], f) {
+ t.Errorf("Tan(%g) = %g, want %g", vfsinSC[i], f, sinSC[i])
+ }
+ }
+
+ // Make sure portable Tan(Pi/2) doesn't panic (it used to).
+ // The portable implementation returns NaN.
+ // Assembly implementations might not,
+ // because Pi/2 is not exactly representable.
+ if runtime.GOARCH != "386" {
+ if f := Tan(Pi / 2); !alike(f, NaN()) {
+ t.Errorf("Tan(%g) = %g, want %g", Pi/2, f, NaN())
+ }
+ }
+}
+
+func TestTanh(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Tanh(vf[i]); !veryclose(tanh[i], f) {
+ t.Errorf("Tanh(%g) = %g, want %g", vf[i], f, tanh[i])
+ }
+ }
+ for i := 0; i < len(vftanhSC); i++ {
+ if f := Tanh(vftanhSC[i]); !alike(tanhSC[i], f) {
+ t.Errorf("Tanh(%g) = %g, want %g", vftanhSC[i], f, tanhSC[i])
+ }
+ }
+}
+
+func TestTrunc(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ if f := Trunc(vf[i]); trunc[i] != f {
+ t.Errorf("Trunc(%g) = %g, want %g", vf[i], f, trunc[i])
+ }
+ }
+ for i := 0; i < len(vfceilSC); i++ {
+ if f := Trunc(vfceilSC[i]); !alike(ceilSC[i], f) {
+ t.Errorf("Trunc(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
+ }
+ }
+}
+
+func TestY0(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Y0(a); !close(y0[i], f) {
+ t.Errorf("Y0(%g) = %g, want %g", a, f, y0[i])
+ }
+ }
+ for i := 0; i < len(vfy0SC); i++ {
+ if f := Y0(vfy0SC[i]); !alike(y0SC[i], f) {
+ t.Errorf("Y0(%g) = %g, want %g", vfy0SC[i], f, y0SC[i])
+ }
+ }
+}
+
+func TestY1(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Y1(a); !soclose(y1[i], f, 2e-14) {
+ t.Errorf("Y1(%g) = %g, want %g", a, f, y1[i])
+ }
+ }
+ for i := 0; i < len(vfy0SC); i++ {
+ if f := Y1(vfy0SC[i]); !alike(y1SC[i], f) {
+ t.Errorf("Y1(%g) = %g, want %g", vfy0SC[i], f, y1SC[i])
+ }
+ }
+}
+
+func TestYn(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Fabs(vf[i])
+ if f := Yn(2, a); !close(y2[i], f) {
+ t.Errorf("Yn(2, %g) = %g, want %g", a, f, y2[i])
+ }
+ if f := Yn(-3, a); !close(yM3[i], f) {
+ t.Errorf("Yn(-3, %g) = %g, want %g", a, f, yM3[i])
+ }
+ }
+ for i := 0; i < len(vfy0SC); i++ {
+ if f := Yn(2, vfy0SC[i]); !alike(y2SC[i], f) {
+ t.Errorf("Yn(2, %g) = %g, want %g", vfy0SC[i], f, y2SC[i])
+ }
+ if f := Yn(-3, vfy0SC[i]); !alike(yM3SC[i], f) {
+ t.Errorf("Yn(-3, %g) = %g, want %g", vfy0SC[i], f, yM3SC[i])
+ }
+ }
+}
+
+// Check that math functions of high angle values
+// return similar results to low angle values
+func TestLargeCos(t *testing.T) {
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1 := Cos(vf[i])
+ f2 := Cos(vf[i] + large)
+ if !kindaclose(f1, f2) {
+ t.Errorf("Cos(%g) = %g, want %g", vf[i]+large, f2, f1)
+ }
+ }
+}
+
+func TestLargeSin(t *testing.T) {
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1 := Sin(vf[i])
+ f2 := Sin(vf[i] + large)
+ if !kindaclose(f1, f2) {
+ t.Errorf("Sin(%g) = %g, want %g", vf[i]+large, f2, f1)
+ }
+ }
+}
+
+func TestLargeSincos(t *testing.T) {
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1, g1 := Sincos(vf[i])
+ f2, g2 := Sincos(vf[i] + large)
+ if !kindaclose(f1, f2) || !kindaclose(g1, g2) {
+ t.Errorf("Sincos(%g) = %g, %g, want %g, %g", vf[i]+large, f2, g2, f1, g1)
+ }
+ }
+}
+
+func TestLargeTan(t *testing.T) {
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1 := Tan(vf[i])
+ f2 := Tan(vf[i] + large)
+ if !kindaclose(f1, f2) {
+ t.Errorf("Tan(%g) = %g, want %g", vf[i]+large, f2, f1)
+ }
+ }
+}
+
+// Check that math constants are accepted by compiler
+// and have right value (assumes strconv.Atof works).
+// http://code.google.com/p/go/issues/detail?id=201
+
+type floatTest struct {
+ val interface{}
+ name string
+ str string
+}
+
+var floatTests = []floatTest{
+ {float64(MaxFloat64), "MaxFloat64", "1.7976931348623157e+308"},
+ {float64(SmallestNonzeroFloat64), "SmallestNonzeroFloat64", "5e-324"},
+ {float32(MaxFloat32), "MaxFloat32", "3.4028235e+38"},
+ {float32(SmallestNonzeroFloat32), "SmallestNonzeroFloat32", "1e-45"},
+}
+
+func TestFloatMinMax(t *testing.T) {
+ for _, tt := range floatTests {
+ s := fmt.Sprint(tt.val)
+ if s != tt.str {
+ t.Errorf("Sprint(%v) = %s, want %s", tt.name, s, tt.str)
+ }
+ }
+}
+
+// Benchmarks
+
+func BenchmarkAcos(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Acos(.5)
+ }
+}
+
+func BenchmarkAcosh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Acosh(1.5)
+ }
+}
+
+func BenchmarkAsin(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Asin(.5)
+ }
+}
+
+func BenchmarkAsinh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Asinh(.5)
+ }
+}
+
+func BenchmarkAtan(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atan(.5)
+ }
+}
+
+func BenchmarkAtanh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atanh(.5)
+ }
+}
+
+func BenchmarkAtan2(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atan2(.5, 1)
+ }
+}
+
+func BenchmarkCbrt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Cbrt(10)
+ }
+}
+
+func BenchmarkCeil(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Ceil(.5)
+ }
+}
+
+func BenchmarkCopysign(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Copysign(.5, -1)
+ }
+}
+
+func BenchmarkCos(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Cos(.5)
+ }
+}
+
+func BenchmarkCosh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Cosh(2.5)
+ }
+}
+
+func BenchmarkErf(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Erf(.5)
+ }
+}
+
+func BenchmarkErfc(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Erfc(.5)
+ }
+}
+
+func BenchmarkExp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Exp(.5)
+ }
+}
+
+func BenchmarkExpGo(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ExpGo(.5)
+ }
+}
+
+func BenchmarkExpm1(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Expm1(.5)
+ }
+}
+
+func BenchmarkExp2(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Exp2(.5)
+ }
+}
+
+func BenchmarkExp2Go(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Exp2Go(.5)
+ }
+}
+
+func BenchmarkFabs(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Fabs(.5)
+ }
+}
+
+func BenchmarkFdim(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Fdim(10, 3)
+ }
+}
+
+func BenchmarkFloor(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Floor(.5)
+ }
+}
+
+func BenchmarkFmax(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Fmax(10, 3)
+ }
+}
+
+func BenchmarkFmin(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Fmin(10, 3)
+ }
+}
+
+func BenchmarkFmod(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Fmod(10, 3)
+ }
+}
+
+func BenchmarkFrexp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Frexp(8)
+ }
+}
+
+func BenchmarkGamma(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Gamma(2.5)
+ }
+}
+
+func BenchmarkHypot(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Hypot(3, 4)
+ }
+}
+
+func BenchmarkHypotGo(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ HypotGo(3, 4)
+ }
+}
+
+func BenchmarkIlogb(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Ilogb(.5)
+ }
+}
+
+func BenchmarkJ0(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ J0(2.5)
+ }
+}
+
+func BenchmarkJ1(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ J1(2.5)
+ }
+}
+
+func BenchmarkJn(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Jn(2, 2.5)
+ }
+}
+
+func BenchmarkLdexp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Ldexp(.5, 2)
+ }
+}
+
+func BenchmarkLgamma(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Lgamma(2.5)
+ }
+}
+
+func BenchmarkLog(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log(.5)
+ }
+}
+
+func BenchmarkLogb(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Logb(.5)
+ }
+}
+
+func BenchmarkLog1p(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log1p(.5)
+ }
+}
+
+func BenchmarkLog10(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log10(.5)
+ }
+}
+
+func BenchmarkLog2(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Log2(.5)
+ }
+}
+
+func BenchmarkModf(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Modf(1.5)
+ }
+}
+
+func BenchmarkNextafter(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Nextafter(.5, 1)
+ }
+}
+
+func BenchmarkPowInt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Pow(2, 2)
+ }
+}
+
+func BenchmarkPowFrac(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Pow(2.5, 1.5)
+ }
+}
+
+func BenchmarkRemainder(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Remainder(10, 3)
+ }
+}
+
+func BenchmarkSignbit(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Signbit(2.5)
+ }
+}
+
+func BenchmarkSin(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sin(.5)
+ }
+}
+
+func BenchmarkSincos(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sincos(.5)
+ }
+}
+
+func BenchmarkSinh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sinh(2.5)
+ }
+}
+
+func BenchmarkSqrt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sqrt(10)
+ }
+}
+
+func BenchmarkSqrtGo(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ SqrtGo(10)
+ }
+}
+
+func BenchmarkTan(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Tan(.5)
+ }
+}
+
+func BenchmarkTanh(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Tanh(2.5)
+ }
+}
+func BenchmarkTrunc(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Trunc(.5)
+ }
+}
+
+func BenchmarkY0(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Y0(2.5)
+ }
+}
+
+func BenchmarkY1(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Y1(2.5)
+ }
+}
+
+func BenchmarkYn(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Yn(2, 2.5)
+ }
+}
diff --git a/libgo/go/math/asin.go b/libgo/go/math/asin.go
new file mode 100644
index 000000000..3bace8ff1
--- /dev/null
+++ b/libgo/go/math/asin.go
@@ -0,0 +1,50 @@
+// 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 math
+
+
+/*
+ Floating-point arcsine and arccosine.
+
+ They are implemented by computing the arctangent
+ after appropriate range reduction.
+*/
+
+// Asin returns the arcsine of x.
+//
+// Special cases are:
+// Asin(±0) = ±0
+// Asin(x) = NaN if x < -1 or x > 1
+func Asin(x float64) float64 {
+ if x == 0 {
+ return x // special case
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ if x > 1 {
+ return NaN() // special case
+ }
+
+ temp := Sqrt(1 - x*x)
+ if x > 0.7 {
+ temp = Pi/2 - satan(temp/x)
+ } else {
+ temp = satan(x / temp)
+ }
+
+ if sign {
+ temp = -temp
+ }
+ return temp
+}
+
+// Acos returns the arccosine of x.
+//
+// Special case is:
+// Acos(x) = NaN if x < -1 or x > 1
+func Acos(x float64) float64 { return Pi/2 - Asin(x) }
diff --git a/libgo/go/math/asinh.go b/libgo/go/math/asinh.go
new file mode 100644
index 000000000..90dcd27ab
--- /dev/null
+++ b/libgo/go/math/asinh.go
@@ -0,0 +1,72 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/s_asinh.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// asinh(x)
+// Method :
+// Based on
+// asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+// we have
+// asinh(x) := x if 1+x*x=1,
+// := sign(x)*(log(x)+ln2)) for large |x|, else
+// := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+// := sign(x)*log1p(|x| + x**2/(1 + sqrt(1+x**2)))
+//
+
+// Asinh(x) calculates the inverse hyperbolic sine of x.
+//
+// Special cases are:
+// Asinh(+Inf) = +Inf
+// Asinh(-Inf) = -Inf
+// Asinh(NaN) = NaN
+func Asinh(x float64) float64 {
+ const (
+ Ln2 = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF
+ NearZero = 1.0 / (1 << 28) // 2**-28
+ Large = 1 << 28 // 2**28
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ if x != x || x > MaxFloat64 || x < -MaxFloat64 { // IsNaN(x) || IsInf(x, 0)
+ return x
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ var temp float64
+ switch {
+ case x > Large:
+ temp = Log(x) + Ln2 // |x| > 2**28
+ case x > 2:
+ temp = Log(2*x + 1/(Sqrt(x*x+1)+x)) // 2**28 > |x| > 2.0
+ case x < NearZero:
+ temp = x // |x| < 2**-28
+ default:
+ temp = Log1p(x + x*x/(1+Sqrt(1+x*x))) // 2.0 > |x| > 2**-28
+ }
+ if sign {
+ temp = -temp
+ }
+ return temp
+}
diff --git a/libgo/go/math/atan.go b/libgo/go/math/atan.go
new file mode 100644
index 000000000..9d4ec2f72
--- /dev/null
+++ b/libgo/go/math/atan.go
@@ -0,0 +1,62 @@
+// 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 math
+
+/*
+ Floating-point arctangent.
+
+ Atan returns the value of the arctangent of its
+ argument in the range [-pi/2,pi/2].
+ There are no error returns.
+ Coefficients are #5077 from Hart & Cheney. (19.56D)
+*/
+
+// xatan evaluates a series valid in the
+// range [-0.414...,+0.414...]. (tan(pi/8))
+func xatan(arg float64) float64 {
+ const (
+ P4 = .161536412982230228262e2
+ P3 = .26842548195503973794141e3
+ P2 = .11530293515404850115428136e4
+ P1 = .178040631643319697105464587e4
+ P0 = .89678597403663861959987488e3
+ Q4 = .5895697050844462222791e2
+ Q3 = .536265374031215315104235e3
+ Q2 = .16667838148816337184521798e4
+ Q1 = .207933497444540981287275926e4
+ Q0 = .89678597403663861962481162e3
+ )
+ sq := arg * arg
+ value := ((((P4*sq+P3)*sq+P2)*sq+P1)*sq + P0)
+ value = value / (((((sq+Q4)*sq+Q3)*sq+Q2)*sq+Q1)*sq + Q0)
+ return value * arg
+}
+
+// satan reduces its argument (known to be positive)
+// to the range [0,0.414...] and calls xatan.
+func satan(arg float64) float64 {
+ if arg < Sqrt2-1 {
+ return xatan(arg)
+ }
+ if arg > Sqrt2+1 {
+ return Pi/2 - xatan(1/arg)
+ }
+ return Pi/4 + xatan((arg-1)/(arg+1))
+}
+
+// Atan returns the arctangent of x.
+//
+// Special cases are:
+// Atan(±0) = ±0
+// Atan(±Inf) = ±Pi/2
+func Atan(x float64) float64 {
+ if x == 0 {
+ return x
+ }
+ if x > 0 {
+ return satan(x)
+ }
+ return -satan(-x)
+}
diff --git a/libgo/go/math/atan2.go b/libgo/go/math/atan2.go
new file mode 100644
index 000000000..49d4bdd71
--- /dev/null
+++ b/libgo/go/math/atan2.go
@@ -0,0 +1,71 @@
+// 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 math
+
+// Atan2 returns the arc tangent of y/x, using
+// the signs of the two to determine the quadrant
+// of the return value.
+//
+// Special cases are (in order):
+// Atan2(y, NaN) = NaN
+// Atan2(NaN, x) = NaN
+// Atan2(+0, x>=0) = +0
+// Atan2(-0, x>=0) = -0
+// Atan2(+0, x<=-0) = +Pi
+// Atan2(-0, x<=-0) = -Pi
+// Atan2(y>0, 0) = +Pi/2
+// Atan2(y<0, 0) = -Pi/2
+// Atan2(+Inf, +Inf) = +Pi/4
+// Atan2(-Inf, +Inf) = -Pi/4
+// Atan2(+Inf, -Inf) = 3Pi/4
+// Atan2(-Inf, -Inf) = -3Pi/4
+// Atan2(y, +Inf) = 0
+// Atan2(y>0, -Inf) = +Pi
+// Atan2(y<0, -Inf) = -Pi
+// Atan2(+Inf, x) = +Pi/2
+// Atan2(-Inf, x) = -Pi/2
+func Atan2(y, x float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case y != y || x != x: // IsNaN(y) || IsNaN(x):
+ return NaN()
+ case y == 0:
+ if x >= 0 && !Signbit(x) {
+ return Copysign(0, y)
+ }
+ return Copysign(Pi, y)
+ case x == 0:
+ return Copysign(Pi/2, y)
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ if x > MaxFloat64 { // IsInf(x, 1) {
+ switch {
+ case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y, -1) || IsInf(y, 1):
+ return Copysign(Pi/4, y)
+ default:
+ return Copysign(0, y)
+ }
+ }
+ switch {
+ case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y, -1) || IsInf(y, 1):
+ return Copysign(3*Pi/4, y)
+ default:
+ return Copysign(Pi, y)
+ }
+ case y < -MaxFloat64 || y > MaxFloat64: //IsInf(y, 0):
+ return Copysign(Pi/2, y)
+ }
+
+ // Call atan and determine the quadrant.
+ q := Atan(y / x)
+ if x < 0 {
+ if q <= 0 {
+ return q + Pi
+ }
+ return q - Pi
+ }
+ return q
+}
diff --git a/libgo/go/math/atanh.go b/libgo/go/math/atanh.go
new file mode 100644
index 000000000..6aecb7b3b
--- /dev/null
+++ b/libgo/go/math/atanh.go
@@ -0,0 +1,79 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_atanh.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// __ieee754_atanh(x)
+// Method :
+// 1. Reduce x to positive by atanh(-x) = -atanh(x)
+// 2. For x>=0.5
+// 1 2x x
+// atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+// 2 1 - x 1 - x
+//
+// For x<0.5
+// atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+//
+// Special cases:
+// atanh(x) is NaN if |x| > 1 with signal;
+// atanh(NaN) is that NaN with no signal;
+// atanh(+-1) is +-INF with signal.
+//
+
+// Atanh(x) calculates the inverse hyperbolic tangent of x.
+//
+// Special cases are:
+// Atanh(x) = NaN if x < -1 or x > 1
+// Atanh(1) = +Inf
+// Atanh(-1) = -Inf
+// Atanh(NaN) = NaN
+func Atanh(x float64) float64 {
+ const NearZero = 1.0 / (1 << 28) // 2**-28
+ // TODO(rsc): Remove manual inlining of IsNaN
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x < -1 || x > 1 || x != x: // x < -1 || x > 1 || IsNaN(x):
+ return NaN()
+ case x == 1:
+ return Inf(1)
+ case x == -1:
+ return Inf(-1)
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ var temp float64
+ switch {
+ case x < NearZero:
+ temp = x
+ case x < 0.5:
+ temp = x + x
+ temp = 0.5 * Log1p(temp+temp*x/(1-x))
+ default:
+ temp = 0.5 * Log1p((x+x)/(1-x))
+ }
+ if sign {
+ temp = -temp
+ }
+ return temp
+}
diff --git a/libgo/go/math/bits.go b/libgo/go/math/bits.go
new file mode 100644
index 000000000..a1dca3ed6
--- /dev/null
+++ b/libgo/go/math/bits.go
@@ -0,0 +1,59 @@
+// 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 math
+
+const (
+ uvnan = 0x7FF0000000000001
+ uvinf = 0x7FF0000000000000
+ uvneginf = 0xFFF0000000000000
+ mask = 0x7FF
+ shift = 64 - 11 - 1
+ bias = 1023
+)
+
+// Inf returns positive infinity if sign >= 0, negative infinity if sign < 0.
+func Inf(sign int) float64 {
+ var v uint64
+ if sign >= 0 {
+ v = uvinf
+ } else {
+ v = uvneginf
+ }
+ return Float64frombits(v)
+}
+
+// NaN returns an IEEE 754 ``not-a-number'' value.
+func NaN() float64 { return Float64frombits(uvnan) }
+
+// IsNaN returns whether f is an IEEE 754 ``not-a-number'' value.
+func IsNaN(f float64) (is bool) {
+ // IEEE 754 says that only NaNs satisfy f != f.
+ // To avoid the floating-point hardware, could use:
+ // x := Float64bits(f);
+ // return uint32(x>>shift)&mask == mask && x != uvinf && x != uvneginf
+ return f != f
+}
+
+// IsInf returns whether f is an infinity, according to sign.
+// If sign > 0, IsInf returns whether f is positive infinity.
+// If sign < 0, IsInf returns whether f is negative infinity.
+// If sign == 0, IsInf returns whether f is either infinity.
+func IsInf(f float64, sign int) bool {
+ // Test for infinity by comparing against maximum float.
+ // To avoid the floating-point hardware, could use:
+ // x := Float64bits(f);
+ // return sign >= 0 && x == uvinf || sign <= 0 && x == uvneginf;
+ return sign >= 0 && f > MaxFloat64 || sign <= 0 && f < -MaxFloat64
+}
+
+// normalize returns a normal number y and exponent exp
+// satisfying x == y × 2**exp. It assumes x is finite and non-zero.
+func normalize(x float64) (y float64, exp int) {
+ const SmallestNormal = 2.2250738585072014e-308 // 2**-1022
+ if Fabs(x) < SmallestNormal {
+ return x * (1 << 52), -52
+ }
+ return x, 0
+}
diff --git a/libgo/go/math/cbrt.go b/libgo/go/math/cbrt.go
new file mode 100644
index 000000000..d2b7e910b
--- /dev/null
+++ b/libgo/go/math/cbrt.go
@@ -0,0 +1,79 @@
+// 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 math
+
+/*
+ The algorithm is based in part on "Optimal Partitioning of
+ Newton's Method for Calculating Roots", by Gunter Meinardus
+ and G. D. Taylor, Mathematics of Computation © 1980 American
+ Mathematical Society.
+ (http://www.jstor.org/stable/2006387?seq=9, accessed 11-Feb-2010)
+*/
+
+// Cbrt returns the cube root of its argument.
+//
+// Special cases are:
+// Cbrt(±0) = ±0
+// Cbrt(±Inf) = ±Inf
+// Cbrt(NaN) = NaN
+func Cbrt(x float64) float64 {
+ const (
+ A1 = 1.662848358e-01
+ A2 = 1.096040958e+00
+ A3 = 4.105032829e-01
+ A4 = 5.649335816e-01
+ B1 = 2.639607233e-01
+ B2 = 8.699282849e-01
+ B3 = 1.629083358e-01
+ B4 = 2.824667908e-01
+ C1 = 4.190115298e-01
+ C2 = 6.904625373e-01
+ C3 = 6.46502159e-02
+ C4 = 1.412333954e-01
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x == 0 || x != x || x < -MaxFloat64 || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 0):
+ return x
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ // Reduce argument
+ f, e := Frexp(x)
+ m := e % 3
+ if m > 0 {
+ m -= 3
+ e -= m // e is multiple of 3
+ }
+ f = Ldexp(f, m) // 0.125 <= f < 1.0
+
+ // Estimate cube root
+ switch m {
+ case 0: // 0.5 <= f < 1.0
+ f = A1*f + A2 - A3/(A4+f)
+ case -1: // 0.25 <= f < 0.5
+ f = B1*f + B2 - B3/(B4+f)
+ default: // 0.125 <= f < 0.25
+ f = C1*f + C2 - C3/(C4+f)
+ }
+ y := Ldexp(f, e/3) // e/3 = exponent of cube root
+
+ // Iterate
+ s := y * y * y
+ t := s + x
+ y *= (t + x) / (s + t)
+ // Reiterate
+ s = (y*y*y - x) / x
+ y -= y * (((14.0/81.0)*s-(2.0/9.0))*s + (1.0 / 3.0)) * s
+ if sign {
+ y = -y
+ }
+ return y
+}
diff --git a/libgo/go/math/const.go b/libgo/go/math/const.go
new file mode 100644
index 000000000..b53527a4f
--- /dev/null
+++ b/libgo/go/math/const.go
@@ -0,0 +1,53 @@
+// 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.
+
+// The math package provides basic constants and mathematical functions.
+package math
+
+// Mathematical constants.
+// Reference: http://www.research.att.com/~njas/sequences/Axxxxxx
+const (
+ E = 2.71828182845904523536028747135266249775724709369995957496696763 // A001113
+ Pi = 3.14159265358979323846264338327950288419716939937510582097494459 // A000796
+ Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // A001622
+
+ Sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974 // A002193
+ SqrtE = 1.64872127070012814684865078781416357165377610071014801157507931 // A019774
+ SqrtPi = 1.77245385090551602729816748334114518279754945612238712821380779 // A002161
+ SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // A139339
+
+ Ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 // A002162
+ Log2E = 1 / Ln2
+ Ln10 = 2.30258509299404568401799145468436420760110148862877297603332790 // A002392
+ Log10E = 1 / Ln10
+)
+
+// Floating-point limit values.
+// Max is the largest finite value representable by the type.
+// SmallestNonzero is the smallest positive, non-zero value representable by the type.
+const (
+ MaxFloat32 = 3.40282346638528859811704183484516925440e+38 /* 2**127 * (2**24 - 1) / 2**23 */
+ SmallestNonzeroFloat32 = 1.401298464324817070923729583289916131280e-45 /* 1 / 2**(127 - 1 + 23) */
+
+ MaxFloat64 = 1.797693134862315708145274237317043567981e+308 /* 2**1023 * (2**53 - 1) / 2**52 */
+ SmallestNonzeroFloat64 = 4.940656458412465441765687928682213723651e-324 /* 1 / 2**(1023 - 1 + 52) */
+)
+
+// Integer limit values.
+const (
+ MaxInt8 = 1<<7 - 1
+ MinInt8 = -1 << 7
+ MaxInt16 = 1<<15 - 1
+ MinInt16 = -1 << 15
+ MaxInt32 = 1<<31 - 1
+ MinInt32 = -1 << 31
+ MaxInt64 = 1<<63 - 1
+ MinInt64 = -1 << 63
+ MaxUint8 = 1<<8 - 1
+ MaxUint16 = 1<<16 - 1
+ MaxUint32 = 1<<32 - 1
+ MaxUint64 = 1<<64 - 1
+)
+
+// BUG(rsc): The manual should define the special cases for all of these functions.
diff --git a/libgo/go/math/copysign.go b/libgo/go/math/copysign.go
new file mode 100644
index 000000000..ee65456a1
--- /dev/null
+++ b/libgo/go/math/copysign.go
@@ -0,0 +1,12 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Copysign(x, y) returns a value with the magnitude
+// of x and the sign of y.
+func Copysign(x, y float64) float64 {
+ const sign = 1 << 63
+ return Float64frombits(Float64bits(x)&^sign | Float64bits(y)&sign)
+}
diff --git a/libgo/go/math/erf.go b/libgo/go/math/erf.go
new file mode 100644
index 000000000..b60899933
--- /dev/null
+++ b/libgo/go/math/erf.go
@@ -0,0 +1,340 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+/*
+ Floating-point error function and complementary error function.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/s_erf.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// double erf(double x)
+// double erfc(double x)
+// x
+// 2 |\
+// erf(x) = --------- | exp(-t*t)dt
+// sqrt(pi) \|
+// 0
+//
+// erfc(x) = 1-erf(x)
+// Note that
+// erf(-x) = -erf(x)
+// erfc(-x) = 2 - erfc(x)
+//
+// Method:
+// 1. For |x| in [0, 0.84375]
+// erf(x) = x + x*R(x**2)
+// erfc(x) = 1 - erf(x) if x in [-.84375,0.25]
+// = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375]
+// where R = P/Q where P is an odd poly of degree 8 and
+// Q is an odd poly of degree 10.
+// -57.90
+// | R - (erf(x)-x)/x | <= 2
+//
+//
+// Remark. The formula is derived by noting
+// erf(x) = (2/sqrt(pi))*(x - x**3/3 + x**5/10 - x**7/42 + ....)
+// and that
+// 2/sqrt(pi) = 1.128379167095512573896158903121545171688
+// is close to one. The interval is chosen because the fix
+// point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+// near 0.6174), and by some experiment, 0.84375 is chosen to
+// guarantee the error is less than one ulp for erf.
+//
+// 2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+// c = 0.84506291151 rounded to single (24 bits)
+// erf(x) = sign(x) * (c + P1(s)/Q1(s))
+// erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0
+// 1+(c+P1(s)/Q1(s)) if x < 0
+// |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+// Remark: here we use the taylor series expansion at x=1.
+// erf(1+s) = erf(1) + s*Poly(s)
+// = 0.845.. + P1(s)/Q1(s)
+// That is, we use rational approximation to approximate
+// erf(1+s) - (c = (single)0.84506291151)
+// Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+// where
+// P1(s) = degree 6 poly in s
+// Q1(s) = degree 6 poly in s
+//
+// 3. For x in [1.25,1/0.35(~2.857143)],
+// erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+// erf(x) = 1 - erfc(x)
+// where
+// R1(z) = degree 7 poly in z, (z=1/x**2)
+// S1(z) = degree 8 poly in z
+//
+// 4. For x in [1/0.35,28]
+// erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+// = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+// = 2.0 - tiny (if x <= -6)
+// erf(x) = sign(x)*(1.0 - erfc(x)) if x < 6, else
+// erf(x) = sign(x)*(1.0 - tiny)
+// where
+// R2(z) = degree 6 poly in z, (z=1/x**2)
+// S2(z) = degree 7 poly in z
+//
+// Note1:
+// To compute exp(-x*x-0.5625+R/S), let s be a single
+// precision number and s := x; then
+// -x*x = -s*s + (s-x)*(s+x)
+// exp(-x*x-0.5626+R/S) =
+// exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+// Note2:
+// Here 4 and 5 make use of the asymptotic series
+// exp(-x*x)
+// erfc(x) ~ ---------- * ( 1 + Poly(1/x**2) )
+// x*sqrt(pi)
+// We use rational approximation to approximate
+// g(s)=f(1/x**2) = log(erfc(x)*x) - x*x + 0.5625
+// Here is the error bound for R1/S1 and R2/S2
+// |R1/S1 - f(x)| < 2**(-62.57)
+// |R2/S2 - f(x)| < 2**(-61.52)
+//
+// 5. For inf > x >= 28
+// erf(x) = sign(x) *(1 - tiny) (raise inexact)
+// erfc(x) = tiny*tiny (raise underflow) if x > 0
+// = 2 - tiny if x<0
+//
+// 7. Special case:
+// erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
+// erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+// erfc/erf(NaN) is NaN
+
+const (
+ erx = 8.45062911510467529297e-01 // 0x3FEB0AC160000000
+ // Coefficients for approximation to erf in [0, 0.84375]
+ efx = 1.28379167095512586316e-01 // 0x3FC06EBA8214DB69
+ efx8 = 1.02703333676410069053e+00 // 0x3FF06EBA8214DB69
+ pp0 = 1.28379167095512558561e-01 // 0x3FC06EBA8214DB68
+ pp1 = -3.25042107247001499370e-01 // 0xBFD4CD7D691CB913
+ pp2 = -2.84817495755985104766e-02 // 0xBF9D2A51DBD7194F
+ pp3 = -5.77027029648944159157e-03 // 0xBF77A291236668E4
+ pp4 = -2.37630166566501626084e-05 // 0xBEF8EAD6120016AC
+ qq1 = 3.97917223959155352819e-01 // 0x3FD97779CDDADC09
+ qq2 = 6.50222499887672944485e-02 // 0x3FB0A54C5536CEBA
+ qq3 = 5.08130628187576562776e-03 // 0x3F74D022C4D36B0F
+ qq4 = 1.32494738004321644526e-04 // 0x3F215DC9221C1A10
+ qq5 = -3.96022827877536812320e-06 // 0xBED09C4342A26120
+ // Coefficients for approximation to erf in [0.84375, 1.25]
+ pa0 = -2.36211856075265944077e-03 // 0xBF6359B8BEF77538
+ pa1 = 4.14856118683748331666e-01 // 0x3FDA8D00AD92B34D
+ pa2 = -3.72207876035701323847e-01 // 0xBFD7D240FBB8C3F1
+ pa3 = 3.18346619901161753674e-01 // 0x3FD45FCA805120E4
+ pa4 = -1.10894694282396677476e-01 // 0xBFBC63983D3E28EC
+ pa5 = 3.54783043256182359371e-02 // 0x3FA22A36599795EB
+ pa6 = -2.16637559486879084300e-03 // 0xBF61BF380A96073F
+ qa1 = 1.06420880400844228286e-01 // 0x3FBB3E6618EEE323
+ qa2 = 5.40397917702171048937e-01 // 0x3FE14AF092EB6F33
+ qa3 = 7.18286544141962662868e-02 // 0x3FB2635CD99FE9A7
+ qa4 = 1.26171219808761642112e-01 // 0x3FC02660E763351F
+ qa5 = 1.36370839120290507362e-02 // 0x3F8BEDC26B51DD1C
+ qa6 = 1.19844998467991074170e-02 // 0x3F888B545735151D
+ // Coefficients for approximation to erfc in [1.25, 1/0.35]
+ ra0 = -9.86494403484714822705e-03 // 0xBF843412600D6435
+ ra1 = -6.93858572707181764372e-01 // 0xBFE63416E4BA7360
+ ra2 = -1.05586262253232909814e+01 // 0xC0251E0441B0E726
+ ra3 = -6.23753324503260060396e+01 // 0xC04F300AE4CBA38D
+ ra4 = -1.62396669462573470355e+02 // 0xC0644CB184282266
+ ra5 = -1.84605092906711035994e+02 // 0xC067135CEBCCABB2
+ ra6 = -8.12874355063065934246e+01 // 0xC054526557E4D2F2
+ ra7 = -9.81432934416914548592e+00 // 0xC023A0EFC69AC25C
+ sa1 = 1.96512716674392571292e+01 // 0x4033A6B9BD707687
+ sa2 = 1.37657754143519042600e+02 // 0x4061350C526AE721
+ sa3 = 4.34565877475229228821e+02 // 0x407B290DD58A1A71
+ sa4 = 6.45387271733267880336e+02 // 0x40842B1921EC2868
+ sa5 = 4.29008140027567833386e+02 // 0x407AD02157700314
+ sa6 = 1.08635005541779435134e+02 // 0x405B28A3EE48AE2C
+ sa7 = 6.57024977031928170135e+00 // 0x401A47EF8E484A93
+ sa8 = -6.04244152148580987438e-02 // 0xBFAEEFF2EE749A62
+ // Coefficients for approximation to erfc in [1/.35, 28]
+ rb0 = -9.86494292470009928597e-03 // 0xBF84341239E86F4A
+ rb1 = -7.99283237680523006574e-01 // 0xBFE993BA70C285DE
+ rb2 = -1.77579549177547519889e+01 // 0xC031C209555F995A
+ rb3 = -1.60636384855821916062e+02 // 0xC064145D43C5ED98
+ rb4 = -6.37566443368389627722e+02 // 0xC083EC881375F228
+ rb5 = -1.02509513161107724954e+03 // 0xC09004616A2E5992
+ rb6 = -4.83519191608651397019e+02 // 0xC07E384E9BDC383F
+ sb1 = 3.03380607434824582924e+01 // 0x403E568B261D5190
+ sb2 = 3.25792512996573918826e+02 // 0x40745CAE221B9F0A
+ sb3 = 1.53672958608443695994e+03 // 0x409802EB189D5118
+ sb4 = 3.19985821950859553908e+03 // 0x40A8FFB7688C246A
+ sb5 = 2.55305040643316442583e+03 // 0x40A3F219CEDF3BE6
+ sb6 = 4.74528541206955367215e+02 // 0x407DA874E79FE763
+ sb7 = -2.24409524465858183362e+01 // 0xC03670E242712D62
+)
+
+// Erf(x) returns the error function of x.
+//
+// Special cases are:
+// Erf(+Inf) = 1
+// Erf(-Inf) = -1
+// Erf(NaN) = NaN
+func Erf(x float64) float64 {
+ const (
+ VeryTiny = 2.848094538889218e-306 // 0x0080000000000000
+ Small = 1.0 / (1 << 28) // 2**-28
+ )
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x != x: // IsNaN(x):
+ return NaN()
+ case x > MaxFloat64: // IsInf(x, 1):
+ return 1
+ case x < -MaxFloat64: // IsInf(x, -1):
+ return -1
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ if x < 0.84375 { // |x| < 0.84375
+ var temp float64
+ if x < Small { // |x| < 2**-28
+ if x < VeryTiny {
+ temp = 0.125 * (8.0*x + efx8*x) // avoid underflow
+ } else {
+ temp = x + efx*x
+ }
+ } else {
+ z := x * x
+ r := pp0 + z*(pp1+z*(pp2+z*(pp3+z*pp4)))
+ s := 1 + z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))))
+ y := r / s
+ temp = x + x*y
+ }
+ if sign {
+ return -temp
+ }
+ return temp
+ }
+ if x < 1.25 { // 0.84375 <= |x| < 1.25
+ s := x - 1
+ P := pa0 + s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))))
+ Q := 1 + s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))))
+ if sign {
+ return -erx - P/Q
+ }
+ return erx + P/Q
+ }
+ if x >= 6 { // inf > |x| >= 6
+ if sign {
+ return -1
+ }
+ return 1
+ }
+ s := 1 / (x * x)
+ var R, S float64
+ if x < 1/0.35 { // |x| < 1 / 0.35 ~ 2.857143
+ R = ra0 + s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(ra5+s*(ra6+s*ra7))))))
+ S = 1 + s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(sa5+s*(sa6+s*(sa7+s*sa8)))))))
+ } else { // |x| >= 1 / 0.35 ~ 2.857143
+ R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
+ S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
+ }
+ z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x
+ r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
+ if sign {
+ return r/x - 1
+ }
+ return 1 - r/x
+}
+
+// Erfc(x) returns the complementary error function of x.
+//
+// Special cases are:
+// Erfc(+Inf) = 0
+// Erfc(-Inf) = 2
+// Erfc(NaN) = NaN
+func Erfc(x float64) float64 {
+ const Tiny = 1.0 / (1 << 56) // 2**-56
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x != x: // IsNaN(x):
+ return NaN()
+ case x > MaxFloat64: // IsInf(x, 1):
+ return 0
+ case x < -MaxFloat64: // IsInf(x, -1):
+ return 2
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ if x < 0.84375 { // |x| < 0.84375
+ var temp float64
+ if x < Tiny { // |x| < 2**-56
+ temp = x
+ } else {
+ z := x * x
+ r := pp0 + z*(pp1+z*(pp2+z*(pp3+z*pp4)))
+ s := 1 + z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))))
+ y := r / s
+ if x < 0.25 { // |x| < 1/4
+ temp = x + x*y
+ } else {
+ temp = 0.5 + (x*y + (x - 0.5))
+ }
+ }
+ if sign {
+ return 1 + temp
+ }
+ return 1 - temp
+ }
+ if x < 1.25 { // 0.84375 <= |x| < 1.25
+ s := x - 1
+ P := pa0 + s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))))
+ Q := 1 + s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))))
+ if sign {
+ return 1 + erx + P/Q
+ }
+ return 1 - erx - P/Q
+
+ }
+ if x < 28 { // |x| < 28
+ s := 1 / (x * x)
+ var R, S float64
+ if x < 1/0.35 { // |x| < 1 / 0.35 ~ 2.857143
+ R = ra0 + s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(ra5+s*(ra6+s*ra7))))))
+ S = 1 + s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(sa5+s*(sa6+s*(sa7+s*sa8)))))))
+ } else { // |x| >= 1 / 0.35 ~ 2.857143
+ if sign && x > 6 {
+ return 2 // x < -6
+ }
+ R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
+ S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
+ }
+ z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x
+ r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
+ if sign {
+ return 2 - r/x
+ }
+ return r / x
+ }
+ if sign {
+ return 2
+ }
+ return 0
+}
diff --git a/libgo/go/math/exp.go b/libgo/go/math/exp.go
new file mode 100644
index 000000000..c519c2cb6
--- /dev/null
+++ b/libgo/go/math/exp.go
@@ -0,0 +1,14 @@
+// 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 math
+
+// Exp returns e**x, the base-e exponential of x.
+//
+// Special cases are:
+// Exp(+Inf) = +Inf
+// Exp(NaN) = NaN
+// Very large values overflow to 0 or +Inf.
+// Very small values underflow to 1.
+func Exp(x float64) float64 { return expGo(x) }
diff --git a/libgo/go/math/exp2.go b/libgo/go/math/exp2.go
new file mode 100644
index 000000000..1cface9d3
--- /dev/null
+++ b/libgo/go/math/exp2.go
@@ -0,0 +1,10 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Exp2 returns 2**x, the base-2 exponential of x.
+//
+// Special cases are the same as Exp.
+func Exp2(x float64) float64 { return exp2Go(x) }
diff --git a/libgo/go/math/exp_port.go b/libgo/go/math/exp_port.go
new file mode 100644
index 000000000..071420c24
--- /dev/null
+++ b/libgo/go/math/exp_port.go
@@ -0,0 +1,192 @@
+// 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 math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_exp.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+//
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// exp(x)
+// Returns the exponential of x.
+//
+// Method
+// 1. Argument reduction:
+// Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+// Given x, find r and integer k such that
+//
+// x = k*ln2 + r, |r| <= 0.5*ln2.
+//
+// Here r will be represented as r = hi-lo for better
+// accuracy.
+//
+// 2. Approximation of exp(r) by a special rational function on
+// the interval [0,0.34658]:
+// Write
+// R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+// We use a special Remes algorithm on [0,0.34658] to generate
+// a polynomial of degree 5 to approximate R. The maximum error
+// of this polynomial approximation is bounded by 2**-59. In
+// other words,
+// R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+// (where z=r*r, and the values of P1 to P5 are listed below)
+// and
+// | 5 | -59
+// | 2.0+P1*z+...+P5*z - R(z) | <= 2
+// | |
+// The computation of exp(r) thus becomes
+// 2*r
+// exp(r) = 1 + -------
+// R - r
+// r*R1(r)
+// = 1 + r + ----------- (for better accuracy)
+// 2 - R1(r)
+// where
+// 2 4 10
+// R1(r) = r - (P1*r + P2*r + ... + P5*r ).
+//
+// 3. Scale back to obtain exp(x):
+// From step 1, we have
+// exp(x) = 2**k * exp(r)
+//
+// Special cases:
+// exp(INF) is INF, exp(NaN) is NaN;
+// exp(-INF) is 0, and
+// for finite argument, only exp(0)=1 is exact.
+//
+// Accuracy:
+// according to an error analysis, the error is always less than
+// 1 ulp (unit in the last place).
+//
+// Misc. info.
+// For IEEE double
+// if x > 7.09782712893383973096e+02 then exp(x) overflow
+// if x < -7.45133219101941108420e+02 then exp(x) underflow
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+
+// Exp returns e**x, the base-e exponential of x.
+//
+// Special cases are:
+// Exp(+Inf) = +Inf
+// Exp(NaN) = NaN
+// Very large values overflow to 0 or +Inf.
+// Very small values underflow to 1.
+func expGo(x float64) float64 {
+ const (
+ Ln2Hi = 6.93147180369123816490e-01
+ Ln2Lo = 1.90821492927058770002e-10
+ Log2e = 1.44269504088896338700e+00
+
+ Overflow = 7.09782712893383973096e+02
+ Underflow = -7.45133219101941108420e+02
+ NearZero = 1.0 / (1 << 28) // 2**-28
+ )
+
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+ return x
+ case x < -MaxFloat64: // IsInf(x, -1):
+ return 0
+ case x > Overflow:
+ return Inf(1)
+ case x < Underflow:
+ return 0
+ case -NearZero < x && x < NearZero:
+ return 1 + x
+ }
+
+ // reduce; computed as r = hi - lo for extra precision.
+ var k int
+ switch {
+ case x < 0:
+ k = int(Log2e*x - 0.5)
+ case x > 0:
+ k = int(Log2e*x + 0.5)
+ }
+ hi := x - float64(k)*Ln2Hi
+ lo := float64(k) * Ln2Lo
+
+ // compute
+ return exp(hi, lo, k)
+}
+
+// Exp2 returns 2**x, the base-2 exponential of x.
+//
+// Special cases are the same as Exp.
+func exp2Go(x float64) float64 {
+ const (
+ Ln2Hi = 6.93147180369123816490e-01
+ Ln2Lo = 1.90821492927058770002e-10
+
+ Overflow = 1.0239999999999999e+03
+ Underflow = -1.0740e+03
+ )
+
+ // TODO: remove manual inlining of IsNaN and IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+ return x
+ case x < -MaxFloat64: // IsInf(x, -1):
+ return 0
+ case x > Overflow:
+ return Inf(1)
+ case x < Underflow:
+ return 0
+ }
+
+ // argument reduction; x = r×lg(e) + k with |r| ≤ ln(2)/2.
+ // computed as r = hi - lo for extra precision.
+ var k int
+ switch {
+ case x > 0:
+ k = int(x + 0.5)
+ case x < 0:
+ k = int(x - 0.5)
+ }
+ t := x - float64(k)
+ hi := t * Ln2Hi
+ lo := -t * Ln2Lo
+
+ // compute
+ return exp(hi, lo, k)
+}
+
+// exp returns e**r × 2**k where r = hi - lo and |r| ≤ ln(2)/2.
+func exp(hi, lo float64, k int) float64 {
+ const (
+ P1 = 1.66666666666666019037e-01 /* 0x3FC55555; 0x5555553E */
+ P2 = -2.77777777770155933842e-03 /* 0xBF66C16C; 0x16BEBD93 */
+ P3 = 6.61375632143793436117e-05 /* 0x3F11566A; 0xAF25DE2C */
+ P4 = -1.65339022054652515390e-06 /* 0xBEBBBD41; 0xC5D26BF1 */
+ P5 = 4.13813679705723846039e-08 /* 0x3E663769; 0x72BEA4D0 */
+ )
+
+ r := hi - lo
+ t := r * r
+ c := r - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))))
+ y := 1 - ((lo - (r*c)/(2-c)) - hi)
+ // TODO(rsc): make sure Ldexp can handle boundary k
+ return Ldexp(y, k)
+}
diff --git a/libgo/go/math/exp_test.go b/libgo/go/math/exp_test.go
new file mode 100644
index 000000000..7381fd5ad
--- /dev/null
+++ b/libgo/go/math/exp_test.go
@@ -0,0 +1,10 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Make expGo and exp2Go available for testing.
+
+func ExpGo(x float64) float64 { return expGo(x) }
+func Exp2Go(x float64) float64 { return exp2Go(x) }
diff --git a/libgo/go/math/expm1.go b/libgo/go/math/expm1.go
new file mode 100644
index 000000000..35100caa4
--- /dev/null
+++ b/libgo/go/math/expm1.go
@@ -0,0 +1,238 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/s_expm1.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// expm1(x)
+// Returns exp(x)-1, the exponential of x minus 1.
+//
+// Method
+// 1. Argument reduction:
+// Given x, find r and integer k such that
+//
+// x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658
+//
+// Here a correction term c will be computed to compensate
+// the error in r when rounded to a floating-point number.
+//
+// 2. Approximating expm1(r) by a special rational function on
+// the interval [0,0.34658]:
+// Since
+// r*(exp(r)+1)/(exp(r)-1) = 2+ r**2/6 - r**4/360 + ...
+// we define R1(r*r) by
+// r*(exp(r)+1)/(exp(r)-1) = 2+ r**2/6 * R1(r*r)
+// That is,
+// R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+// = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+// = 1 - r**2/60 + r**4/2520 - r**6/100800 + ...
+// We use a special Reme algorithm on [0,0.347] to generate
+// a polynomial of degree 5 in r*r to approximate R1. The
+// maximum error of this polynomial approximation is bounded
+// by 2**-61. In other words,
+// R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+// where Q1 = -1.6666666666666567384E-2,
+// Q2 = 3.9682539681370365873E-4,
+// Q3 = -9.9206344733435987357E-6,
+// Q4 = 2.5051361420808517002E-7,
+// Q5 = -6.2843505682382617102E-9;
+// (where z=r*r, and the values of Q1 to Q5 are listed below)
+// with error bounded by
+// | 5 | -61
+// | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2
+// | |
+//
+// expm1(r) = exp(r)-1 is then computed by the following
+// specific way which minimize the accumulation rounding error:
+// 2 3
+// r r [ 3 - (R1 + R1*r/2) ]
+// expm1(r) = r + --- + --- * [--------------------]
+// 2 2 [ 6 - r*(3 - R1*r/2) ]
+//
+// To compensate the error in the argument reduction, we use
+// expm1(r+c) = expm1(r) + c + expm1(r)*c
+// ~ expm1(r) + c + r*c
+// Thus c+r*c will be added in as the correction terms for
+// expm1(r+c). Now rearrange the term to avoid optimization
+// screw up:
+// ( 2 2 )
+// ({ ( r [ R1 - (3 - R1*r/2) ] ) } r )
+// expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+// ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 )
+// ( )
+//
+// = r - E
+// 3. Scale back to obtain expm1(x):
+// From step 1, we have
+// expm1(x) = either 2**k*[expm1(r)+1] - 1
+// = or 2**k*[expm1(r) + (1-2**-k)]
+// 4. Implementation notes:
+// (A). To save one multiplication, we scale the coefficient Qi
+// to Qi*2**i, and replace z by (x**2)/2.
+// (B). To achieve maximum accuracy, we compute expm1(x) by
+// (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+// (ii) if k=0, return r-E
+// (iii) if k=-1, return 0.5*(r-E)-0.5
+// (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E)
+// else return 1.0+2.0*(r-E);
+// (v) if (k<-2||k>56) return 2**k(1-(E-r)) - 1 (or exp(x)-1)
+// (vi) if k <= 20, return 2**k((1-2**-k)-(E-r)), else
+// (vii) return 2**k(1-((E+2**-k)-r))
+//
+// Special cases:
+// expm1(INF) is INF, expm1(NaN) is NaN;
+// expm1(-INF) is -1, and
+// for finite argument, only expm1(0)=0 is exact.
+//
+// Accuracy:
+// according to an error analysis, the error is always less than
+// 1 ulp (unit in the last place).
+//
+// Misc. info.
+// For IEEE double
+// if x > 7.09782712893383973096e+02 then expm1(x) overflow
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+//
+
+// Expm1 returns e**x - 1, the base-e exponential of x minus 1.
+// It is more accurate than Exp(x) - 1 when x is near zero.
+//
+// Special cases are:
+// Expm1(+Inf) = +Inf
+// Expm1(-Inf) = -1
+// Expm1(NaN) = NaN
+// Very large values overflow to -1 or +Inf.
+func Expm1(x float64) float64 {
+ const (
+ Othreshold = 7.09782712893383973096e+02 // 0x40862E42FEFA39EF
+ Ln2X56 = 3.88162421113569373274e+01 // 0x4043687a9f1af2b1
+ Ln2HalfX3 = 1.03972077083991796413e+00 // 0x3ff0a2b23f3bab73
+ Ln2Half = 3.46573590279972654709e-01 // 0x3fd62e42fefa39ef
+ Ln2Hi = 6.93147180369123816490e-01 // 0x3fe62e42fee00000
+ Ln2Lo = 1.90821492927058770002e-10 // 0x3dea39ef35793c76
+ InvLn2 = 1.44269504088896338700e+00 // 0x3ff71547652b82fe
+ Tiny = 1.0 / (1 << 54) // 2**-54 = 0x3c90000000000000
+ // scaled coefficients related to expm1
+ Q1 = -3.33333333333331316428e-02 // 0xBFA11111111110F4
+ Q2 = 1.58730158725481460165e-03 // 0x3F5A01A019FE5585
+ Q3 = -7.93650757867487942473e-05 // 0xBF14CE199EAADBB7
+ Q4 = 4.00821782732936239552e-06 // 0x3ED0CFCA86E65239
+ Q5 = -2.01099218183624371326e-07 // 0xBE8AFDB76E09C32D
+ )
+
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x > MaxFloat64 || x != x: // IsInf(x, 1) || IsNaN(x):
+ return x
+ case x < -MaxFloat64: // IsInf(x, -1):
+ return -1
+ }
+
+ absx := x
+ sign := false
+ if x < 0 {
+ absx = -absx
+ sign = true
+ }
+
+ // filter out huge argument
+ if absx >= Ln2X56 { // if |x| >= 56 * ln2
+ if absx >= Othreshold { // if |x| >= 709.78...
+ return Inf(1) // overflow
+ }
+ if sign {
+ return -1 // x < -56*ln2, return -1.0
+ }
+ }
+
+ // argument reduction
+ var c float64
+ var k int
+ if absx > Ln2Half { // if |x| > 0.5 * ln2
+ var hi, lo float64
+ if absx < Ln2HalfX3 { // and |x| < 1.5 * ln2
+ if !sign {
+ hi = x - Ln2Hi
+ lo = Ln2Lo
+ k = 1
+ } else {
+ hi = x + Ln2Hi
+ lo = -Ln2Lo
+ k = -1
+ }
+ } else {
+ if !sign {
+ k = int(InvLn2*x + 0.5)
+ } else {
+ k = int(InvLn2*x - 0.5)
+ }
+ t := float64(k)
+ hi = x - t*Ln2Hi // t * Ln2Hi is exact here
+ lo = t * Ln2Lo
+ }
+ x = hi - lo
+ c = (hi - x) - lo
+ } else if absx < Tiny { // when |x| < 2**-54, return x
+ return x
+ } else {
+ k = 0
+ }
+
+ // x is now in primary range
+ hfx := 0.5 * x
+ hxs := x * hfx
+ r1 := 1 + hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))))
+ t := 3 - r1*hfx
+ e := hxs * ((r1 - t) / (6.0 - x*t))
+ if k != 0 {
+ e = (x*(e-c) - c)
+ e -= hxs
+ switch {
+ case k == -1:
+ return 0.5*(x-e) - 0.5
+ case k == 1:
+ if x < -0.25 {
+ return -2 * (e - (x + 0.5))
+ }
+ return 1 + 2*(x-e)
+ case k <= -2 || k > 56: // suffice to return exp(x)-1
+ y := 1 - (e - x)
+ y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
+ return y - 1
+ }
+ if k < 20 {
+ t := Float64frombits(0x3ff0000000000000 - (0x20000000000000 >> uint(k))) // t=1-2**-k
+ y := t - (e - x)
+ y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
+ return y
+ }
+ t := Float64frombits(uint64((0x3ff - k) << 52)) // 2**-k
+ y := x - (e + t)
+ y += 1
+ y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
+ return y
+ }
+ return x - (x*e - hxs) // c is 0
+}
diff --git a/libgo/go/math/fabs.go b/libgo/go/math/fabs.go
new file mode 100644
index 000000000..343123126
--- /dev/null
+++ b/libgo/go/math/fabs.go
@@ -0,0 +1,21 @@
+// 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 math
+
+// Fabs returns the absolute value of x.
+//
+// Special cases are:
+// Fabs(+Inf) = +Inf
+// Fabs(-Inf) = +Inf
+// Fabs(NaN) = NaN
+func Fabs(x float64) float64 {
+ switch {
+ case x < 0:
+ return -x
+ case x == 0:
+ return 0 // return correctly fabs(-0)
+ }
+ return x
+}
diff --git a/libgo/go/math/fdim.go b/libgo/go/math/fdim.go
new file mode 100644
index 000000000..18993137a
--- /dev/null
+++ b/libgo/go/math/fdim.go
@@ -0,0 +1,29 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Fdim returns the maximum of x-y or 0.
+func Fdim(x, y float64) float64 {
+ if x > y {
+ return x - y
+ }
+ return 0
+}
+
+// Fmax returns the larger of x or y.
+func Fmax(x, y float64) float64 {
+ if x > y {
+ return x
+ }
+ return y
+}
+
+// Fmin returns the smaller of x or y.
+func Fmin(x, y float64) float64 {
+ if x < y {
+ return x
+ }
+ return y
+}
diff --git a/libgo/go/math/floor.go b/libgo/go/math/floor.go
new file mode 100644
index 000000000..b22b94ad6
--- /dev/null
+++ b/libgo/go/math/floor.go
@@ -0,0 +1,53 @@
+// Copyright 2009-2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// Floor returns the greatest integer value less than or equal to x.
+//
+// Special cases are:
+// Floor(+Inf) = +Inf
+// Floor(-Inf) = -Inf
+// Floor(NaN) = NaN
+func Floor(x float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ if x == 0 || x != x || x > MaxFloat64 || x < -MaxFloat64 { // x == 0 || IsNaN(x) || IsInf(x, 0)
+ return x
+ }
+ if x < 0 {
+ d, fract := Modf(-x)
+ if fract != 0.0 {
+ d = d + 1
+ }
+ return -d
+ }
+ d, _ := Modf(x)
+ return d
+}
+
+// Ceil returns the least integer value greater than or equal to x.
+//
+// Special cases are:
+// Ceil(+Inf) = +Inf
+// Ceil(-Inf) = -Inf
+// Ceil(NaN) = NaN
+func Ceil(x float64) float64 { return -Floor(-x) }
+
+// Trunc returns the integer value of x.
+//
+// Special cases are:
+// Trunc(+Inf) = +Inf
+// Trunc(-Inf) = -Inf
+// Trunc(NaN) = NaN
+func Trunc(x float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ if x == 0 || x != x || x > MaxFloat64 || x < -MaxFloat64 { // x == 0 || IsNaN(x) || IsInf(x, 0)
+ return x
+ }
+ d, _ := Modf(x)
+ return d
+}
diff --git a/libgo/go/math/fmod.go b/libgo/go/math/fmod.go
new file mode 100644
index 000000000..fc57f7483
--- /dev/null
+++ b/libgo/go/math/fmod.go
@@ -0,0 +1,48 @@
+// Copyright 2009-2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+/*
+ Floating-point mod function.
+*/
+
+// Fmod returns the floating-point remainder of x/y.
+// The magnitude of the result is less than y and its
+// sign agrees with that of x.
+//
+// Special cases are:
+// if x is not finite, Fmod returns NaN
+// if y is 0 or NaN, Fmod returns NaN
+func Fmod(x, y float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us.
+ if y == 0 || x > MaxFloat64 || x < -MaxFloat64 || x != x || y != y { // y == 0 || IsInf(x, 0) || IsNaN(x) || IsNan(y)
+ return NaN()
+ }
+ if y < 0 {
+ y = -y
+ }
+
+ yfr, yexp := Frexp(y)
+ sign := false
+ r := x
+ if x < 0 {
+ r = -x
+ sign = true
+ }
+
+ for r >= y {
+ rfr, rexp := Frexp(r)
+ if rfr < yfr {
+ rexp = rexp - 1
+ }
+ r = r - Ldexp(y, rexp-yexp)
+ }
+ if sign {
+ r = -r
+ }
+ return r
+}
diff --git a/libgo/go/math/frexp.go b/libgo/go/math/frexp.go
new file mode 100644
index 000000000..867b78f36
--- /dev/null
+++ b/libgo/go/math/frexp.go
@@ -0,0 +1,33 @@
+// 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 math
+
+// Frexp breaks f into a normalized fraction
+// and an integral power of two.
+// It returns frac and exp satisfying f == frac × 2**exp,
+// with the absolute value of frac in the interval [½, 1).
+//
+// Special cases are:
+// Frexp(±0) = ±0, 0
+// Frexp(±Inf) = ±Inf, 0
+// Frexp(NaN) = NaN, 0
+func Frexp(f float64) (frac float64, exp int) {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case f == 0:
+ return f, 0 // correctly return -0
+ case f < -MaxFloat64 || f > MaxFloat64 || f != f: // IsInf(f, 0) || IsNaN(f):
+ return f, 0
+ }
+ f, exp = normalize(f)
+ x := Float64bits(f)
+ exp += int((x>>shift)&mask) - bias + 1
+ x &^= mask << shift
+ x |= (-1 + bias) << shift
+ frac = Float64frombits(x)
+ return
+}
diff --git a/libgo/go/math/gamma.go b/libgo/go/math/gamma.go
new file mode 100644
index 000000000..73ca0e53a
--- /dev/null
+++ b/libgo/go/math/gamma.go
@@ -0,0 +1,188 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// The original C code, the long comment, and the constants
+// below are from http://netlib.sandia.gov/cephes/cprob/gamma.c.
+// The go code is a simplified version of the original C.
+//
+// tgamma.c
+//
+// Gamma function
+//
+// SYNOPSIS:
+//
+// double x, y, tgamma();
+// extern int signgam;
+//
+// y = tgamma( x );
+//
+// DESCRIPTION:
+//
+// Returns gamma function of the argument. The result is
+// correctly signed, and the sign (+1 or -1) is also
+// returned in a global (extern) variable named signgam.
+// This variable is also filled in by the logarithmic gamma
+// function lgamma().
+//
+// Arguments |x| <= 34 are reduced by recurrence and the function
+// approximated by a rational function of degree 6/7 in the
+// interval (2,3). Large arguments are handled by Stirling's
+// formula. Large negative arguments are made positive using
+// a reflection formula.
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC -34, 34 10000 1.3e-16 2.5e-17
+// IEEE -170,-33 20000 2.3e-15 3.3e-16
+// IEEE -33, 33 20000 9.4e-16 2.2e-16
+// IEEE 33, 171.6 20000 2.3e-15 3.2e-16
+//
+// Error for arguments outside the test range will be larger
+// owing to error amplification by the exponential function.
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+var _P = []float64{
+ 1.60119522476751861407e-04,
+ 1.19135147006586384913e-03,
+ 1.04213797561761569935e-02,
+ 4.76367800457137231464e-02,
+ 2.07448227648435975150e-01,
+ 4.94214826801497100753e-01,
+ 9.99999999999999996796e-01,
+}
+var _Q = []float64{
+ -2.31581873324120129819e-05,
+ 5.39605580493303397842e-04,
+ -4.45641913851797240494e-03,
+ 1.18139785222060435552e-02,
+ 3.58236398605498653373e-02,
+ -2.34591795718243348568e-01,
+ 7.14304917030273074085e-02,
+ 1.00000000000000000320e+00,
+}
+var _S = []float64{
+ 7.87311395793093628397e-04,
+ -2.29549961613378126380e-04,
+ -2.68132617805781232825e-03,
+ 3.47222221605458667310e-03,
+ 8.33333333333482257126e-02,
+}
+
+// Gamma function computed by Stirling's formula.
+// The polynomial is valid for 33 <= x <= 172.
+func stirling(x float64) float64 {
+ const (
+ SqrtTwoPi = 2.506628274631000502417
+ MaxStirling = 143.01608
+ )
+ w := 1 / x
+ w = 1 + w*((((_S[0]*w+_S[1])*w+_S[2])*w+_S[3])*w+_S[4])
+ y := Exp(x)
+ if x > MaxStirling { // avoid Pow() overflow
+ v := Pow(x, 0.5*x-0.25)
+ y = v * (v / y)
+ } else {
+ y = Pow(x, x-0.5) / y
+ }
+ y = SqrtTwoPi * y * w
+ return y
+}
+
+// Gamma(x) returns the Gamma function of x.
+//
+// Special cases are:
+// Gamma(Inf) = Inf
+// Gamma(-Inf) = -Inf
+// Gamma(NaN) = NaN
+// Large values overflow to +Inf.
+// Negative integer values equal ±Inf.
+func Gamma(x float64) float64 {
+ const Euler = 0.57721566490153286060651209008240243104215933593992 // A001620
+ // special cases
+ switch {
+ case x < -MaxFloat64 || x != x: // IsInf(x, -1) || IsNaN(x):
+ return x
+ case x < -170.5674972726612 || x > 171.61447887182298:
+ return Inf(1)
+ }
+ q := Fabs(x)
+ p := Floor(q)
+ if q > 33 {
+ if x >= 0 {
+ return stirling(x)
+ }
+ signgam := 1
+ if ip := int(p); ip&1 == 0 {
+ signgam = -1
+ }
+ z := q - p
+ if z > 0.5 {
+ p = p + 1
+ z = q - p
+ }
+ z = q * Sin(Pi*z)
+ if z == 0 {
+ return Inf(signgam)
+ }
+ z = Pi / (Fabs(z) * stirling(q))
+ return float64(signgam) * z
+ }
+
+ // Reduce argument
+ z := 1.0
+ for x >= 3 {
+ x = x - 1
+ z = z * x
+ }
+ for x < 0 {
+ if x > -1e-09 {
+ goto small
+ }
+ z = z / x
+ x = x + 1
+ }
+ for x < 2 {
+ if x < 1e-09 {
+ goto small
+ }
+ z = z / x
+ x = x + 1
+ }
+
+ if x == 2 {
+ return z
+ }
+
+ x = x - 2
+ p = (((((x*_P[0]+_P[1])*x+_P[2])*x+_P[3])*x+_P[4])*x+_P[5])*x + _P[6]
+ q = ((((((x*_Q[0]+_Q[1])*x+_Q[2])*x+_Q[3])*x+_Q[4])*x+_Q[5])*x+_Q[6])*x + _Q[7]
+ return z * p / q
+
+small:
+ if x == 0 {
+ return Inf(1)
+ }
+ return z / ((1 + Euler*x) * x)
+}
diff --git a/libgo/go/math/hypot.go b/libgo/go/math/hypot.go
new file mode 100644
index 000000000..ecd115d9e
--- /dev/null
+++ b/libgo/go/math/hypot.go
@@ -0,0 +1,41 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Hypot -- sqrt(p*p + q*q), but overflows only if the result does.
+*/
+
+// Hypot computes Sqrt(p*p + q*q), taking care to avoid
+// unnecessary overflow and underflow.
+//
+// Special cases are:
+// Hypot(p, q) = +Inf if p or q is infinite
+// Hypot(p, q) = NaN if p or q is NaN
+func Hypot(p, q float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case p < -MaxFloat64 || p > MaxFloat64 || q < -MaxFloat64 || q > MaxFloat64: // IsInf(p, 0) || IsInf(q, 0):
+ return Inf(1)
+ case p != p || q != q: // IsNaN(p) || IsNaN(q):
+ return NaN()
+ }
+ if p < 0 {
+ p = -p
+ }
+ if q < 0 {
+ q = -q
+ }
+ if p < q {
+ p, q = q, p
+ }
+ if p == 0 {
+ return 0
+ }
+ q = q / p
+ return p * Sqrt(1+q*q)
+}
diff --git a/libgo/go/math/hypot_port.go b/libgo/go/math/hypot_port.go
new file mode 100644
index 000000000..27f335ba2
--- /dev/null
+++ b/libgo/go/math/hypot_port.go
@@ -0,0 +1,63 @@
+// Copyright 2009-2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Hypot -- sqrt(p*p + q*q), but overflows only if the result does.
+ See:
+ Cleve Moler and Donald Morrison,
+ Replacing Square Roots by Pythagorean Sums
+ IBM Journal of Research and Development,
+ Vol. 27, Number 6, pp. 577-581, Nov. 1983
+*/
+
+// Hypot computes Sqrt(p*p + q*q), taking care to avoid
+// unnecessary overflow and underflow.
+//
+// Special cases are:
+// Hypot(p, q) = +Inf if p or q is infinite
+// Hypot(p, q) = NaN if p or q is NaN
+func hypotGo(p, q float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case p < -MaxFloat64 || p > MaxFloat64 || q < -MaxFloat64 || q > MaxFloat64: // IsInf(p, 0) || IsInf(q, 0):
+ return Inf(1)
+ case p != p || q != q: // IsNaN(p) || IsNaN(q):
+ return NaN()
+ }
+ if p < 0 {
+ p = -p
+ }
+ if q < 0 {
+ q = -q
+ }
+
+ if p < q {
+ p, q = q, p
+ }
+
+ if p == 0 {
+ return 0
+ }
+
+ pfac := p
+ q = q / p
+ r := q
+ p = 1
+ for {
+ r = r * r
+ s := r + 4
+ if s == 4 {
+ return p * pfac
+ }
+ r = r / s
+ p = p + 2*r*p
+ q = q * r
+ r = q / p
+ }
+ panic("unreachable")
+}
diff --git a/libgo/go/math/hypot_test.go b/libgo/go/math/hypot_test.go
new file mode 100644
index 000000000..85ce1d404
--- /dev/null
+++ b/libgo/go/math/hypot_test.go
@@ -0,0 +1,9 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Make hypotGo available for testing.
+
+func HypotGo(x, y float64) float64 { return hypotGo(x, y) }
diff --git a/libgo/go/math/j0.go b/libgo/go/math/j0.go
new file mode 100644
index 000000000..5aaf4ab9c
--- /dev/null
+++ b/libgo/go/math/j0.go
@@ -0,0 +1,433 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Bessel function of the first and second kinds of order zero.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_j0.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_j0(x), __ieee754_y0(x)
+// Bessel function of the first and second kinds of order zero.
+// Method -- j0(x):
+// 1. For tiny x, we use j0(x) = 1 - x**2/4 + x**4/64 - ...
+// 2. Reduce x to |x| since j0(x)=j0(-x), and
+// for x in (0,2)
+// j0(x) = 1-z/4+ z**2*R0/S0, where z = x*x;
+// (precision: |j0-1+z/4-z**2R0/S0 |<2**-63.67 )
+// for x in (2,inf)
+// j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0))
+// where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+// as follow:
+// cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+// = 1/sqrt(2) * (cos(x) + sin(x))
+// sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
+// = 1/sqrt(2) * (sin(x) - cos(x))
+// (To avoid cancellation, use
+// sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+// to compute the worse one.)
+//
+// 3 Special cases
+// j0(nan)= nan
+// j0(0) = 1
+// j0(inf) = 0
+//
+// Method -- y0(x):
+// 1. For x<2.
+// Since
+// y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x**2/4 - ...)
+// therefore y0(x)-2/pi*j0(x)*ln(x) is an even function.
+// We use the following function to approximate y0,
+// y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x**2
+// where
+// U(z) = u00 + u01*z + ... + u06*z**6
+// V(z) = 1 + v01*z + ... + v04*z**4
+// with absolute approximation error bounded by 2**-72.
+// Note: For tiny x, U/V = u0 and j0(x)~1, hence
+// y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27)
+// 2. For x>=2.
+// y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0))
+// where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+// by the method mentioned above.
+// 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0.
+//
+
+// J0 returns the order-zero Bessel function of the first kind.
+//
+// Special cases are:
+// J0(±Inf) = 0
+// J0(0) = 1
+// J0(NaN) = NaN
+func J0(x float64) float64 {
+ const (
+ Huge = 1e300
+ TwoM27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000
+ TwoM13 = 1.0 / (1 << 13) // 2**-13 0x3f20000000000000
+ Two129 = 1 << 129 // 2**129 0x4800000000000000
+ // R0/S0 on [0, 2]
+ R02 = 1.56249999999999947958e-02 // 0x3F8FFFFFFFFFFFFD
+ R03 = -1.89979294238854721751e-04 // 0xBF28E6A5B61AC6E9
+ R04 = 1.82954049532700665670e-06 // 0x3EBEB1D10C503919
+ R05 = -4.61832688532103189199e-09 // 0xBE33D5E773D63FCE
+ S01 = 1.56191029464890010492e-02 // 0x3F8FFCE882C8C2A4
+ S02 = 1.16926784663337450260e-04 // 0x3F1EA6D2DD57DBF4
+ S03 = 5.13546550207318111446e-07 // 0x3EA13B54CE84D5A9
+ S04 = 1.16614003333790000205e-09 // 0x3E1408BCF4745D8F
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x: // IsNaN(x)
+ return x
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ return 0
+ case x == 0:
+ return 1
+ }
+
+ if x < 0 {
+ x = -x
+ }
+ if x >= 2 {
+ s, c := Sincos(x)
+ ss := s - c
+ cc := s + c
+
+ // make sure x+x does not overflow
+ if x < MaxFloat64/2 {
+ z := -Cos(x + x)
+ if s*c < 0 {
+ cc = z / ss
+ } else {
+ ss = z / cc
+ }
+ }
+
+ // j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ // y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+
+ var z float64
+ if x > Two129 { // |x| > ~6.8056e+38
+ z = (1 / SqrtPi) * cc / Sqrt(x)
+ } else {
+ u := pzero(x)
+ v := qzero(x)
+ z = (1 / SqrtPi) * (u*cc - v*ss) / Sqrt(x)
+ }
+ return z // |x| >= 2.0
+ }
+ if x < TwoM13 { // |x| < ~1.2207e-4
+ if x < TwoM27 {
+ return 1 // |x| < ~7.4506e-9
+ }
+ return 1 - 0.25*x*x // ~7.4506e-9 < |x| < ~1.2207e-4
+ }
+ z := x * x
+ r := z * (R02 + z*(R03+z*(R04+z*R05)))
+ s := 1 + z*(S01+z*(S02+z*(S03+z*S04)))
+ if x < 1 {
+ return 1 + z*(-0.25+(r/s)) // |x| < 1.00
+ }
+ u := 0.5 * x
+ return (1+u)*(1-u) + z*(r/s) // 1.0 < |x| < 2.0
+}
+
+// Y0 returns the order-zero Bessel function of the second kind.
+//
+// Special cases are:
+// Y0(+Inf) = 0
+// Y0(0) = -Inf
+// Y0(x < 0) = NaN
+// Y0(NaN) = NaN
+func Y0(x float64) float64 {
+ const (
+ TwoM27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000
+ Two129 = 1 << 129 // 2**129 0x4800000000000000
+ U00 = -7.38042951086872317523e-02 // 0xBFB2E4D699CBD01F
+ U01 = 1.76666452509181115538e-01 // 0x3FC69D019DE9E3FC
+ U02 = -1.38185671945596898896e-02 // 0xBF8C4CE8B16CFA97
+ U03 = 3.47453432093683650238e-04 // 0x3F36C54D20B29B6B
+ U04 = -3.81407053724364161125e-06 // 0xBECFFEA773D25CAD
+ U05 = 1.95590137035022920206e-08 // 0x3E5500573B4EABD4
+ U06 = -3.98205194132103398453e-11 // 0xBDC5E43D693FB3C8
+ V01 = 1.27304834834123699328e-02 // 0x3F8A127091C9C71A
+ V02 = 7.60068627350353253702e-05 // 0x3F13ECBBF578C6C1
+ V03 = 2.59150851840457805467e-07 // 0x3E91642D7FF202FD
+ V04 = 4.41110311332675467403e-10 // 0x3DFE50183BD6D9EF
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x < 0 || x != x: // x < 0 || IsNaN(x):
+ return NaN()
+ case x > MaxFloat64: // IsInf(x, 1):
+ return 0
+ case x == 0:
+ return Inf(-1)
+ }
+
+ if x >= 2 { // |x| >= 2.0
+
+ // y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+ // where x0 = x-pi/4
+ // Better formula:
+ // cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ // = 1/sqrt(2) * (sin(x) + cos(x))
+ // sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ // = 1/sqrt(2) * (sin(x) - cos(x))
+ // To avoid cancellation, use
+ // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ // to compute the worse one.
+
+ s, c := Sincos(x)
+ ss := s - c
+ cc := s + c
+
+ // j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ // y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+
+ // make sure x+x does not overflow
+ if x < MaxFloat64/2 {
+ z := -Cos(x + x)
+ if s*c < 0 {
+ cc = z / ss
+ } else {
+ ss = z / cc
+ }
+ }
+ var z float64
+ if x > Two129 { // |x| > ~6.8056e+38
+ z = (1 / SqrtPi) * ss / Sqrt(x)
+ } else {
+ u := pzero(x)
+ v := qzero(x)
+ z = (1 / SqrtPi) * (u*ss + v*cc) / Sqrt(x)
+ }
+ return z // |x| >= 2.0
+ }
+ if x <= TwoM27 {
+ return U00 + (2/Pi)*Log(x) // |x| < ~7.4506e-9
+ }
+ z := x * x
+ u := U00 + z*(U01+z*(U02+z*(U03+z*(U04+z*(U05+z*U06)))))
+ v := 1 + z*(V01+z*(V02+z*(V03+z*V04)))
+ return u/v + (2/Pi)*J0(x)*Log(x) // ~7.4506e-9 < |x| < 2.0
+}
+
+// The asymptotic expansions of pzero is
+// 1 - 9/128 s**2 + 11025/98304 s**4 - ..., where s = 1/x.
+// For x >= 2, We approximate pzero by
+// pzero(x) = 1 + (R/S)
+// where R = pR0 + pR1*s**2 + pR2*s**4 + ... + pR5*s**10
+// S = 1 + pS0*s**2 + ... + pS4*s**10
+// and
+// | pzero(x)-1-R/S | <= 2 ** ( -60.26)
+
+// for x in [inf, 8]=1/[0,0.125]
+var p0R8 = [6]float64{
+ 0.00000000000000000000e+00, // 0x0000000000000000
+ -7.03124999999900357484e-02, // 0xBFB1FFFFFFFFFD32
+ -8.08167041275349795626e+00, // 0xC02029D0B44FA779
+ -2.57063105679704847262e+02, // 0xC07011027B19E863
+ -2.48521641009428822144e+03, // 0xC0A36A6ECD4DCAFC
+ -5.25304380490729545272e+03, // 0xC0B4850B36CC643D
+}
+var p0S8 = [5]float64{
+ 1.16534364619668181717e+02, // 0x405D223307A96751
+ 3.83374475364121826715e+03, // 0x40ADF37D50596938
+ 4.05978572648472545552e+04, // 0x40E3D2BB6EB6B05F
+ 1.16752972564375915681e+05, // 0x40FC810F8F9FA9BD
+ 4.76277284146730962675e+04, // 0x40E741774F2C49DC
+}
+
+// for x in [8,4.5454]=1/[0.125,0.22001]
+var p0R5 = [6]float64{
+ -1.14125464691894502584e-11, // 0xBDA918B147E495CC
+ -7.03124940873599280078e-02, // 0xBFB1FFFFE69AFBC6
+ -4.15961064470587782438e+00, // 0xC010A370F90C6BBF
+ -6.76747652265167261021e+01, // 0xC050EB2F5A7D1783
+ -3.31231299649172967747e+02, // 0xC074B3B36742CC63
+ -3.46433388365604912451e+02, // 0xC075A6EF28A38BD7
+}
+var p0S5 = [5]float64{
+ 6.07539382692300335975e+01, // 0x404E60810C98C5DE
+ 1.05125230595704579173e+03, // 0x40906D025C7E2864
+ 5.97897094333855784498e+03, // 0x40B75AF88FBE1D60
+ 9.62544514357774460223e+03, // 0x40C2CCB8FA76FA38
+ 2.40605815922939109441e+03, // 0x40A2CC1DC70BE864
+}
+
+// for x in [4.547,2.8571]=1/[0.2199,0.35001]
+var p0R3 = [6]float64{
+ -2.54704601771951915620e-09, // 0xBE25E1036FE1AA86
+ -7.03119616381481654654e-02, // 0xBFB1FFF6F7C0E24B
+ -2.40903221549529611423e+00, // 0xC00345B2AEA48074
+ -2.19659774734883086467e+01, // 0xC035F74A4CB94E14
+ -5.80791704701737572236e+01, // 0xC04D0A22420A1A45
+ -3.14479470594888503854e+01, // 0xC03F72ACA892D80F
+}
+var p0S3 = [5]float64{
+ 3.58560338055209726349e+01, // 0x4041ED9284077DD3
+ 3.61513983050303863820e+02, // 0x40769839464A7C0E
+ 1.19360783792111533330e+03, // 0x4092A66E6D1061D6
+ 1.12799679856907414432e+03, // 0x40919FFCB8C39B7E
+ 1.73580930813335754692e+02, // 0x4065B296FC379081
+}
+
+// for x in [2.8570,2]=1/[0.3499,0.5]
+var p0R2 = [6]float64{
+ -8.87534333032526411254e-08, // 0xBE77D316E927026D
+ -7.03030995483624743247e-02, // 0xBFB1FF62495E1E42
+ -1.45073846780952986357e+00, // 0xBFF736398A24A843
+ -7.63569613823527770791e+00, // 0xC01E8AF3EDAFA7F3
+ -1.11931668860356747786e+01, // 0xC02662E6C5246303
+ -3.23364579351335335033e+00, // 0xC009DE81AF8FE70F
+}
+var p0S2 = [5]float64{
+ 2.22202997532088808441e+01, // 0x40363865908B5959
+ 1.36206794218215208048e+02, // 0x4061069E0EE8878F
+ 2.70470278658083486789e+02, // 0x4070E78642EA079B
+ 1.53875394208320329881e+02, // 0x40633C033AB6FAFF
+ 1.46576176948256193810e+01, // 0x402D50B344391809
+}
+
+func pzero(x float64) float64 {
+ var p [6]float64
+ var q [5]float64
+ if x >= 8 {
+ p = p0R8
+ q = p0S8
+ } else if x >= 4.5454 {
+ p = p0R5
+ q = p0S5
+ } else if x >= 2.8571 {
+ p = p0R3
+ q = p0S3
+ } else if x >= 2 {
+ p = p0R2
+ q = p0S2
+ }
+ z := 1 / (x * x)
+ r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+ s := 1 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))))
+ return 1 + r/s
+}
+
+// For x >= 8, the asymptotic expansions of qzero is
+// -1/8 s + 75/1024 s**3 - ..., where s = 1/x.
+// We approximate pzero by
+// qzero(x) = s*(-1.25 + (R/S))
+// where R = qR0 + qR1*s**2 + qR2*s**4 + ... + qR5*s**10
+// S = 1 + qS0*s**2 + ... + qS5*s**12
+// and
+// | qzero(x)/s +1.25-R/S | <= 2**(-61.22)
+
+// for x in [inf, 8]=1/[0,0.125]
+var q0R8 = [6]float64{
+ 0.00000000000000000000e+00, // 0x0000000000000000
+ 7.32421874999935051953e-02, // 0x3FB2BFFFFFFFFE2C
+ 1.17682064682252693899e+01, // 0x402789525BB334D6
+ 5.57673380256401856059e+02, // 0x40816D6315301825
+ 8.85919720756468632317e+03, // 0x40C14D993E18F46D
+ 3.70146267776887834771e+04, // 0x40E212D40E901566
+}
+var q0S8 = [6]float64{
+ 1.63776026895689824414e+02, // 0x406478D5365B39BC
+ 8.09834494656449805916e+03, // 0x40BFA2584E6B0563
+ 1.42538291419120476348e+05, // 0x4101665254D38C3F
+ 8.03309257119514397345e+05, // 0x412883DA83A52B43
+ 8.40501579819060512818e+05, // 0x4129A66B28DE0B3D
+ -3.43899293537866615225e+05, // 0xC114FD6D2C9530C5
+}
+
+// for x in [8,4.5454]=1/[0.125,0.22001]
+var q0R5 = [6]float64{
+ 1.84085963594515531381e-11, // 0x3DB43D8F29CC8CD9
+ 7.32421766612684765896e-02, // 0x3FB2BFFFD172B04C
+ 5.83563508962056953777e+00, // 0x401757B0B9953DD3
+ 1.35111577286449829671e+02, // 0x4060E3920A8788E9
+ 1.02724376596164097464e+03, // 0x40900CF99DC8C481
+ 1.98997785864605384631e+03, // 0x409F17E953C6E3A6
+}
+var q0S5 = [6]float64{
+ 8.27766102236537761883e+01, // 0x4054B1B3FB5E1543
+ 2.07781416421392987104e+03, // 0x40A03BA0DA21C0CE
+ 1.88472887785718085070e+04, // 0x40D267D27B591E6D
+ 5.67511122894947329769e+04, // 0x40EBB5E397E02372
+ 3.59767538425114471465e+04, // 0x40E191181F7A54A0
+ -5.35434275601944773371e+03, // 0xC0B4EA57BEDBC609
+}
+
+// for x in [4.547,2.8571]=1/[0.2199,0.35001]
+var q0R3 = [6]float64{
+ 4.37741014089738620906e-09, // 0x3E32CD036ADECB82
+ 7.32411180042911447163e-02, // 0x3FB2BFEE0E8D0842
+ 3.34423137516170720929e+00, // 0x400AC0FC61149CF5
+ 4.26218440745412650017e+01, // 0x40454F98962DAEDD
+ 1.70808091340565596283e+02, // 0x406559DBE25EFD1F
+ 1.66733948696651168575e+02, // 0x4064D77C81FA21E0
+}
+var q0S3 = [6]float64{
+ 4.87588729724587182091e+01, // 0x40486122BFE343A6
+ 7.09689221056606015736e+02, // 0x40862D8386544EB3
+ 3.70414822620111362994e+03, // 0x40ACF04BE44DFC63
+ 6.46042516752568917582e+03, // 0x40B93C6CD7C76A28
+ 2.51633368920368957333e+03, // 0x40A3A8AAD94FB1C0
+ -1.49247451836156386662e+02, // 0xC062A7EB201CF40F
+}
+
+// for x in [2.8570,2]=1/[0.3499,0.5]
+var q0R2 = [6]float64{
+ 1.50444444886983272379e-07, // 0x3E84313B54F76BDB
+ 7.32234265963079278272e-02, // 0x3FB2BEC53E883E34
+ 1.99819174093815998816e+00, // 0x3FFFF897E727779C
+ 1.44956029347885735348e+01, // 0x402CFDBFAAF96FE5
+ 3.16662317504781540833e+01, // 0x403FAA8E29FBDC4A
+ 1.62527075710929267416e+01, // 0x403040B171814BB4
+}
+var q0S2 = [6]float64{
+ 3.03655848355219184498e+01, // 0x403E5D96F7C07AED
+ 2.69348118608049844624e+02, // 0x4070D591E4D14B40
+ 8.44783757595320139444e+02, // 0x408A664522B3BF22
+ 8.82935845112488550512e+02, // 0x408B977C9C5CC214
+ 2.12666388511798828631e+02, // 0x406A95530E001365
+ -5.31095493882666946917e+00, // 0xC0153E6AF8B32931
+}
+
+func qzero(x float64) float64 {
+ var p, q [6]float64
+ if x >= 8 {
+ p = q0R8
+ q = q0S8
+ } else if x >= 4.5454 {
+ p = q0R5
+ q = q0S5
+ } else if x >= 2.8571 {
+ p = q0R3
+ q = q0S3
+ } else if x >= 2 {
+ p = q0R2
+ q = q0S2
+ }
+ z := 1 / (x * x)
+ r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+ s := 1 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))))
+ return (-0.125 + r/s) / x
+}
diff --git a/libgo/go/math/j1.go b/libgo/go/math/j1.go
new file mode 100644
index 000000000..278162e9d
--- /dev/null
+++ b/libgo/go/math/j1.go
@@ -0,0 +1,426 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Bessel function of the first and second kinds of order one.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_j1.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_j1(x), __ieee754_y1(x)
+// Bessel function of the first and second kinds of order one.
+// Method -- j1(x):
+// 1. For tiny x, we use j1(x) = x/2 - x**3/16 + x**5/384 - ...
+// 2. Reduce x to |x| since j1(x)=-j1(-x), and
+// for x in (0,2)
+// j1(x) = x/2 + x*z*R0/S0, where z = x*x;
+// (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 )
+// for x in (2,inf)
+// j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
+// y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+// where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+// as follow:
+// cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+// = 1/sqrt(2) * (sin(x) - cos(x))
+// sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+// = -1/sqrt(2) * (sin(x) + cos(x))
+// (To avoid cancellation, use
+// sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+// to compute the worse one.)
+//
+// 3 Special cases
+// j1(nan)= nan
+// j1(0) = 0
+// j1(inf) = 0
+//
+// Method -- y1(x):
+// 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN
+// 2. For x<2.
+// Since
+// y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x**3-...)
+// therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function.
+// We use the following function to approximate y1,
+// y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x**2
+// where for x in [0,2] (abs err less than 2**-65.89)
+// U(z) = U0[0] + U0[1]*z + ... + U0[4]*z**4
+// V(z) = 1 + v0[0]*z + ... + v0[4]*z**5
+// Note: For tiny x, 1/x dominate y1 and hence
+// y1(tiny) = -2/pi/tiny, (choose tiny<2**-54)
+// 3. For x>=2.
+// y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+// where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+// by method mentioned above.
+
+// J1 returns the order-one Bessel function of the first kind.
+//
+// Special cases are:
+// J1(±Inf) = 0
+// J1(NaN) = NaN
+func J1(x float64) float64 {
+ const (
+ TwoM27 = 1.0 / (1 << 27) // 2**-27 0x3e40000000000000
+ Two129 = 1 << 129 // 2**129 0x4800000000000000
+ // R0/S0 on [0, 2]
+ R00 = -6.25000000000000000000e-02 // 0xBFB0000000000000
+ R01 = 1.40705666955189706048e-03 // 0x3F570D9F98472C61
+ R02 = -1.59955631084035597520e-05 // 0xBEF0C5C6BA169668
+ R03 = 4.96727999609584448412e-08 // 0x3E6AAAFA46CA0BD9
+ S01 = 1.91537599538363460805e-02 // 0x3F939D0B12637E53
+ S02 = 1.85946785588630915560e-04 // 0x3F285F56B9CDF664
+ S03 = 1.17718464042623683263e-06 // 0x3EB3BFF8333F8498
+ S04 = 5.04636257076217042715e-09 // 0x3E35AC88C97DFF2C
+ S05 = 1.23542274426137913908e-11 // 0x3DAB2ACFCFB97ED8
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x: // IsNaN(x)
+ return x
+ case x < -MaxFloat64 || x > MaxFloat64 || x == 0: // IsInf(x, 0) || x == 0:
+ return 0
+ }
+
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ if x >= 2 {
+ s, c := Sincos(x)
+ ss := -s - c
+ cc := s - c
+
+ // make sure x+x does not overflow
+ if x < MaxFloat64/2 {
+ z := Cos(x + x)
+ if s*c > 0 {
+ cc = z / ss
+ } else {
+ ss = z / cc
+ }
+ }
+
+ // j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+ // y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+
+ var z float64
+ if x > Two129 {
+ z = (1 / SqrtPi) * cc / Sqrt(x)
+ } else {
+ u := pone(x)
+ v := qone(x)
+ z = (1 / SqrtPi) * (u*cc - v*ss) / Sqrt(x)
+ }
+ if sign {
+ return -z
+ }
+ return z
+ }
+ if x < TwoM27 { // |x|<2**-27
+ return 0.5 * x // inexact if x!=0 necessary
+ }
+ z := x * x
+ r := z * (R00 + z*(R01+z*(R02+z*R03)))
+ s := 1.0 + z*(S01+z*(S02+z*(S03+z*(S04+z*S05))))
+ r *= x
+ z = 0.5*x + r/s
+ if sign {
+ return -z
+ }
+ return z
+}
+
+// Y1 returns the order-one Bessel function of the second kind.
+//
+// Special cases are:
+// Y1(+Inf) = 0
+// Y1(0) = -Inf
+// Y1(x < 0) = NaN
+// Y1(NaN) = NaN
+func Y1(x float64) float64 {
+ const (
+ TwoM54 = 1.0 / (1 << 54) // 2**-54 0x3c90000000000000
+ Two129 = 1 << 129 // 2**129 0x4800000000000000
+ U00 = -1.96057090646238940668e-01 // 0xBFC91866143CBC8A
+ U01 = 5.04438716639811282616e-02 // 0x3FA9D3C776292CD1
+ U02 = -1.91256895875763547298e-03 // 0xBF5F55E54844F50F
+ U03 = 2.35252600561610495928e-05 // 0x3EF8AB038FA6B88E
+ U04 = -9.19099158039878874504e-08 // 0xBE78AC00569105B8
+ V00 = 1.99167318236649903973e-02 // 0x3F94650D3F4DA9F0
+ V01 = 2.02552581025135171496e-04 // 0x3F2A8C896C257764
+ V02 = 1.35608801097516229404e-06 // 0x3EB6C05A894E8CA6
+ V03 = 6.22741452364621501295e-09 // 0x3E3ABF1D5BA69A86
+ V04 = 1.66559246207992079114e-11 // 0x3DB25039DACA772A
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x < 0 || x != x: // x < 0 || IsNaN(x):
+ return NaN()
+ case x > MaxFloat64: // IsInf(x, 1):
+ return 0
+ case x == 0:
+ return Inf(-1)
+ }
+
+ if x >= 2 {
+ s, c := Sincos(x)
+ ss := -s - c
+ cc := s - c
+
+ // make sure x+x does not overflow
+ if x < MaxFloat64/2 {
+ z := Cos(x + x)
+ if s*c > 0 {
+ cc = z / ss
+ } else {
+ ss = z / cc
+ }
+ }
+ // y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+ // where x0 = x-3pi/4
+ // Better formula:
+ // cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ // = 1/sqrt(2) * (sin(x) - cos(x))
+ // sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ // = -1/sqrt(2) * (cos(x) + sin(x))
+ // To avoid cancellation, use
+ // sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ // to compute the worse one.
+
+ var z float64
+ if x > Two129 {
+ z = (1 / SqrtPi) * ss / Sqrt(x)
+ } else {
+ u := pone(x)
+ v := qone(x)
+ z = (1 / SqrtPi) * (u*ss + v*cc) / Sqrt(x)
+ }
+ return z
+ }
+ if x <= TwoM54 { // x < 2**-54
+ return -(2 / Pi) / x
+ }
+ z := x * x
+ u := U00 + z*(U01+z*(U02+z*(U03+z*U04)))
+ v := 1 + z*(V00+z*(V01+z*(V02+z*(V03+z*V04))))
+ return x*(u/v) + (2/Pi)*(J1(x)*Log(x)-1/x)
+}
+
+// For x >= 8, the asymptotic expansions of pone is
+// 1 + 15/128 s**2 - 4725/2**15 s**4 - ..., where s = 1/x.
+// We approximate pone by
+// pone(x) = 1 + (R/S)
+// where R = pr0 + pr1*s**2 + pr2*s**4 + ... + pr5*s**10
+// S = 1 + ps0*s**2 + ... + ps4*s**10
+// and
+// | pone(x)-1-R/S | <= 2**(-60.06)
+
+// for x in [inf, 8]=1/[0,0.125]
+var p1R8 = [6]float64{
+ 0.00000000000000000000e+00, // 0x0000000000000000
+ 1.17187499999988647970e-01, // 0x3FBDFFFFFFFFFCCE
+ 1.32394806593073575129e+01, // 0x402A7A9D357F7FCE
+ 4.12051854307378562225e+02, // 0x4079C0D4652EA590
+ 3.87474538913960532227e+03, // 0x40AE457DA3A532CC
+ 7.91447954031891731574e+03, // 0x40BEEA7AC32782DD
+}
+var p1S8 = [5]float64{
+ 1.14207370375678408436e+02, // 0x405C8D458E656CAC
+ 3.65093083420853463394e+03, // 0x40AC85DC964D274F
+ 3.69562060269033463555e+04, // 0x40E20B8697C5BB7F
+ 9.76027935934950801311e+04, // 0x40F7D42CB28F17BB
+ 3.08042720627888811578e+04, // 0x40DE1511697A0B2D
+}
+
+// for x in [8,4.5454] = 1/[0.125,0.22001]
+var p1R5 = [6]float64{
+ 1.31990519556243522749e-11, // 0x3DAD0667DAE1CA7D
+ 1.17187493190614097638e-01, // 0x3FBDFFFFE2C10043
+ 6.80275127868432871736e+00, // 0x401B36046E6315E3
+ 1.08308182990189109773e+02, // 0x405B13B9452602ED
+ 5.17636139533199752805e+02, // 0x40802D16D052D649
+ 5.28715201363337541807e+02, // 0x408085B8BB7E0CB7
+}
+var p1S5 = [5]float64{
+ 5.92805987221131331921e+01, // 0x404DA3EAA8AF633D
+ 9.91401418733614377743e+02, // 0x408EFB361B066701
+ 5.35326695291487976647e+03, // 0x40B4E9445706B6FB
+ 7.84469031749551231769e+03, // 0x40BEA4B0B8A5BB15
+ 1.50404688810361062679e+03, // 0x40978030036F5E51
+}
+
+// for x in[4.5453,2.8571] = 1/[0.2199,0.35001]
+var p1R3 = [6]float64{
+ 3.02503916137373618024e-09, // 0x3E29FC21A7AD9EDD
+ 1.17186865567253592491e-01, // 0x3FBDFFF55B21D17B
+ 3.93297750033315640650e+00, // 0x400F76BCE85EAD8A
+ 3.51194035591636932736e+01, // 0x40418F489DA6D129
+ 9.10550110750781271918e+01, // 0x4056C3854D2C1837
+ 4.85590685197364919645e+01, // 0x4048478F8EA83EE5
+}
+var p1S3 = [5]float64{
+ 3.47913095001251519989e+01, // 0x40416549A134069C
+ 3.36762458747825746741e+02, // 0x40750C3307F1A75F
+ 1.04687139975775130551e+03, // 0x40905B7C5037D523
+ 8.90811346398256432622e+02, // 0x408BD67DA32E31E9
+ 1.03787932439639277504e+02, // 0x4059F26D7C2EED53
+}
+
+// for x in [2.8570,2] = 1/[0.3499,0.5]
+var p1R2 = [6]float64{
+ 1.07710830106873743082e-07, // 0x3E7CE9D4F65544F4
+ 1.17176219462683348094e-01, // 0x3FBDFF42BE760D83
+ 2.36851496667608785174e+00, // 0x4002F2B7F98FAEC0
+ 1.22426109148261232917e+01, // 0x40287C377F71A964
+ 1.76939711271687727390e+01, // 0x4031B1A8177F8EE2
+ 5.07352312588818499250e+00, // 0x40144B49A574C1FE
+}
+var p1S2 = [5]float64{
+ 2.14364859363821409488e+01, // 0x40356FBD8AD5ECDC
+ 1.25290227168402751090e+02, // 0x405F529314F92CD5
+ 2.32276469057162813669e+02, // 0x406D08D8D5A2DBD9
+ 1.17679373287147100768e+02, // 0x405D6B7ADA1884A9
+ 8.36463893371618283368e+00, // 0x4020BAB1F44E5192
+}
+
+func pone(x float64) float64 {
+ var p [6]float64
+ var q [5]float64
+ if x >= 8 {
+ p = p1R8
+ q = p1S8
+ } else if x >= 4.5454 {
+ p = p1R5
+ q = p1S5
+ } else if x >= 2.8571 {
+ p = p1R3
+ q = p1S3
+ } else if x >= 2 {
+ p = p1R2
+ q = p1S2
+ }
+ z := 1 / (x * x)
+ r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+ s := 1.0 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))))
+ return 1 + r/s
+}
+
+// For x >= 8, the asymptotic expansions of qone is
+// 3/8 s - 105/1024 s**3 - ..., where s = 1/x.
+// We approximate qone by
+// qone(x) = s*(0.375 + (R/S))
+// where R = qr1*s**2 + qr2*s**4 + ... + qr5*s**10
+// S = 1 + qs1*s**2 + ... + qs6*s**12
+// and
+// | qone(x)/s -0.375-R/S | <= 2**(-61.13)
+
+// for x in [inf, 8] = 1/[0,0.125]
+var q1R8 = [6]float64{
+ 0.00000000000000000000e+00, // 0x0000000000000000
+ -1.02539062499992714161e-01, // 0xBFBA3FFFFFFFFDF3
+ -1.62717534544589987888e+01, // 0xC0304591A26779F7
+ -7.59601722513950107896e+02, // 0xC087BCD053E4B576
+ -1.18498066702429587167e+04, // 0xC0C724E740F87415
+ -4.84385124285750353010e+04, // 0xC0E7A6D065D09C6A
+}
+var q1S8 = [6]float64{
+ 1.61395369700722909556e+02, // 0x40642CA6DE5BCDE5
+ 7.82538599923348465381e+03, // 0x40BE9162D0D88419
+ 1.33875336287249578163e+05, // 0x4100579AB0B75E98
+ 7.19657723683240939863e+05, // 0x4125F65372869C19
+ 6.66601232617776375264e+05, // 0x412457D27719AD5C
+ -2.94490264303834643215e+05, // 0xC111F9690EA5AA18
+}
+
+// for x in [8,4.5454] = 1/[0.125,0.22001]
+var q1R5 = [6]float64{
+ -2.08979931141764104297e-11, // 0xBDB6FA431AA1A098
+ -1.02539050241375426231e-01, // 0xBFBA3FFFCB597FEF
+ -8.05644828123936029840e+00, // 0xC0201CE6CA03AD4B
+ -1.83669607474888380239e+02, // 0xC066F56D6CA7B9B0
+ -1.37319376065508163265e+03, // 0xC09574C66931734F
+ -2.61244440453215656817e+03, // 0xC0A468E388FDA79D
+}
+var q1S5 = [6]float64{
+ 8.12765501384335777857e+01, // 0x405451B2FF5A11B2
+ 1.99179873460485964642e+03, // 0x409F1F31E77BF839
+ 1.74684851924908907677e+04, // 0x40D10F1F0D64CE29
+ 4.98514270910352279316e+04, // 0x40E8576DAABAD197
+ 2.79480751638918118260e+04, // 0x40DB4B04CF7C364B
+ -4.71918354795128470869e+03, // 0xC0B26F2EFCFFA004
+}
+
+// for x in [4.5454,2.8571] = 1/[0.2199,0.35001] ???
+var q1R3 = [6]float64{
+ -5.07831226461766561369e-09, // 0xBE35CFA9D38FC84F
+ -1.02537829820837089745e-01, // 0xBFBA3FEB51AEED54
+ -4.61011581139473403113e+00, // 0xC01270C23302D9FF
+ -5.78472216562783643212e+01, // 0xC04CEC71C25D16DA
+ -2.28244540737631695038e+02, // 0xC06C87D34718D55F
+ -2.19210128478909325622e+02, // 0xC06B66B95F5C1BF6
+}
+var q1S3 = [6]float64{
+ 4.76651550323729509273e+01, // 0x4047D523CCD367E4
+ 6.73865112676699709482e+02, // 0x40850EEBC031EE3E
+ 3.38015286679526343505e+03, // 0x40AA684E448E7C9A
+ 5.54772909720722782367e+03, // 0x40B5ABBAA61D54A6
+ 1.90311919338810798763e+03, // 0x409DBC7A0DD4DF4B
+ -1.35201191444307340817e+02, // 0xC060E670290A311F
+}
+
+// for x in [2.8570,2] = 1/[0.3499,0.5]
+var q1R2 = [6]float64{
+ -1.78381727510958865572e-07, // 0xBE87F12644C626D2
+ -1.02517042607985553460e-01, // 0xBFBA3E8E9148B010
+ -2.75220568278187460720e+00, // 0xC006048469BB4EDA
+ -1.96636162643703720221e+01, // 0xC033A9E2C168907F
+ -4.23253133372830490089e+01, // 0xC04529A3DE104AAA
+ -2.13719211703704061733e+01, // 0xC0355F3639CF6E52
+}
+var q1S2 = [6]float64{
+ 2.95333629060523854548e+01, // 0x403D888A78AE64FF
+ 2.52981549982190529136e+02, // 0x406F9F68DB821CBA
+ 7.57502834868645436472e+02, // 0x4087AC05CE49A0F7
+ 7.39393205320467245656e+02, // 0x40871B2548D4C029
+ 1.55949003336666123687e+02, // 0x40637E5E3C3ED8D4
+ -4.95949898822628210127e+00, // 0xC013D686E71BE86B
+}
+
+func qone(x float64) float64 {
+ var p, q [6]float64
+ if x >= 8 {
+ p = q1R8
+ q = q1S8
+ } else if x >= 4.5454 {
+ p = q1R5
+ q = q1S5
+ } else if x >= 2.8571 {
+ p = q1R3
+ q = q1S3
+ } else if x >= 2 {
+ p = q1R2
+ q = q1S2
+ }
+ z := 1 / (x * x)
+ r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
+ s := 1 + z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))))
+ return (0.375 + r/s) / x
+}
diff --git a/libgo/go/math/jn.go b/libgo/go/math/jn.go
new file mode 100644
index 000000000..9024af3c2
--- /dev/null
+++ b/libgo/go/math/jn.go
@@ -0,0 +1,310 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Bessel function of the first and second kinds of order n.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_jn.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_jn(n, x), __ieee754_yn(n, x)
+// floating point Bessel's function of the 1st and 2nd kind
+// of order n
+//
+// Special cases:
+// y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+// y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+// Note 2. About jn(n,x), yn(n,x)
+// For n=0, j0(x) is called,
+// for n=1, j1(x) is called,
+// for n<x, forward recursion is used starting
+// from values of j0(x) and j1(x).
+// for n>x, a continued fraction approximation to
+// j(n,x)/j(n-1,x) is evaluated and then backward
+// recursion is used starting from a supposed value
+// for j(n,x). The resulting value of j(0,x) is
+// compared with the actual value to correct the
+// supposed value of j(n,x).
+//
+// yn(n,x) is similar in all respects, except
+// that forward recursion is used for all
+// values of n>1.
+
+// Jn returns the order-n Bessel function of the first kind.
+//
+// Special cases are:
+// Jn(n, ±Inf) = 0
+// Jn(n, NaN) = NaN
+func Jn(n int, x float64) float64 {
+ const (
+ TwoM29 = 1.0 / (1 << 29) // 2**-29 0x3e10000000000000
+ Two302 = 1 << 302 // 2**302 0x52D0000000000000
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x: // IsNaN(x)
+ return x
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ return 0
+ }
+ // J(-n, x) = (-1)**n * J(n, x), J(n, -x) = (-1)**n * J(n, x)
+ // Thus, J(-n, x) = J(n, -x)
+
+ if n == 0 {
+ return J0(x)
+ }
+ if x == 0 {
+ return 0
+ }
+ if n < 0 {
+ n, x = -n, -x
+ }
+ if n == 1 {
+ return J1(x)
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ if n&1 == 1 {
+ sign = true // odd n and negative x
+ }
+ }
+ var b float64
+ if float64(n) <= x {
+ // Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x)
+ if x >= Two302 { // x > 2**302
+
+ // (x >> n**2)
+ // Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ // Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ // Let s=sin(x), c=cos(x),
+ // xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ //
+ // n sin(xn)*sqt2 cos(xn)*sqt2
+ // ----------------------------------
+ // 0 s-c c+s
+ // 1 -s-c -c+s
+ // 2 -s+c -c-s
+ // 3 s+c c-s
+
+ var temp float64
+ switch n & 3 {
+ case 0:
+ temp = Cos(x) + Sin(x)
+ case 1:
+ temp = -Cos(x) + Sin(x)
+ case 2:
+ temp = -Cos(x) - Sin(x)
+ case 3:
+ temp = Cos(x) - Sin(x)
+ }
+ b = (1 / SqrtPi) * temp / Sqrt(x)
+ } else {
+ b = J1(x)
+ for i, a := 1, J0(x); i < n; i++ {
+ a, b = b, b*(float64(i+i)/x)-a // avoid underflow
+ }
+ }
+ } else {
+ if x < TwoM29 { // x < 2**-29
+ // x is tiny, return the first Taylor expansion of J(n,x)
+ // J(n,x) = 1/n!*(x/2)**n - ...
+
+ if n > 33 { // underflow
+ b = 0
+ } else {
+ temp := x * 0.5
+ b = temp
+ a := 1.0
+ for i := 2; i <= n; i++ {
+ a *= float64(i) // a = n!
+ b *= temp // b = (x/2)**n
+ }
+ b /= a
+ }
+ } else {
+ // use backward recurrence
+ // x x**2 x**2
+ // J(n,x)/J(n-1,x) = ---- ------ ------ .....
+ // 2n - 2(n+1) - 2(n+2)
+ //
+ // 1 1 1
+ // (for large x) = ---- ------ ------ .....
+ // 2n 2(n+1) 2(n+2)
+ // -- - ------ - ------ -
+ // x x x
+ //
+ // Let w = 2n/x and h=2/x, then the above quotient
+ // is equal to the continued fraction:
+ // 1
+ // = -----------------------
+ // 1
+ // w - -----------------
+ // 1
+ // w+h - ---------
+ // w+2h - ...
+ //
+ // To determine how many terms needed, let
+ // Q(0) = w, Q(1) = w(w+h) - 1,
+ // Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+ // When Q(k) > 1e4 good for single
+ // When Q(k) > 1e9 good for double
+ // When Q(k) > 1e17 good for quadruple
+
+ // determine k
+ w := float64(n+n) / x
+ h := 2 / x
+ q0 := w
+ z := w + h
+ q1 := w*z - 1
+ k := 1
+ for q1 < 1e9 {
+ k += 1
+ z += h
+ q0, q1 = q1, z*q1-q0
+ }
+ m := n + n
+ t := 0.0
+ for i := 2 * (n + k); i >= m; i -= 2 {
+ t = 1 / (float64(i)/x - t)
+ }
+ a := t
+ b = 1
+ // estimate log((2/x)**n*n!) = n*log(2/x)+n*ln(n)
+ // Hence, if n*(log(2n/x)) > ...
+ // single 8.8722839355e+01
+ // double 7.09782712893383973096e+02
+ // long double 1.1356523406294143949491931077970765006170e+04
+ // then recurrent value may overflow and the result is
+ // likely underflow to zero
+
+ tmp := float64(n)
+ v := 2 / x
+ tmp = tmp * Log(Fabs(v*tmp))
+ if tmp < 7.09782712893383973096e+02 {
+ for i := n - 1; i > 0; i-- {
+ di := float64(i + i)
+ a, b = b, b*di/x-a
+ di -= 2
+ }
+ } else {
+ for i := n - 1; i > 0; i-- {
+ di := float64(i + i)
+ a, b = b, b*di/x-a
+ di -= 2
+ // scale b to avoid spurious overflow
+ if b > 1e100 {
+ a /= b
+ t /= b
+ b = 1
+ }
+ }
+ }
+ b = t * J0(x) / b
+ }
+ }
+ if sign {
+ return -b
+ }
+ return b
+}
+
+// Yn returns the order-n Bessel function of the second kind.
+//
+// Special cases are:
+// Yn(n, +Inf) = 0
+// Yn(n > 0, 0) = -Inf
+// Yn(n < 0, 0) = +Inf if n is odd, -Inf if n is even
+// Y1(n, x < 0) = NaN
+// Y1(n, NaN) = NaN
+func Yn(n int, x float64) float64 {
+ const Two302 = 1 << 302 // 2**302 0x52D0000000000000
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x < 0 || x != x: // x < 0 || IsNaN(x):
+ return NaN()
+ case x > MaxFloat64: // IsInf(x, 1)
+ return 0
+ }
+
+ if n == 0 {
+ return Y0(x)
+ }
+ if x == 0 {
+ if n < 0 && n&1 == 1 {
+ return Inf(1)
+ }
+ return Inf(-1)
+ }
+ sign := false
+ if n < 0 {
+ n = -n
+ if n&1 == 1 {
+ sign = true // sign true if n < 0 && |n| odd
+ }
+ }
+ if n == 1 {
+ if sign {
+ return -Y1(x)
+ }
+ return Y1(x)
+ }
+ var b float64
+ if x >= Two302 { // x > 2**302
+ // (x >> n**2)
+ // Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ // Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ // Let s=sin(x), c=cos(x),
+ // xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ //
+ // n sin(xn)*sqt2 cos(xn)*sqt2
+ // ----------------------------------
+ // 0 s-c c+s
+ // 1 -s-c -c+s
+ // 2 -s+c -c-s
+ // 3 s+c c-s
+
+ var temp float64
+ switch n & 3 {
+ case 0:
+ temp = Sin(x) - Cos(x)
+ case 1:
+ temp = -Sin(x) - Cos(x)
+ case 2:
+ temp = -Sin(x) + Cos(x)
+ case 3:
+ temp = Sin(x) + Cos(x)
+ }
+ b = (1 / SqrtPi) * temp / Sqrt(x)
+ } else {
+ a := Y0(x)
+ b = Y1(x)
+ // quit if b is -inf
+ for i := 1; i < n && b >= -MaxFloat64; i++ { // for i := 1; i < n && !IsInf(b, -1); i++ {
+ a, b = b, (float64(i+i)/x)*b-a
+ }
+ }
+ if sign {
+ return -b
+ }
+ return b
+}
diff --git a/libgo/go/math/ldexp.go b/libgo/go/math/ldexp.go
new file mode 100644
index 000000000..96c95cad4
--- /dev/null
+++ b/libgo/go/math/ldexp.go
@@ -0,0 +1,45 @@
+// 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 math
+
+// Ldexp is the inverse of Frexp.
+// It returns frac × 2**exp.
+//
+// Special cases are:
+// Ldexp(±0, exp) = ±0
+// Ldexp(±Inf, exp) = ±Inf
+// Ldexp(NaN, exp) = NaN
+func Ldexp(frac float64, exp int) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case frac == 0:
+ return frac // correctly return -0
+ case frac < -MaxFloat64 || frac > MaxFloat64 || frac != frac: // IsInf(frac, 0) || IsNaN(frac):
+ return frac
+ }
+ frac, e := normalize(frac)
+ exp += e
+ x := Float64bits(frac)
+ exp += int(x>>shift)&mask - bias
+ if exp < -1074 {
+ return Copysign(0, frac) // underflow
+ }
+ if exp > 1023 { // overflow
+ if frac < 0 {
+ return Inf(-1)
+ }
+ return Inf(1)
+ }
+ var m float64 = 1
+ if exp < -1022 { // denormal
+ exp += 52
+ m = 1.0 / (1 << 52) // 2**-52
+ }
+ x &^= mask << shift
+ x |= uint64(exp+bias) << shift
+ return m * Float64frombits(x)
+}
diff --git a/libgo/go/math/lgamma.go b/libgo/go/math/lgamma.go
new file mode 100644
index 000000000..dc30f468f
--- /dev/null
+++ b/libgo/go/math/lgamma.go
@@ -0,0 +1,350 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point logarithm of the Gamma function.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_lgamma_r.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_lgamma_r(x, signgamp)
+// Reentrant version of the logarithm of the Gamma function
+// with user provided pointer for the sign of Gamma(x).
+//
+// Method:
+// 1. Argument Reduction for 0 < x <= 8
+// Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+// reduce x to a number in [1.5,2.5] by
+// lgamma(1+s) = log(s) + lgamma(s)
+// for example,
+// lgamma(7.3) = log(6.3) + lgamma(6.3)
+// = log(6.3*5.3) + lgamma(5.3)
+// = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+// 2. Polynomial approximation of lgamma around its
+// minimum (ymin=1.461632144968362245) to maintain monotonicity.
+// On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+// Let z = x-ymin;
+// lgamma(x) = -1.214862905358496078218 + z**2*poly(z)
+// poly(z) is a 14 degree polynomial.
+// 2. Rational approximation in the primary interval [2,3]
+// We use the following approximation:
+// s = x-2.0;
+// lgamma(x) = 0.5*s + s*P(s)/Q(s)
+// with accuracy
+// |P/Q - (lgamma(x)-0.5s)| < 2**-61.71
+// Our algorithms are based on the following observation
+//
+// zeta(2)-1 2 zeta(3)-1 3
+// lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ...
+// 2 3
+//
+// where Euler = 0.5772156649... is the Euler constant, which
+// is very close to 0.5.
+//
+// 3. For x>=8, we have
+// lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+// (better formula:
+// lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+// Let z = 1/x, then we approximation
+// f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+// by
+// 3 5 11
+// w = w0 + w1*z + w2*z + w3*z + ... + w6*z
+// where
+// |w - f(z)| < 2**-58.74
+//
+// 4. For negative x, since (G is gamma function)
+// -x*G(-x)*G(x) = pi/sin(pi*x),
+// we have
+// G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+// since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+// Hence, for x<0, signgam = sign(sin(pi*x)) and
+// lgamma(x) = log(|Gamma(x)|)
+// = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+// Note: one should avoid computing pi*(-x) directly in the
+// computation of sin(pi*(-x)).
+//
+// 5. Special Cases
+// lgamma(2+s) ~ s*(1-Euler) for tiny s
+// lgamma(1)=lgamma(2)=0
+// lgamma(x) ~ -log(x) for tiny x
+// lgamma(0) = lgamma(inf) = inf
+// lgamma(-integer) = +-inf
+//
+//
+
+// Lgamma returns the natural logarithm and sign (-1 or +1) of Gamma(x).
+//
+// Special cases are:
+// Lgamma(+Inf) = +Inf
+// Lgamma(0) = +Inf
+// Lgamma(-integer) = +Inf
+// Lgamma(-Inf) = -Inf
+// Lgamma(NaN) = NaN
+func Lgamma(x float64) (lgamma float64, sign int) {
+ const (
+ Ymin = 1.461632144968362245
+ Two52 = 1 << 52 // 0x4330000000000000 ~4.5036e+15
+ Two53 = 1 << 53 // 0x4340000000000000 ~9.0072e+15
+ Two58 = 1 << 58 // 0x4390000000000000 ~2.8823e+17
+ Tiny = 1.0 / (1 << 70) // 0x3b90000000000000 ~8.47033e-22
+ A0 = 7.72156649015328655494e-02 // 0x3FB3C467E37DB0C8
+ A1 = 3.22467033424113591611e-01 // 0x3FD4A34CC4A60FAD
+ A2 = 6.73523010531292681824e-02 // 0x3FB13E001A5562A7
+ A3 = 2.05808084325167332806e-02 // 0x3F951322AC92547B
+ A4 = 7.38555086081402883957e-03 // 0x3F7E404FB68FEFE8
+ A5 = 2.89051383673415629091e-03 // 0x3F67ADD8CCB7926B
+ A6 = 1.19270763183362067845e-03 // 0x3F538A94116F3F5D
+ A7 = 5.10069792153511336608e-04 // 0x3F40B6C689B99C00
+ A8 = 2.20862790713908385557e-04 // 0x3F2CF2ECED10E54D
+ A9 = 1.08011567247583939954e-04 // 0x3F1C5088987DFB07
+ A10 = 2.52144565451257326939e-05 // 0x3EFA7074428CFA52
+ A11 = 4.48640949618915160150e-05 // 0x3F07858E90A45837
+ Tc = 1.46163214496836224576e+00 // 0x3FF762D86356BE3F
+ Tf = -1.21486290535849611461e-01 // 0xBFBF19B9BCC38A42
+ // Tt = -(tail of Tf)
+ Tt = -3.63867699703950536541e-18 // 0xBC50C7CAA48A971F
+ T0 = 4.83836122723810047042e-01 // 0x3FDEF72BC8EE38A2
+ T1 = -1.47587722994593911752e-01 // 0xBFC2E4278DC6C509
+ T2 = 6.46249402391333854778e-02 // 0x3FB08B4294D5419B
+ T3 = -3.27885410759859649565e-02 // 0xBFA0C9A8DF35B713
+ T4 = 1.79706750811820387126e-02 // 0x3F9266E7970AF9EC
+ T5 = -1.03142241298341437450e-02 // 0xBF851F9FBA91EC6A
+ T6 = 6.10053870246291332635e-03 // 0x3F78FCE0E370E344
+ T7 = -3.68452016781138256760e-03 // 0xBF6E2EFFB3E914D7
+ T8 = 2.25964780900612472250e-03 // 0x3F6282D32E15C915
+ T9 = -1.40346469989232843813e-03 // 0xBF56FE8EBF2D1AF1
+ T10 = 8.81081882437654011382e-04 // 0x3F4CDF0CEF61A8E9
+ T11 = -5.38595305356740546715e-04 // 0xBF41A6109C73E0EC
+ T12 = 3.15632070903625950361e-04 // 0x3F34AF6D6C0EBBF7
+ T13 = -3.12754168375120860518e-04 // 0xBF347F24ECC38C38
+ T14 = 3.35529192635519073543e-04 // 0x3F35FD3EE8C2D3F4
+ U0 = -7.72156649015328655494e-02 // 0xBFB3C467E37DB0C8
+ U1 = 6.32827064025093366517e-01 // 0x3FE4401E8B005DFF
+ U2 = 1.45492250137234768737e+00 // 0x3FF7475CD119BD6F
+ U3 = 9.77717527963372745603e-01 // 0x3FEF497644EA8450
+ U4 = 2.28963728064692451092e-01 // 0x3FCD4EAEF6010924
+ U5 = 1.33810918536787660377e-02 // 0x3F8B678BBF2BAB09
+ V1 = 2.45597793713041134822e+00 // 0x4003A5D7C2BD619C
+ V2 = 2.12848976379893395361e+00 // 0x40010725A42B18F5
+ V3 = 7.69285150456672783825e-01 // 0x3FE89DFBE45050AF
+ V4 = 1.04222645593369134254e-01 // 0x3FBAAE55D6537C88
+ V5 = 3.21709242282423911810e-03 // 0x3F6A5ABB57D0CF61
+ S0 = -7.72156649015328655494e-02 // 0xBFB3C467E37DB0C8
+ S1 = 2.14982415960608852501e-01 // 0x3FCB848B36E20878
+ S2 = 3.25778796408930981787e-01 // 0x3FD4D98F4F139F59
+ S3 = 1.46350472652464452805e-01 // 0x3FC2BB9CBEE5F2F7
+ S4 = 2.66422703033638609560e-02 // 0x3F9B481C7E939961
+ S5 = 1.84028451407337715652e-03 // 0x3F5E26B67368F239
+ S6 = 3.19475326584100867617e-05 // 0x3F00BFECDD17E945
+ R1 = 1.39200533467621045958e+00 // 0x3FF645A762C4AB74
+ R2 = 7.21935547567138069525e-01 // 0x3FE71A1893D3DCDC
+ R3 = 1.71933865632803078993e-01 // 0x3FC601EDCCFBDF27
+ R4 = 1.86459191715652901344e-02 // 0x3F9317EA742ED475
+ R5 = 7.77942496381893596434e-04 // 0x3F497DDACA41A95B
+ R6 = 7.32668430744625636189e-06 // 0x3EDEBAF7A5B38140
+ W0 = 4.18938533204672725052e-01 // 0x3FDACFE390C97D69
+ W1 = 8.33333333333329678849e-02 // 0x3FB555555555553B
+ W2 = -2.77777777728775536470e-03 // 0xBF66C16C16B02E5C
+ W3 = 7.93650558643019558500e-04 // 0x3F4A019F98CF38B6
+ W4 = -5.95187557450339963135e-04 // 0xBF4380CB8C0FE741
+ W5 = 8.36339918996282139126e-04 // 0x3F4B67BA4CDAD5D1
+ W6 = -1.63092934096575273989e-03 // 0xBF5AB89D0B9E43E4
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ sign = 1
+ switch {
+ case x != x: // IsNaN(x):
+ lgamma = x
+ return
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ lgamma = x
+ return
+ case x == 0:
+ lgamma = Inf(1)
+ return
+ }
+
+ neg := false
+ if x < 0 {
+ x = -x
+ neg = true
+ }
+
+ if x < Tiny { // if |x| < 2**-70, return -log(|x|)
+ if neg {
+ sign = -1
+ }
+ lgamma = -Log(x)
+ return
+ }
+ var nadj float64
+ if neg {
+ if x >= Two52 { // |x| >= 2**52, must be -integer
+ lgamma = Inf(1)
+ return
+ }
+ t := sinPi(x)
+ if t == 0 {
+ lgamma = Inf(1) // -integer
+ return
+ }
+ nadj = Log(Pi / Fabs(t*x))
+ if t < 0 {
+ sign = -1
+ }
+ }
+
+ switch {
+ case x == 1 || x == 2: // purge off 1 and 2
+ lgamma = 0
+ return
+ case x < 2: // use lgamma(x) = lgamma(x+1) - log(x)
+ var y float64
+ var i int
+ if x <= 0.9 {
+ lgamma = -Log(x)
+ switch {
+ case x >= (Ymin - 1 + 0.27): // 0.7316 <= x <= 0.9
+ y = 1 - x
+ i = 0
+ case x >= (Ymin - 1 - 0.27): // 0.2316 <= x < 0.7316
+ y = x - (Tc - 1)
+ i = 1
+ default: // 0 < x < 0.2316
+ y = x
+ i = 2
+ }
+ } else {
+ lgamma = 0
+ switch {
+ case x >= (Ymin + 0.27): // 1.7316 <= x < 2
+ y = 2 - x
+ i = 0
+ case x >= (Ymin - 0.27): // 1.2316 <= x < 1.7316
+ y = x - Tc
+ i = 1
+ default: // 0.9 < x < 1.2316
+ y = x - 1
+ i = 2
+ }
+ }
+ switch i {
+ case 0:
+ z := y * y
+ p1 := A0 + z*(A2+z*(A4+z*(A6+z*(A8+z*A10))))
+ p2 := z * (A1 + z*(A3+z*(A5+z*(A7+z*(A9+z*A11)))))
+ p := y*p1 + p2
+ lgamma += (p - 0.5*y)
+ case 1:
+ z := y * y
+ w := z * y
+ p1 := T0 + w*(T3+w*(T6+w*(T9+w*T12))) // parallel comp
+ p2 := T1 + w*(T4+w*(T7+w*(T10+w*T13)))
+ p3 := T2 + w*(T5+w*(T8+w*(T11+w*T14)))
+ p := z*p1 - (Tt - w*(p2+y*p3))
+ lgamma += (Tf + p)
+ case 2:
+ p1 := y * (U0 + y*(U1+y*(U2+y*(U3+y*(U4+y*U5)))))
+ p2 := 1 + y*(V1+y*(V2+y*(V3+y*(V4+y*V5))))
+ lgamma += (-0.5*y + p1/p2)
+ }
+ case x < 8: // 2 <= x < 8
+ i := int(x)
+ y := x - float64(i)
+ p := y * (S0 + y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6))))))
+ q := 1 + y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6)))))
+ lgamma = 0.5*y + p/q
+ z := 1.0 // Lgamma(1+s) = Log(s) + Lgamma(s)
+ switch i {
+ case 7:
+ z *= (y + 6)
+ fallthrough
+ case 6:
+ z *= (y + 5)
+ fallthrough
+ case 5:
+ z *= (y + 4)
+ fallthrough
+ case 4:
+ z *= (y + 3)
+ fallthrough
+ case 3:
+ z *= (y + 2)
+ lgamma += Log(z)
+ }
+ case x < Two58: // 8 <= x < 2**58
+ t := Log(x)
+ z := 1 / x
+ y := z * z
+ w := W0 + z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6)))))
+ lgamma = (x-0.5)*(t-1) + w
+ default: // 2**58 <= x <= Inf
+ lgamma = x * (Log(x) - 1)
+ }
+ if neg {
+ lgamma = nadj - lgamma
+ }
+ return
+}
+
+// sinPi(x) is a helper function for negative x
+func sinPi(x float64) float64 {
+ const (
+ Two52 = 1 << 52 // 0x4330000000000000 ~4.5036e+15
+ Two53 = 1 << 53 // 0x4340000000000000 ~9.0072e+15
+ )
+ if x < 0.25 {
+ return -Sin(Pi * x)
+ }
+
+ // argument reduction
+ z := Floor(x)
+ var n int
+ if z != x { // inexact
+ x = Fmod(x, 2)
+ n = int(x * 4)
+ } else {
+ if x >= Two53 { // x must be even
+ x = 0
+ n = 0
+ } else {
+ if x < Two52 {
+ z = x + Two52 // exact
+ }
+ n = int(1 & Float64bits(z))
+ x = float64(n)
+ n <<= 2
+ }
+ }
+ switch n {
+ case 0:
+ x = Sin(Pi * x)
+ case 1, 2:
+ x = Cos(Pi * (0.5 - x))
+ case 3, 4:
+ x = Sin(Pi * (1 - x))
+ case 5, 6:
+ x = -Cos(Pi * (x - 1.5))
+ default:
+ x = Sin(Pi * (x - 2))
+ }
+ return -x
+}
diff --git a/libgo/go/math/log.go b/libgo/go/math/log.go
new file mode 100644
index 000000000..39d94512d
--- /dev/null
+++ b/libgo/go/math/log.go
@@ -0,0 +1,123 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+/*
+ Floating-point logarithm.
+*/
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_log.c
+// and came with this notice. The go code is a simpler
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_log(x)
+// Return the logrithm of x
+//
+// Method :
+// 1. Argument Reduction: find k and f such that
+// x = 2**k * (1+f),
+// where sqrt(2)/2 < 1+f < sqrt(2) .
+//
+// 2. Approximation of log(1+f).
+// Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+// = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+// = 2s + s*R
+// We use a special Reme algorithm on [0,0.1716] to generate
+// a polynomial of degree 14 to approximate R. The maximum error
+// of this polynomial approximation is bounded by 2**-58.45. In
+// other words,
+// 2 4 6 8 10 12 14
+// R(z) ~ L1*s +L2*s +L3*s +L4*s +L5*s +L6*s +L7*s
+// (the values of L1 to L7 are listed in the program) and
+// | 2 14 | -58.45
+// | L1*s +...+L7*s - R(z) | <= 2
+// | |
+// Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+// In order to guarantee error in log below 1ulp, we compute log by
+// log(1+f) = f - s*(f - R) (if f is not too large)
+// log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy)
+//
+// 3. Finally, log(x) = k*Ln2 + log(1+f).
+// = k*Ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*Ln2_lo)))
+// Here Ln2 is split into two floating point number:
+// Ln2_hi + Ln2_lo,
+// where n*Ln2_hi is always exact for |n| < 2000.
+//
+// Special cases:
+// log(x) is NaN with signal if x < 0 (including -INF) ;
+// log(+INF) is +INF; log(0) is -INF with signal;
+// log(NaN) is that NaN with no signal.
+//
+// Accuracy:
+// according to an error analysis, the error is always less than
+// 1 ulp (unit in the last place).
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+
+// Log returns the natural logarithm of x.
+//
+// Special cases are:
+// Log(+Inf) = +Inf
+// Log(0) = -Inf
+// Log(x < 0) = NaN
+// Log(NaN) = NaN
+func Log(x float64) float64 {
+ const (
+ Ln2Hi = 6.93147180369123816490e-01 /* 3fe62e42 fee00000 */
+ Ln2Lo = 1.90821492927058770002e-10 /* 3dea39ef 35793c76 */
+ L1 = 6.666666666666735130e-01 /* 3FE55555 55555593 */
+ L2 = 3.999999999940941908e-01 /* 3FD99999 9997FA04 */
+ L3 = 2.857142874366239149e-01 /* 3FD24924 94229359 */
+ L4 = 2.222219843214978396e-01 /* 3FCC71C5 1D8E78AF */
+ L5 = 1.818357216161805012e-01 /* 3FC74664 96CB03DE */
+ L6 = 1.531383769920937332e-01 /* 3FC39A09 D078C69F */
+ L7 = 1.479819860511658591e-01 /* 3FC2F112 DF3E5244 */
+ )
+
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+ return x
+ case x < 0:
+ return NaN()
+ case x == 0:
+ return Inf(-1)
+ }
+
+ // reduce
+ f1, ki := Frexp(x)
+ if f1 < Sqrt2/2 {
+ f1 *= 2
+ ki--
+ }
+ f := f1 - 1
+ k := float64(ki)
+
+ // compute
+ s := f / (2 + f)
+ s2 := s * s
+ s4 := s2 * s2
+ t1 := s2 * (L1 + s4*(L3+s4*(L5+s4*L7)))
+ t2 := s4 * (L2 + s4*(L4+s4*L6))
+ R := t1 + t2
+ hfsq := 0.5 * f * f
+ return k*Ln2Hi - ((hfsq - (s*(hfsq+R) + k*Ln2Lo)) - f)
+}
diff --git a/libgo/go/math/log10.go b/libgo/go/math/log10.go
new file mode 100644
index 000000000..6d18baae2
--- /dev/null
+++ b/libgo/go/math/log10.go
@@ -0,0 +1,13 @@
+// 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 math
+
+// Log10 returns the decimal logarithm of x.
+// The special cases are the same as for Log.
+func Log10(x float64) float64 { return Log(x) * (1 / Ln10) }
+
+// Log2 returns the binary logarithm of x.
+// The special cases are the same as for Log.
+func Log2(x float64) float64 { return Log(x) * (1 / Ln2) }
diff --git a/libgo/go/math/log10_decl.go b/libgo/go/math/log10_decl.go
new file mode 100644
index 000000000..5aec94e1c
--- /dev/null
+++ b/libgo/go/math/log10_decl.go
@@ -0,0 +1,8 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Log10(x float64) float64
+func Log2(x float64) float64
diff --git a/libgo/go/math/log1p.go b/libgo/go/math/log1p.go
new file mode 100644
index 000000000..e1fc275d0
--- /dev/null
+++ b/libgo/go/math/log1p.go
@@ -0,0 +1,200 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/s_log1p.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// double log1p(double x)
+//
+// Method :
+// 1. Argument Reduction: find k and f such that
+// 1+x = 2**k * (1+f),
+// where sqrt(2)/2 < 1+f < sqrt(2) .
+//
+// Note. If k=0, then f=x is exact. However, if k!=0, then f
+// may not be representable exactly. In that case, a correction
+// term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+// log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+// and add back the correction term c/u.
+// (Note: when x > 2**53, one can simply return log(x))
+//
+// 2. Approximation of log1p(f).
+// Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+// = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+// = 2s + s*R
+// We use a special Reme algorithm on [0,0.1716] to generate
+// a polynomial of degree 14 to approximate R The maximum error
+// of this polynomial approximation is bounded by 2**-58.45. In
+// other words,
+// 2 4 6 8 10 12 14
+// R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
+// (the values of Lp1 to Lp7 are listed in the program)
+// a-0.2929nd
+// | 2 14 | -58.45
+// | Lp1*s +...+Lp7*s - R(z) | <= 2
+// | |
+// Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+// In order to guarantee error in log below 1ulp, we compute log
+// by
+// log1p(f) = f - (hfsq - s*(hfsq+R)).
+//
+// 3. Finally, log1p(x) = k*ln2 + log1p(f).
+// = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+// Here ln2 is split into two floating point number:
+// ln2_hi + ln2_lo,
+// where n*ln2_hi is always exact for |n| < 2000.
+//
+// Special cases:
+// log1p(x) is NaN with signal if x < -1 (including -INF) ;
+// log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+// log1p(NaN) is that NaN with no signal.
+//
+// Accuracy:
+// according to an error analysis, the error is always less than
+// 1 ulp (unit in the last place).
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+//
+// Note: Assuming log() return accurate answer, the following
+// algorithm can be used to compute log1p(x) to within a few ULP:
+//
+// u = 1+x;
+// if(u==1.0) return x ; else
+// return log(u)*(x/(u-1.0));
+//
+// See HP-15C Advanced Functions Handbook, p.193.
+
+// Log1p returns the natural logarithm of 1 plus its argument x.
+// It is more accurate than Log(1 + x) when x is near zero.
+//
+// Special cases are:
+// Log1p(+Inf) = +Inf
+// Log1p(-1) = -Inf
+// Log1p(x < -1) = NaN
+// Log1p(NaN) = NaN
+func Log1p(x float64) float64 {
+ const (
+ Sqrt2M1 = 4.142135623730950488017e-01 // Sqrt(2)-1 = 0x3fda827999fcef34
+ Sqrt2HalfM1 = -2.928932188134524755992e-01 // Sqrt(2)/2-1 = 0xbfd2bec333018866
+ Small = 1.0 / (1 << 29) // 2**-29 = 0x3e20000000000000
+ Tiny = 1.0 / (1 << 54) // 2**-54
+ Two53 = 1 << 53 // 2**53
+ Ln2Hi = 6.93147180369123816490e-01 // 3fe62e42fee00000
+ Ln2Lo = 1.90821492927058770002e-10 // 3dea39ef35793c76
+ Lp1 = 6.666666666666735130e-01 // 3FE5555555555593
+ Lp2 = 3.999999999940941908e-01 // 3FD999999997FA04
+ Lp3 = 2.857142874366239149e-01 // 3FD2492494229359
+ Lp4 = 2.222219843214978396e-01 // 3FCC71C51D8E78AF
+ Lp5 = 1.818357216161805012e-01 // 3FC7466496CB03DE
+ Lp6 = 1.531383769920937332e-01 // 3FC39A09D078C69F
+ Lp7 = 1.479819860511658591e-01 // 3FC2F112DF3E5244
+ )
+
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x < -1 || x != x: // x < -1 || IsNaN(x): // includes -Inf
+ return NaN()
+ case x == -1:
+ return Inf(-1)
+ case x > MaxFloat64: // IsInf(x, 1):
+ return Inf(1)
+ }
+
+ absx := x
+ if absx < 0 {
+ absx = -absx
+ }
+
+ var f float64
+ var iu uint64
+ k := 1
+ if absx < Sqrt2M1 { // |x| < Sqrt(2)-1
+ if absx < Small { // |x| < 2**-29
+ if absx < Tiny { // |x| < 2**-54
+ return x
+ }
+ return x - x*x*0.5
+ }
+ if x > Sqrt2HalfM1 { // Sqrt(2)/2-1 < x
+ // (Sqrt(2)/2-1) < x < (Sqrt(2)-1)
+ k = 0
+ f = x
+ iu = 1
+ }
+ }
+ var c float64
+ if k != 0 {
+ var u float64
+ if absx < Two53 { // 1<<53
+ u = 1.0 + x
+ iu = Float64bits(u)
+ k = int((iu >> 52) - 1023)
+ if k > 0 {
+ c = 1.0 - (u - x)
+ } else {
+ c = x - (u - 1.0) // correction term
+ c /= u
+ }
+ } else {
+ u = x
+ iu = Float64bits(u)
+ k = int((iu >> 52) - 1023)
+ c = 0
+ }
+ iu &= 0x000fffffffffffff
+ if iu < 0x0006a09e667f3bcd { // mantissa of Sqrt(2)
+ u = Float64frombits(iu | 0x3ff0000000000000) // normalize u
+ } else {
+ k += 1
+ u = Float64frombits(iu | 0x3fe0000000000000) // normalize u/2
+ iu = (0x0010000000000000 - iu) >> 2
+ }
+ f = u - 1.0 // Sqrt(2)/2 < u < Sqrt(2)
+ }
+ hfsq := 0.5 * f * f
+ var s, R, z float64
+ if iu == 0 { // |f| < 2**-20
+ if f == 0 {
+ if k == 0 {
+ return 0
+ } else {
+ c += float64(k) * Ln2Lo
+ return float64(k)*Ln2Hi + c
+ }
+ }
+ R = hfsq * (1.0 - 0.66666666666666666*f) // avoid division
+ if k == 0 {
+ return f - R
+ }
+ return float64(k)*Ln2Hi - ((R - (float64(k)*Ln2Lo + c)) - f)
+ }
+ s = f / (2.0 + f)
+ z = s * s
+ R = z * (Lp1 + z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))))
+ if k == 0 {
+ return f - (hfsq - s*(hfsq+R))
+ }
+ return float64(k)*Ln2Hi - ((hfsq - (s*(hfsq+R) + (float64(k)*Ln2Lo + c))) - f)
+}
diff --git a/libgo/go/math/logb.go b/libgo/go/math/logb.go
new file mode 100644
index 000000000..072281ddf
--- /dev/null
+++ b/libgo/go/math/logb.go
@@ -0,0 +1,54 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Logb(x) returns the binary exponent of x.
+//
+// Special cases are:
+// Logb(±Inf) = +Inf
+// Logb(0) = -Inf
+// Logb(NaN) = NaN
+func Logb(x float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x == 0:
+ return Inf(-1)
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ return Inf(1)
+ case x != x: // IsNaN(x):
+ return x
+ }
+ return float64(ilogb(x))
+}
+
+// Ilogb(x) returns the binary exponent of x as an integer.
+//
+// Special cases are:
+// Ilogb(±Inf) = MaxInt32
+// Ilogb(0) = MinInt32
+// Ilogb(NaN) = MaxInt32
+func Ilogb(x float64) int {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x == 0:
+ return MinInt32
+ case x != x: // IsNaN(x):
+ return MaxInt32
+ case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ return MaxInt32
+ }
+ return ilogb(x)
+}
+
+// logb returns the binary exponent of x. It assumes x is finite and
+// non-zero.
+func ilogb(x float64) int {
+ x, exp := normalize(x)
+ return int((Float64bits(x)>>shift)&mask) - bias + exp
+}
diff --git a/libgo/go/math/modf.go b/libgo/go/math/modf.go
new file mode 100644
index 000000000..315174b70
--- /dev/null
+++ b/libgo/go/math/modf.go
@@ -0,0 +1,33 @@
+// 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 math
+
+// Modf returns integer and fractional floating-point numbers
+// that sum to f. Both values have the same sign as f.
+//
+// Special cases are:
+// Modf(+Inf) = +Inf, NaN
+// Modf(-Inf) = -Inf, NaN
+// Modf(NaN) = NaN, NaN
+func Modf(f float64) (int float64, frac float64) {
+ if f < 1 {
+ if f < 0 {
+ int, frac = Modf(-f)
+ return -int, -frac
+ }
+ return 0, f
+ }
+
+ x := Float64bits(f)
+ e := uint(x>>shift)&mask - bias
+
+ // Keep the top 12+e bits, the integer part; clear the rest.
+ if e < 64-12 {
+ x &^= 1<<(64-12-e) - 1
+ }
+ int = Float64frombits(x)
+ frac = f - int
+ return
+}
diff --git a/libgo/go/math/nextafter.go b/libgo/go/math/nextafter.go
new file mode 100644
index 000000000..86114340c
--- /dev/null
+++ b/libgo/go/math/nextafter.go
@@ -0,0 +1,29 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Nextafter returns the next representable value after x towards y.
+// If x == y, then x is returned.
+//
+// Special cases are:
+// Nextafter(NaN, y) = NaN
+// Nextafter(x, NaN) = NaN
+func Nextafter(x, y float64) (r float64) {
+ // TODO(rsc): Remove manual inlining of IsNaN
+ // when compiler does it for us
+ switch {
+ case x != x || y != y: // IsNaN(x) || IsNaN(y): // special case
+ r = NaN()
+ case x == y:
+ r = x
+ case x == 0:
+ r = Copysign(Float64frombits(1), y)
+ case (y > x) == (x > 0):
+ r = Float64frombits(Float64bits(x) + 1)
+ default:
+ r = Float64frombits(Float64bits(x) - 1)
+ }
+ return r
+}
diff --git a/libgo/go/math/pow.go b/libgo/go/math/pow.go
new file mode 100644
index 000000000..06b107401
--- /dev/null
+++ b/libgo/go/math/pow.go
@@ -0,0 +1,139 @@
+// 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 math
+
+func isOddInt(x float64) bool {
+ xi, xf := Modf(x)
+ return xf == 0 && int64(xi)&1 == 1
+}
+
+// Special cases taken from FreeBSD's /usr/src/lib/msun/src/e_pow.c
+// updated by IEEE Std. 754-2008 "Section 9.2.1 Special values".
+
+// Pow returns x**y, the base-x exponential of y.
+//
+// Special cases are (in order):
+// Pow(x, ±0) = 1 for any x
+// Pow(1, y) = 1 for any y
+// Pow(x, 1) = x for any x
+// Pow(NaN, y) = NaN
+// Pow(x, NaN) = NaN
+// Pow(±0, y) = ±Inf for y an odd integer < 0
+// Pow(±0, -Inf) = +Inf
+// Pow(±0, +Inf) = +0
+// Pow(±0, y) = +Inf for finite y < 0 and not an odd integer
+// Pow(±0, y) = ±0 for y an odd integer > 0
+// Pow(±0, y) = +0 for finite y > 0 and not an odd integer
+// Pow(-1, ±Inf) = 1
+// Pow(x, +Inf) = +Inf for |x| > 1
+// Pow(x, -Inf) = +0 for |x| > 1
+// Pow(x, +Inf) = +0 for |x| < 1
+// Pow(x, -Inf) = +Inf for |x| < 1
+// Pow(+Inf, y) = +Inf for y > 0
+// Pow(+Inf, y) = +0 for y < 0
+// Pow(-Inf, y) = Pow(-0, -y)
+// Pow(x, y) = NaN for finite x < 0 and finite non-integer y
+func Pow(x, y float64) float64 {
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case y == 0 || x == 1:
+ return 1
+ case y == 1:
+ return x
+ case y == 0.5:
+ return Sqrt(x)
+ case y == -0.5:
+ return 1 / Sqrt(x)
+ case x != x || y != y: // IsNaN(x) || IsNaN(y):
+ return NaN()
+ case x == 0:
+ switch {
+ case y < 0:
+ if isOddInt(y) {
+ return Copysign(Inf(1), x)
+ }
+ return Inf(1)
+ case y > 0:
+ if isOddInt(y) {
+ return x
+ }
+ return 0
+ }
+ case y > MaxFloat64 || y < -MaxFloat64: // IsInf(y, 0):
+ switch {
+ case x == -1:
+ return 1
+ case (Fabs(x) < 1) == IsInf(y, 1):
+ return 0
+ default:
+ return Inf(1)
+ }
+ case x > MaxFloat64 || x < -MaxFloat64: // IsInf(x, 0):
+ if IsInf(x, -1) {
+ return Pow(1/x, -y) // Pow(-0, -y)
+ }
+ switch {
+ case y < 0:
+ return 0
+ case y > 0:
+ return Inf(1)
+ }
+ }
+
+ absy := y
+ flip := false
+ if absy < 0 {
+ absy = -absy
+ flip = true
+ }
+ yi, yf := Modf(absy)
+ if yf != 0 && x < 0 {
+ return NaN()
+ }
+ if yi >= 1<<63 {
+ return Exp(y * Log(x))
+ }
+
+ // ans = a1 * 2**ae (= 1 for now).
+ a1 := 1.0
+ ae := 0
+
+ // ans *= x**yf
+ if yf != 0 {
+ if yf > 0.5 {
+ yf--
+ yi++
+ }
+ a1 = Exp(yf * Log(x))
+ }
+
+ // ans *= x**yi
+ // by multiplying in successive squarings
+ // of x according to bits of yi.
+ // accumulate powers of two into exp.
+ x1, xe := Frexp(x)
+ for i := int64(yi); i != 0; i >>= 1 {
+ if i&1 == 1 {
+ a1 *= x1
+ ae += xe
+ }
+ x1 *= x1
+ xe <<= 1
+ if x1 < .5 {
+ x1 += x1
+ xe--
+ }
+ }
+
+ // ans = a1*2**ae
+ // if flip { ans = 1 / ans }
+ // but in the opposite order
+ if flip {
+ a1 = 1 / a1
+ ae = -ae
+ }
+ return Ldexp(a1, ae)
+}
diff --git a/libgo/go/math/pow10.go b/libgo/go/math/pow10.go
new file mode 100644
index 000000000..bda2e824e
--- /dev/null
+++ b/libgo/go/math/pow10.go
@@ -0,0 +1,30 @@
+// 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 math
+
+// This table might overflow 127-bit exponent representations.
+// In that case, truncate it after 1.0e38.
+var pow10tab [70]float64
+
+// Pow10 returns 10**e, the base-10 exponential of e.
+func Pow10(e int) float64 {
+ if e < 0 {
+ return 1 / Pow10(-e)
+ }
+ if e < len(pow10tab) {
+ return pow10tab[e]
+ }
+ m := e / 2
+ return Pow10(m) * Pow10(e-m)
+}
+
+func init() {
+ pow10tab[0] = 1.0e0
+ pow10tab[1] = 1.0e1
+ for i := 2; i < len(pow10tab); i++ {
+ m := i / 2
+ pow10tab[i] = pow10tab[m] * pow10tab[i-m]
+ }
+}
diff --git a/libgo/go/math/remainder.go b/libgo/go/math/remainder.go
new file mode 100644
index 000000000..be8724c7f
--- /dev/null
+++ b/libgo/go/math/remainder.go
@@ -0,0 +1,85 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// The original C code and the the comment below are from
+// FreeBSD's /usr/src/lib/msun/src/e_remainder.c and came
+// with this notice. The go code is a simplified version of
+// the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_remainder(x,y)
+// Return :
+// returns x REM y = x - [x/y]*y as if in infinite
+// precision arithmetic, where [x/y] is the (infinite bit)
+// integer nearest x/y (in half way cases, choose the even one).
+// Method :
+// Based on fmod() returning x - [x/y]chopped * y exactly.
+
+// Remainder returns the IEEE 754 floating-point remainder of x/y.
+//
+// Special cases are:
+// Remainder(x, NaN) = NaN
+// Remainder(NaN, y) = NaN
+// Remainder(Inf, y) = NaN
+// Remainder(x, 0) = NaN
+// Remainder(x, Inf) = x
+func Remainder(x, y float64) float64 {
+ const (
+ Tiny = 4.45014771701440276618e-308 // 0x0020000000000000
+ HalfMax = MaxFloat64 / 2
+ )
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x || y != y || x < -MaxFloat64 || x > MaxFloat64 || y == 0: // IsNaN(x) || IsNaN(y) || IsInf(x, 0) || y == 0:
+ return NaN()
+ case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y):
+ return x
+ }
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ if y < 0 {
+ y = -y
+ }
+ if x == y {
+ return 0
+ }
+ if y <= HalfMax {
+ x = Fmod(x, y+y) // now x < 2y
+ }
+ if y < Tiny {
+ if x+x > y {
+ x -= y
+ if x+x >= y {
+ x -= y
+ }
+ }
+ } else {
+ yHalf := 0.5 * y
+ if x > yHalf {
+ x -= y
+ if x >= yHalf {
+ x -= y
+ }
+ }
+ }
+ if sign {
+ x = -x
+ }
+ return x
+}
diff --git a/libgo/go/math/signbit.go b/libgo/go/math/signbit.go
new file mode 100644
index 000000000..670cc1a66
--- /dev/null
+++ b/libgo/go/math/signbit.go
@@ -0,0 +1,10 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Signbit returns true if x is negative or negative zero.
+func Signbit(x float64) bool {
+ return Float64bits(x)&(1<<63) != 0
+}
diff --git a/libgo/go/math/sin.go b/libgo/go/math/sin.go
new file mode 100644
index 000000000..35220cb3e
--- /dev/null
+++ b/libgo/go/math/sin.go
@@ -0,0 +1,66 @@
+// 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 math
+
+
+/*
+ Floating-point sine and cosine.
+
+ Coefficients are #5077 from Hart & Cheney. (18.80D)
+*/
+
+func sinus(x float64, quad int) float64 {
+ const (
+ P0 = .1357884097877375669092680e8
+ P1 = -.4942908100902844161158627e7
+ P2 = .4401030535375266501944918e6
+ P3 = -.1384727249982452873054457e5
+ P4 = .1459688406665768722226959e3
+ Q0 = .8644558652922534429915149e7
+ Q1 = .4081792252343299749395779e6
+ Q2 = .9463096101538208180571257e4
+ Q3 = .1326534908786136358911494e3
+ )
+ if x < 0 {
+ x = -x
+ quad = quad + 2
+ }
+ x = x * (2 / Pi) /* underflow? */
+ var y float64
+ if x > 32764 {
+ var e float64
+ e, y = Modf(x)
+ e = e + float64(quad)
+ f, _ := Modf(0.25 * e)
+ quad = int(e - 4*f)
+ } else {
+ k := int32(x)
+ y = x - float64(k)
+ quad = (quad + int(k)) & 3
+ }
+
+ if quad&1 != 0 {
+ y = 1 - y
+ }
+ if quad > 1 {
+ y = -y
+ }
+
+ yy := y * y
+ temp1 := ((((P4*yy+P3)*yy+P2)*yy+P1)*yy + P0) * y
+ temp2 := ((((yy+Q3)*yy+Q2)*yy+Q1)*yy + Q0)
+ return temp1 / temp2
+}
+
+// Cos returns the cosine of x.
+func Cos(x float64) float64 {
+ if x < 0 {
+ x = -x
+ }
+ return sinus(x, 1)
+}
+
+// Sin returns the sine of x.
+func Sin(x float64) float64 { return sinus(x, 0) }
diff --git a/libgo/go/math/sincos.go b/libgo/go/math/sincos.go
new file mode 100644
index 000000000..4c1576bea
--- /dev/null
+++ b/libgo/go/math/sincos.go
@@ -0,0 +1,13 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Sincos(x) returns Sin(x), Cos(x).
+//
+// Special conditions are:
+// Sincos(+Inf) = NaN, NaN
+// Sincos(-Inf) = NaN, NaN
+// Sincos(NaN) = NaN, NaN
+func Sincos(x float64) (sin, cos float64) { return Sin(x), Cos(x) }
diff --git a/libgo/go/math/sinh.go b/libgo/go/math/sinh.go
new file mode 100644
index 000000000..23a8719f2
--- /dev/null
+++ b/libgo/go/math/sinh.go
@@ -0,0 +1,68 @@
+// 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 math
+
+
+/*
+ Floating-point hyperbolic sine and cosine.
+
+ The exponential func is called for arguments
+ greater in magnitude than 0.5.
+
+ A series is used for arguments smaller in magnitude than 0.5.
+
+ Cosh(x) is computed from the exponential func for
+ all arguments.
+*/
+
+// Sinh returns the hyperbolic sine of x.
+func Sinh(x float64) float64 {
+ // The coefficients are #2029 from Hart & Cheney. (20.36D)
+ const (
+ P0 = -0.6307673640497716991184787251e+6
+ P1 = -0.8991272022039509355398013511e+5
+ P2 = -0.2894211355989563807284660366e+4
+ P3 = -0.2630563213397497062819489e+2
+ Q0 = -0.6307673640497716991212077277e+6
+ Q1 = 0.1521517378790019070696485176e+5
+ Q2 = -0.173678953558233699533450911e+3
+ )
+
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+
+ var temp float64
+ switch true {
+ case x > 21:
+ temp = Exp(x) / 2
+
+ case x > 0.5:
+ temp = (Exp(x) - Exp(-x)) / 2
+
+ default:
+ sq := x * x
+ temp = (((P3*sq+P2)*sq+P1)*sq + P0) * x
+ temp = temp / (((sq+Q2)*sq+Q1)*sq + Q0)
+ }
+
+ if sign {
+ temp = -temp
+ }
+ return temp
+}
+
+// Cosh returns the hyperbolic cosine of x.
+func Cosh(x float64) float64 {
+ if x < 0 {
+ x = -x
+ }
+ if x > 21 {
+ return Exp(x) / 2
+ }
+ return (Exp(x) + Exp(-x)) / 2
+}
diff --git a/libgo/go/math/sqrt.go b/libgo/go/math/sqrt.go
new file mode 100644
index 000000000..bf6ef64a0
--- /dev/null
+++ b/libgo/go/math/sqrt.go
@@ -0,0 +1,28 @@
+// 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 math
+
+func libc_sqrt(float64) float64 __asm__("sqrt")
+
+// Sqrt returns the square root of x.
+//
+// Special cases are:
+// Sqrt(+Inf) = +Inf
+// Sqrt(±0) = ±0
+// Sqrt(x < 0) = NaN
+// Sqrt(NaN) = NaN
+func Sqrt(x float64) float64 {
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x == 0 || x != x || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 1):
+ return x
+ case x < 0:
+ return NaN()
+ }
+
+ return libc_sqrt(x)
+}
diff --git a/libgo/go/math/sqrt_decl.go b/libgo/go/math/sqrt_decl.go
new file mode 100644
index 000000000..e50774645
--- /dev/null
+++ b/libgo/go/math/sqrt_decl.go
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Sqrt(x float64) float64
diff --git a/libgo/go/math/sqrt_port.go b/libgo/go/math/sqrt_port.go
new file mode 100644
index 000000000..6f35a383d
--- /dev/null
+++ b/libgo/go/math/sqrt_port.go
@@ -0,0 +1,143 @@
+// 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 math
+
+/*
+ Floating-point square root.
+*/
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_sqrt(x)
+// Return correctly rounded sqrt.
+// -----------------------------------------
+// | Use the hardware sqrt if you have one |
+// -----------------------------------------
+// Method:
+// Bit by bit method using integer arithmetic. (Slow, but portable)
+// 1. Normalization
+// Scale x to y in [1,4) with even powers of 2:
+// find an integer k such that 1 <= (y=x*2**(2k)) < 4, then
+// sqrt(x) = 2**k * sqrt(y)
+// 2. Bit by bit computation
+// Let q = sqrt(y) truncated to i bit after binary point (q = 1),
+// i 0
+// i+1 2
+// s = 2*q , and y = 2 * ( y - q ). (1)
+// i i i i
+//
+// To compute q from q , one checks whether
+// i+1 i
+//
+// -(i+1) 2
+// (q + 2 ) <= y. (2)
+// i
+// -(i+1)
+// If (2) is false, then q = q ; otherwise q = q + 2 .
+// i+1 i i+1 i
+//
+// With some algebric manipulation, it is not difficult to see
+// that (2) is equivalent to
+// -(i+1)
+// s + 2 <= y (3)
+// i i
+//
+// The advantage of (3) is that s and y can be computed by
+// i i
+// the following recurrence formula:
+// if (3) is false
+//
+// s = s , y = y ; (4)
+// i+1 i i+1 i
+//
+// otherwise,
+// -i -(i+1)
+// s = s + 2 , y = y - s - 2 (5)
+// i+1 i i+1 i i
+//
+// One may easily use induction to prove (4) and (5).
+// Note. Since the left hand side of (3) contain only i+2 bits,
+// it does not necessary to do a full (53-bit) comparison
+// in (3).
+// 3. Final rounding
+// After generating the 53 bits result, we compute one more bit.
+// Together with the remainder, we can decide whether the
+// result is exact, bigger than 1/2ulp, or less than 1/2ulp
+// (it will never equal to 1/2ulp).
+// The rounding mode can be detected by checking whether
+// huge + tiny is equal to huge, and whether huge - tiny is
+// equal to huge for some floating point number "huge" and "tiny".
+//
+//
+// Notes: Rounding mode detection omitted. The constants "mask", "shift",
+// and "bias" are found in src/pkg/math/bits.go
+
+// Sqrt returns the square root of x.
+//
+// Special cases are:
+// Sqrt(+Inf) = +Inf
+// Sqrt(±0) = ±0
+// Sqrt(x < 0) = NaN
+// Sqrt(NaN) = NaN
+func sqrtGo(x float64) float64 {
+ // special cases
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ switch {
+ case x == 0 || x != x || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 1):
+ return x
+ case x < 0:
+ return NaN()
+ }
+ ix := Float64bits(x)
+ // normalize x
+ exp := int((ix >> shift) & mask)
+ if exp == 0 { // subnormal x
+ for ix&1<<shift == 0 {
+ ix <<= 1
+ exp--
+ }
+ exp++
+ }
+ exp -= bias // unbias exponent
+ ix &^= mask << shift
+ ix |= 1 << shift
+ if exp&1 == 1 { // odd exp, double x to make it even
+ ix <<= 1
+ }
+ exp >>= 1 // exp = exp/2, exponent of square root
+ // generate sqrt(x) bit by bit
+ ix <<= 1
+ var q, s uint64 // q = sqrt(x)
+ r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
+ for r != 0 {
+ t := s + r
+ if t <= ix {
+ s = t + r
+ ix -= t
+ q += r
+ }
+ ix <<= 1
+ r >>= 1
+ }
+ // final rounding
+ if ix != 0 { // remainder, result not exact
+ q += q & 1 // round according to extra bit
+ }
+ ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
+ return Float64frombits(ix)
+}
diff --git a/libgo/go/math/sqrt_test.go b/libgo/go/math/sqrt_test.go
new file mode 100644
index 000000000..84cbc169e
--- /dev/null
+++ b/libgo/go/math/sqrt_test.go
@@ -0,0 +1,9 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Make sqrtGo available for testing.
+
+func SqrtGo(x float64) float64 { return sqrtGo(x) }
diff --git a/libgo/go/math/tan.go b/libgo/go/math/tan.go
new file mode 100644
index 000000000..a36ebbf44
--- /dev/null
+++ b/libgo/go/math/tan.go
@@ -0,0 +1,65 @@
+// 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 math
+
+
+/*
+ Floating point tangent.
+*/
+
+// Tan returns the tangent of x.
+func Tan(x float64) float64 {
+ // Coefficients are #4285 from Hart & Cheney. (19.74D)
+ const (
+ P0 = -.1306820264754825668269611177e+5
+ P1 = .1055970901714953193602353981e+4
+ P2 = -.1550685653483266376941705728e+2
+ P3 = .3422554387241003435328470489e-1
+ P4 = .3386638642677172096076369e-4
+ Q0 = -.1663895238947119001851464661e+5
+ Q1 = .4765751362916483698926655581e+4
+ Q2 = -.1555033164031709966900124574e+3
+ )
+
+ flag := false
+ sign := false
+ if x < 0 {
+ x = -x
+ sign = true
+ }
+ x = x * (4 / Pi) /* overflow? */
+ var e float64
+ e, x = Modf(x)
+ i := int32(e)
+
+ switch i & 3 {
+ case 1:
+ x = 1 - x
+ flag = true
+
+ case 2:
+ sign = !sign
+ flag = true
+
+ case 3:
+ x = 1 - x
+ sign = !sign
+ }
+
+ xsq := x * x
+ temp := ((((P4*xsq+P3)*xsq+P2)*xsq+P1)*xsq + P0) * x
+ temp = temp / (((xsq+Q2)*xsq+Q1)*xsq + Q0)
+
+ if flag {
+ if temp == 0 {
+ return NaN()
+ }
+ temp = 1 / temp
+ }
+ if sign {
+ temp = -temp
+ }
+ return temp
+}
diff --git a/libgo/go/math/tanh.go b/libgo/go/math/tanh.go
new file mode 100644
index 000000000..8bcf2ddac
--- /dev/null
+++ b/libgo/go/math/tanh.go
@@ -0,0 +1,28 @@
+// 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 math
+
+
+/*
+ Floating-point hyperbolic tangent.
+
+ Sinh and Cosh are called except for large arguments, which
+ would cause overflow improperly.
+*/
+
+// Tanh computes the hyperbolic tangent of x.
+func Tanh(x float64) float64 {
+ if x < 0 {
+ x = -x
+ if x > 21 {
+ return -1
+ }
+ return -Sinh(x) / Cosh(x)
+ }
+ if x > 21 {
+ return 1
+ }
+ return Sinh(x) / Cosh(x)
+}
diff --git a/libgo/go/math/unsafe.go b/libgo/go/math/unsafe.go
new file mode 100644
index 000000000..5ae67420f
--- /dev/null
+++ b/libgo/go/math/unsafe.go
@@ -0,0 +1,21 @@
+// 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 math
+
+import "unsafe"
+
+// Float32bits returns the IEEE 754 binary representation of f.
+func Float32bits(f float32) uint32 { return *(*uint32)(unsafe.Pointer(&f)) }
+
+// Float32frombits returns the floating point number corresponding
+// to the IEEE 754 binary representation b.
+func Float32frombits(b uint32) float32 { return *(*float32)(unsafe.Pointer(&b)) }
+
+// Float64bits returns the IEEE 754 binary representation of f.
+func Float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
+
+// Float64frombits returns the floating point number corresponding
+// the IEEE 754 binary representation b.
+func Float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }
diff --git a/libgo/go/mime/grammar.go b/libgo/go/mime/grammar.go
new file mode 100644
index 000000000..e60cbb8df
--- /dev/null
+++ b/libgo/go/mime/grammar.go
@@ -0,0 +1,36 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mime
+
+import (
+ "strings"
+)
+
+// isTSpecial returns true if rune is in 'tspecials' as defined by RFC
+// 1531 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.
+func IsTokenChar(rune int) bool {
+ // token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
+ // or tspecials>
+ return rune > 0x20 && rune < 0x7f && !isTSpecial(rune)
+}
+
+// IsQText returns true if rune is in 'qtext' as defined by RFC 822.
+func IsQText(rune int) bool {
+ // CHAR = <any ASCII character> ; ( 0-177, 0.-127.)
+ // qtext = <any CHAR excepting <">, ; => may be folded
+ // "\" & CR, and including
+ // linear-white-space>
+ switch rune {
+ case '"', '\\', '\r':
+ return false
+ }
+ return rune < 0x80
+}
diff --git a/libgo/go/mime/mediatype.go b/libgo/go/mime/mediatype.go
new file mode 100644
index 000000000..eb629aa6f
--- /dev/null
+++ b/libgo/go/mime/mediatype.go
@@ -0,0 +1,120 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mime
+
+import (
+ "bytes"
+ "strings"
+ "unicode"
+)
+
+// ParseMediaType parses a media type value and any optional
+// parameters, per RFC 1531. 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
+// error, it returns an empty string and a nil params.
+func ParseMediaType(v string) (mediatype string, params map[string]string) {
+ i := strings.Index(v, ";")
+ if i == -1 {
+ i = len(v)
+ }
+ mediatype = strings.TrimSpace(strings.ToLower(v[0:i]))
+ params = make(map[string]string)
+
+ v = v[i:]
+ for len(v) > 0 {
+ v = strings.TrimLeftFunc(v, unicode.IsSpace)
+ if len(v) == 0 {
+ return
+ }
+ key, value, rest := consumeMediaParam(v)
+ if key == "" {
+ // Parse error.
+ return "", nil
+ }
+ params[key] = value
+ v = rest
+ }
+ return
+}
+
+func isNotTokenChar(rune int) bool {
+ return !IsTokenChar(rune)
+}
+
+// consumeToken consumes a token from the beginning of provided
+// string, per RFC 2045 section 5.1 (referenced from 2183), and return
+// the token consumed and the rest of the string. Returns ("", v) on
+// failure to consume at least one character.
+func consumeToken(v string) (token, rest string) {
+ notPos := strings.IndexFunc(v, isNotTokenChar)
+ if notPos == -1 {
+ return v, ""
+ }
+ if notPos == 0 {
+ return "", v
+ }
+ return v[0:notPos], v[notPos:]
+}
+
+// consumeValue consumes a "value" per RFC 2045, where a value is
+// either a 'token' or a 'quoted-string'. On success, consumeValue
+// returns the value consumed (and de-quoted/escaped, if a
+// quoted-string) and the rest of the string. On failure, returns
+// ("", v).
+func consumeValue(v string) (value, rest string) {
+ if !strings.HasPrefix(v, `"`) {
+ return consumeToken(v)
+ }
+
+ // parse a quoted-string
+ rest = v[1:] // consume the leading quote
+ buffer := new(bytes.Buffer)
+ var idx, rune int
+ var nextIsLiteral bool
+ for idx, rune = range rest {
+ switch {
+ case nextIsLiteral:
+ if rune >= 0x80 {
+ return "", v
+ }
+ buffer.WriteRune(rune)
+ nextIsLiteral = false
+ case rune == '"':
+ return buffer.String(), rest[idx+1:]
+ case IsQText(rune):
+ buffer.WriteRune(rune)
+ case rune == '\\':
+ nextIsLiteral = true
+ default:
+ return "", v
+ }
+ }
+ return "", v
+}
+
+func consumeMediaParam(v string) (param, value, rest string) {
+ rest = strings.TrimLeftFunc(v, unicode.IsSpace)
+ if !strings.HasPrefix(rest, ";") {
+ return "", "", v
+ }
+
+ rest = rest[1:] // consume semicolon
+ rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
+ param, rest = consumeToken(rest)
+ if param == "" {
+ return "", "", v
+ }
+ if !strings.HasPrefix(rest, "=") {
+ return "", "", v
+ }
+ rest = rest[1:] // consume equals sign
+ value, rest = consumeValue(rest)
+ if value == "" {
+ return "", "", v
+ }
+ return param, value, rest
+}
diff --git a/libgo/go/mime/mediatype_test.go b/libgo/go/mime/mediatype_test.go
new file mode 100644
index 000000000..4891e899d
--- /dev/null
+++ b/libgo/go/mime/mediatype_test.go
@@ -0,0 +1,117 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mime
+
+import (
+ "testing"
+)
+
+func TestConsumeToken(t *testing.T) {
+ tests := [...][3]string{
+ {"foo bar", "foo", " bar"},
+ {"bar", "bar", ""},
+ {"", "", ""},
+ {" foo", "", " foo"},
+ }
+ for _, test := range tests {
+ token, rest := consumeToken(test[0])
+ expectedToken := test[1]
+ expectedRest := test[2]
+ if token != expectedToken {
+ t.Errorf("expected to consume token '%s', not '%s' from '%s'",
+ expectedToken, token, test[0])
+ } else if rest != expectedRest {
+ t.Errorf("expected to have left '%s', not '%s' after reading token '%s' from '%s'",
+ expectedRest, rest, token, test[0])
+ }
+ }
+}
+
+func TestConsumeValue(t *testing.T) {
+ tests := [...][3]string{
+ {"foo bar", "foo", " bar"},
+ {"bar", "bar", ""},
+ {" bar ", "", " bar "},
+ {`"My value"end`, "My value", "end"},
+ {`"My value" end`, "My value", " end"},
+ {`"\\" rest`, "\\", " rest"},
+ {`"My \" value"end`, "My \" value", "end"},
+ {`"\" rest`, "", `"\" rest`},
+ }
+ for _, test := range tests {
+ value, rest := consumeValue(test[0])
+ expectedValue := test[1]
+ expectedRest := test[2]
+ if value != expectedValue {
+ t.Errorf("expected to consume value [%s], not [%s] from [%s]",
+ expectedValue, value, test[0])
+ } else if rest != expectedRest {
+ t.Errorf("expected to have left [%s], not [%s] after reading value [%s] from [%s]",
+ expectedRest, rest, value, test[0])
+ }
+ }
+}
+
+func TestConsumeMediaParam(t *testing.T) {
+ tests := [...][4]string{
+ {" ; foo=bar", "foo", "bar", ""},
+ {"; foo=bar", "foo", "bar", ""},
+ {";foo=bar", "foo", "bar", ""},
+ {`;foo="bar"`, "foo", "bar", ""},
+ {`;foo="bar"; `, "foo", "bar", "; "},
+ {`;foo="bar"; foo=baz`, "foo", "bar", "; foo=baz"},
+ {` ; boundary=----CUT;`, "boundary", "----CUT", ";"},
+ {` ; key=value; blah="value";name="foo" `, "key", "value", `; blah="value";name="foo" `},
+ {`; blah="value";name="foo" `, "blah", "value", `;name="foo" `},
+ {`;name="foo" `, "name", "foo", ` `},
+ }
+ for _, test := range tests {
+ param, value, rest := consumeMediaParam(test[0])
+ expectedParam := test[1]
+ expectedValue := test[2]
+ expectedRest := test[3]
+ if param != expectedParam {
+ t.Errorf("expected to consume param [%s], not [%s] from [%s]",
+ expectedParam, param, test[0])
+ } else if value != expectedValue {
+ t.Errorf("expected to consume value [%s], not [%s] from [%s]",
+ expectedValue, value, test[0])
+ } else if rest != expectedRest {
+ t.Errorf("expected to have left [%s], not [%s] after reading [%s/%s] from [%s]",
+ expectedRest, rest, param, value, test[0])
+ }
+ }
+}
+
+func TestParseMediaType(t *testing.T) {
+ tests := [...]string{
+ `form-data; name="foo"`,
+ ` form-data ; name=foo`,
+ `FORM-DATA;name="foo"`,
+ ` FORM-DATA ; name="foo"`,
+ ` FORM-DATA ; name="foo"`,
+ `form-data; key=value; blah="value";name="foo" `,
+ }
+ for _, test := range tests {
+ mt, params := ParseMediaType(test)
+ if mt != "form-data" {
+ t.Errorf("expected type form-data for %s, got [%s]", test, mt)
+ continue
+ }
+ if params["name"] != "foo" {
+ t.Errorf("expected name=foo for %s", test)
+ }
+ }
+}
+
+func TestParseMediaTypeBogus(t *testing.T) {
+ mt, params := ParseMediaType("bogus ;=========")
+ if mt != "" {
+ t.Error("expected empty type")
+ }
+ if params != nil {
+ t.Error("expected nil params")
+ }
+}
diff --git a/libgo/go/mime/mime_test.go b/libgo/go/mime/mime_test.go
new file mode 100644
index 000000000..17e610443
--- /dev/null
+++ b/libgo/go/mime/mime_test.go
@@ -0,0 +1,27 @@
+// 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.
+
+// Tests for type.go
+
+package mime
+
+import "testing"
+
+var typeTests = map[string]string{
+ ".t1": "application/test",
+ ".t2": "text/test; charset=utf-8",
+ ".png": "image/png",
+}
+
+func TestType(t *testing.T) {
+ typeFiles = []string{"test.types"}
+
+ for ext, want := range typeTests {
+ val := TypeByExtension(ext)
+ if val != want {
+ t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want)
+ }
+
+ }
+}
diff --git a/libgo/go/mime/multipart/multipart.go b/libgo/go/mime/multipart/multipart.go
new file mode 100644
index 000000000..1d855c74c
--- /dev/null
+++ b/libgo/go/mime/multipart/multipart.go
@@ -0,0 +1,280 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+
+/*
+Package multipart implements MIME multipart parsing, as defined in RFC
+2046.
+
+The implementation is sufficient for HTTP (RFC 2388) and the multipart
+bodies generated by popular browsers.
+*/
+package multipart
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "mime"
+ "os"
+ "regexp"
+ "strings"
+)
+
+var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r\n]+)")
+
+// 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 (nil,
+ // nil) on EOF. An error is returned if the underlying reader
+ // reports errors, or on truncated or otherwise malformed
+ // input.
+ NextPart() (*Part, 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
+ // in the same fashion that the Go http.Request headers are.
+ // i.e. "foo-bar" changes case to "Foo-Bar"
+ Header map[string]string
+
+ buffer *bytes.Buffer
+ mr *multiReader
+}
+
+// FormName returns the name parameter if p has a Content-Disposition
+// of type "form-data". Otherwise it returns the empty string.
+func (p *Part) FormName() string {
+ // See http://tools.ietf.org/html/rfc2183 section 2 for EBNF
+ // of Content-Disposition value format.
+ v, ok := p.Header["Content-Disposition"]
+ if !ok {
+ return ""
+ }
+ d, params := mime.ParseMediaType(v)
+ if d != "form-data" {
+ return ""
+ }
+ return params["name"]
+}
+
+// NewReader creates a new multipart Reader reading from r using the
+// given MIME boundary.
+func NewReader(reader io.Reader, boundary string) Reader {
+ return &multiReader{
+ boundary: boundary,
+ dashBoundary: "--" + boundary,
+ endLine: "--" + boundary + "--",
+ bufReader: bufio.NewReader(reader),
+ }
+}
+
+// Implementation ....
+
+type devNullWriter bool
+
+func (*devNullWriter) Write(p []byte) (n int, err os.Error) {
+ return len(p), nil
+}
+
+var devNull = devNullWriter(false)
+
+func newPart(mr *multiReader) (bp *Part, err os.Error) {
+ bp = new(Part)
+ bp.Header = make(map[string]string)
+ bp.mr = mr
+ bp.buffer = new(bytes.Buffer)
+ if err = bp.populateHeaders(); err != nil {
+ bp = nil
+ }
+ return
+}
+
+func (bp *Part) populateHeaders() os.Error {
+ for {
+ line, err := bp.mr.bufReader.ReadString('\n')
+ if err != nil {
+ return err
+ }
+ if line == "\n" || line == "\r\n" {
+ return nil
+ }
+ if matches := headerRegexp.FindStringSubmatch(line); len(matches) == 3 {
+ key := matches[1]
+ value := matches[2]
+ // TODO: canonicalize headers ala http.Request.Header?
+ bp.Header[key] = value
+ continue
+ }
+ return os.NewError("Unexpected header line found parsing multipart body")
+ }
+ panic("unreachable")
+}
+
+// Read reads the body of a part, after its headers and before the
+// next part (if any) begins.
+func (bp *Part) Read(p []byte) (n int, err os.Error) {
+ for {
+ if bp.buffer.Len() >= len(p) {
+ // Internal buffer of unconsumed data is large enough for
+ // the read request. No need to parse more at the moment.
+ break
+ }
+ if !bp.mr.ensureBufferedLine() {
+ return 0, io.ErrUnexpectedEOF
+ }
+ if bp.mr.bufferedLineIsBoundary() {
+ // Don't consume this line
+ break
+ }
+
+ // Write all of this line, except the final CRLF
+ s := *bp.mr.bufferedLine
+ if strings.HasSuffix(s, "\r\n") {
+ bp.mr.consumeLine()
+ if !bp.mr.ensureBufferedLine() {
+ return 0, io.ErrUnexpectedEOF
+ }
+ if bp.mr.bufferedLineIsBoundary() {
+ // The final \r\n isn't ours. It logically belongs
+ // to the boundary line which follows.
+ bp.buffer.WriteString(s[0 : len(s)-2])
+ } else {
+ bp.buffer.WriteString(s)
+ }
+ break
+ }
+ if strings.HasSuffix(s, "\n") {
+ bp.buffer.WriteString(s)
+ bp.mr.consumeLine()
+ continue
+ }
+ return 0, os.NewError("multipart parse error during Read; unexpected line: " + s)
+ }
+ return bp.buffer.Read(p)
+}
+
+func (bp *Part) Close() os.Error {
+ io.Copy(&devNull, bp)
+ return nil
+}
+
+type multiReader struct {
+ boundary string
+ dashBoundary string // --boundary
+ endLine string // --boundary--
+
+ bufferedLine *string
+
+ bufReader *bufio.Reader
+ currentPart *Part
+ partsRead int
+}
+
+func (mr *multiReader) eof() bool {
+ return mr.bufferedLine == nil &&
+ !mr.readLine()
+}
+
+func (mr *multiReader) readLine() bool {
+ line, err := mr.bufReader.ReadString('\n')
+ if err != nil {
+ // TODO: care about err being EOF or not?
+ return false
+ }
+ mr.bufferedLine = &line
+ return true
+}
+
+func (mr *multiReader) bufferedLineIsBoundary() bool {
+ return strings.HasPrefix(*mr.bufferedLine, mr.dashBoundary)
+}
+
+func (mr *multiReader) ensureBufferedLine() bool {
+ if mr.bufferedLine == nil {
+ return mr.readLine()
+ }
+ return true
+}
+
+func (mr *multiReader) consumeLine() {
+ mr.bufferedLine = nil
+}
+
+func (mr *multiReader) NextPart() (*Part, os.Error) {
+ if mr.currentPart != nil {
+ mr.currentPart.Close()
+ }
+
+ for {
+ if mr.eof() {
+ return nil, io.ErrUnexpectedEOF
+ }
+
+ if isBoundaryDelimiterLine(*mr.bufferedLine, mr.dashBoundary) {
+ mr.consumeLine()
+ mr.partsRead++
+ bp, err := newPart(mr)
+ if err != nil {
+ return nil, err
+ }
+ mr.currentPart = bp
+ return bp, nil
+ }
+
+ if hasPrefixThenNewline(*mr.bufferedLine, mr.endLine) {
+ mr.consumeLine()
+ // Expected EOF (no error)
+ return nil, nil
+ }
+
+ if mr.partsRead == 0 {
+ // skip line
+ mr.consumeLine()
+ continue
+ }
+
+ return nil, os.NewError("Unexpected line in Next().")
+ }
+ panic("unreachable")
+}
+
+func isBoundaryDelimiterLine(line, dashPrefix string) 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 ("-",
+ // decimal value 45) followed by the boundary parameter
+ // value from the Content-Type header field, optional linear
+ // whitespace, and a terminating CRLF.
+ if !strings.HasPrefix(line, dashPrefix) {
+ return false
+ }
+ if strings.HasSuffix(line, "\r\n") {
+ return onlyHorizontalWhitespace(line[len(dashPrefix) : len(line)-2])
+ }
+ // Violate the spec and also support newlines without the
+ // carriage return...
+ if strings.HasSuffix(line, "\n") {
+ return onlyHorizontalWhitespace(line[len(dashPrefix) : len(line)-1])
+ }
+ return false
+}
+
+func onlyHorizontalWhitespace(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] != ' ' && s[i] != '\t' {
+ return false
+ }
+ }
+ return true
+}
+
+func hasPrefixThenNewline(s, prefix string) bool {
+ return strings.HasPrefix(s, prefix) &&
+ (len(s) == len(prefix)+1 && strings.HasSuffix(s, "\n") ||
+ len(s) == len(prefix)+2 && strings.HasSuffix(s, "\r\n"))
+}
diff --git a/libgo/go/mime/multipart/multipart_test.go b/libgo/go/mime/multipart/multipart_test.go
new file mode 100644
index 000000000..7e1ed133e
--- /dev/null
+++ b/libgo/go/mime/multipart/multipart_test.go
@@ -0,0 +1,204 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package multipart
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "json"
+ "regexp"
+ "strings"
+ "testing"
+)
+
+func TestHorizontalWhitespace(t *testing.T) {
+ if !onlyHorizontalWhitespace(" \t") {
+ t.Error("expected pass")
+ }
+ if onlyHorizontalWhitespace("foo bar") {
+ t.Error("expected failure")
+ }
+}
+
+func TestBoundaryLine(t *testing.T) {
+ boundary := "myBoundary"
+ prefix := "--" + boundary
+ if !isBoundaryDelimiterLine("--myBoundary\r\n", prefix) {
+ t.Error("expected")
+ }
+ if !isBoundaryDelimiterLine("--myBoundary \r\n", prefix) {
+ t.Error("expected")
+ }
+ if !isBoundaryDelimiterLine("--myBoundary \n", prefix) {
+ t.Error("expected")
+ }
+ if isBoundaryDelimiterLine("--myBoundary bogus \n", prefix) {
+ t.Error("expected fail")
+ }
+ if isBoundaryDelimiterLine("--myBoundary bogus--", prefix) {
+ t.Error("expected fail")
+ }
+}
+
+func escapeString(v string) string {
+ bytes, _ := json.Marshal(v)
+ return string(bytes)
+}
+
+func expectEq(t *testing.T, expected, actual, what string) {
+ if expected == actual {
+ return
+ }
+ t.Errorf("Unexpected value for %s; got %s (len %d) but expected: %s (len %d)",
+ what, escapeString(actual), len(actual), escapeString(expected), len(expected))
+}
+
+func TestFormName(t *testing.T) {
+ p := new(Part)
+ p.Header = make(map[string]string)
+ tests := [...][2]string{
+ {`form-data; name="foo"`, "foo"},
+ {` form-data ; name=foo`, "foo"},
+ {`FORM-DATA;name="foo"`, "foo"},
+ {` FORM-DATA ; name="foo"`, "foo"},
+ {` FORM-DATA ; name="foo"`, "foo"},
+ {` FORM-DATA ; name=foo`, "foo"},
+ {` FORM-DATA ; filename="foo.txt"; name=foo; baz=quux`, "foo"},
+ }
+ for _, test := range tests {
+ p.Header["Content-Disposition"] = test[0]
+ expected := test[1]
+ actual := p.FormName()
+ if actual != expected {
+ t.Errorf("expected \"%s\"; got: \"%s\"", expected, actual)
+ }
+ }
+}
+
+func TestMultipart(t *testing.T) {
+ testBody := `
+This is a multi-part message. This line is ignored.
+--MyBoundary
+Header1: value1
+HEADER2: value2
+foo-bar: baz
+
+My value
+The end.
+--MyBoundary
+Header1: value1b
+HEADER2: value2b
+foo-bar: bazb
+
+Line 1
+Line 2
+Line 3 ends in a newline, but just one.
+
+--MyBoundary
+
+never read data
+--MyBoundary--
+`
+ testBody = regexp.MustCompile("\n").ReplaceAllString(testBody, "\r\n")
+ bodyReader := strings.NewReader(testBody)
+
+ reader := NewReader(bodyReader, "MyBoundary")
+ buf := new(bytes.Buffer)
+
+ // Part1
+ part, err := reader.NextPart()
+ if part == nil || err != nil {
+ t.Error("Expected part1")
+ return
+ }
+ if part.Header["Header1"] != "value1" {
+ t.Error("Expected Header1: value")
+ }
+ if part.Header["foo-bar"] != "baz" {
+ t.Error("Expected foo-bar: baz")
+ }
+ buf.Reset()
+ io.Copy(buf, part)
+ expectEq(t, "My value\r\nThe end.",
+ buf.String(), "Value of first part")
+
+ // Part2
+ part, err = reader.NextPart()
+ if part == nil || err != nil {
+ t.Error("Expected part2")
+ return
+ }
+ if part.Header["foo-bar"] != "bazb" {
+ t.Error("Expected foo-bar: bazb")
+ }
+ buf.Reset()
+ io.Copy(buf, part)
+ expectEq(t, "Line 1\r\nLine 2\r\nLine 3 ends in a newline, but just one.\r\n",
+ buf.String(), "Value of second part")
+
+ // Part3
+ part, err = reader.NextPart()
+ if part == nil || err != nil {
+ t.Error("Expected part3 without errors")
+ return
+ }
+
+ // Non-existent part4
+ part, err = reader.NextPart()
+ if part != nil {
+ t.Error("Didn't expect a third part.")
+ }
+ if err != nil {
+ t.Errorf("Unexpected error getting third part: %v", err)
+ }
+}
+
+func TestVariousTextLineEndings(t *testing.T) {
+ tests := [...]string{
+ "Foo\nBar",
+ "Foo\nBar\n",
+ "Foo\r\nBar",
+ "Foo\r\nBar\r\n",
+ "Foo\rBar",
+ "Foo\rBar\r",
+ "\x00\x01\x02\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10",
+ }
+
+ for testNum, expectedBody := range tests {
+ body := "--BOUNDARY\r\n" +
+ "Content-Disposition: form-data; name=\"value\"\r\n" +
+ "\r\n" +
+ expectedBody +
+ "\r\n--BOUNDARY--\r\n"
+ bodyReader := strings.NewReader(body)
+
+ reader := NewReader(bodyReader, "BOUNDARY")
+ buf := new(bytes.Buffer)
+ part, err := reader.NextPart()
+ if part == nil {
+ t.Errorf("Expected a body part on text %d", testNum)
+ continue
+ }
+ if err != nil {
+ t.Errorf("Unexpected error on text %d: %v", testNum, err)
+ continue
+ }
+ written, err := io.Copy(buf, part)
+ expectEq(t, expectedBody, buf.String(), fmt.Sprintf("test %d", testNum))
+ if err != nil {
+ t.Errorf("Error copying multipart; bytes=%v, error=%v", written, err)
+ }
+
+ part, err = reader.NextPart()
+ if part != nil {
+ t.Errorf("Unexpected part in test %d", testNum)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error in test %d: %v", testNum, err)
+ }
+
+ }
+}
diff --git a/libgo/go/mime/test.types b/libgo/go/mime/test.types
new file mode 100644
index 000000000..9b040edd7
--- /dev/null
+++ b/libgo/go/mime/test.types
@@ -0,0 +1,8 @@
+# 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.
+
+
+ # mime package test
+application/test t1 # Simple test
+text/test t2 # Text test
diff --git a/libgo/go/mime/type.go b/libgo/go/mime/type.go
new file mode 100644
index 000000000..a10b780ae
--- /dev/null
+++ b/libgo/go/mime/type.go
@@ -0,0 +1,104 @@
+// 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.
+
+// The mime package implements parts of the MIME spec.
+package mime
+
+import (
+ "bufio"
+ "os"
+ "strings"
+ "sync"
+)
+
+var typeFiles = []string{
+ "/etc/mime.types",
+ "/etc/apache2/mime.types",
+ "/etc/apache/mime.types",
+}
+
+var mimeTypes = map[string]string{
+ ".css": "text/css",
+ ".gif": "image/gif",
+ ".htm": "text/html; charset=utf-8",
+ ".html": "text/html; charset=utf-8",
+ ".jpg": "image/jpeg",
+ ".js": "application/x-javascript",
+ ".pdf": "application/pdf",
+ ".png": "image/png",
+ ".xml": "text/xml; charset=utf-8",
+}
+
+var mimeLock sync.RWMutex
+
+func loadMimeFile(filename string) {
+ f, err := os.Open(filename, os.O_RDONLY, 0666)
+ if err != nil {
+ return
+ }
+
+ reader := bufio.NewReader(f)
+ for {
+ line, err := reader.ReadString('\n')
+ if err != nil {
+ f.Close()
+ return
+ }
+ fields := strings.Fields(line)
+ if len(fields) <= 1 || fields[0][0] == '#' {
+ continue
+ }
+ typename := fields[0]
+ if strings.HasPrefix(typename, "text/") {
+ typename += "; charset=utf-8"
+ }
+ for _, ext := range fields[1:] {
+ if ext[0] == '#' {
+ break
+ }
+ mimeTypes["."+ext] = typename
+ }
+ }
+}
+
+func initMime() {
+ for _, filename := range typeFiles {
+ loadMimeFile(filename)
+ }
+}
+
+var once sync.Once
+
+// TypeByExtension returns the MIME type associated with the file extension ext.
+// The extension ext should begin with a leading dot, as in ".html".
+// When ext has no associated type, TypeByExtension returns "".
+//
+// The built-in table is small but is is augmented by the local
+// system's mime.types file(s) if available under one or more of these
+// names:
+//
+// /etc/mime.types
+// /etc/apache2/mime.types
+// /etc/apache/mime.types
+func TypeByExtension(ext string) string {
+ once.Do(initMime)
+ mimeLock.RLock()
+ typename := mimeTypes[ext]
+ mimeLock.RUnlock()
+ return typename
+}
+
+// AddExtensionType sets the MIME type associated with
+// the extension ext to typ. The extension should begin with
+// a leading dot, as in ".html".
+func AddExtensionType(ext, typ string) os.Error {
+ once.Do(initMime)
+ if len(ext) < 1 || ext[0] != '.' {
+ return os.EINVAL
+ }
+ mimeLock.Lock()
+ mimeTypes[ext] = typ
+ mimeLock.Unlock()
+ return nil
+}
diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go
new file mode 100644
index 000000000..03b9d87be
--- /dev/null
+++ b/libgo/go/net/dial.go
@@ -0,0 +1,179 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import "os"
+
+// Dial connects to the remote address raddr on the network net.
+// If the string laddr is not empty, it is used as the local address
+// for the connection.
+//
+// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
+// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
+// (IPv4-only), "ip6" (IPv6-only), "unix" and "unixgram".
+//
+// For IP networks, addresses have the form host:port. If host is
+// a literal IPv6 address, it must be enclosed in square brackets.
+//
+// Examples:
+// Dial("tcp", "", "12.34.56.78:80")
+// Dial("tcp", "", "google.com:80")
+// Dial("tcp", "", "[de:ad:be:ef::ca:fe]:80")
+// Dial("tcp", "127.0.0.1:123", "127.0.0.1:88")
+//
+func Dial(net, laddr, raddr string) (c Conn, err os.Error) {
+ switch prefixBefore(net, ':') {
+ case "tcp", "tcp4", "tcp6":
+ var la, ra *TCPAddr
+ if laddr != "" {
+ if la, err = ResolveTCPAddr(laddr); err != nil {
+ goto Error
+ }
+ }
+ if raddr != "" {
+ if ra, err = ResolveTCPAddr(raddr); err != nil {
+ goto Error
+ }
+ }
+ c, err := DialTCP(net, la, ra)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+ case "udp", "udp4", "udp6":
+ var la, ra *UDPAddr
+ if laddr != "" {
+ if la, err = ResolveUDPAddr(laddr); err != nil {
+ goto Error
+ }
+ }
+ if raddr != "" {
+ if ra, err = ResolveUDPAddr(raddr); err != nil {
+ goto Error
+ }
+ }
+ c, err := DialUDP(net, la, ra)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+ case "unix", "unixgram", "unixpacket":
+ var la, ra *UnixAddr
+ if raddr != "" {
+ if ra, err = ResolveUnixAddr(net, raddr); err != nil {
+ goto Error
+ }
+ }
+ if laddr != "" {
+ if la, err = ResolveUnixAddr(net, laddr); err != nil {
+ goto Error
+ }
+ }
+ c, err = DialUnix(net, la, ra)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+ case "ip", "ip4", "ip6":
+ var la, ra *IPAddr
+ if laddr != "" {
+ if la, err = ResolveIPAddr(laddr); err != nil {
+ goto Error
+ }
+ }
+ if raddr != "" {
+ if ra, err = ResolveIPAddr(raddr); err != nil {
+ goto Error
+ }
+ }
+ c, err := DialIP(net, la, ra)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+
+ }
+ err = UnknownNetworkError(net)
+Error:
+ return nil, &OpError{"dial", net + " " + raddr, nil, err}
+}
+
+// Listen announces on the local network address laddr.
+// The network string net must be a stream-oriented
+// network: "tcp", "tcp4", "tcp6", or "unix", or "unixpacket".
+func Listen(net, laddr string) (l Listener, err os.Error) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ var la *TCPAddr
+ if laddr != "" {
+ if la, err = ResolveTCPAddr(laddr); err != nil {
+ return nil, err
+ }
+ }
+ l, err := ListenTCP(net, la)
+ if err != nil {
+ return nil, err
+ }
+ return l, nil
+ case "unix", "unixpacket":
+ var la *UnixAddr
+ if laddr != "" {
+ if la, err = ResolveUnixAddr(net, laddr); err != nil {
+ return nil, err
+ }
+ }
+ l, err := ListenUnix(net, la)
+ if err != nil {
+ return nil, err
+ }
+ return l, nil
+ }
+ return nil, UnknownNetworkError(net)
+}
+
+// ListenPacket announces on the local network address laddr.
+// The network string net must be a packet-oriented network:
+// "udp", "udp4", "udp6", or "unixgram".
+func ListenPacket(net, laddr string) (c PacketConn, err os.Error) {
+ switch prefixBefore(net, ':') {
+ case "udp", "udp4", "udp6":
+ var la *UDPAddr
+ if laddr != "" {
+ if la, err = ResolveUDPAddr(laddr); err != nil {
+ return nil, err
+ }
+ }
+ c, err := ListenUDP(net, la)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+ case "unixgram":
+ var la *UnixAddr
+ if laddr != "" {
+ if la, err = ResolveUnixAddr(net, laddr); err != nil {
+ return nil, err
+ }
+ }
+ c, err := DialUnix(net, la, nil)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+ case "ip", "ip4", "ip6":
+ var la *IPAddr
+ if laddr != "" {
+ if la, err = ResolveIPAddr(laddr); err != nil {
+ return nil, err
+ }
+ }
+ c, err := ListenIP(net, la)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+ }
+ return nil, UnknownNetworkError(net)
+}
diff --git a/libgo/go/net/dialgoogle_test.go b/libgo/go/net/dialgoogle_test.go
new file mode 100644
index 000000000..a432800cf
--- /dev/null
+++ b/libgo/go/net/dialgoogle_test.go
@@ -0,0 +1,107 @@
+// 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 net
+
+import (
+ "flag"
+ "fmt"
+ "io"
+ "strings"
+ "syscall"
+ "testing"
+)
+
+// If an IPv6 tunnel is running, we can try dialing a real IPv6 address.
+var ipv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
+
+// fd is already connected to the destination, port 80.
+// Run an HTTP request to fetch the appropriate page.
+func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
+ req := []byte("GET /intl/en/privacy/ HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
+ n, err := fd.Write(req)
+
+ buf := make([]byte, 1000)
+ n, err = io.ReadFull(fd, buf)
+
+ if n < 1000 {
+ t.Errorf("fetchGoogle: short HTTP read from %s %s - %v", network, addr, err)
+ return
+ }
+}
+
+func doDial(t *testing.T, network, addr string) {
+ fd, err := Dial(network, "", addr)
+ if err != nil {
+ t.Errorf("Dial(%q, %q, %q) = _, %v", network, "", addr, err)
+ return
+ }
+ fetchGoogle(t, fd, network, addr)
+ fd.Close()
+}
+
+var googleaddrs = []string{
+ "%d.%d.%d.%d:80",
+ "www.google.com:80",
+ "%d.%d.%d.%d:http",
+ "www.google.com:http",
+ "%03d.%03d.%03d.%03d:0080",
+ "[::ffff:%d.%d.%d.%d]:80",
+ "[::ffff:%02x%02x:%02x%02x]:80",
+ "[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80",
+ "[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80",
+ "[0:0:0:0:0:ffff::%d.%d.%d.%d]:80",
+ "[2001:4860:0:2001::68]:80", // ipv6.google.com; removed if ipv6 flag not set
+}
+
+func TestDialGoogle(t *testing.T) {
+ // If no ipv6 tunnel, don't try the last address.
+ if !*ipv6 {
+ googleaddrs[len(googleaddrs)-1] = ""
+ }
+
+ // Insert an actual IP address for google.com
+ // into the table.
+
+ _, addrs, err := LookupHost("www.google.com")
+ if err != nil {
+ t.Fatalf("lookup www.google.com: %v", err)
+ }
+ if len(addrs) == 0 {
+ t.Fatalf("no addresses for www.google.com")
+ }
+ ip := ParseIP(addrs[0]).To4()
+
+ for i, s := range googleaddrs {
+ if strings.Contains(s, "%") {
+ googleaddrs[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3])
+ }
+ }
+
+ for i := 0; i < len(googleaddrs); i++ {
+ addr := googleaddrs[i]
+ if addr == "" {
+ continue
+ }
+ t.Logf("-- %s --", addr)
+ doDial(t, "tcp", addr)
+ if addr[0] != '[' {
+ doDial(t, "tcp4", addr)
+
+ if !preferIPv4 {
+ // make sure preferIPv4 flag works.
+ preferIPv4 = true
+ syscall.SocketDisableIPv6 = true
+ doDial(t, "tcp4", addr)
+ syscall.SocketDisableIPv6 = false
+ preferIPv4 = false
+ }
+ }
+
+ // Only run tcp6 if the kernel will take it.
+ if kernelSupportsIPv6() {
+ doDial(t, "tcp6", addr)
+ }
+ }
+}
diff --git a/libgo/go/net/dict/dict.go b/libgo/go/net/dict/dict.go
new file mode 100644
index 000000000..42f6553ad
--- /dev/null
+++ b/libgo/go/net/dict/dict.go
@@ -0,0 +1,212 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package dict implements the Dictionary Server Protocol
+// as defined in RFC 2229.
+package dict
+
+import (
+ "container/vector"
+ "net/textproto"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// A Client represents a client connection to a dictionary server.
+type Client struct {
+ text *textproto.Conn
+}
+
+// Dial returns a new client connected to a dictionary server at
+// addr on the given network.
+func Dial(network, addr string) (*Client, os.Error) {
+ text, err := textproto.Dial(network, addr)
+ if err != nil {
+ return nil, err
+ }
+ _, _, err = text.ReadCodeLine(220)
+ if err != nil {
+ text.Close()
+ return nil, err
+ }
+ return &Client{text: text}, nil
+}
+
+// Close closes the connection to the dictionary server.
+func (c *Client) Close() os.Error {
+ return c.text.Close()
+}
+
+// A Dict represents a dictionary available on the server.
+type Dict struct {
+ Name string // short name of dictionary
+ Desc string // long description
+}
+
+// Dicts returns a list of the dictionaries available on the server.
+func (c *Client) Dicts() ([]Dict, os.Error) {
+ id, err := c.text.Cmd("SHOW DB")
+ if err != nil {
+ return nil, err
+ }
+
+ c.text.StartResponse(id)
+ defer c.text.EndResponse(id)
+
+ _, _, err = c.text.ReadCodeLine(110)
+ if err != nil {
+ return nil, err
+ }
+ lines, err := c.text.ReadDotLines()
+ if err != nil {
+ return nil, err
+ }
+ _, _, err = c.text.ReadCodeLine(250)
+
+ dicts := make([]Dict, len(lines))
+ for i := range dicts {
+ d := &dicts[i]
+ a, _ := fields(lines[i])
+ if len(a) < 2 {
+ return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
+ }
+ d.Name = a[0]
+ d.Desc = a[1]
+ }
+ return dicts, err
+}
+
+// A Defn represents a definition.
+type Defn struct {
+ Dict Dict // Dict where definition was found
+ Word string // Word being defined
+ Text []byte // Definition text, typically multiple lines
+}
+
+// Define requests the definition of the given word.
+// The argument dict names the dictionary to use,
+// the Name field of a Dict returned by Dicts.
+//
+// The special dictionary name "*" means to look in all the
+// server's dictionaries.
+// The special dictionary name "!" means to look in all the
+// server's dictionaries in turn, stopping after finding the word
+// in one of them.
+func (c *Client) Define(dict, word string) ([]*Defn, os.Error) {
+ id, err := c.text.Cmd("DEFINE %s %q", dict, word)
+ if err != nil {
+ return nil, err
+ }
+
+ c.text.StartResponse(id)
+ defer c.text.EndResponse(id)
+
+ _, line, err := c.text.ReadCodeLine(150)
+ if err != nil {
+ return nil, err
+ }
+ a, _ := fields(line)
+ if len(a) < 1 {
+ return nil, textproto.ProtocolError("malformed response: " + line)
+ }
+ n, err := strconv.Atoi(a[0])
+ if err != nil {
+ return nil, textproto.ProtocolError("invalid definition count: " + a[0])
+ }
+ def := make([]*Defn, n)
+ for i := 0; i < n; i++ {
+ _, line, err = c.text.ReadCodeLine(151)
+ if err != nil {
+ return nil, err
+ }
+ a, _ := fields(line)
+ if len(a) < 3 {
+ // skip it, to keep protocol in sync
+ i--
+ n--
+ def = def[0:n]
+ continue
+ }
+ d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
+ d.Text, err = c.text.ReadDotBytes()
+ if err != nil {
+ return nil, err
+ }
+ def[i] = d
+ }
+ _, _, err = c.text.ReadCodeLine(250)
+ return def, err
+}
+
+// Fields returns the fields in s.
+// Fields are space separated unquoted words
+// or quoted with single or double quote.
+func fields(s string) ([]string, os.Error) {
+ var v vector.StringVector
+ i := 0
+ for {
+ for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
+ i++
+ }
+ if i >= len(s) {
+ break
+ }
+ if s[i] == '"' || s[i] == '\'' {
+ q := s[i]
+ // quoted string
+ var j int
+ for j = i + 1; ; j++ {
+ if j >= len(s) {
+ return nil, textproto.ProtocolError("malformed quoted string")
+ }
+ if s[j] == '\\' {
+ j++
+ continue
+ }
+ if s[j] == q {
+ j++
+ break
+ }
+ }
+ v.Push(unquote(s[i+1 : j-1]))
+ i = j
+ } else {
+ // atom
+ var j int
+ for j = i; j < len(s); j++ {
+ if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
+ break
+ }
+ }
+ v.Push(s[i:j])
+ i = j
+ }
+ if i < len(s) {
+ c := s[i]
+ if c != ' ' && c != '\t' {
+ return nil, textproto.ProtocolError("quotes not on word boundaries")
+ }
+ }
+ }
+ return v, nil
+}
+
+func unquote(s string) string {
+ if strings.Index(s, "\\") < 0 {
+ return s
+ }
+ b := []byte(s)
+ w := 0
+ for r := 0; r < len(b); r++ {
+ c := b[r]
+ if c == '\\' {
+ r++
+ c = b[r]
+ }
+ b[w] = c
+ w++
+ }
+ return string(b[0:w])
+}
diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go
new file mode 100644
index 000000000..87d76261f
--- /dev/null
+++ b/libgo/go/net/dnsclient.go
@@ -0,0 +1,417 @@
+// 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 (
+ "bytes"
+ "fmt"
+ "os"
+ "rand"
+ "sync"
+ "time"
+)
+
+// 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 (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 }
+
+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}
+ }
+
+ 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}
+}
+
+
+// Find answer for name in dns message.
+// On return, if err == nil, addrs != nil.
+func answer(name, server string, dns *dnsMsg, qtype uint16) (addrs []dnsRR, err os.Error) {
+ addrs = make([]dnsRR, 0, len(dns.answer))
+
+ if dns.rcode == dnsRcodeNameError && dns.recursion_available {
+ return nil, &DNSError{Error: noSuchHost, Name: name}
+ }
+ if dns.rcode != dnsRcodeSuccess {
+ // None of the error codes make sense
+ // for the query we sent. If we didn't get
+ // a name error and we didn't get success,
+ // the server is behaving incorrectly.
+ return nil, &DNSError{Error: "server misbehaving", Name: name, Server: server}
+ }
+
+ // Look for the name.
+ // Presotto says it's okay to assume that servers listed in
+ // /etc/resolv.conf are recursive resolvers.
+ // We asked for recursion, so it should have included
+ // all the answers we need in this one packet.
+Cname:
+ for cnameloop := 0; cnameloop < 10; cnameloop++ {
+ addrs = addrs[0:0]
+ for i := 0; i < len(dns.answer); i++ {
+ rr := dns.answer[i]
+ h := rr.Header()
+ if h.Class == dnsClassINET && h.Name == name {
+ switch h.Rrtype {
+ case qtype:
+ n := len(addrs)
+ addrs = addrs[0 : n+1]
+ addrs[n] = rr
+ case dnsTypeCNAME:
+ // redirect to cname
+ name = rr.(*dnsRR_CNAME).Cname
+ continue Cname
+ }
+ }
+ }
+ if len(addrs) == 0 {
+ return nil, &DNSError{Error: noSuchHost, Name: name, Server: server}
+ }
+ return addrs, nil
+ }
+
+ 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) (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
+ }
+ addrs, err = answer(name, server, msg, qtype)
+ if err == nil || err.(*DNSError).Error == noSuchHost {
+ break
+ }
+ }
+ return
+}
+
+func convertRR_A(records []dnsRR) []string {
+ addrs := make([]string, len(records))
+ for i := 0; i < len(records); i++ {
+ rr := records[i]
+ a := rr.(*dnsRR_A).A
+ addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a)).String()
+ }
+ 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 {
+ return false
+ }
+ if len(s) > 255 {
+ return false
+ }
+ if s[len(s)-1] != '.' { // simplify checking loop: make name end in dot
+ s += "."
+ }
+
+ last := byte('.')
+ ok := false // ok once we've seen a letter
+ partlen := 0
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ switch {
+ default:
+ return false
+ case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_':
+ ok = true
+ partlen++
+ case '0' <= c && c <= '9':
+ // fine
+ partlen++
+ case c == '-':
+ // byte before dash cannot be dot
+ if last == '.' {
+ return false
+ }
+ partlen++
+ case c == '.':
+ // byte before dot cannot be dot, dash
+ if last == '.' || last == '-' {
+ return false
+ }
+ if partlen > 63 || partlen == 0 {
+ return false
+ }
+ partlen = 0
+ }
+ last = c
+ }
+
+ 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.
+ addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ cname = rname
+ 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 += "."
+ }
+ addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ cname = rname
+ return
+ }
+ }
+
+ // Last ditch effort: try unsuffixed.
+ rname := name
+ if !rooted {
+ rname += "."
+ }
+ addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ cname = rname
+ return
+ }
+ return
+}
+
+// LookupHost looks for name using the local hosts file and DNS resolver.
+// It returns the canonical name for the host and an array of that
+// host's addresses.
+func LookupHost(name string) (cname string, addrs []string, err os.Error) {
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ // Use entries from /etc/hosts if they match.
+ addrs = lookupStaticHost(name)
+ if len(addrs) > 0 {
+ cname = name
+ return
+ }
+ var records []dnsRR
+ cname, records, err = lookup(name, dnsTypeA)
+ if err != nil {
+ return
+ }
+ addrs = convertRR_A(records)
+ return
+}
+
+type SRV struct {
+ Target string
+ Port uint16
+ Priority uint16
+ Weight uint16
+}
+
+// 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().
+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 := 0; i < len(records); i++ {
+ r := records[i].(*dnsRR_SRV)
+ addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
+ }
+ return
+}
+
+type MX struct {
+ Host string
+ Pref uint16
+}
+
+func LookupMX(name string) (entries []*MX, err os.Error) {
+ var records []dnsRR
+ _, records, err = lookup(name, dnsTypeMX)
+ if err != nil {
+ return
+ }
+ entries = make([]*MX, len(records))
+ for i := range records {
+ r := records[i].(*dnsRR_MX)
+ entries[i] = &MX{r.Mx, r.Pref}
+ }
+ 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/libgo/go/net/dnsconfig.go b/libgo/go/net/dnsconfig.go
new file mode 100644
index 000000000..26f0e04e9
--- /dev/null
+++ b/libgo/go/net/dnsconfig.go
@@ -0,0 +1,120 @@
+// 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.
+
+// Read system DNS config from /etc/resolv.conf
+
+package net
+
+import "os"
+
+type dnsConfig struct {
+ servers []string // servers to use
+ search []string // suffixes to append to local name
+ ndots int // number of dots in name to trigger absolute lookup
+ timeout int // seconds before giving up on packet
+ attempts int // lost packets before giving up on server
+ rotate bool // round robin among servers
+}
+
+var dnsconfigError os.Error
+
+type DNSConfigError struct {
+ Error os.Error
+}
+
+func (e *DNSConfigError) String() string {
+ return "error reading DNS config: " + e.Error.String()
+}
+
+func (e *DNSConfigError) Timeout() bool { return false }
+func (e *DNSConfigError) Temporary() bool { return false }
+
+
+// See resolv.conf(5) on a Linux machine.
+// TODO(rsc): Supposed to call uname() and chop the beginning
+// of the host name to get the default search domain.
+// We assume it's in resolv.conf anyway.
+func dnsReadConfig() (*dnsConfig, os.Error) {
+ file, err := open("/etc/resolv.conf")
+ if err != nil {
+ return nil, &DNSConfigError{err}
+ }
+ conf := new(dnsConfig)
+ conf.servers = make([]string, 3)[0:0] // small, but the standard limit
+ conf.search = make([]string, 0)
+ conf.ndots = 1
+ conf.timeout = 5
+ conf.attempts = 2
+ conf.rotate = false
+ for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+ f := getFields(line)
+ if len(f) < 1 {
+ continue
+ }
+ switch f[0] {
+ case "nameserver": // add one name server
+ a := conf.servers
+ n := len(a)
+ if len(f) > 1 && n < cap(a) {
+ // One more check: make sure server name is
+ // just an IP address. Otherwise we need DNS
+ // to look it up.
+ name := f[1]
+ switch len(ParseIP(name)) {
+ case 16:
+ name = "[" + name + "]"
+ fallthrough
+ case 4:
+ a = a[0 : n+1]
+ a[n] = name
+ conf.servers = a
+ }
+ }
+
+ case "domain": // set search path to just this domain
+ if len(f) > 1 {
+ conf.search = make([]string, 1)
+ conf.search[0] = f[1]
+ } else {
+ conf.search = make([]string, 0)
+ }
+
+ case "search": // set search path to given servers
+ conf.search = make([]string, len(f)-1)
+ for i := 0; i < len(conf.search); i++ {
+ conf.search[i] = f[i+1]
+ }
+
+ case "options": // magic options
+ for i := 1; i < len(f); i++ {
+ s := f[i]
+ switch {
+ case len(s) >= 6 && s[0:6] == "ndots:":
+ n, _, _ := dtoi(s, 6)
+ if n < 1 {
+ n = 1
+ }
+ conf.ndots = n
+ case len(s) >= 8 && s[0:8] == "timeout:":
+ n, _, _ := dtoi(s, 8)
+ if n < 1 {
+ n = 1
+ }
+ conf.timeout = n
+ case len(s) >= 8 && s[0:9] == "attempts:":
+ n, _, _ := dtoi(s, 9)
+ if n < 1 {
+ n = 1
+ }
+ conf.attempts = n
+ case s == "rotate":
+ conf.rotate = true
+ }
+ }
+ }
+ }
+ file.close()
+
+ return conf, nil
+}
diff --git a/libgo/go/net/dnsmsg.go b/libgo/go/net/dnsmsg.go
new file mode 100644
index 000000000..dc195caf8
--- /dev/null
+++ b/libgo/go/net/dnsmsg.go
@@ -0,0 +1,743 @@
+// 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 packet assembly. See RFC 1035.
+//
+// This is intended to support name resolution during net.Dial.
+// It doesn't have to be blazing fast.
+//
+// Rather than write the usual handful of routines to pack and
+// unpack every message that can appear on the wire, we use
+// reflection to write a generic pack/unpack for structs and then
+// use it. Thus, if in the future we need to define new message
+// structs, no new pack/unpack/printing code needs to be written.
+//
+// The first half of this file defines the DNS message formats.
+// The second half implements the conversion to and from wire format.
+// A few of the structure elements have string tags to aid the
+// generic pack/unpack routines.
+//
+// TODO(rsc): There are enough names defined in this file that they're all
+// prefixed with dns. Perhaps put this in its own package later.
+
+package net
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+)
+
+// Packet formats
+
+// Wire constants.
+const (
+ // valid dnsRR_Header.Rrtype and dnsQuestion.qtype
+ dnsTypeA = 1
+ dnsTypeNS = 2
+ dnsTypeMD = 3
+ dnsTypeMF = 4
+ dnsTypeCNAME = 5
+ dnsTypeSOA = 6
+ dnsTypeMB = 7
+ dnsTypeMG = 8
+ dnsTypeMR = 9
+ dnsTypeNULL = 10
+ dnsTypeWKS = 11
+ dnsTypePTR = 12
+ dnsTypeHINFO = 13
+ dnsTypeMINFO = 14
+ dnsTypeMX = 15
+ dnsTypeTXT = 16
+ dnsTypeSRV = 33
+
+ // valid dnsQuestion.qtype only
+ dnsTypeAXFR = 252
+ dnsTypeMAILB = 253
+ dnsTypeMAILA = 254
+ dnsTypeALL = 255
+
+ // valid dnsQuestion.qclass
+ dnsClassINET = 1
+ dnsClassCSNET = 2
+ dnsClassCHAOS = 3
+ dnsClassHESIOD = 4
+ dnsClassANY = 255
+
+ // dnsMsg.rcode
+ dnsRcodeSuccess = 0
+ dnsRcodeFormatError = 1
+ dnsRcodeServerFailure = 2
+ dnsRcodeNameError = 3
+ dnsRcodeNotImplemented = 4
+ dnsRcodeRefused = 5
+)
+
+// The wire format for the DNS packet header.
+type dnsHeader struct {
+ Id uint16
+ Bits uint16
+ Qdcount, Ancount, Nscount, Arcount uint16
+}
+
+const (
+ // dnsHeader.Bits
+ _QR = 1 << 15 // query/response (response=1)
+ _AA = 1 << 10 // authoritative
+ _TC = 1 << 9 // truncated
+ _RD = 1 << 8 // recursion desired
+ _RA = 1 << 7 // recursion available
+)
+
+// DNS queries.
+type dnsQuestion struct {
+ Name string "domain-name" // "domain-name" specifies encoding; see packers below
+ Qtype uint16
+ Qclass uint16
+}
+
+// DNS responses (resource records).
+// There are many types of messages,
+// but they all share the same header.
+type dnsRR_Header struct {
+ Name string "domain-name"
+ Rrtype uint16
+ Class uint16
+ Ttl uint32
+ Rdlength uint16 // length of data after header
+}
+
+func (h *dnsRR_Header) Header() *dnsRR_Header {
+ return h
+}
+
+type dnsRR interface {
+ Header() *dnsRR_Header
+}
+
+
+// Specific DNS RR formats for each query type.
+
+type dnsRR_CNAME struct {
+ Hdr dnsRR_Header
+ Cname string "domain-name"
+}
+
+func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_HINFO struct {
+ Hdr dnsRR_Header
+ Cpu string
+ Os string
+}
+
+func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MB struct {
+ Hdr dnsRR_Header
+ Mb string "domain-name"
+}
+
+func (rr *dnsRR_MB) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MG struct {
+ Hdr dnsRR_Header
+ Mg string "domain-name"
+}
+
+func (rr *dnsRR_MG) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MINFO struct {
+ Hdr dnsRR_Header
+ Rmail string "domain-name"
+ Email string "domain-name"
+}
+
+func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MR struct {
+ Hdr dnsRR_Header
+ Mr string "domain-name"
+}
+
+func (rr *dnsRR_MR) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_MX struct {
+ Hdr dnsRR_Header
+ Pref uint16
+ Mx string "domain-name"
+}
+
+func (rr *dnsRR_MX) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_NS struct {
+ Hdr dnsRR_Header
+ Ns string "domain-name"
+}
+
+func (rr *dnsRR_NS) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_PTR struct {
+ Hdr dnsRR_Header
+ Ptr string "domain-name"
+}
+
+func (rr *dnsRR_PTR) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_SOA struct {
+ Hdr dnsRR_Header
+ Ns string "domain-name"
+ Mbox string "domain-name"
+ Serial uint32
+ Refresh uint32
+ Retry uint32
+ Expire uint32
+ Minttl uint32
+}
+
+func (rr *dnsRR_SOA) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_TXT struct {
+ Hdr dnsRR_Header
+ Txt string // not domain name
+}
+
+func (rr *dnsRR_TXT) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_SRV struct {
+ Hdr dnsRR_Header
+ Priority uint16
+ Weight uint16
+ Port uint16
+ Target string "domain-name"
+}
+
+func (rr *dnsRR_SRV) Header() *dnsRR_Header {
+ return &rr.Hdr
+}
+
+type dnsRR_A struct {
+ Hdr dnsRR_Header
+ A uint32 "ipv4"
+}
+
+func (rr *dnsRR_A) Header() *dnsRR_Header { return &rr.Hdr }
+
+
+// Packing and unpacking.
+//
+// All the packers and unpackers take a (msg []byte, off int)
+// and return (off1 int, ok bool). If they return ok==false, they
+// also return off1==len(msg), so that the next unpacker will
+// also fail. This lets us avoid checks of ok until the end of a
+// packing sequence.
+
+// Map of constructors for each RR wire type.
+var rr_mk = map[int]func() dnsRR{
+ dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
+ dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
+ dnsTypeMB: func() dnsRR { return new(dnsRR_MB) },
+ dnsTypeMG: func() dnsRR { return new(dnsRR_MG) },
+ dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
+ dnsTypeMR: func() dnsRR { return new(dnsRR_MR) },
+ dnsTypeMX: func() dnsRR { return new(dnsRR_MX) },
+ dnsTypeNS: func() dnsRR { return new(dnsRR_NS) },
+ dnsTypePTR: func() dnsRR { return new(dnsRR_PTR) },
+ dnsTypeSOA: func() dnsRR { return new(dnsRR_SOA) },
+ dnsTypeTXT: func() dnsRR { return new(dnsRR_TXT) },
+ dnsTypeSRV: func() dnsRR { return new(dnsRR_SRV) },
+ dnsTypeA: func() dnsRR { return new(dnsRR_A) },
+}
+
+// Pack a domain name s into msg[off:].
+// Domain names are a sequence of counted strings
+// split at the dots. They end with a zero-length string.
+func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
+ // Add trailing dot to canonicalize name.
+ if n := len(s); n == 0 || s[n-1] != '.' {
+ s += "."
+ }
+
+ // Each dot ends a segment of the name.
+ // We trade each dot byte for a length byte.
+ // There is also a trailing zero.
+ // Check that we have all the space we need.
+ tot := len(s) + 1
+ if off+tot > len(msg) {
+ return len(msg), false
+ }
+
+ // Emit sequence of counted strings, chopping at dots.
+ begin := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == '.' {
+ if i-begin >= 1<<6 { // top two bits of length must be clear
+ return len(msg), false
+ }
+ msg[off] = byte(i - begin)
+ off++
+ for j := begin; j < i; j++ {
+ msg[off] = s[j]
+ off++
+ }
+ begin = i + 1
+ }
+ }
+ msg[off] = 0
+ off++
+ return off, true
+}
+
+// Unpack a domain name.
+// In addition to the simple sequences of counted strings above,
+// domain names are allowed to refer to strings elsewhere in the
+// packet, to avoid repeating common suffixes when returning
+// many entries in a single domain. The pointers are marked
+// by a length byte with the top two bits set. Ignoring those
+// two bits, that byte and the next give a 14 bit offset from msg[0]
+// where we should pick up the trail.
+// Note that if we jump elsewhere in the packet,
+// we return off1 == the offset after the first pointer we found,
+// which is where the next record will start.
+// In theory, the pointers are only allowed to jump backward.
+// We let them jump anywhere and stop jumping after a while.
+func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) {
+ s = ""
+ ptr := 0 // number of pointers followed
+Loop:
+ for {
+ if off >= len(msg) {
+ return "", len(msg), false
+ }
+ c := int(msg[off])
+ off++
+ switch c & 0xC0 {
+ case 0x00:
+ if c == 0x00 {
+ // end of name
+ break Loop
+ }
+ // literal string
+ if off+c > len(msg) {
+ return "", len(msg), false
+ }
+ s += string(msg[off:off+c]) + "."
+ off += c
+ case 0xC0:
+ // pointer to somewhere else in msg.
+ // remember location after first ptr,
+ // since that's how many bytes we consumed.
+ // also, don't follow too many pointers --
+ // maybe there's a loop.
+ if off >= len(msg) {
+ return "", len(msg), false
+ }
+ c1 := msg[off]
+ off++
+ if ptr == 0 {
+ off1 = off
+ }
+ if ptr++; ptr > 10 {
+ return "", len(msg), false
+ }
+ off = (c^0xC0)<<8 | int(c1)
+ default:
+ // 0x80 and 0x40 are reserved
+ return "", len(msg), false
+ }
+ }
+ if ptr == 0 {
+ off1 = off
+ }
+ return s, off1, true
+}
+
+// TODO(rsc): Move into generic library?
+// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string,
+// and other (often anonymous) structs.
+func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) {
+ for i := 0; i < val.NumField(); i++ {
+ f := val.Type().(*reflect.StructType).Field(i)
+ switch fv := val.Field(i).(type) {
+ default:
+ BadType:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
+ case *reflect.StructValue:
+ off, ok = packStructValue(fv, msg, off)
+ case *reflect.UintValue:
+ i := fv.Get()
+ switch fv.Type().Kind() {
+ default:
+ goto BadType
+ case reflect.Uint16:
+ if off+2 > len(msg) {
+ return len(msg), false
+ }
+ msg[off] = byte(i >> 8)
+ msg[off+1] = byte(i)
+ off += 2
+ case reflect.Uint32:
+ if off+4 > len(msg) {
+ return len(msg), false
+ }
+ msg[off] = byte(i >> 24)
+ msg[off+1] = byte(i >> 16)
+ msg[off+2] = byte(i >> 8)
+ msg[off+3] = byte(i)
+ off += 4
+ }
+ case *reflect.StringValue:
+ // There are multiple string encodings.
+ // The tag distinguishes ordinary strings from domain names.
+ s := fv.Get()
+ switch f.Tag {
+ default:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
+ return len(msg), false
+ case "domain-name":
+ off, ok = packDomainName(s, msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ case "":
+ // Counted string: 1 byte length.
+ if len(s) > 255 || off+1+len(s) > len(msg) {
+ return len(msg), false
+ }
+ msg[off] = byte(len(s))
+ off++
+ off += copy(msg[off:], s)
+ }
+ }
+ }
+ return off, true
+}
+
+func structValue(any interface{}) *reflect.StructValue {
+ return reflect.NewValue(any).(*reflect.PtrValue).Elem().(*reflect.StructValue)
+}
+
+func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
+ off, ok = packStructValue(structValue(any), msg, off)
+ return off, ok
+}
+
+// TODO(rsc): Move into generic library?
+// Unpack a reflect.StructValue from msg.
+// Same restrictions as packStructValue.
+func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) {
+ for i := 0; i < val.NumField(); i++ {
+ f := val.Type().(*reflect.StructType).Field(i)
+ switch fv := val.Field(i).(type) {
+ default:
+ BadType:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
+ case *reflect.StructValue:
+ off, ok = unpackStructValue(fv, msg, off)
+ case *reflect.UintValue:
+ switch fv.Type().Kind() {
+ default:
+ goto BadType
+ case reflect.Uint16:
+ if off+2 > len(msg) {
+ return len(msg), false
+ }
+ i := uint16(msg[off])<<8 | uint16(msg[off+1])
+ fv.Set(uint64(i))
+ off += 2
+ case reflect.Uint32:
+ if off+4 > len(msg) {
+ return len(msg), false
+ }
+ i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
+ fv.Set(uint64(i))
+ off += 4
+ }
+ case *reflect.StringValue:
+ var s string
+ switch f.Tag {
+ default:
+ fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
+ return len(msg), false
+ case "domain-name":
+ s, off, ok = unpackDomainName(msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ case "":
+ if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
+ return len(msg), false
+ }
+ n := int(msg[off])
+ off++
+ b := make([]byte, n)
+ for i := 0; i < n; i++ {
+ b[i] = msg[off+i]
+ }
+ off += n
+ s = string(b)
+ }
+ fv.Set(s)
+ }
+ }
+ return off, true
+}
+
+func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
+ off, ok = unpackStructValue(structValue(any), msg, off)
+ return off, ok
+}
+
+// Generic struct printer.
+// Doesn't care about the string tag "domain-name",
+// but does look for an "ipv4" tag on uint32 variables,
+// printing them as IP addresses.
+func printStructValue(val *reflect.StructValue) string {
+ s := "{"
+ for i := 0; i < val.NumField(); i++ {
+ if i > 0 {
+ s += ", "
+ }
+ f := val.Type().(*reflect.StructType).Field(i)
+ if !f.Anonymous {
+ s += f.Name + "="
+ }
+ fval := val.Field(i)
+ if fv, ok := fval.(*reflect.StructValue); ok {
+ s += printStructValue(fv)
+ } else if fv, ok := fval.(*reflect.UintValue); ok && f.Tag == "ipv4" {
+ i := fv.Get()
+ s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
+ } else {
+ s += fmt.Sprint(fval.Interface())
+ }
+ }
+ s += "}"
+ return s
+}
+
+func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
+
+// Resource record packer.
+func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
+ var off1 int
+ // pack twice, once to find end of header
+ // and again to find end of packet.
+ // a bit inefficient but this doesn't need to be fast.
+ // off1 is end of header
+ // off2 is end of rr
+ off1, ok = packStruct(rr.Header(), msg, off)
+ off2, ok = packStruct(rr, msg, off)
+ if !ok {
+ return len(msg), false
+ }
+ // pack a third time; redo header with correct data length
+ rr.Header().Rdlength = uint16(off2 - off1)
+ packStruct(rr.Header(), msg, off)
+ return off2, true
+}
+
+// Resource record unpacker.
+func unpackRR(msg []byte, off int) (rr dnsRR, off1 int, ok bool) {
+ // unpack just the header, to find the rr type and length
+ var h dnsRR_Header
+ off0 := off
+ if off, ok = unpackStruct(&h, msg, off); !ok {
+ return nil, len(msg), false
+ }
+ end := off + int(h.Rdlength)
+
+ // make an rr of that type and re-unpack.
+ // again inefficient but doesn't need to be fast.
+ mk, known := rr_mk[int(h.Rrtype)]
+ if !known {
+ return &h, end, true
+ }
+ rr = mk()
+ off, ok = unpackStruct(rr, msg, off0)
+ if off != end {
+ return &h, end, true
+ }
+ return rr, off, ok
+}
+
+// Usable representation of a DNS packet.
+
+// A manually-unpacked version of (id, bits).
+// This is in its own struct for easy printing.
+type dnsMsgHdr struct {
+ id uint16
+ response bool
+ opcode int
+ authoritative bool
+ truncated bool
+ recursion_desired bool
+ recursion_available bool
+ rcode int
+}
+
+type dnsMsg struct {
+ dnsMsgHdr
+ question []dnsQuestion
+ answer []dnsRR
+ ns []dnsRR
+ extra []dnsRR
+}
+
+
+func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
+ var dh dnsHeader
+
+ // Convert convenient dnsMsg into wire-like dnsHeader.
+ dh.Id = dns.id
+ dh.Bits = uint16(dns.opcode)<<11 | uint16(dns.rcode)
+ if dns.recursion_available {
+ dh.Bits |= _RA
+ }
+ if dns.recursion_desired {
+ dh.Bits |= _RD
+ }
+ if dns.truncated {
+ dh.Bits |= _TC
+ }
+ if dns.authoritative {
+ dh.Bits |= _AA
+ }
+ if dns.response {
+ dh.Bits |= _QR
+ }
+
+ // Prepare variable sized arrays.
+ question := dns.question
+ answer := dns.answer
+ ns := dns.ns
+ extra := dns.extra
+
+ dh.Qdcount = uint16(len(question))
+ dh.Ancount = uint16(len(answer))
+ dh.Nscount = uint16(len(ns))
+ dh.Arcount = uint16(len(extra))
+
+ // Could work harder to calculate message size,
+ // but this is far more than we need and not
+ // big enough to hurt the allocator.
+ msg = make([]byte, 2000)
+
+ // Pack it in: header and then the pieces.
+ off := 0
+ off, ok = packStruct(&dh, msg, off)
+ for i := 0; i < len(question); i++ {
+ off, ok = packStruct(&question[i], msg, off)
+ }
+ for i := 0; i < len(answer); i++ {
+ off, ok = packRR(answer[i], msg, off)
+ }
+ for i := 0; i < len(ns); i++ {
+ off, ok = packRR(ns[i], msg, off)
+ }
+ for i := 0; i < len(extra); i++ {
+ off, ok = packRR(extra[i], msg, off)
+ }
+ if !ok {
+ return nil, false
+ }
+ return msg[0:off], true
+}
+
+func (dns *dnsMsg) Unpack(msg []byte) bool {
+ // Header.
+ var dh dnsHeader
+ off := 0
+ var ok bool
+ if off, ok = unpackStruct(&dh, msg, off); !ok {
+ return false
+ }
+ dns.id = dh.Id
+ dns.response = (dh.Bits & _QR) != 0
+ dns.opcode = int(dh.Bits>>11) & 0xF
+ dns.authoritative = (dh.Bits & _AA) != 0
+ dns.truncated = (dh.Bits & _TC) != 0
+ dns.recursion_desired = (dh.Bits & _RD) != 0
+ dns.recursion_available = (dh.Bits & _RA) != 0
+ dns.rcode = int(dh.Bits & 0xF)
+
+ // Arrays.
+ dns.question = make([]dnsQuestion, dh.Qdcount)
+ dns.answer = make([]dnsRR, dh.Ancount)
+ dns.ns = make([]dnsRR, dh.Nscount)
+ dns.extra = make([]dnsRR, dh.Arcount)
+
+ for i := 0; i < len(dns.question); i++ {
+ off, ok = unpackStruct(&dns.question[i], msg, off)
+ }
+ for i := 0; i < len(dns.answer); i++ {
+ dns.answer[i], off, ok = unpackRR(msg, off)
+ }
+ for i := 0; i < len(dns.ns); i++ {
+ dns.ns[i], off, ok = unpackRR(msg, off)
+ }
+ for i := 0; i < len(dns.extra); i++ {
+ dns.extra[i], off, ok = unpackRR(msg, off)
+ }
+ if !ok {
+ return false
+ }
+ // if off != len(msg) {
+ // println("extra bytes in dns packet", off, "<", len(msg));
+ // }
+ return true
+}
+
+func (dns *dnsMsg) String() string {
+ s := "DNS: " + printStruct(&dns.dnsMsgHdr) + "\n"
+ if len(dns.question) > 0 {
+ s += "-- Questions\n"
+ for i := 0; i < len(dns.question); i++ {
+ s += printStruct(&dns.question[i]) + "\n"
+ }
+ }
+ if len(dns.answer) > 0 {
+ s += "-- Answers\n"
+ for i := 0; i < len(dns.answer); i++ {
+ s += printStruct(dns.answer[i]) + "\n"
+ }
+ }
+ if len(dns.ns) > 0 {
+ s += "-- Name servers\n"
+ for i := 0; i < len(dns.ns); i++ {
+ s += printStruct(dns.ns[i]) + "\n"
+ }
+ }
+ if len(dns.extra) > 0 {
+ s += "-- Extra\n"
+ for i := 0; i < len(dns.extra); i++ {
+ s += printStruct(dns.extra[i]) + "\n"
+ }
+ }
+ return s
+}
diff --git a/libgo/go/net/dnsname_test.go b/libgo/go/net/dnsname_test.go
new file mode 100644
index 000000000..0c1a62518
--- /dev/null
+++ b/libgo/go/net/dnsname_test.go
@@ -0,0 +1,69 @@
+// 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 net
+
+import (
+ "testing"
+ "runtime"
+)
+
+type testCase struct {
+ name string
+ result bool
+}
+
+var tests = []testCase{
+ // RFC2181, section 11.
+ {"_xmpp-server._tcp.google.com", true},
+ {"_xmpp-server._tcp.google.com", true},
+ {"foo.com", true},
+ {"1foo.com", true},
+ {"26.0.0.73.com", true},
+ {"fo-o.com", true},
+ {"fo1o.com", true},
+ {"foo1.com", true},
+ {"a.b..com", false},
+}
+
+func getTestCases(ch chan<- testCase) {
+ defer close(ch)
+ var char59 = ""
+ var char63 = ""
+ var char64 = ""
+ for i := 0; i < 59; i++ {
+ char59 += "a"
+ }
+ char63 = char59 + "aaaa"
+ char64 = char63 + "a"
+
+ for _, tc := range tests {
+ ch <- tc
+ }
+
+ ch <- testCase{char63 + ".com", true}
+ ch <- testCase{char64 + ".com", false}
+ // 255 char name is fine:
+ ch <- testCase{char59 + "." + char63 + "." + char63 + "." +
+ char63 + ".com",
+ true}
+ // 256 char name is bad:
+ ch <- testCase{char59 + "a." + char63 + "." + char63 + "." +
+ char63 + ".com",
+ false}
+}
+
+func TestDNSNames(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ return
+ }
+ ch := make(chan testCase)
+ go getTestCases(ch)
+ for tc := range ch {
+ if isDomainName(tc.name) != tc.result {
+ t.Errorf("isDomainName(%v) failed: Should be %v",
+ tc.name, tc.result)
+ }
+ }
+}
diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go
new file mode 100644
index 000000000..26d17d4e0
--- /dev/null
+++ b/libgo/go/net/fd.go
@@ -0,0 +1,612 @@
+// 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.
+
+// TODO(rsc): All the prints in this file should go to standard error.
+
+package net
+
+import (
+ "io"
+ "os"
+ "sync"
+ "syscall"
+ "time"
+)
+
+// Network file descriptor.
+type netFD struct {
+ // locking/lifetime of sysfd
+ sysmu sync.Mutex
+ sysref int
+ closing bool
+
+ // immutable until Close
+ sysfd int
+ family int
+ proto int
+ sysfile *os.File
+ cr chan bool
+ cw chan bool
+ net string
+ laddr Addr
+ raddr Addr
+
+ // owned by client
+ rdeadline_delta int64
+ rdeadline int64
+ rio sync.Mutex
+ wdeadline_delta int64
+ wdeadline int64
+ wio sync.Mutex
+
+ // owned by fd wait server
+ ncr, ncw int
+}
+
+type InvalidConnError struct{}
+
+func (e *InvalidConnError) String() string { return "invalid net.Conn" }
+func (e *InvalidConnError) Temporary() bool { return false }
+func (e *InvalidConnError) Timeout() bool { return false }
+
+// A pollServer helps FDs determine when to retry a non-blocking
+// read or write after they get EAGAIN. When an FD needs to wait,
+// send the fd on s.cr (for a read) or s.cw (for a write) to pass the
+// request to the poll server. Then receive on fd.cr/fd.cw.
+// When the pollServer finds that i/o on FD should be possible
+// again, it will send fd on fd.cr/fd.cw to wake any waiting processes.
+// This protocol is implemented as s.WaitRead() and s.WaitWrite().
+//
+// There is one subtlety: when sending on s.cr/s.cw, the
+// poll server is probably in a system call, waiting for an fd
+// to become ready. It's not looking at the request channels.
+// To resolve this, the poll server waits not just on the FDs it has
+// been given but also its own pipe. After sending on the
+// buffered channel s.cr/s.cw, WaitRead/WaitWrite writes a
+// byte to the pipe, causing the pollServer's poll system call to
+// return. In response to the pipe being readable, the pollServer
+// re-polls its request channels.
+//
+// Note that the ordering is "send request" and then "wake up server".
+// If the operations were reversed, there would be a race: the poll
+// server might wake up and look at the request channel, see that it
+// was empty, and go back to sleep, all before the requester managed
+// to send the request. Because the send must complete before the wakeup,
+// the request channel must be buffered. A buffer of size 1 is sufficient
+// for any request load. If many processes are trying to submit requests,
+// one will succeed, the pollServer will read the request, and then the
+// channel will be empty for the next process's request. A larger buffer
+// might help batch requests.
+//
+// To avoid races in closing, all fd operations are locked and
+// refcounted. when netFD.Close() is called, it calls syscall.Shutdown
+// and sets a closing flag. Only when the last reference is removed
+// will the fd be closed.
+
+type pollServer struct {
+ cr, cw chan *netFD // buffered >= 1
+ pr, pw *os.File
+ pending map[int]*netFD
+ poll *pollster // low-level OS hooks
+ deadline int64 // next deadline (nsec since 1970)
+}
+
+func (s *pollServer) AddFD(fd *netFD, mode int) {
+ intfd := fd.sysfd
+ if intfd < 0 {
+ // fd closed underfoot
+ if mode == 'r' {
+ fd.cr <- true
+ } else {
+ fd.cw <- true
+ }
+ return
+ }
+ if err := s.poll.AddFD(intfd, mode, false); err != nil {
+ panic("pollServer AddFD " + err.String())
+ return
+ }
+
+ var t int64
+ key := intfd << 1
+ if mode == 'r' {
+ fd.ncr++
+ t = fd.rdeadline
+ } else {
+ fd.ncw++
+ key++
+ t = fd.wdeadline
+ }
+ s.pending[key] = fd
+ if t > 0 && (s.deadline == 0 || t < s.deadline) {
+ s.deadline = t
+ }
+}
+
+func (s *pollServer) LookupFD(fd int, mode int) *netFD {
+ key := fd << 1
+ if mode == 'w' {
+ key++
+ }
+ netfd, ok := s.pending[key]
+ if !ok {
+ return nil
+ }
+ s.pending[key] = nil, false
+ return netfd
+}
+
+func (s *pollServer) WakeFD(fd *netFD, mode int) {
+ if mode == 'r' {
+ for fd.ncr > 0 {
+ fd.ncr--
+ fd.cr <- true
+ }
+ } else {
+ for fd.ncw > 0 {
+ fd.ncw--
+ fd.cw <- true
+ }
+ }
+}
+
+func (s *pollServer) Now() int64 {
+ return time.Nanoseconds()
+}
+
+func (s *pollServer) CheckDeadlines() {
+ now := s.Now()
+ // TODO(rsc): This will need to be handled more efficiently,
+ // probably with a heap indexed by wakeup time.
+
+ var next_deadline int64
+ for key, fd := range s.pending {
+ var t int64
+ var mode int
+ if key&1 == 0 {
+ mode = 'r'
+ } else {
+ mode = 'w'
+ }
+ if mode == 'r' {
+ t = fd.rdeadline
+ } else {
+ t = fd.wdeadline
+ }
+ if t > 0 {
+ if t <= now {
+ s.pending[key] = nil, false
+ if mode == 'r' {
+ s.poll.DelFD(fd.sysfd, mode)
+ fd.rdeadline = -1
+ } else {
+ s.poll.DelFD(fd.sysfd, mode)
+ fd.wdeadline = -1
+ }
+ s.WakeFD(fd, mode)
+ } else if next_deadline == 0 || t < next_deadline {
+ next_deadline = t
+ }
+ }
+ }
+ s.deadline = next_deadline
+}
+
+func (s *pollServer) Run() {
+ var scratch [100]byte
+ for {
+ var t = s.deadline
+ if t > 0 {
+ t = t - s.Now()
+ if t <= 0 {
+ s.CheckDeadlines()
+ continue
+ }
+ }
+ fd, mode, err := s.poll.WaitFD(t)
+ if err != nil {
+ print("pollServer WaitFD: ", err.String(), "\n")
+ return
+ }
+ if fd < 0 {
+ // Timeout happened.
+ s.CheckDeadlines()
+ continue
+ }
+ if fd == s.pr.Fd() {
+ // Drain our wakeup pipe.
+ for nn, _ := s.pr.Read(scratch[0:]); nn > 0; {
+ nn, _ = s.pr.Read(scratch[0:])
+ }
+ // Read from channels
+ for fd, ok := <-s.cr; ok; fd, ok = <-s.cr {
+ s.AddFD(fd, 'r')
+ }
+ for fd, ok := <-s.cw; ok; fd, ok = <-s.cw {
+ s.AddFD(fd, 'w')
+ }
+ } else {
+ netfd := s.LookupFD(fd, mode)
+ if netfd == nil {
+ print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n")
+ continue
+ }
+ s.WakeFD(netfd, mode)
+ }
+ }
+}
+
+var wakeupbuf [1]byte
+
+func (s *pollServer) Wakeup() { s.pw.Write(wakeupbuf[0:]) }
+
+func (s *pollServer) WaitRead(fd *netFD) {
+ s.cr <- fd
+ s.Wakeup()
+ <-fd.cr
+}
+
+func (s *pollServer) WaitWrite(fd *netFD) {
+ s.cw <- fd
+ s.Wakeup()
+ <-fd.cw
+}
+
+// Network FD methods.
+// All the network FDs use a single pollServer.
+
+var pollserver *pollServer
+var onceStartServer sync.Once
+
+func startServer() {
+ p, err := newPollServer()
+ if err != nil {
+ print("Start pollServer: ", err.String(), "\n")
+ }
+ pollserver = p
+}
+
+func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
+ onceStartServer.Do(startServer)
+ if e := syscall.SetNonblock(fd, true); e != 0 {
+ return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)}
+ }
+ f = &netFD{
+ sysfd: fd,
+ family: family,
+ proto: proto,
+ net: net,
+ laddr: laddr,
+ raddr: raddr,
+ }
+ var ls, rs string
+ if laddr != nil {
+ ls = laddr.String()
+ }
+ if raddr != nil {
+ rs = raddr.String()
+ }
+ f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs)
+ f.cr = make(chan bool, 1)
+ f.cw = make(chan bool, 1)
+ return f, nil
+}
+
+// Add a reference to this fd.
+func (fd *netFD) incref() {
+ fd.sysmu.Lock()
+ fd.sysref++
+ fd.sysmu.Unlock()
+}
+
+// Remove a reference to this FD and close if we've been asked to do so (and
+// there are no references left.
+func (fd *netFD) decref() {
+ fd.sysmu.Lock()
+ fd.sysref--
+ if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
+ // In case the user has set linger, switch to blocking mode so
+ // the close blocks. As long as this doesn't happen often, we
+ // can handle the extra OS processes. Otherwise we'll need to
+ // use the pollserver for Close too. Sigh.
+ syscall.SetNonblock(fd.sysfd, false)
+ fd.sysfile.Close()
+ fd.sysfile = nil
+ fd.sysfd = -1
+ }
+ fd.sysmu.Unlock()
+}
+
+func (fd *netFD) Close() os.Error {
+ if fd == nil || fd.sysfile == nil {
+ return os.EINVAL
+ }
+
+ fd.incref()
+ syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
+ fd.closing = true
+ fd.decref()
+ return nil
+}
+
+func (fd *netFD) Read(p []byte) (n int, err os.Error) {
+ if fd == nil {
+ return 0, os.EINVAL
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfile == nil {
+ return 0, os.EINVAL
+ }
+ if fd.rdeadline_delta > 0 {
+ fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+ } else {
+ fd.rdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ n, errno = syscall.Read(fd.sysfile.Fd(), p)
+ if (errno == syscall.EAGAIN || errno == syscall.EINTR) && fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ if errno != 0 {
+ n = 0
+ oserr = os.Errno(errno)
+ } else if n == 0 && errno == 0 && fd.proto != syscall.SOCK_DGRAM {
+ err = os.EOF
+ }
+ break
+ }
+ if oserr != nil {
+ err = &OpError{"read", fd.net, fd.raddr, oserr}
+ }
+ return
+}
+
+func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, nil, os.EINVAL
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.rdeadline_delta > 0 {
+ fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+ } else {
+ fd.rdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0)
+ if (errno == syscall.EAGAIN || errno == syscall.EINTR) && fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ if errno != 0 {
+ n = 0
+ oserr = os.Errno(errno)
+ }
+ break
+ }
+ if oserr != nil {
+ err = &OpError{"read", fd.net, fd.laddr, oserr}
+ }
+ return
+}
+
+func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, 0, 0, nil, os.EINVAL
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.rdeadline_delta > 0 {
+ fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+ } else {
+ fd.rdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ n, oobn, flags, sa, errno = syscall.Recvmsg(fd.sysfd, p, oob, 0)
+ if (errno == syscall.EAGAIN || errno == syscall.EINTR) && fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ if errno != 0 {
+ oserr = os.Errno(errno)
+ }
+ if n == 0 {
+ oserr = os.EOF
+ }
+ break
+ }
+ if oserr != nil {
+ err = &OpError{"read", fd.net, fd.laddr, oserr}
+ return
+ }
+ return
+}
+
+func (fd *netFD) Write(p []byte) (n int, err os.Error) {
+ if fd == nil {
+ return 0, os.EINVAL
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfile == nil {
+ return 0, os.EINVAL
+ }
+ if fd.wdeadline_delta > 0 {
+ fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
+ } else {
+ fd.wdeadline = 0
+ }
+ nn := 0
+ var oserr os.Error
+
+ for {
+ n, errno := syscall.Write(fd.sysfile.Fd(), p[nn:])
+ if n > 0 {
+ nn += n
+ }
+ if nn == len(p) {
+ break
+ }
+ if (errno == syscall.EAGAIN || errno == syscall.EINTR) && fd.wdeadline >= 0 {
+ pollserver.WaitWrite(fd)
+ continue
+ }
+ if errno != 0 {
+ n = 0
+ oserr = os.Errno(errno)
+ break
+ }
+ if n == 0 {
+ oserr = io.ErrUnexpectedEOF
+ break
+ }
+ }
+ if oserr != nil {
+ err = &OpError{"write", fd.net, fd.raddr, oserr}
+ }
+ return nn, err
+}
+
+func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, os.EINVAL
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.wdeadline_delta > 0 {
+ fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
+ } else {
+ fd.wdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ errno := syscall.Sendto(fd.sysfd, p, 0, sa)
+ if (errno == syscall.EAGAIN || errno == syscall.EINTR) && fd.wdeadline >= 0 {
+ pollserver.WaitWrite(fd)
+ continue
+ }
+ if errno != 0 {
+ oserr = os.Errno(errno)
+ }
+ break
+ }
+ if oserr == nil {
+ n = len(p)
+ } else {
+ err = &OpError{"write", fd.net, fd.raddr, oserr}
+ }
+ return
+}
+
+func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, 0, os.EINVAL
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.wdeadline_delta > 0 {
+ fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
+ } else {
+ fd.wdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ errno = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
+ if (errno == syscall.EAGAIN || errno == syscall.EINTR) && fd.wdeadline >= 0 {
+ pollserver.WaitWrite(fd)
+ continue
+ }
+ if errno != 0 {
+ oserr = os.Errno(errno)
+ }
+ break
+ }
+ if oserr == nil {
+ n = len(p)
+ oobn = len(oob)
+ } else {
+ err = &OpError{"write", fd.net, fd.raddr, oserr}
+ }
+ return
+}
+
+func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return nil, os.EINVAL
+ }
+
+ fd.incref()
+ defer fd.decref()
+
+ // See ../syscall/exec.go for description of ForkLock.
+ // It is okay to hold the lock across syscall.Accept
+ // because we have put fd.sysfd into non-blocking mode.
+ syscall.ForkLock.RLock()
+ var s, e int
+ var sa syscall.Sockaddr
+ for {
+ if fd.closing {
+ syscall.ForkLock.RUnlock()
+ return nil, os.EINVAL
+ }
+ s, sa, e = syscall.Accept(fd.sysfd)
+ if e != syscall.EAGAIN && e != syscall.EINTR {
+ break
+ }
+ syscall.ForkLock.RUnlock()
+ pollserver.WaitRead(fd)
+ syscall.ForkLock.RLock()
+ }
+ if e != 0 {
+ syscall.ForkLock.RUnlock()
+ return nil, &OpError{"accept", fd.net, fd.laddr, os.Errno(e)}
+ }
+ syscall.CloseOnExec(s)
+ syscall.ForkLock.RUnlock()
+
+ if nfd, err = newFD(s, fd.family, fd.proto, fd.net, fd.laddr, toAddr(sa)); err != nil {
+ syscall.Close(s)
+ return nil, err
+ }
+ return nfd, nil
+}
+
+func (fd *netFD) dup() (f *os.File, err os.Error) {
+ ns, e := syscall.Dup(fd.sysfd)
+ if e != 0 {
+ return nil, &OpError{"dup", fd.net, fd.laddr, os.Errno(e)}
+ }
+
+ // We want blocking mode for the new fd, hence the double negative.
+ if e = syscall.SetNonblock(ns, false); e != 0 {
+ return nil, &OpError{"setnonblock", fd.net, fd.laddr, os.Errno(e)}
+ }
+
+ return os.NewFile(ns, fd.sysfile.Name()), nil
+}
+
+func closesocket(s int) (errno int) {
+ return syscall.Close(s)
+}
diff --git a/libgo/go/net/fd_linux.go b/libgo/go/net/fd_linux.go
new file mode 100644
index 000000000..ef86cb17f
--- /dev/null
+++ b/libgo/go/net/fd_linux.go
@@ -0,0 +1,149 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Waiting for FDs via epoll(7).
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+const (
+ readFlags = syscall.EPOLLIN | syscall.EPOLLRDHUP
+ writeFlags = syscall.EPOLLOUT
+)
+
+type pollster struct {
+ epfd int
+
+ // Events we're already waiting for
+ events map[int]uint32
+}
+
+func newpollster() (p *pollster, err os.Error) {
+ p = new(pollster)
+ var e int
+
+ // The arg to epoll_create is a hint to the kernel
+ // about the number of FDs we will care about.
+ // We don't know.
+ if p.epfd, e = syscall.EpollCreate(16); e != 0 {
+ return nil, os.NewSyscallError("epoll_create", e)
+ }
+ p.events = make(map[int]uint32)
+ return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
+ var ev syscall.EpollEvent
+ var already bool
+ ev.Fd = int32(fd)
+ ev.Events, already = p.events[fd]
+ if !repeat {
+ ev.Events |= syscall.EPOLLONESHOT
+ }
+ if mode == 'r' {
+ ev.Events |= readFlags
+ } else {
+ ev.Events |= writeFlags
+ }
+
+ var op int
+ if already {
+ op = syscall.EPOLL_CTL_MOD
+ } else {
+ op = syscall.EPOLL_CTL_ADD
+ }
+ if e := syscall.EpollCtl(p.epfd, op, fd, &ev); e != 0 {
+ return os.NewSyscallError("epoll_ctl", e)
+ }
+ p.events[fd] = ev.Events
+ return nil
+}
+
+func (p *pollster) StopWaiting(fd int, bits uint) {
+ events, already := p.events[fd]
+ if !already {
+ print("Epoll unexpected fd=", fd, "\n")
+ return
+ }
+
+ // If syscall.EPOLLONESHOT is not set, the wait
+ // is a repeating wait, so don't change it.
+ if events&syscall.EPOLLONESHOT == 0 {
+ return
+ }
+
+ // Disable the given bits.
+ // If we're still waiting for other events, modify the fd
+ // event in the kernel. Otherwise, delete it.
+ events &= ^uint32(bits)
+ if int32(events)&^syscall.EPOLLONESHOT != 0 {
+ var ev syscall.EpollEvent
+ ev.Fd = int32(fd)
+ ev.Events = events
+ if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &ev); e != 0 {
+ print("Epoll modify fd=", fd, ": ", os.Errno(e).String(), "\n")
+ }
+ p.events[fd] = events
+ } else {
+ if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); e != 0 {
+ print("Epoll delete fd=", fd, ": ", os.Errno(e).String(), "\n")
+ }
+ p.events[fd] = 0, false
+ }
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+ if mode == 'r' {
+ p.StopWaiting(fd, readFlags)
+ } else {
+ p.StopWaiting(fd, writeFlags)
+ }
+}
+
+func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
+ // Get an event.
+ var evarray [1]syscall.EpollEvent
+ ev := &evarray[0]
+ var msec int = -1
+ if nsec > 0 {
+ msec = int((nsec + 1e6 - 1) / 1e6)
+ }
+ n, e := syscall.EpollWait(p.epfd, evarray[0:], msec)
+ for e == syscall.EAGAIN || e == syscall.EINTR {
+ n, e = syscall.EpollWait(p.epfd, evarray[0:], msec)
+ }
+ if e != 0 {
+ return -1, 0, os.NewSyscallError("epoll_wait", e)
+ }
+ if n == 0 {
+ return -1, 0, nil
+ }
+ fd = int(ev.Fd)
+
+ if ev.Events&writeFlags != 0 {
+ p.StopWaiting(fd, writeFlags)
+ return fd, 'w', nil
+ }
+ if ev.Events&readFlags != 0 {
+ p.StopWaiting(fd, readFlags)
+ return fd, 'r', nil
+ }
+
+ // Other events are error conditions - wake whoever is waiting.
+ events, _ := p.events[fd]
+ if events&writeFlags != 0 {
+ p.StopWaiting(fd, writeFlags)
+ return fd, 'w', nil
+ }
+ p.StopWaiting(fd, readFlags)
+ return fd, 'r', nil
+}
+
+func (p *pollster) Close() os.Error {
+ return os.NewSyscallError("close", syscall.Close(p.epfd))
+}
diff --git a/libgo/go/net/fd_rtems.go b/libgo/go/net/fd_rtems.go
new file mode 100644
index 000000000..61759ca6e
--- /dev/null
+++ b/libgo/go/net/fd_rtems.go
@@ -0,0 +1,137 @@
+// 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.
+
+// Waiting for FDs via select(2).
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+type pollster struct {
+ readFds, writeFds, repeatFds *syscall.FdSet_t
+ maxFd int
+ readyReadFds, readyWriteFds *syscall.FdSet_t
+ nReady int
+ lastFd int
+}
+
+func newpollster() (p *pollster, err os.Error) {
+ p = new(pollster)
+ p.readFds = new(syscall.FdSet_t)
+ p.writeFds = new(syscall.FdSet_t)
+ p.repeatFds = new(syscall.FdSet_t)
+ p.readyReadFds = new(syscall.FdSet_t)
+ p.readyWriteFds = new(syscall.FdSet_t)
+ p.maxFd = -1
+ p.nReady = 0
+ p.lastFd = 0
+ return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
+ if mode == 'r' {
+ syscall.FDSet(fd, p.readFds)
+ } else {
+ syscall.FDSet(fd, p.writeFds)
+ }
+
+ if repeat {
+ syscall.FDSet(fd, p.repeatFds)
+ }
+
+ if fd > p.maxFd {
+ p.maxFd = fd
+ }
+
+ return nil
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+ if mode == 'r' {
+ if !syscall.FDIsSet(fd, p.readFds) {
+ print("Select unexpected fd=", fd, " for read\n")
+ return
+ }
+ syscall.FDClr(fd, p.readFds)
+ } else {
+ if !syscall.FDIsSet(fd, p.writeFds) {
+ print("Select unexpected fd=", fd, " for write\n")
+ return
+ }
+ syscall.FDClr(fd, p.writeFds)
+ }
+
+ // Doesn't matter if not already present.
+ syscall.FDClr(fd, p.repeatFds)
+
+ // We don't worry about maxFd here.
+}
+
+func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
+ if p.nReady == 0 {
+ var timeout *syscall.Timeval
+ var tv syscall.Timeval
+ timeout = nil
+ if nsec > 0 {
+ tv = syscall.NsecToTimeval(nsec)
+ timeout = &tv
+ }
+
+ var n, e int
+ var tmpReadFds, tmpWriteFds syscall.FdSet_t
+ for {
+ // Temporary syscall.FdSet_ts into which the values are copied
+ // because select mutates the values.
+ tmpReadFds = *p.readFds
+ tmpWriteFds = *p.writeFds
+
+ n, e = syscall.Select(p.maxFd + 1, &tmpReadFds, &tmpWriteFds, nil, timeout)
+ if e != syscall.EINTR {
+ break
+ }
+ }
+ if e != 0 {
+ return -1, 0, os.NewSyscallError("select", e)
+ }
+ if n == 0 {
+ return -1, 0, nil
+ }
+
+ p.nReady = n
+ *p.readyReadFds = tmpReadFds
+ *p.readyWriteFds = tmpWriteFds
+ p.lastFd = 0
+ }
+
+ flag := false
+ for i := p.lastFd; i < p.maxFd + 1; i++ {
+ if syscall.FDIsSet(i, p.readyReadFds) {
+ flag = true
+ mode = 'r'
+ syscall.FDClr(i, p.readyReadFds)
+ } else if syscall.FDIsSet(i, p.readyWriteFds) {
+ flag = true
+ mode = 'w'
+ syscall.FDClr(i, p.readyWriteFds)
+ }
+ if flag {
+ if !syscall.FDIsSet(i, p.repeatFds) {
+ p.DelFD(i, mode)
+ }
+ p.nReady--
+ p.lastFd = i
+ return i, mode, nil
+ }
+ }
+
+ // Will not reach here. Just to shut up the compiler.
+ return -1, 0, nil
+}
+
+func (p *pollster) Close() os.Error {
+ return nil
+}
diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go
new file mode 100644
index 000000000..9b91eb398
--- /dev/null
+++ b/libgo/go/net/fd_windows.go
@@ -0,0 +1,555 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "runtime"
+ "sync"
+ "syscall"
+ "time"
+ "unsafe"
+)
+
+// IO completion result parameters.
+type ioResult struct {
+ key uint32
+ qty uint32
+ errno int
+}
+
+// Network file descriptor.
+type netFD struct {
+ // locking/lifetime of sysfd
+ sysmu sync.Mutex
+ sysref int
+ closing bool
+
+ // immutable until Close
+ sysfd int
+ family int
+ proto int
+ cr chan *ioResult
+ cw chan *ioResult
+ net string
+ laddr Addr
+ raddr Addr
+
+ // owned by client
+ rdeadline_delta int64
+ rdeadline int64
+ rio sync.Mutex
+ wdeadline_delta int64
+ wdeadline int64
+ wio sync.Mutex
+}
+
+type InvalidConnError struct{}
+
+func (e *InvalidConnError) String() string { return "invalid net.Conn" }
+func (e *InvalidConnError) Temporary() bool { return false }
+func (e *InvalidConnError) Timeout() bool { return false }
+
+// pollServer will run around waiting for io completion request
+// to arrive. Every request received will contain channel to signal
+// io owner about the completion.
+
+type pollServer struct {
+ iocp int32
+}
+
+func newPollServer() (s *pollServer, err os.Error) {
+ s = new(pollServer)
+ var e int
+ if s.iocp, e = syscall.CreateIoCompletionPort(-1, 0, 0, 1); e != 0 {
+ return nil, os.NewSyscallError("CreateIoCompletionPort", e)
+ }
+ go s.Run()
+ return s, nil
+}
+
+type ioPacket struct {
+ // Used by IOCP interface,
+ // it must be first field of the struct,
+ // as our code rely on it.
+ o syscall.Overlapped
+
+ // Link to the io owner.
+ c chan *ioResult
+
+ w *syscall.WSABuf
+}
+
+func (s *pollServer) getCompletedIO() (ov *syscall.Overlapped, result *ioResult, err os.Error) {
+ var r ioResult
+ var o *syscall.Overlapped
+ _, e := syscall.GetQueuedCompletionStatus(s.iocp, &r.qty, &r.key, &o, syscall.INFINITE)
+ switch {
+ case e == 0:
+ // Dequeued successfully completed io packet.
+ return o, &r, nil
+ case e == syscall.WAIT_TIMEOUT && o == nil:
+ // Wait has timed out (should not happen now, but might be used in the future).
+ return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e)
+ case o == nil:
+ // Failed to dequeue anything -> report the error.
+ return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e)
+ default:
+ // Dequeued failed io packet.
+ r.errno = e
+ return o, &r, nil
+ }
+ return
+}
+
+func (s *pollServer) Run() {
+ for {
+ o, r, err := s.getCompletedIO()
+ if err != nil {
+ panic("Run pollServer: " + err.String() + "\n")
+ }
+ p := (*ioPacket)(unsafe.Pointer(o))
+ p.c <- r
+ }
+}
+
+// Network FD methods.
+// All the network FDs use a single pollServer.
+
+var pollserver *pollServer
+var onceStartServer sync.Once
+
+func startServer() {
+ p, err := newPollServer()
+ if err != nil {
+ panic("Start pollServer: " + err.String() + "\n")
+ }
+ pollserver = p
+
+ go timeoutIO()
+}
+
+var initErr os.Error
+
+func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
+ if initErr != nil {
+ return nil, initErr
+ }
+ onceStartServer.Do(startServer)
+ // Associate our socket with pollserver.iocp.
+ if _, e := syscall.CreateIoCompletionPort(int32(fd), pollserver.iocp, 0, 0); e != 0 {
+ return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)}
+ }
+ f = &netFD{
+ sysfd: fd,
+ family: family,
+ proto: proto,
+ cr: make(chan *ioResult, 1),
+ cw: make(chan *ioResult, 1),
+ net: net,
+ laddr: laddr,
+ raddr: raddr,
+ }
+ runtime.SetFinalizer(f, (*netFD).Close)
+ return f, nil
+}
+
+// Add a reference to this fd.
+func (fd *netFD) incref() {
+ fd.sysmu.Lock()
+ fd.sysref++
+ fd.sysmu.Unlock()
+}
+
+// Remove a reference to this FD and close if we've been asked to do so (and
+// there are no references left.
+func (fd *netFD) decref() {
+ fd.sysmu.Lock()
+ fd.sysref--
+ if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
+ // In case the user has set linger, switch to blocking mode so
+ // the close blocks. As long as this doesn't happen often, we
+ // can handle the extra OS processes. Otherwise we'll need to
+ // use the pollserver for Close too. Sigh.
+ syscall.SetNonblock(fd.sysfd, false)
+ closesocket(fd.sysfd)
+ fd.sysfd = -1
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(fd, nil)
+ }
+ fd.sysmu.Unlock()
+}
+
+func (fd *netFD) Close() os.Error {
+ if fd == nil || fd.sysfd == -1 {
+ return os.EINVAL
+ }
+
+ fd.incref()
+ syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
+ fd.closing = true
+ fd.decref()
+ return nil
+}
+
+func newWSABuf(p []byte) *syscall.WSABuf {
+ var p0 *byte
+ if len(p) > 0 {
+ p0 = (*byte)(unsafe.Pointer(&p[0]))
+ }
+ return &syscall.WSABuf{uint32(len(p)), p0}
+}
+
+func waitPacket(fd *netFD, pckt *ioPacket, mode int) (r *ioResult) {
+ var delta int64
+ if mode == 'r' {
+ delta = fd.rdeadline_delta
+ }
+ if mode == 'w' {
+ delta = fd.wdeadline_delta
+ }
+ if delta <= 0 {
+ return <-pckt.c
+ }
+
+ select {
+ case r = <-pckt.c:
+ case <-time.After(delta):
+ a := &arg{f: cancel, fd: fd, pckt: pckt, c: make(chan int)}
+ ioChan <- a
+ <-a.c
+ r = <-pckt.c
+ if r.errno == 995 { // IO Canceled
+ r.errno = syscall.EWOULDBLOCK
+ }
+ }
+ return r
+}
+
+const (
+ read = iota
+ readfrom
+ write
+ writeto
+ cancel
+)
+
+type arg struct {
+ f int
+ fd *netFD
+ pckt *ioPacket
+ done *uint32
+ flags *uint32
+ rsa *syscall.RawSockaddrAny
+ size *int32
+ sa *syscall.Sockaddr
+ c chan int
+}
+
+var ioChan chan *arg = make(chan *arg)
+
+func timeoutIO() {
+ // CancelIO only cancels all pending input and output (I/O) operations that are
+ // issued by the calling thread for the specified file, does not cancel I/O
+ // operations that other threads issue for a file handle. So we need do all timeout
+ // I/O in single OS thread.
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ for {
+ o := <-ioChan
+ var e int
+ switch o.f {
+ case read:
+ e = syscall.WSARecv(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, o.flags, &o.pckt.o, nil)
+ case readfrom:
+ e = syscall.WSARecvFrom(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, o.flags, o.rsa, o.size, &o.pckt.o, nil)
+ case write:
+ e = syscall.WSASend(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, uint32(0), &o.pckt.o, nil)
+ case writeto:
+ e = syscall.WSASendto(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, 0, *o.sa, &o.pckt.o, nil)
+ case cancel:
+ _, e = syscall.CancelIo(uint32(o.fd.sysfd))
+ }
+ o.c <- e
+ }
+}
+
+func (fd *netFD) Read(p []byte) (n int, err os.Error) {
+ if fd == nil {
+ return 0, os.EINVAL
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfd == -1 {
+ return 0, os.EINVAL
+ }
+ // Submit receive request.
+ var pckt ioPacket
+ pckt.c = fd.cr
+ pckt.w = newWSABuf(p)
+ var done uint32
+ flags := uint32(0)
+ var e int
+ if fd.rdeadline_delta > 0 {
+ a := &arg{f: read, fd: fd, pckt: &pckt, done: &done, flags: &flags, c: make(chan int)}
+ ioChan <- a
+ e = <-a.c
+ } else {
+ e = syscall.WSARecv(uint32(fd.sysfd), pckt.w, 1, &done, &flags, &pckt.o, nil)
+ }
+ switch e {
+ case 0:
+ // IO completed immediately, but we need to get our completion message anyway.
+ case syscall.ERROR_IO_PENDING:
+ // IO started, and we have to wait for it's completion.
+ default:
+ return 0, &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(e)}
+ }
+ // Wait for our request to complete.
+ r := waitPacket(fd, &pckt, 'r')
+ if r.errno != 0 {
+ err = &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(r.errno)}
+ }
+ n = int(r.qty)
+ if err == nil && n == 0 {
+ err = os.EOF
+ }
+ return
+}
+
+func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
+ if fd == nil {
+ return 0, nil, os.EINVAL
+ }
+ if len(p) == 0 {
+ return 0, nil, nil
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfd == -1 {
+ return 0, nil, os.EINVAL
+ }
+ // Submit receive request.
+ var pckt ioPacket
+ pckt.c = fd.cr
+ pckt.w = newWSABuf(p)
+ var done uint32
+ flags := uint32(0)
+ var rsa syscall.RawSockaddrAny
+ l := int32(unsafe.Sizeof(rsa))
+ var e int
+ if fd.rdeadline_delta > 0 {
+ a := &arg{f: readfrom, fd: fd, pckt: &pckt, done: &done, flags: &flags, rsa: &rsa, size: &l, c: make(chan int)}
+ ioChan <- a
+ e = <-a.c
+ } else {
+ e = syscall.WSARecvFrom(uint32(fd.sysfd), pckt.w, 1, &done, &flags, &rsa, &l, &pckt.o, nil)
+ }
+ switch e {
+ case 0:
+ // IO completed immediately, but we need to get our completion message anyway.
+ case syscall.ERROR_IO_PENDING:
+ // IO started, and we have to wait for it's completion.
+ default:
+ return 0, nil, &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(e)}
+ }
+ // Wait for our request to complete.
+ r := waitPacket(fd, &pckt, 'r')
+ if r.errno != 0 {
+ err = &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(r.errno)}
+ }
+ n = int(r.qty)
+ sa, _ = rsa.Sockaddr()
+ return
+}
+
+func (fd *netFD) Write(p []byte) (n int, err os.Error) {
+ if fd == nil {
+ return 0, os.EINVAL
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfd == -1 {
+ return 0, os.EINVAL
+ }
+ // Submit send request.
+ var pckt ioPacket
+ pckt.c = fd.cw
+ pckt.w = newWSABuf(p)
+ var done uint32
+ var e int
+ if fd.wdeadline_delta > 0 {
+ a := &arg{f: write, fd: fd, pckt: &pckt, done: &done, c: make(chan int)}
+ ioChan <- a
+ e = <-a.c
+ } else {
+ e = syscall.WSASend(uint32(fd.sysfd), pckt.w, 1, &done, uint32(0), &pckt.o, nil)
+ }
+ switch e {
+ case 0:
+ // IO completed immediately, but we need to get our completion message anyway.
+ case syscall.ERROR_IO_PENDING:
+ // IO started, and we have to wait for it's completion.
+ default:
+ return 0, &OpError{"WSASend", fd.net, fd.laddr, os.Errno(e)}
+ }
+ // Wait for our request to complete.
+ r := waitPacket(fd, &pckt, 'w')
+ if r.errno != 0 {
+ err = &OpError{"WSASend", fd.net, fd.laddr, os.Errno(r.errno)}
+ }
+ n = int(r.qty)
+ return
+}
+
+func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
+ if fd == nil {
+ return 0, os.EINVAL
+ }
+ if len(p) == 0 {
+ return 0, nil
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfd == -1 {
+ return 0, os.EINVAL
+ }
+ // Submit send request.
+ var pckt ioPacket
+ pckt.c = fd.cw
+ pckt.w = newWSABuf(p)
+ var done uint32
+ var e int
+ if fd.wdeadline_delta > 0 {
+ a := &arg{f: writeto, fd: fd, pckt: &pckt, done: &done, sa: &sa, c: make(chan int)}
+ ioChan <- a
+ e = <-a.c
+ } else {
+ e = syscall.WSASendto(uint32(fd.sysfd), pckt.w, 1, &done, 0, sa, &pckt.o, nil)
+ }
+ switch e {
+ case 0:
+ // IO completed immediately, but we need to get our completion message anyway.
+ case syscall.ERROR_IO_PENDING:
+ // IO started, and we have to wait for it's completion.
+ default:
+ return 0, &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(e)}
+ }
+ // Wait for our request to complete.
+ r := waitPacket(fd, &pckt, 'w')
+ if r.errno != 0 {
+ err = &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(r.errno)}
+ }
+ n = int(r.qty)
+ return
+}
+
+func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
+ if fd == nil || fd.sysfd == -1 {
+ return nil, os.EINVAL
+ }
+ fd.incref()
+ defer fd.decref()
+
+ // Get new socket.
+ // See ../syscall/exec.go for description of ForkLock.
+ syscall.ForkLock.RLock()
+ s, e := syscall.Socket(fd.family, fd.proto, 0)
+ if e != 0 {
+ syscall.ForkLock.RUnlock()
+ return nil, os.Errno(e)
+ }
+ syscall.CloseOnExec(s)
+ syscall.ForkLock.RUnlock()
+
+ // Associate our new socket with IOCP.
+ onceStartServer.Do(startServer)
+ if _, e = syscall.CreateIoCompletionPort(int32(s), pollserver.iocp, 0, 0); e != 0 {
+ return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
+ }
+
+ // Submit accept request.
+ // Will use new unique channel here, because, unlike Read or Write,
+ // Accept is expected to be executed by many goroutines simultaniously.
+ var pckt ioPacket
+ pckt.c = make(chan *ioResult)
+ attrs, e := syscall.AcceptIOCP(fd.sysfd, s, &pckt.o)
+ switch e {
+ case 0:
+ // IO completed immediately, but we need to get our completion message anyway.
+ case syscall.ERROR_IO_PENDING:
+ // IO started, and we have to wait for it's completion.
+ default:
+ closesocket(s)
+ return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(e)}
+ }
+
+ // Wait for peer connection.
+ r := <-pckt.c
+ if r.errno != 0 {
+ closesocket(s)
+ return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(r.errno)}
+ }
+
+ // Inherit properties of the listening socket.
+ e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd)
+ if e != 0 {
+ closesocket(s)
+ return nil, &OpError{"Setsockopt", fd.net, fd.laddr, os.Errno(r.errno)}
+ }
+
+ // Get local and peer addr out of AcceptEx buffer.
+ lsa, rsa := syscall.GetAcceptIOCPSockaddrs(attrs)
+
+ // Create our netFD and return it for further use.
+ laddr := toAddr(lsa)
+ raddr := toAddr(rsa)
+
+ f := &netFD{
+ sysfd: s,
+ family: fd.family,
+ proto: fd.proto,
+ cr: make(chan *ioResult, 1),
+ cw: make(chan *ioResult, 1),
+ net: fd.net,
+ laddr: laddr,
+ raddr: raddr,
+ }
+ runtime.SetFinalizer(f, (*netFD).Close)
+ return f, nil
+}
+
+func closesocket(s int) (errno int) {
+ return syscall.Closesocket(int32(s))
+}
+
+func init() {
+ var d syscall.WSAData
+ e := syscall.WSAStartup(uint32(0x101), &d)
+ if e != 0 {
+ initErr = os.NewSyscallError("WSAStartup", e)
+ }
+}
+
+func (fd *netFD) dup() (f *os.File, err os.Error) {
+ // TODO: Implement this
+ return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
+}
+
+func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) {
+ return 0, 0, 0, nil, os.EAFNOSUPPORT
+}
+
+func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) {
+ return 0, 0, os.EAFNOSUPPORT
+}
diff --git a/libgo/go/net/hosts.go b/libgo/go/net/hosts.go
new file mode 100644
index 000000000..8525f578d
--- /dev/null
+++ b/libgo/go/net/hosts.go
@@ -0,0 +1,86 @@
+// 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.
+
+// Read static host/IP entries from /etc/hosts.
+
+package net
+
+import (
+ "os"
+ "sync"
+)
+
+const cacheMaxAge = int64(300) // 5 minutes.
+
+// hostsPath points to the file with static IP/address entries.
+var hostsPath = "/etc/hosts"
+
+// Simple cache.
+var hosts struct {
+ sync.Mutex
+ byName map[string][]string
+ byAddr map[string][]string
+ time int64
+ path string
+}
+
+func readHosts() {
+ now, _, _ := os.Time()
+ hp := hostsPath
+ if len(hosts.byName) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp {
+ hs := make(map[string][]string)
+ is := make(map[string][]string)
+ var file *file
+ if file, _ = open(hp); file == nil {
+ return
+ }
+ for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+ if i := byteIndex(line, '#'); i >= 0 {
+ // Discard comments.
+ line = line[0:i]
+ }
+ f := getFields(line)
+ if len(f) < 2 || ParseIP(f[0]) == nil {
+ continue
+ }
+ for i := 1; i < len(f); i++ {
+ h := f[i]
+ hs[h] = append(hs[h], f[0])
+ is[f[0]] = append(is[f[0]], h)
+ }
+ }
+ // Update the data cache.
+ hosts.time, _, _ = os.Time()
+ hosts.path = hp
+ hosts.byName = hs
+ hosts.byAddr = is
+ file.close()
+ }
+}
+
+// lookupStaticHosts looks up the addresses for the given host from /etc/hosts.
+func lookupStaticHost(host string) []string {
+ hosts.Lock()
+ defer hosts.Unlock()
+ readHosts()
+ if len(hosts.byName) != 0 {
+ if ips, ok := hosts.byName[host]; ok {
+ return ips
+ }
+ }
+ return nil
+}
+
+// rlookupStaticHosts looks up the hosts for the given address from /etc/hosts.
+func lookupStaticAddr(addr string) []string {
+ hosts.Lock()
+ defer hosts.Unlock()
+ readHosts()
+ if len(hosts.byAddr) != 0 {
+ if hosts, ok := hosts.byAddr[addr]; ok {
+ return hosts
+ }
+ }
+ return nil
+}
diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go
new file mode 100644
index 000000000..84cd92e37
--- /dev/null
+++ b/libgo/go/net/hosts_test.go
@@ -0,0 +1,54 @@
+// 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 net
+
+import (
+ "testing"
+)
+
+type hostTest struct {
+ host string
+ ips []IP
+}
+
+
+var hosttests = []hostTest{
+ {"odin", []IP{
+ IPv4(127, 0, 0, 2),
+ IPv4(127, 0, 0, 3),
+ ParseIP("::2"),
+ }},
+ {"thor", []IP{
+ IPv4(127, 1, 1, 1),
+ }},
+ {"loki", []IP{}},
+ {"ullr", []IP{
+ IPv4(127, 1, 1, 2),
+ }},
+ {"ullrhost", []IP{
+ IPv4(127, 1, 1, 2),
+ }},
+}
+
+func TestLookupStaticHost(t *testing.T) {
+ p := hostsPath
+ hostsPath = "hosts_testdata"
+ for i := 0; i < len(hosttests); i++ {
+ tt := hosttests[i]
+ ips := lookupStaticHost(tt.host)
+ if len(ips) != len(tt.ips) {
+ t.Errorf("# of hosts = %v; want %v",
+ len(ips), len(tt.ips))
+ return
+ }
+ for k, v := range ips {
+ if tt.ips[k].String() != v {
+ t.Errorf("lookupStaticHost(%q) = %v; want %v",
+ tt.host, v, tt.ips[k])
+ }
+ }
+ }
+ hostsPath = p
+}
diff --git a/libgo/go/net/hosts_testdata b/libgo/go/net/hosts_testdata
new file mode 100644
index 000000000..b60176389
--- /dev/null
+++ b/libgo/go/net/hosts_testdata
@@ -0,0 +1,12 @@
+255.255.255.255 broadcasthost
+127.0.0.2 odin
+127.0.0.3 odin # inline comment
+::2 odin
+127.1.1.1 thor
+# aliases
+127.1.1.2 ullr ullrhost
+# Bogus entries that must be ignored.
+123.123.123 loki
+321.321.321.321
+# TODO(yvesj): Should we be able to parse this? From a Darwin system.
+fe80::1%lo0 localhost
diff --git a/libgo/go/net/ip.go b/libgo/go/net/ip.go
new file mode 100644
index 000000000..e82224a28
--- /dev/null
+++ b/libgo/go/net/ip.go
@@ -0,0 +1,446 @@
+// 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.
+
+// IP address manipulations
+//
+// IPv4 addresses are 4 bytes; IPv6 addresses are 16 bytes.
+// An IPv4 address can be converted to an IPv6 address by
+// adding a canonical prefix (10 zeros, 2 0xFFs).
+// This library accepts either size of byte array but always
+// returns 16-byte addresses.
+
+package net
+
+// IP address lengths (bytes).
+const (
+ IPv4len = 4
+ IPv6len = 16
+)
+
+// An IP is a single IP address, an array of bytes.
+// Functions in this package accept either 4-byte (IP v4)
+// or 16-byte (IP v6) arrays as input. Unless otherwise
+// specified, functions in this package always return
+// IP addresses in 16-byte form using the canonical
+// embedding.
+//
+// Note that in this documentation, referring to an
+// IP address as an IPv4 address or an IPv6 address
+// is a semantic property of the address, not just the
+// length of the byte array: a 16-byte array can still
+// be an IPv4 address.
+type IP []byte
+
+// An IP mask is an IP address.
+type IPMask []byte
+
+// IPv4 returns the IP address (in 16-byte form) of the
+// IPv4 address a.b.c.d.
+func IPv4(a, b, c, d byte) IP {
+ p := make(IP, IPv6len)
+ for i := 0; i < 10; i++ {
+ p[i] = 0
+ }
+ p[10] = 0xff
+ p[11] = 0xff
+ p[12] = a
+ p[13] = b
+ p[14] = c
+ p[15] = d
+ return p
+}
+
+// IPv4Mask returns the IP mask (in 16-byte form) of the
+// IPv4 mask a.b.c.d.
+func IPv4Mask(a, b, c, d byte) IPMask {
+ p := make(IPMask, IPv6len)
+ for i := 0; i < 12; i++ {
+ p[i] = 0xff
+ }
+ p[12] = a
+ p[13] = b
+ p[14] = c
+ p[15] = d
+ return p
+}
+
+// Well-known IPv4 addresses
+var (
+ IPv4bcast = IPv4(255, 255, 255, 255) // broadcast
+ IPv4allsys = IPv4(224, 0, 0, 1) // all systems
+ IPv4allrouter = IPv4(224, 0, 0, 2) // all routers
+ IPv4zero = IPv4(0, 0, 0, 0) // all zeros
+)
+
+// Well-known IPv6 addresses
+var (
+ IPzero = make(IP, IPv6len) // all zeros
+)
+
+// Is p all zeros?
+func isZeros(p IP) bool {
+ for i := 0; i < len(p); i++ {
+ if p[i] != 0 {
+ return false
+ }
+ }
+ return true
+}
+
+// To4 converts the IPv4 address ip to a 4-byte representation.
+// If ip is not an IPv4 address, To4 returns nil.
+func (ip IP) To4() IP {
+ if len(ip) == IPv4len {
+ return ip
+ }
+ if len(ip) == IPv6len &&
+ isZeros(ip[0:10]) &&
+ ip[10] == 0xff &&
+ ip[11] == 0xff {
+ return ip[12:16]
+ }
+ return nil
+}
+
+// To16 converts the IP address ip to a 16-byte representation.
+// If ip is not an IP address (it is the wrong length), To16 returns nil.
+func (ip IP) To16() IP {
+ if len(ip) == IPv4len {
+ return IPv4(ip[0], ip[1], ip[2], ip[3])
+ }
+ if len(ip) == IPv6len {
+ return ip
+ }
+ return nil
+}
+
+// Default route masks for IPv4.
+var (
+ classAMask = IPv4Mask(0xff, 0, 0, 0)
+ classBMask = IPv4Mask(0xff, 0xff, 0, 0)
+ classCMask = IPv4Mask(0xff, 0xff, 0xff, 0)
+)
+
+// DefaultMask returns the default IP mask for the IP address ip.
+// Only IPv4 addresses have default masks; DefaultMask returns
+// nil if ip is not a valid IPv4 address.
+func (ip IP) DefaultMask() IPMask {
+ if ip = ip.To4(); ip == nil {
+ return nil
+ }
+ switch true {
+ case ip[0] < 0x80:
+ return classAMask
+ case ip[0] < 0xC0:
+ return classBMask
+ default:
+ return classCMask
+ }
+ return nil // not reached
+}
+
+// Mask returns the result of masking the IP address ip with mask.
+func (ip IP) Mask(mask IPMask) IP {
+ n := len(ip)
+ if n != len(mask) {
+ return nil
+ }
+ out := make(IP, n)
+ for i := 0; i < n; i++ {
+ out[i] = ip[i] & mask[i]
+ }
+ return out
+}
+
+// Convert i to decimal string.
+func itod(i uint) string {
+ if i == 0 {
+ return "0"
+ }
+
+ // Assemble decimal in reverse order.
+ var b [32]byte
+ bp := len(b)
+ for ; i > 0; i /= 10 {
+ bp--
+ b[bp] = byte(i%10) + '0'
+ }
+
+ return string(b[bp:])
+}
+
+// Convert i to hexadecimal string.
+func itox(i uint) string {
+ if i == 0 {
+ return "0"
+ }
+
+ // Assemble hexadecimal in reverse order.
+ var b [32]byte
+ bp := len(b)
+ for ; i > 0; i /= 16 {
+ bp--
+ b[bp] = "0123456789abcdef"[byte(i%16)]
+ }
+
+ return string(b[bp:])
+}
+
+// String returns the string form of the IP address ip.
+// If the address is an IPv4 address, the string representation
+// is dotted decimal ("74.125.19.99"). Otherwise the representation
+// is IPv6 ("2001:4860:0:2001::68").
+func (ip IP) String() string {
+ p := ip
+
+ if len(ip) == 0 {
+ return ""
+ }
+
+ // If IPv4, use dotted notation.
+ if p4 := p.To4(); len(p4) == 4 {
+ return itod(uint(p4[0])) + "." +
+ itod(uint(p4[1])) + "." +
+ itod(uint(p4[2])) + "." +
+ itod(uint(p4[3]))
+ }
+ if len(p) != IPv6len {
+ return "?"
+ }
+
+ // Find longest run of zeros.
+ e0 := -1
+ e1 := -1
+ for i := 0; i < 16; i += 2 {
+ j := i
+ for j < 16 && p[j] == 0 && p[j+1] == 0 {
+ j += 2
+ }
+ if j > i && j-i > e1-e0 {
+ e0 = i
+ e1 = j
+ }
+ }
+ // The symbol "::" MUST NOT be used to shorten just one 16 bit 0 field.
+ if e1-e0 <= 2 {
+ e0 = -1
+ e1 = -1
+ }
+
+ // Print with possible :: in place of run of zeros
+ var s string
+ for i := 0; i < 16; i += 2 {
+ if i == e0 {
+ s += "::"
+ i = e1
+ if i >= 16 {
+ break
+ }
+ } else if i > 0 {
+ s += ":"
+ }
+ s += itox((uint(p[i]) << 8) | uint(p[i+1]))
+ }
+ return s
+}
+
+// If mask is a sequence of 1 bits followed by 0 bits,
+// return the number of 1 bits.
+func simpleMaskLength(mask IPMask) int {
+ var n int
+ for i, v := range mask {
+ if v == 0xff {
+ n += 8
+ continue
+ }
+ // found non-ff byte
+ // count 1 bits
+ for v&0x80 != 0 {
+ n++
+ v <<= 1
+ }
+ // rest must be 0 bits
+ if v != 0 {
+ return -1
+ }
+ for i++; i < len(mask); i++ {
+ if mask[i] != 0 {
+ return -1
+ }
+ }
+ break
+ }
+ return n
+}
+
+// String returns the string representation of mask.
+// If the mask is in the canonical form--ones followed by zeros--the
+// string representation is just the decimal number of ones.
+// If the mask is in a non-canonical form, it is formatted
+// as an IP address.
+func (mask IPMask) String() string {
+ switch len(mask) {
+ case 4:
+ n := simpleMaskLength(mask)
+ if n >= 0 {
+ return itod(uint(n + (IPv6len-IPv4len)*8))
+ }
+ case 16:
+ n := simpleMaskLength(mask)
+ if n >= 12*8 {
+ return itod(uint(n - 12*8))
+ }
+ }
+ return IP(mask).String()
+}
+
+// Parse IPv4 address (d.d.d.d).
+func parseIPv4(s string) IP {
+ var p [IPv4len]byte
+ i := 0
+ for j := 0; j < IPv4len; j++ {
+ if i >= len(s) {
+ // Missing octets.
+ return nil
+ }
+ if j > 0 {
+ if s[i] != '.' {
+ return nil
+ }
+ i++
+ }
+ var (
+ n int
+ ok bool
+ )
+ n, i, ok = dtoi(s, i)
+ if !ok || n > 0xFF {
+ return nil
+ }
+ p[j] = byte(n)
+ }
+ if i != len(s) {
+ return nil
+ }
+ return IPv4(p[0], p[1], p[2], p[3])
+}
+
+// Parse IPv6 address. Many forms.
+// The basic form is a sequence of eight colon-separated
+// 16-bit hex numbers separated by colons,
+// as in 0123:4567:89ab:cdef:0123:4567:89ab:cdef.
+// Two exceptions:
+// * A run of zeros can be replaced with "::".
+// * The last 32 bits can be in IPv4 form.
+// Thus, ::ffff:1.2.3.4 is the IPv4 address 1.2.3.4.
+func parseIPv6(s string) IP {
+ p := make(IP, 16)
+ ellipsis := -1 // position of ellipsis in p
+ i := 0 // index in string s
+
+ // Might have leading ellipsis
+ if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
+ ellipsis = 0
+ i = 2
+ // Might be only ellipsis
+ if i == len(s) {
+ return p
+ }
+ }
+
+ // Loop, parsing hex numbers followed by colon.
+ j := 0
+L:
+ for j < IPv6len {
+ // Hex number.
+ n, i1, ok := xtoi(s, i)
+ if !ok || n > 0xFFFF {
+ return nil
+ }
+
+ // If followed by dot, might be in trailing IPv4.
+ if i1 < len(s) && s[i1] == '.' {
+ if ellipsis < 0 && j != IPv6len-IPv4len {
+ // Not the right place.
+ return nil
+ }
+ if j+IPv4len > IPv6len {
+ // Not enough room.
+ return nil
+ }
+ p4 := parseIPv4(s[i:])
+ if p4 == nil {
+ return nil
+ }
+ p[j] = p4[12]
+ p[j+1] = p4[13]
+ p[j+2] = p4[14]
+ p[j+3] = p4[15]
+ i = len(s)
+ j += 4
+ break
+ }
+
+ // Save this 16-bit chunk.
+ p[j] = byte(n >> 8)
+ p[j+1] = byte(n)
+ j += 2
+
+ // Stop at end of string.
+ i = i1
+ if i == len(s) {
+ break
+ }
+
+ // Otherwise must be followed by colon and more.
+ if s[i] != ':' && i+1 == len(s) {
+ return nil
+ }
+ i++
+
+ // Look for ellipsis.
+ if s[i] == ':' {
+ if ellipsis >= 0 { // already have one
+ return nil
+ }
+ ellipsis = j
+ if i++; i == len(s) { // can be at end
+ break
+ }
+ }
+ }
+
+ // Must have used entire string.
+ if i != len(s) {
+ return nil
+ }
+
+ // If didn't parse enough, expand ellipsis.
+ if j < IPv6len {
+ if ellipsis < 0 {
+ return nil
+ }
+ n := IPv6len - j
+ for k := j - 1; k >= ellipsis; k-- {
+ p[k+n] = p[k]
+ }
+ for k := ellipsis + n - 1; k >= ellipsis; k-- {
+ p[k] = 0
+ }
+ }
+ return p
+}
+
+// ParseIP parses s as an IP address, returning the result.
+// The string s can be in dotted decimal ("74.125.19.99")
+// or IPv6 ("2001:4860:0:2001::68") form.
+// If s is not a valid textual representation of an IP address,
+// ParseIP returns nil.
+func ParseIP(s string) IP {
+ p := parseIPv4(s)
+ if p != nil {
+ return p
+ }
+ return parseIPv6(s)
+}
diff --git a/libgo/go/net/ip_test.go b/libgo/go/net/ip_test.go
new file mode 100644
index 000000000..e29c3021d
--- /dev/null
+++ b/libgo/go/net/ip_test.go
@@ -0,0 +1,94 @@
+// 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 net
+
+import (
+ "testing"
+)
+
+func isEqual(a, b IP) bool {
+ if a == nil && b == nil {
+ return true
+ }
+ if a == nil || b == nil || len(a) != len(b) {
+ return false
+ }
+ for i := 0; i < len(a); i++ {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+type parseIPTest struct {
+ in string
+ out IP
+}
+
+var parseiptests = []parseIPTest{
+ {"127.0.1.2", IPv4(127, 0, 1, 2)},
+ {"127.0.0.1", IPv4(127, 0, 0, 1)},
+ {"127.0.0.256", nil},
+ {"abc", nil},
+ {"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)},
+ {"2001:4860:0:2001::68",
+ IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01,
+ 0, 0, 0, 0, 0, 0, 0x00, 0x68,
+ },
+ },
+ {"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)},
+}
+
+func TestParseIP(t *testing.T) {
+ for i := 0; i < len(parseiptests); i++ {
+ tt := parseiptests[i]
+ if out := ParseIP(tt.in); !isEqual(out, tt.out) {
+ t.Errorf("ParseIP(%#q) = %v, want %v", tt.in, out, tt.out)
+ }
+ }
+}
+
+type ipStringTest struct {
+ in IP
+ out string
+}
+
+var ipstringtests = []ipStringTest{
+ // cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation)
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+ 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
+ "2001:db8::123:12:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x1},
+ "2001:db8::1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1,
+ 0, 0, 0, 0x1, 0, 0, 0, 0x1},
+ "2001:db8:0:1:0:1:0:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0,
+ 0, 0x1, 0, 0, 0, 0x1, 0, 0},
+ "2001:db8:1:0:1:0:1:0"},
+ {IP{0x20, 0x1, 0, 0, 0, 0, 0, 0,
+ 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ "2001::1:0:0:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+ 0, 0x1, 0, 0, 0, 0, 0, 0},
+ "2001:db8:0:0:1::"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+ 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ "2001:db8::1:0:0:1"},
+ {IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0,
+ 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD},
+ "2001:db8::a:b:c:d"},
+}
+
+func TestIPString(t *testing.T) {
+ for i := 0; i < len(ipstringtests); i++ {
+ tt := ipstringtests[i]
+ if out := tt.in.String(); out != tt.out {
+ t.Errorf("IP.String(%v) = %#q, want %#q", tt.in, out, tt.out)
+ }
+ }
+}
diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go
new file mode 100644
index 000000000..562298bdf
--- /dev/null
+++ b/libgo/go/net/ipraw_test.go
@@ -0,0 +1,117 @@
+// 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.
+
+
+// TODO(cw): ListenPacket test, Read() test, ipv6 test &
+// Dial()/Listen() level tests
+
+package net
+
+import (
+ "bytes"
+ "flag"
+ "os"
+ "testing"
+)
+
+const ICMP_ECHO_REQUEST = 8
+const ICMP_ECHO_REPLY = 0
+
+// returns a suitable 'ping request' packet, with id & seq and a
+// payload length of pktlen
+func makePingRequest(id, seq, pktlen int, filler []byte) []byte {
+ p := make([]byte, pktlen)
+ copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1))
+
+ p[0] = ICMP_ECHO_REQUEST // type
+ p[1] = 0 // code
+ p[2] = 0 // cksum
+ p[3] = 0 // cksum
+ p[4] = uint8(id >> 8) // id
+ p[5] = uint8(id & 0xff) // id
+ p[6] = uint8(seq >> 8) // sequence
+ p[7] = uint8(seq & 0xff) // sequence
+
+ // calculate icmp checksum
+ cklen := len(p)
+ s := uint32(0)
+ for i := 0; i < (cklen - 1); i += 2 {
+ s += uint32(p[i+1])<<8 | uint32(p[i])
+ }
+ if cklen&1 == 1 {
+ s += uint32(p[cklen-1])
+ }
+ s = (s >> 16) + (s & 0xffff)
+ s = s + (s >> 16)
+
+ // place checksum back in header; using ^= avoids the
+ // assumption the checksum bytes are zero
+ p[2] ^= uint8(^s & 0xff)
+ p[3] ^= uint8(^s >> 8)
+
+ return p
+}
+
+func parsePingReply(p []byte) (id, seq int) {
+ id = int(p[4])<<8 | int(p[5])
+ seq = int(p[6])<<8 | int(p[7])
+ return
+}
+
+var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
+var dsthost = flag.String("dsthost", "localhost", "Destination for the ICMP ECHO request")
+
+// test (raw) IP socket using ICMP
+func TestICMP(t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Logf("test disabled; must be root")
+ return
+ }
+
+ var laddr *IPAddr
+ if *srchost != "" {
+ laddr, err := ResolveIPAddr(*srchost)
+ if err != nil {
+ t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *srchost, laddr, err)
+ }
+ }
+
+ raddr, err := ResolveIPAddr(*dsthost)
+ if err != nil {
+ t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *dsthost, raddr, err)
+ }
+
+ c, err := ListenIP("ip4:icmp", laddr)
+ if err != nil {
+ t.Fatalf(`net.ListenIP("ip4:icmp", %v) = %v, %v`, *srchost, c, err)
+ }
+
+ sendid := os.Getpid() & 0xffff
+ const sendseq = 61455
+ const pingpktlen = 128
+ sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Go Gadget Ping!!!"))
+
+ n, err := c.WriteToIP(sendpkt, raddr)
+ if err != nil || n != pingpktlen {
+ t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err)
+ }
+
+ c.SetTimeout(100e6)
+ resp := make([]byte, 1024)
+ for {
+ n, from, err := c.ReadFrom(resp)
+ if err != nil {
+ t.Fatalf(`ReadFrom(...) = %v, %v, %v`, n, from, err)
+ }
+ if resp[0] != ICMP_ECHO_REPLY {
+ continue
+ }
+ rcvid, rcvseq := parsePingReply(resp)
+ if rcvid != sendid || rcvseq != sendseq {
+ t.Fatalf(`Ping reply saw id,seq=0x%x,0x%x (expected 0x%x, 0x%x)`, rcvid, rcvseq, sendid, sendseq)
+ }
+ return
+ }
+ t.Fatalf("saw no ping return")
+}
diff --git a/libgo/go/net/iprawsock.go b/libgo/go/net/iprawsock.go
new file mode 100644
index 000000000..241be1509
--- /dev/null
+++ b/libgo/go/net/iprawsock.go
@@ -0,0 +1,358 @@
+// 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.
+
+// (Raw) IP sockets
+
+package net
+
+import (
+ "os"
+ "sync"
+ "syscall"
+)
+
+var onceReadProtocols sync.Once
+
+func sockaddrToIP(sa syscall.Sockaddr) Addr {
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return &IPAddr{sa.Addr[0:]}
+ case *syscall.SockaddrInet6:
+ return &IPAddr{sa.Addr[0:]}
+ }
+ return nil
+}
+
+// IPAddr represents the address of a IP end point.
+type IPAddr struct {
+ IP IP
+}
+
+// Network returns the address's network name, "ip".
+func (a *IPAddr) Network() string { return "ip" }
+
+func (a *IPAddr) String() string {
+ if a == nil {
+ return "<nil>"
+ }
+ return a.IP.String()
+}
+
+func (a *IPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if ip := a.IP.To4(); ip != nil {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+ return ipToSockaddr(family, a.IP, 0)
+}
+
+func (a *IPAddr) toAddr() sockaddr {
+ if a == nil { // nil *IPAddr
+ return nil // nil interface
+ }
+ return a
+}
+
+// ResolveIPAddr parses addr as a IP address and resolves domain
+// names to numeric addresses. A literal IPv6 host address must be
+// enclosed in square brackets, as in "[::]".
+func ResolveIPAddr(addr string) (*IPAddr, os.Error) {
+ ip, err := hostToIP(addr)
+ if err != nil {
+ return nil, err
+ }
+ return &IPAddr{ip}, nil
+}
+
+// IPConn is the implementation of the Conn and PacketConn
+// interfaces for IP network connections.
+type IPConn struct {
+ fd *netFD
+}
+
+func newIPConn(fd *netFD) *IPConn { return &IPConn{fd} }
+
+func (c *IPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *IPConn) Read(b []byte) (n int, err os.Error) {
+ n, _, err = c.ReadFrom(b)
+ return
+}
+
+// Write implements the net.Conn Write method.
+func (c *IPConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the IP connection.
+func (c *IPConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address.
+func (c *IPConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *IPAddr.
+func (c *IPConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *IPConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *IPConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *IPConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *IPConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *IPConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// IP-specific methods.
+
+// ReadFromIP reads a IP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromIP can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetTimeout and
+// SetReadTimeout.
+func (c *IPConn) ReadFromIP(b []byte) (n int, addr *IPAddr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ // TODO(cw,rsc): consider using readv if we know the family
+ // type to avoid the header trim/copy
+ n, sa, err := c.fd.ReadFrom(b)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ addr = &IPAddr{sa.Addr[0:]}
+ if len(b) >= 4 { // discard ipv4 header
+ hsize := (int(b[0]) & 0xf) * 4
+ copy(b, b[hsize:])
+ n -= hsize
+ }
+ case *syscall.SockaddrInet6:
+ addr = &IPAddr{sa.Addr[0:]}
+ }
+ return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, uaddr, err := c.ReadFromIP(b)
+ return n, uaddr.toAddr(), err
+}
+
+// WriteToIP writes a IP packet to addr via c, copying the payload from b.
+//
+// WriteToIP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ sa, err1 := addr.sockaddr(c.fd.family)
+ if err1 != nil {
+ return 0, &OpError{Op: "write", Net: "ip", Addr: addr, Error: err1}
+ }
+ return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *IPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ a, ok := addr.(*IPAddr)
+ if !ok {
+ return 0, &OpError{"writeto", "ip", addr, os.EINVAL}
+ }
+ return c.WriteToIP(b, a)
+}
+
+// Convert "host" into IP address.
+func hostToIP(host string) (ip IP, err os.Error) {
+ var addr IP
+ // Try as an IP address.
+ addr = ParseIP(host)
+ if addr == nil {
+ // Not an IP address. Try as a DNS name.
+ _, addrs, err1 := LookupHost(host)
+ if err1 != nil {
+ err = err1
+ goto Error
+ }
+ addr = ParseIP(addrs[0])
+ if addr == nil {
+ // should not happen
+ err = &AddrError{"LookupHost returned invalid address", addrs[0]}
+ goto Error
+ }
+ }
+
+ return addr, nil
+
+Error:
+ return nil, err
+}
+
+
+var protocols map[string]int
+
+func readProtocols() {
+ protocols = make(map[string]int)
+ if file, err := open("/etc/protocols"); err == nil {
+ for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+ // tcp 6 TCP # transmission control protocol
+ if i := byteIndex(line, '#'); i >= 0 {
+ line = line[0:i]
+ }
+ f := getFields(line)
+ if len(f) < 2 {
+ continue
+ }
+ if proto, _, ok := dtoi(f[1], 0); ok {
+ protocols[f[0]] = proto
+ for _, alias := range f[2:] {
+ protocols[alias] = proto
+ }
+ }
+ }
+ file.close()
+ }
+}
+
+func netProtoSplit(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")
+ }
+ net = netProto[0:i]
+ protostr := netProto[i+1:]
+ proto, i, ok := dtoi(protostr, 0)
+ if !ok || i != len(protostr) {
+ // lookup by name
+ proto, ok = protocols[protostr]
+ if ok {
+ return
+ }
+ }
+ return
+}
+
+// DialIP connects to the remote address raddr on the network net,
+// which must be "ip", "ip4", or "ip6".
+func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err os.Error) {
+ net, proto, err := netProtoSplit(netProto)
+ if err != nil {
+ return
+ }
+ switch prefixBefore(net, ':') {
+ case "ip", "ip4", "ip6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if raddr == nil {
+ return nil, &OpError{"dial", "ip", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
+ if e != nil {
+ return nil, e
+ }
+ return newIPConn(fd), nil
+}
+
+// ListenIP listens for incoming IP packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send IP
+// packets with per-packet addressing.
+func ListenIP(netProto string, laddr *IPAddr) (c *IPConn, err os.Error) {
+ net, proto, err := netProtoSplit(netProto)
+ if err != nil {
+ return
+ }
+ switch prefixBefore(net, ':') {
+ case "ip", "ip4", "ip6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
+ if e != nil {
+ return nil, e
+ }
+ return newIPConn(fd), nil
+}
+
+// BindToDevice binds an IPConn to a network interface.
+func (c *IPConn) BindToDevice(device string) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ c.fd.incref()
+ defer c.fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
+}
diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go
new file mode 100644
index 000000000..4ba6a55b9
--- /dev/null
+++ b/libgo/go/net/ipsock.go
@@ -0,0 +1,236 @@
+// 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.
+
+// IP sockets
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+// Should we try to use the IPv4 socket interface if we're
+// only dealing with IPv4 sockets? As long as the host system
+// understands IPv6, it's okay to pass IPv4 addresses to the IPv6
+// interface. That simplifies our code and is most general.
+// Unfortunately, we need to run on kernels built without IPv6 support too.
+// So probe the kernel to figure it out.
+func kernelSupportsIPv6() bool {
+ // FreeBSD does not support this sort of interface.
+ if syscall.OS == "freebsd" {
+ return false
+ }
+ fd, e := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+ if fd >= 0 {
+ closesocket(fd)
+ }
+ return e == 0
+}
+
+var preferIPv4 = !kernelSupportsIPv6()
+
+// TODO(rsc): if syscall.OS == "linux", we're supposd to read
+// /proc/sys/net/core/somaxconn,
+// to take advantage of kernels that have raised the limit.
+func listenBacklog() int { return syscall.SOMAXCONN }
+
+// Internet sockets (TCP, UDP)
+
+// A sockaddr represents a TCP or UDP network address that can
+// be converted into a syscall.Sockaddr.
+type sockaddr interface {
+ Addr
+ sockaddr(family int) (syscall.Sockaddr, os.Error)
+ family() int
+}
+
+func internetSocket(net string, laddr, raddr sockaddr, socktype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
+ // Figure out IP version.
+ // If network has a suffix like "tcp4", obey it.
+ var oserr os.Error
+ family := syscall.AF_INET6
+ switch net[len(net)-1] {
+ case '4':
+ family = syscall.AF_INET
+ case '6':
+ // nothing to do
+ default:
+ // Otherwise, guess.
+ // If the addresses are IPv4 and we prefer IPv4, use 4; else 6.
+ if preferIPv4 &&
+ (laddr == nil || laddr.family() == syscall.AF_INET) &&
+ (raddr == nil || raddr.family() == syscall.AF_INET) {
+ family = syscall.AF_INET
+ }
+ }
+
+ var la, ra syscall.Sockaddr
+ if laddr != nil {
+ if la, oserr = laddr.sockaddr(family); oserr != nil {
+ goto Error
+ }
+ }
+ if raddr != nil {
+ if ra, oserr = raddr.sockaddr(family); oserr != nil {
+ goto Error
+ }
+ }
+ fd, oserr = socket(net, family, socktype, proto, la, ra, toAddr)
+ if oserr != nil {
+ goto Error
+ }
+ return fd, nil
+
+Error:
+ addr := raddr
+ if mode == "listen" {
+ addr = laddr
+ }
+ return nil, &OpError{mode, net, addr, oserr}
+}
+
+func getip(fd int, remote bool) (ip []byte, port int, ok bool) {
+ // No attempt at error reporting because
+ // there are no possible errors, and the
+ // caller won't report them anyway.
+ var sa syscall.Sockaddr
+ if remote {
+ sa, _ = syscall.Getpeername(fd)
+ } else {
+ sa, _ = syscall.Getsockname(fd)
+ }
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return sa.Addr[0:], sa.Port, true
+ case *syscall.SockaddrInet6:
+ return sa.Addr[0:], sa.Port, true
+ }
+ return
+}
+
+type InvalidAddrError string
+
+func (e InvalidAddrError) String() string { return string(e) }
+func (e InvalidAddrError) Timeout() bool { return false }
+func (e InvalidAddrError) Temporary() bool { return false }
+
+
+func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
+ switch family {
+ case syscall.AF_INET:
+ if len(ip) == 0 {
+ ip = IPv4zero
+ }
+ if ip = ip.To4(); ip == nil {
+ return nil, InvalidAddrError("non-IPv4 address")
+ }
+ s := new(syscall.SockaddrInet4)
+ for i := 0; i < IPv4len; i++ {
+ s.Addr[i] = ip[i]
+ }
+ s.Port = port
+ return s, nil
+ case syscall.AF_INET6:
+ if len(ip) == 0 {
+ ip = IPzero
+ }
+ // IPv4 callers use 0.0.0.0 to mean "announce on any available address".
+ // In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
+ // which it refuses to do. Rewrite to the IPv6 all zeros.
+ if p4 := ip.To4(); p4 != nil && p4[0] == 0 && p4[1] == 0 && p4[2] == 0 && p4[3] == 0 {
+ ip = IPzero
+ }
+ if ip = ip.To16(); ip == nil {
+ return nil, InvalidAddrError("non-IPv6 address")
+ }
+ s := new(syscall.SockaddrInet6)
+ for i := 0; i < IPv6len; i++ {
+ s.Addr[i] = ip[i]
+ }
+ s.Port = port
+ return s, nil
+ }
+ return nil, InvalidAddrError("unexpected socket family")
+}
+
+// Split "host:port" into "host" and "port".
+// Host cannot contain colons unless it is bracketed.
+func splitHostPort(hostport string) (host, port string, err os.Error) {
+ // The port starts after the last colon.
+ i := last(hostport, ':')
+ if i < 0 {
+ err = &AddrError{"missing port in address", hostport}
+ return
+ }
+
+ host, port = hostport[0:i], hostport[i+1:]
+
+ // Can put brackets around host ...
+ if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
+ host = host[1 : len(host)-1]
+ } else {
+ // ... but if there are no brackets, no colons.
+ if byteIndex(host, ':') >= 0 {
+ err = &AddrError{"too many colons in address", hostport}
+ return
+ }
+ }
+ return
+}
+
+// Join "host" and "port" into "host:port".
+// If host contains colons, will join into "[host]:port".
+func joinHostPort(host, port string) string {
+ // If host has colons, have to bracket it.
+ if byteIndex(host, ':') >= 0 {
+ return "[" + host + "]:" + port
+ }
+ return host + ":" + port
+}
+
+// Convert "host:port" into IP address and port.
+func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
+ host, port, err := splitHostPort(hostport)
+ if err != nil {
+ goto Error
+ }
+
+ var addr IP
+ if host != "" {
+ // Try as an IP address.
+ addr = ParseIP(host)
+ if addr == nil {
+ // Not an IP address. Try as a DNS name.
+ _, addrs, err1 := LookupHost(host)
+ if err1 != nil {
+ err = err1
+ goto Error
+ }
+ addr = ParseIP(addrs[0])
+ if addr == nil {
+ // should not happen
+ err = &AddrError{"LookupHost returned invalid address", addrs[0]}
+ goto Error
+ }
+ }
+ }
+
+ p, i, ok := dtoi(port, 0)
+ if !ok || i != len(port) {
+ p, err = LookupPort(net, port)
+ if err != nil {
+ goto Error
+ }
+ }
+ if p < 0 || p > 0xFFFF {
+ err = &AddrError{"invalid port", port}
+ goto Error
+ }
+
+ return addr, p, nil
+
+Error:
+ return nil, 0, err
+}
diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go
new file mode 100644
index 000000000..c0c1c3b8a
--- /dev/null
+++ b/libgo/go/net/net.go
@@ -0,0 +1,192 @@
+// 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.
+
+// The net package provides a portable interface to Unix
+// networks sockets, including TCP/IP, UDP, domain name
+// resolution, and Unix domain sockets.
+package net
+
+// TODO(rsc):
+// support for raw ethernet sockets
+
+import "os"
+
+// Addr represents a network end point address.
+type Addr interface {
+ Network() string // name of the network
+ String() string // string form of address
+}
+
+// Conn is a generic stream-oriented network connection.
+type Conn interface {
+ // Read reads data from the connection.
+ // Read can be made to time out and return a net.Error with Timeout() == true
+ // after a fixed time limit; see SetTimeout and SetReadTimeout.
+ Read(b []byte) (n int, err os.Error)
+
+ // Write writes data to the connection.
+ // Write can be made to time out and return a net.Error with Timeout() == true
+ // after a fixed time limit; see SetTimeout and SetWriteTimeout.
+ Write(b []byte) (n int, err os.Error)
+
+ // Close closes the connection.
+ // The error returned is an os.Error to satisfy io.Closer;
+ Close() os.Error
+
+ // LocalAddr returns the local network address.
+ LocalAddr() Addr
+
+ // RemoteAddr returns the remote network address.
+ RemoteAddr() Addr
+
+ // SetTimeout sets the read and write deadlines associated
+ // with the connection.
+ SetTimeout(nsec int64) os.Error
+
+ // SetReadTimeout sets the time (in nanoseconds) that
+ // Read will wait for data before returning an error with Timeout() == true.
+ // Setting nsec == 0 (the default) disables the deadline.
+ SetReadTimeout(nsec int64) os.Error
+
+ // SetWriteTimeout sets the time (in nanoseconds) that
+ // Write will wait to send its data before returning an error with Timeout() == true.
+ // Setting nsec == 0 (the default) disables the deadline.
+ // Even if write times out, it may return n > 0, indicating that
+ // some of the data was successfully written.
+ SetWriteTimeout(nsec int64) os.Error
+}
+
+// An Error represents a network error.
+type Error interface {
+ os.Error
+ Timeout() bool // Is the error a timeout?
+ Temporary() bool // Is the error temporary?
+}
+
+// PacketConn is a generic packet-oriented network connection.
+type PacketConn interface {
+ // ReadFrom reads a packet from the connection,
+ // copying the payload into b. It returns the number of
+ // bytes copied into b and the return address that
+ // was on the packet.
+ // ReadFrom can be made to time out and return
+ // an error with Timeout() == true after a fixed time limit;
+ // see SetTimeout and SetReadTimeout.
+ ReadFrom(b []byte) (n int, addr Addr, err os.Error)
+
+ // WriteTo writes a packet with payload b to addr.
+ // WriteTo can be made to time out and return
+ // an error with Timeout() == true after a fixed time limit;
+ // see SetTimeout and SetWriteTimeout.
+ // On packet-oriented connections, write timeouts are rare.
+ WriteTo(b []byte, addr Addr) (n int, err os.Error)
+
+ // Close closes the connection.
+ // The error returned is an os.Error to satisfy io.Closer;
+ Close() os.Error
+
+ // LocalAddr returns the local network address.
+ LocalAddr() Addr
+
+ // SetTimeout sets the read and write deadlines associated
+ // with the connection.
+ SetTimeout(nsec int64) os.Error
+
+ // SetReadTimeout sets the time (in nanoseconds) that
+ // Read will wait for data before returning an error with Timeout() == true.
+ // Setting nsec == 0 (the default) disables the deadline.
+ SetReadTimeout(nsec int64) os.Error
+
+ // SetWriteTimeout sets the time (in nanoseconds) that
+ // Write will wait to send its data before returning an error with Timeout() == true.
+ // Setting nsec == 0 (the default) disables the deadline.
+ // Even if write times out, it may return n > 0, indicating that
+ // some of the data was successfully written.
+ SetWriteTimeout(nsec int64) os.Error
+}
+
+// A Listener is a generic network listener for stream-oriented protocols.
+type Listener interface {
+ // Accept waits for and returns the next connection to the listener.
+ Accept() (c Conn, err os.Error)
+
+ // Close closes the listener.
+ // The error returned is an os.Error to satisfy io.Closer;
+ Close() os.Error
+
+ // Addr returns the listener's network address.
+ Addr() Addr
+}
+
+var errMissingAddress = os.ErrorString("missing address")
+
+type OpError struct {
+ Op string
+ Net string
+ Addr Addr
+ Error os.Error
+}
+
+func (e *OpError) String() string {
+ if e == nil {
+ return "<nil>"
+ }
+ s := e.Op
+ if e.Net != "" {
+ s += " " + e.Net
+ }
+ if e.Addr != nil {
+ s += " " + e.Addr.String()
+ }
+ s += ": " + e.Error.String()
+ return s
+}
+
+type temporary interface {
+ Temporary() bool
+}
+
+func (e *OpError) Temporary() bool {
+ t, ok := e.Error.(temporary)
+ return ok && t.Temporary()
+}
+
+type timeout interface {
+ Timeout() bool
+}
+
+func (e *OpError) Timeout() bool {
+ t, ok := e.Error.(timeout)
+ return ok && t.Timeout()
+}
+
+type AddrError struct {
+ Error string
+ Addr string
+}
+
+func (e *AddrError) String() string {
+ if e == nil {
+ return "<nil>"
+ }
+ s := e.Error
+ if e.Addr != "" {
+ s += " " + e.Addr
+ }
+ return s
+}
+
+func (e *AddrError) Temporary() bool {
+ return false
+}
+
+func (e *AddrError) Timeout() bool {
+ return false
+}
+
+type UnknownNetworkError string
+
+func (e UnknownNetworkError) String() string { return "unknown network " + string(e) }
+func (e UnknownNetworkError) Temporary() bool { return false }
+func (e UnknownNetworkError) Timeout() bool { return false }
diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go
new file mode 100644
index 000000000..275b31c0e
--- /dev/null
+++ b/libgo/go/net/net_test.go
@@ -0,0 +1,126 @@
+// 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 net
+
+import (
+ "flag"
+ "regexp"
+ "runtime"
+ "testing"
+)
+
+var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
+
+type DialErrorTest struct {
+ Net string
+ Laddr string
+ Raddr string
+ Pattern string
+}
+
+var dialErrorTests = []DialErrorTest{
+ {
+ "datakit", "", "mh/astro/r70",
+ "dial datakit mh/astro/r70: unknown network datakit",
+ },
+ {
+ "tcp", "", "127.0.0.1:☺",
+ "dial tcp 127.0.0.1:☺: unknown port tcp/☺",
+ },
+ {
+ "tcp", "", "no-such-name.google.com.:80",
+ "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
+ },
+ {
+ "tcp", "", "no-such-name.no-such-top-level-domain.:80",
+ "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
+ },
+ {
+ "tcp", "", "no-such-name:80",
+ `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
+ },
+ {
+ "tcp", "", "mh/astro/r70:http",
+ "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
+ },
+ {
+ "unix", "", "/etc/file-not-found",
+ "dial unix /etc/file-not-found: [nN]o such file or directory",
+ },
+ {
+ "unix", "", "/etc/",
+ "dial unix /etc/: ([pP]ermission denied|[sS]ocket operation on non-socket|[cC]onnection refused)",
+ },
+ {
+ "unixpacket", "", "/etc/file-not-found",
+ "dial unixpacket /etc/file-not-found: no such file or directory",
+ },
+ {
+ "unixpacket", "", "/etc/",
+ "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
+ },
+}
+
+func TestDialError(t *testing.T) {
+ if !*runErrorTest {
+ t.Logf("test disabled; use --run_error_test to enable")
+ return
+ }
+ for i, tt := range dialErrorTests {
+ c, e := Dial(tt.Net, tt.Laddr, tt.Raddr)
+ if c != nil {
+ c.Close()
+ }
+ if e == nil {
+ t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
+ continue
+ }
+ s := e.String()
+ match, _ := regexp.MatchString(tt.Pattern, s)
+ if !match {
+ t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
+ }
+ }
+}
+
+var revAddrTests = []struct {
+ Addr string
+ Reverse string
+ ErrPrefix string
+}{
+ {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
+ {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
+ {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
+ {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""},
+ {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""},
+ {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
+ {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
+ {"1.2.3", "", "unrecognized address"},
+ {"1.2.3.4.5", "", "unrecognized address"},
+ {"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
+ {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
+}
+
+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 {
+ t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
+ continue
+ }
+ if len(tt.ErrPrefix) == 0 && e != nil {
+ t.Errorf("#%d: expected <nil>, got %q (error)", i, e)
+ }
+ if e != nil && e.(*DNSError).Error != tt.ErrPrefix {
+ t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, e.(*DNSError).Error)
+ }
+ if a != tt.Reverse {
+ t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
+ }
+ }
+}
diff --git a/libgo/go/net/newpollserver.go b/libgo/go/net/newpollserver.go
new file mode 100644
index 000000000..820e70b46
--- /dev/null
+++ b/libgo/go/net/newpollserver.go
@@ -0,0 +1,41 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func newPollServer() (s *pollServer, err os.Error) {
+ s = new(pollServer)
+ s.cr = make(chan *netFD, 1)
+ s.cw = make(chan *netFD, 1)
+ if s.pr, s.pw, err = os.Pipe(); err != nil {
+ return nil, err
+ }
+ 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
+ }
+ if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
+ goto Errno
+ }
+ if s.poll, err = newpollster(); err != nil {
+ goto Error
+ }
+ if err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil {
+ s.poll.Close()
+ goto Error
+ }
+ s.pending = make(map[int]*netFD)
+ go s.Run()
+ return s, nil
+}
diff --git a/libgo/go/net/newpollserver_rtems.go b/libgo/go/net/newpollserver_rtems.go
new file mode 100644
index 000000000..05cb71a54
--- /dev/null
+++ b/libgo/go/net/newpollserver_rtems.go
@@ -0,0 +1,78 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func selfConnectedTCPSocket() (pr, pw *os.File, err os.Error) {
+ // See ../syscall/exec.go for description of ForkLock.
+ syscall.ForkLock.RLock()
+ sockfd, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, 0)
+ if e != 0 {
+ syscall.ForkLock.RUnlock()
+ return nil, nil, os.Errno(e)
+ }
+ syscall.CloseOnExec(sockfd)
+ syscall.ForkLock.RUnlock()
+
+ // Allow reuse of recently-used addresses.
+ syscall.SetsockoptInt(sockfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+
+ var laTCP *TCPAddr
+ var la syscall.Sockaddr
+ if laTCP, err = ResolveTCPAddr("127.0.0.1:0"); err != nil {
+ Error:
+ return nil, nil, err
+ }
+ if la, err = laTCP.sockaddr(syscall.AF_INET); err != nil {
+ goto Error
+ }
+ e = syscall.Bind(sockfd, la)
+ if e != 0 {
+ Errno:
+ syscall.Close(sockfd)
+ return nil, nil, os.Errno(e)
+ }
+
+ laddr, _ := syscall.Getsockname(sockfd)
+ e = syscall.Connect(sockfd, laddr)
+ if e != 0 {
+ goto Errno
+ }
+
+ fd := os.NewFile(sockfd, "wakeupSocket")
+ return fd, fd, nil
+}
+
+func newPollServer() (s *pollServer, err os.Error) {
+ s = new(pollServer)
+ s.cr = make(chan *netFD, 1)
+ s.cw = make(chan *netFD, 1)
+ // s.pr and s.pw are indistinguishable.
+ if s.pr, s.pw, err = selfConnectedTCPSocket(); err != nil {
+ return nil, err
+ }
+ 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()
+ return nil, err
+ }
+ if s.poll, err = newpollster(); err != nil {
+ goto Error
+ }
+ if err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil {
+ s.poll.Close()
+ goto Error
+ }
+ s.pending = make(map[int]*netFD)
+ go s.Run()
+ return s, nil
+}
diff --git a/libgo/go/net/parse.go b/libgo/go/net/parse.go
new file mode 100644
index 000000000..605f3110b
--- /dev/null
+++ b/libgo/go/net/parse.go
@@ -0,0 +1,214 @@
+// 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.
+
+// Simple file i/o and string manipulation, to avoid
+// depending on strconv and bufio and strings.
+
+package net
+
+import (
+ "io"
+ "os"
+)
+
+type file struct {
+ file *os.File
+ data []byte
+ atEOF bool
+}
+
+func (f *file) close() { f.file.Close() }
+
+func (f *file) getLineFromData() (s string, ok bool) {
+ data := f.data
+ i := 0
+ for i = 0; i < len(data); i++ {
+ if data[i] == '\n' {
+ s = string(data[0:i])
+ ok = true
+ // move data
+ i++
+ n := len(data) - i
+ copy(data[0:], data[i:])
+ f.data = data[0:n]
+ return
+ }
+ }
+ if f.atEOF && len(f.data) > 0 {
+ // EOF, return all we have
+ s = string(data)
+ f.data = f.data[0:0]
+ ok = true
+ }
+ return
+}
+
+func (f *file) readLine() (s string, ok bool) {
+ if s, ok = f.getLineFromData(); ok {
+ return
+ }
+ if len(f.data) < cap(f.data) {
+ ln := len(f.data)
+ n, err := io.ReadFull(f.file, f.data[ln:cap(f.data)])
+ if n >= 0 {
+ f.data = f.data[0 : ln+n]
+ }
+ if err == os.EOF {
+ f.atEOF = true
+ }
+ }
+ s, ok = f.getLineFromData()
+ return
+}
+
+func open(name string) (*file, os.Error) {
+ fd, err := os.Open(name, os.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ return &file{fd, make([]byte, 1024)[0:0], false}, nil
+}
+
+func byteIndex(s string, c byte) int {
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ return i
+ }
+ }
+ return -1
+}
+
+// Count occurrences in s of any bytes in t.
+func countAnyByte(s string, t string) int {
+ n := 0
+ for i := 0; i < len(s); i++ {
+ if byteIndex(t, s[i]) >= 0 {
+ n++
+ }
+ }
+ return n
+}
+
+// Split s at any bytes in t.
+func splitAtBytes(s string, t string) []string {
+ a := make([]string, 1+countAnyByte(s, t))
+ n := 0
+ last := 0
+ for i := 0; i < len(s); i++ {
+ if byteIndex(t, s[i]) >= 0 {
+ if last < i {
+ a[n] = string(s[last:i])
+ n++
+ }
+ last = i + 1
+ }
+ }
+ if last < len(s) {
+ a[n] = string(s[last:])
+ n++
+ }
+ return a[0:n]
+}
+
+func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") }
+
+// Bigger than we need, not too big to worry about overflow
+const big = 0xFFFFFF
+
+// Decimal to integer starting at &s[i0].
+// Returns number, new offset, success.
+func dtoi(s string, i0 int) (n int, i int, ok bool) {
+ n = 0
+ for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+ n = n*10 + int(s[i]-'0')
+ if n >= big {
+ return 0, i, false
+ }
+ }
+ if i == i0 {
+ return 0, i, false
+ }
+ return n, i, true
+}
+
+// Hexadecimal to integer starting at &s[i0].
+// Returns number, new offset, success.
+func xtoi(s string, i0 int) (n int, i int, ok bool) {
+ n = 0
+ for i = i0; i < len(s); i++ {
+ if '0' <= s[i] && s[i] <= '9' {
+ n *= 16
+ n += int(s[i] - '0')
+ } else if 'a' <= s[i] && s[i] <= 'f' {
+ n *= 16
+ n += int(s[i]-'a') + 10
+ } else if 'A' <= s[i] && s[i] <= 'F' {
+ n *= 16
+ n += int(s[i]-'A') + 10
+ } else {
+ break
+ }
+ if n >= big {
+ return 0, i, false
+ }
+ }
+ if i == i0 {
+ return 0, i, false
+ }
+ return n, i, true
+}
+
+// Integer to decimal.
+func itoa(i int) string {
+ var buf [30]byte
+ n := len(buf)
+ neg := false
+ if i < 0 {
+ i = -i
+ neg = true
+ }
+ ui := uint(i)
+ for ui > 0 || n == len(buf) {
+ n--
+ buf[n] = byte('0' + ui%10)
+ ui /= 10
+ }
+ if neg {
+ n--
+ buf[n] = '-'
+ }
+ return string(buf[n:])
+}
+
+// Number of occurrences of b in s.
+func count(s string, b byte) int {
+ n := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] == b {
+ n++
+ }
+ }
+ return n
+}
+
+// Returns the prefix of s up to but not including the character c
+func prefixBefore(s string, c byte) string {
+ for i, v := range s {
+ if v == int(c) {
+ return s[0:i]
+ }
+ }
+ return s
+}
+
+// Index of rightmost occurrence of b in s.
+func last(s string, b byte) int {
+ i := len(s)
+ for i--; i >= 0; i-- {
+ if s[i] == b {
+ break
+ }
+ }
+ return i
+}
diff --git a/libgo/go/net/parse_test.go b/libgo/go/net/parse_test.go
new file mode 100644
index 000000000..2b7784eee
--- /dev/null
+++ b/libgo/go/net/parse_test.go
@@ -0,0 +1,50 @@
+// 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 net
+
+import (
+ "bufio"
+ "os"
+ "testing"
+ "runtime"
+)
+
+func TestReadLine(t *testing.T) {
+ // /etc/services file does not exist on windows.
+ if runtime.GOOS == "windows" {
+ return
+ }
+ filename := "/etc/services" // a nice big file
+
+ fd, err := os.Open(filename, os.O_RDONLY, 0)
+ if err != nil {
+ t.Fatalf("open %s: %v", filename, err)
+ }
+ br := bufio.NewReader(fd)
+
+ file, err := open(filename)
+ if file == nil {
+ t.Fatalf("net.open(%s) = nil", filename)
+ }
+
+ lineno := 1
+ byteno := 0
+ for {
+ bline, berr := br.ReadString('\n')
+ if n := len(bline); n > 0 {
+ bline = bline[0 : n-1]
+ }
+ line, ok := file.readLine()
+ if (berr != nil) != !ok || bline != line {
+ t.Fatalf("%s:%d (#%d)\nbufio => %q, %v\nnet => %q, %v",
+ filename, lineno, byteno, bline, berr, line, ok)
+ }
+ if !ok {
+ break
+ }
+ lineno++
+ byteno += len(line) + 1
+ }
+}
diff --git a/libgo/go/net/pipe.go b/libgo/go/net/pipe.go
new file mode 100644
index 000000000..c0bbd356b
--- /dev/null
+++ b/libgo/go/net/pipe.go
@@ -0,0 +1,62 @@
+package net
+
+import (
+ "io"
+ "os"
+)
+
+// Pipe creates a synchronous, in-memory, full duplex
+// network connection; both ends implement the Conn interface.
+// Reads on one end are matched with writes on the other,
+// copying data directly between the two; there is no internal
+// buffering.
+func Pipe() (Conn, Conn) {
+ r1, w1 := io.Pipe()
+ r2, w2 := io.Pipe()
+
+ return &pipe{r1, w2}, &pipe{r2, w1}
+}
+
+type pipe struct {
+ *io.PipeReader
+ *io.PipeWriter
+}
+
+type pipeAddr int
+
+func (pipeAddr) Network() string {
+ return "pipe"
+}
+
+func (pipeAddr) String() string {
+ return "pipe"
+}
+
+func (p *pipe) Close() os.Error {
+ err := p.PipeReader.Close()
+ err1 := p.PipeWriter.Close()
+ if err == nil {
+ err = err1
+ }
+ return err
+}
+
+func (p *pipe) LocalAddr() Addr {
+ return pipeAddr(0)
+}
+
+func (p *pipe) RemoteAddr() Addr {
+ return pipeAddr(0)
+}
+
+func (p *pipe) SetTimeout(nsec int64) os.Error {
+ return os.NewError("net.Pipe does not support timeouts")
+}
+
+func (p *pipe) SetReadTimeout(nsec int64) os.Error {
+ return os.NewError("net.Pipe does not support timeouts")
+}
+
+func (p *pipe) SetWriteTimeout(nsec int64) os.Error {
+ return os.NewError("net.Pipe does not support timeouts")
+}
diff --git a/libgo/go/net/pipe_test.go b/libgo/go/net/pipe_test.go
new file mode 100644
index 000000000..7e4c6db44
--- /dev/null
+++ b/libgo/go/net/pipe_test.go
@@ -0,0 +1,57 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "testing"
+)
+
+func checkWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
+ n, err := w.Write(data)
+ if err != nil {
+ t.Errorf("write: %v", err)
+ }
+ if n != len(data) {
+ t.Errorf("short write: %d != %d", n, len(data))
+ }
+ c <- 0
+}
+
+func checkRead(t *testing.T, r io.Reader, data []byte, wantErr os.Error) {
+ buf := make([]byte, len(data)+10)
+ n, err := r.Read(buf)
+ if err != wantErr {
+ t.Errorf("read: %v", err)
+ return
+ }
+ if n != len(data) || !bytes.Equal(buf[0:n], data) {
+ t.Errorf("bad read: got %q", buf[0:n])
+ return
+ }
+}
+
+// Test a simple read/write/close sequence.
+// Assumes that the underlying io.Pipe implementation
+// is solid and we're just testing the net wrapping.
+
+func TestPipe(t *testing.T) {
+ c := make(chan int)
+ cli, srv := Pipe()
+ go checkWrite(t, cli, []byte("hello, world"), c)
+ checkRead(t, srv, []byte("hello, world"), nil)
+ <-c
+ go checkWrite(t, srv, []byte("line 2"), c)
+ checkRead(t, cli, []byte("line 2"), nil)
+ <-c
+ go checkWrite(t, cli, []byte("a third line"), c)
+ checkRead(t, srv, []byte("a third line"), nil)
+ <-c
+ go srv.Close()
+ checkRead(t, cli, nil, os.EOF)
+ cli.Close()
+}
diff --git a/libgo/go/net/port.go b/libgo/go/net/port.go
new file mode 100644
index 000000000..7d25058b2
--- /dev/null
+++ b/libgo/go/net/port.go
@@ -0,0 +1,70 @@
+// 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.
+
+// Read system port mappings from /etc/services
+
+package net
+
+import (
+ "os"
+ "sync"
+)
+
+var services map[string]map[string]int
+var servicesError os.Error
+var onceReadServices sync.Once
+
+func readServices() {
+ services = make(map[string]map[string]int)
+ var file *file
+ if file, servicesError = open("/etc/services"); servicesError != nil {
+ return
+ }
+ for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+ // "http 80/tcp www www-http # World Wide Web HTTP"
+ if i := byteIndex(line, '#'); i >= 0 {
+ line = line[0:i]
+ }
+ f := getFields(line)
+ if len(f) < 2 {
+ continue
+ }
+ portnet := f[1] // "tcp/80"
+ port, j, ok := dtoi(portnet, 0)
+ if !ok || port <= 0 || j >= len(portnet) || portnet[j] != '/' {
+ continue
+ }
+ netw := portnet[j+1:] // "tcp"
+ m, ok1 := services[netw]
+ if !ok1 {
+ m = make(map[string]int)
+ services[netw] = m
+ }
+ for i := 0; i < len(f); i++ {
+ if i != 1 { // f[1] was port/net
+ m[f[i]] = port
+ }
+ }
+ }
+ file.close()
+}
+
+// LookupPort looks up the port for the given network and service.
+func LookupPort(network, service string) (port int, err os.Error) {
+ onceReadServices.Do(readServices)
+
+ switch network {
+ case "tcp4", "tcp6":
+ network = "tcp"
+ case "udp4", "udp6":
+ network = "udp"
+ }
+
+ if m, ok := services[network]; ok {
+ if port, ok = m[service]; ok {
+ return
+ }
+ }
+ return 0, &AddrError{"unknown port", network + "/" + service}
+}
diff --git a/libgo/go/net/port_test.go b/libgo/go/net/port_test.go
new file mode 100644
index 000000000..329b169f3
--- /dev/null
+++ b/libgo/go/net/port_test.go
@@ -0,0 +1,53 @@
+// 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 net
+
+import (
+ "testing"
+)
+
+type portTest struct {
+ netw string
+ name string
+ port int
+ ok bool
+}
+
+var porttests = []portTest{
+ {"tcp", "echo", 7, true},
+ {"tcp", "discard", 9, true},
+ {"tcp", "systat", 11, true},
+ {"tcp", "daytime", 13, true},
+ {"tcp", "chargen", 19, true},
+ {"tcp", "ftp-data", 20, true},
+ {"tcp", "ftp", 21, true},
+ {"tcp", "telnet", 23, true},
+ {"tcp", "smtp", 25, true},
+ {"tcp", "time", 37, true},
+ {"tcp", "domain", 53, true},
+ {"tcp", "finger", 79, true},
+
+ {"udp", "echo", 7, true},
+ {"udp", "tftp", 69, true},
+ {"udp", "bootpc", 68, true},
+ {"udp", "bootps", 67, true},
+ {"udp", "domain", 53, true},
+ {"udp", "ntp", 123, true},
+ {"udp", "snmp", 161, true},
+ {"udp", "syslog", 514, true},
+
+ {"--badnet--", "zzz", 0, false},
+ {"tcp", "--badport--", 0, false},
+}
+
+func TestLookupPort(t *testing.T) {
+ for i := 0; i < len(porttests); i++ {
+ tt := porttests[i]
+ if port, err := LookupPort(tt.netw, tt.name); port != tt.port || (err == nil) != tt.ok {
+ t.Errorf("LookupPort(%q, %q) = %v, %s; want %v",
+ tt.netw, tt.name, port, err, tt.port)
+ }
+ }
+}
diff --git a/libgo/go/net/resolv_windows.go b/libgo/go/net/resolv_windows.go
new file mode 100644
index 000000000..f3d854ff2
--- /dev/null
+++ b/libgo/go/net/resolv_windows.go
@@ -0,0 +1,112 @@
+// 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 net
+
+import (
+ "syscall"
+ "unsafe"
+ "os"
+ "sync"
+)
+
+var hostentLock sync.Mutex
+var serventLock sync.Mutex
+
+func LookupHost(name string) (cname string, addrs []string, err os.Error) {
+ hostentLock.Lock()
+ defer hostentLock.Unlock()
+ h, e := syscall.GetHostByName(name)
+ if e != 0 {
+ return "", nil, os.NewSyscallError("GetHostByName", e)
+ }
+ cname = name
+ switch h.AddrType {
+ case syscall.AF_INET:
+ i := 0
+ addrs = make([]string, 100) // plenty of room to grow
+ for p := (*[100](*[4]byte))(unsafe.Pointer(h.AddrList)); i < cap(addrs) && p[i] != nil; i++ {
+ addrs[i] = IPv4(p[i][0], p[i][1], p[i][2], p[i][3]).String()
+ }
+ addrs = addrs[0:i]
+ default: // TODO(vcc): Implement non IPv4 address lookups.
+ return "", nil, os.NewSyscallError("LookupHost", syscall.EWINDOWS)
+ }
+ return cname, addrs, nil
+}
+
+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
+ e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
+ if int(e) != 0 {
+ return "", nil, os.NewSyscallError("LookupSRV", int(e))
+ }
+ defer syscall.DnsRecordListFree(r, 1)
+ addrs = make([]*SRV, 100)
+ i := 0
+ for p := r; p != nil && p.Type == syscall.DNS_TYPE_SRV; p = p.Next {
+ v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
+ addrs[i] = &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight}
+ i++
+ }
+ addrs = addrs[0:i]
+ return name, addrs, nil
+}
+
+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
+}
+
+// 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")
+}
+
+// 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 (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/libgo/go/net/server_test.go b/libgo/go/net/server_test.go
new file mode 100644
index 000000000..3f2442a46
--- /dev/null
+++ b/libgo/go/net/server_test.go
@@ -0,0 +1,203 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "flag"
+ "io"
+ "os"
+ "strings"
+ "syscall"
+ "testing"
+ "runtime"
+)
+
+// Do not test empty datagrams by default.
+// It causes unexplained timeouts on some systems,
+// including Snow Leopard. I think that the kernel
+// doesn't quite expect them.
+var testUDP = flag.Bool("udp", false, "whether to test UDP datagrams")
+
+func runEcho(fd io.ReadWriter, done chan<- int) {
+ var buf [1024]byte
+
+ for {
+ n, err := fd.Read(buf[0:])
+ if err != nil || n == 0 {
+ break
+ }
+ fd.Write(buf[0:n])
+ }
+ done <- 1
+}
+
+func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
+ l, err := Listen(network, addr)
+ if err != nil {
+ t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err)
+ }
+ listening <- l.Addr().String()
+
+ for {
+ fd, err := l.Accept()
+ if err != nil {
+ break
+ }
+ echodone := make(chan int)
+ go runEcho(fd, echodone)
+ <-echodone // make sure Echo stops
+ l.Close()
+ }
+ done <- 1
+}
+
+func connect(t *testing.T, network, addr string, isEmpty bool) {
+ var laddr string
+ if network == "unixgram" {
+ laddr = addr + ".local"
+ }
+ fd, err := Dial(network, laddr, addr)
+ if err != nil {
+ t.Fatalf("net.Dial(%q, %q, %q) = _, %v", network, laddr, addr, err)
+ }
+ fd.SetReadTimeout(1e9) // 1s
+
+ var b []byte
+ if !isEmpty {
+ b = []byte("hello, world\n")
+ }
+ var b1 [100]byte
+
+ n, err1 := fd.Write(b)
+ if n != len(b) {
+ t.Fatalf("fd.Write(%q) = %d, %v", b, n, err1)
+ }
+
+ n, err1 = fd.Read(b1[0:])
+ if n != len(b) || err1 != nil {
+ t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err1, len(b))
+ }
+ fd.Close()
+}
+
+func doTest(t *testing.T, network, listenaddr, dialaddr string) {
+ t.Logf("Test %s %s %s\n", network, listenaddr, dialaddr)
+ listening := make(chan string)
+ done := make(chan int)
+ if network == "tcp" {
+ listenaddr += ":0" // any available port
+ }
+ go runServe(t, network, listenaddr, listening, done)
+ addr := <-listening // wait for server to start
+ if network == "tcp" {
+ dialaddr += addr[strings.LastIndex(addr, ":"):]
+ }
+ connect(t, network, dialaddr, false)
+ <-done // make sure server stopped
+}
+
+func TestTCPServer(t *testing.T) {
+ doTest(t, "tcp", "0.0.0.0", "127.0.0.1")
+ doTest(t, "tcp", "", "127.0.0.1")
+ if kernelSupportsIPv6() {
+ doTest(t, "tcp", "[::]", "[::ffff:127.0.0.1]")
+ doTest(t, "tcp", "[::]", "127.0.0.1")
+ doTest(t, "tcp", "0.0.0.0", "[::ffff:127.0.0.1]")
+ }
+}
+
+func TestUnixServer(t *testing.T) {
+ // "unix" sockets are not supported on windows.
+ if runtime.GOOS == "windows" {
+ return
+ }
+ os.Remove("/tmp/gotest.net")
+ doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net")
+ os.Remove("/tmp/gotest.net")
+ if syscall.OS == "linux" {
+ doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net")
+ os.Remove("/tmp/gotest.net")
+ // Test abstract unix domain socket, a Linux-ism
+ doTest(t, "unix", "@gotest/net", "@gotest/net")
+ doTest(t, "unixpacket", "@gotest/net", "@gotest/net")
+ }
+}
+
+func runPacket(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
+ c, err := ListenPacket(network, addr)
+ if err != nil {
+ t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
+ }
+ listening <- c.LocalAddr().String()
+ c.SetReadTimeout(10e6) // 10ms
+ var buf [1000]byte
+ for {
+ n, addr, err := c.ReadFrom(buf[0:])
+ if e, ok := err.(Error); ok && e.Timeout() {
+ if done <- 1 {
+ break
+ }
+ continue
+ }
+ if err != nil {
+ break
+ }
+ if _, err = c.WriteTo(buf[0:n], addr); err != nil {
+ t.Fatalf("WriteTo %v: %v", addr, err)
+ }
+ }
+ c.Close()
+ done <- 1
+}
+
+func doTestPacket(t *testing.T, network, listenaddr, dialaddr string, isEmpty bool) {
+ t.Logf("TestPacket %s %s %s\n", network, listenaddr, dialaddr)
+ listening := make(chan string)
+ done := make(chan int)
+ if network == "udp" {
+ listenaddr += ":0" // any available port
+ }
+ go runPacket(t, network, listenaddr, listening, done)
+ addr := <-listening // wait for server to start
+ if network == "udp" {
+ dialaddr += addr[strings.LastIndex(addr, ":"):]
+ }
+ connect(t, network, dialaddr, isEmpty)
+ <-done // tell server to stop
+ <-done // wait for stop
+}
+
+func TestUDPServer(t *testing.T) {
+ if !*testUDP {
+ return
+ }
+ for _, isEmpty := range []bool{false, true} {
+ doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1", isEmpty)
+ doTestPacket(t, "udp", "", "127.0.0.1", isEmpty)
+ if kernelSupportsIPv6() {
+ doTestPacket(t, "udp", "[::]", "[::ffff:127.0.0.1]", isEmpty)
+ doTestPacket(t, "udp", "[::]", "127.0.0.1", isEmpty)
+ doTestPacket(t, "udp", "0.0.0.0", "[::ffff:127.0.0.1]", isEmpty)
+ }
+ }
+}
+
+func TestUnixDatagramServer(t *testing.T) {
+ // "unix" sockets are not supported on windows.
+ if runtime.GOOS == "windows" {
+ return
+ }
+ for _, isEmpty := range []bool{false} {
+ os.Remove("/tmp/gotest1.net")
+ os.Remove("/tmp/gotest1.net.local")
+ doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net", isEmpty)
+ os.Remove("/tmp/gotest1.net")
+ os.Remove("/tmp/gotest1.net.local")
+ if syscall.OS == "linux" {
+ // Test abstract unix domain socket, a Linux-ism
+ doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net", isEmpty)
+ }
+ }
+}
diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go
new file mode 100644
index 000000000..5a88ddcbc
--- /dev/null
+++ b/libgo/go/net/sock.go
@@ -0,0 +1,181 @@
+// 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.
+
+// Sockets
+
+package net
+
+import (
+ "os"
+ "reflect"
+ "syscall"
+)
+
+// Boolean to int.
+func boolint(b bool) int {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+// Generic socket creation.
+func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
+ // See ../syscall/exec.go for description of ForkLock.
+ syscall.ForkLock.RLock()
+ s, e := syscall.Socket(f, p, t)
+ if e != 0 {
+ syscall.ForkLock.RUnlock()
+ return nil, os.Errno(e)
+ }
+ syscall.CloseOnExec(s)
+ syscall.ForkLock.RUnlock()
+
+ // Allow reuse of recently-used addresses.
+ syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+
+ // Allow broadcast.
+ syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+
+ if f == syscall.AF_INET6 {
+ // using ip, tcp, udp, etc.
+ // allow both protocols even if the OS default is otherwise.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ }
+
+ if la != nil {
+ e = syscall.Bind(s, la)
+ if e != 0 {
+ closesocket(s)
+ return nil, os.Errno(e)
+ }
+ }
+
+ if ra != nil {
+ e = syscall.Connect(s, ra)
+ for e == syscall.EINTR {
+ e = syscall.Connect(s, ra)
+ }
+ if e != 0 {
+ closesocket(s)
+ return nil, os.Errno(e)
+ }
+ }
+
+ sa, _ := syscall.Getsockname(s)
+ laddr := toAddr(sa)
+ sa, _ = syscall.Getpeername(s)
+ raddr := toAddr(sa)
+
+ fd, err = newFD(s, f, p, net, laddr, raddr)
+ if err != nil {
+ closesocket(s)
+ return nil, err
+ }
+
+ return fd, nil
+}
+
+func setsockoptInt(fd, level, opt int, value int) os.Error {
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, opt, value))
+}
+
+func setsockoptNsec(fd, level, opt int, nsec int64) os.Error {
+ var tv = syscall.NsecToTimeval(nsec)
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd, level, opt, &tv))
+}
+
+func setReadBuffer(fd *netFD, bytes int) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
+}
+
+func setWriteBuffer(fd *netFD, bytes int) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
+}
+
+func setReadTimeout(fd *netFD, nsec int64) os.Error {
+ fd.rdeadline_delta = nsec
+ return nil
+}
+
+func setWriteTimeout(fd *netFD, nsec int64) os.Error {
+ fd.wdeadline_delta = nsec
+ return nil
+}
+
+func setTimeout(fd *netFD, nsec int64) os.Error {
+ if e := setReadTimeout(fd, nsec); e != nil {
+ return e
+ }
+ return setWriteTimeout(fd, nsec)
+}
+
+func setReuseAddr(fd *netFD, reuse bool) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse))
+}
+
+func bindToDevice(fd *netFD, dev string) os.Error {
+ // TODO(rsc): call setsockopt with null-terminated string pointer
+ return os.EINVAL
+}
+
+func setDontRoute(fd *netFD, dontroute bool) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute))
+}
+
+func setKeepAlive(fd *netFD, keepalive bool) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
+}
+
+func setNoDelay(fd *netFD, noDelay bool) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
+}
+
+func setLinger(fd *netFD, sec int) os.Error {
+ var l syscall.Linger
+ if sec >= 0 {
+ l.Onoff = 1
+ l.Linger = int32(sec)
+ } else {
+ l.Onoff = 0
+ l.Linger = 0
+ }
+ fd.incref()
+ defer fd.decref()
+ e := syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l)
+ return os.NewSyscallError("setsockopt", e)
+}
+
+type UnknownSocketError struct {
+ sa syscall.Sockaddr
+}
+
+func (e *UnknownSocketError) String() string {
+ return "unknown socket address type " + reflect.Typeof(e.sa).String()
+}
+
+func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) {
+ switch a := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return joinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
+ case *syscall.SockaddrInet6:
+ return joinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
+ case *syscall.SockaddrUnix:
+ return a.Name, nil
+ }
+
+ return "", &UnknownSocketError{sa}
+}
diff --git a/libgo/go/net/srv_test.go b/libgo/go/net/srv_test.go
new file mode 100644
index 000000000..4dd6089cd
--- /dev/null
+++ b/libgo/go/net/srv_test.go
@@ -0,0 +1,22 @@
+// 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.
+
+// TODO It would be nice to use a mock DNS server, to eliminate
+// external dependencies.
+
+package net
+
+import (
+ "testing"
+)
+
+func TestGoogleSRV(t *testing.T) {
+ _, addrs, err := LookupSRV("xmpp-server", "tcp", "google.com")
+ if err != nil {
+ t.Errorf("failed: %s", err)
+ }
+ if len(addrs) == 0 {
+ t.Errorf("no results")
+ }
+}
diff --git a/libgo/go/net/tcpsock.go b/libgo/go/net/tcpsock.go
new file mode 100644
index 000000000..a4bca11bb
--- /dev/null
+++ b/libgo/go/net/tcpsock.go
@@ -0,0 +1,293 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TCP sockets
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func sockaddrToTCP(sa syscall.Sockaddr) Addr {
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return &TCPAddr{sa.Addr[0:], sa.Port}
+ case *syscall.SockaddrInet6:
+ return &TCPAddr{sa.Addr[0:], sa.Port}
+ }
+ return nil
+}
+
+// TCPAddr represents the address of a TCP end point.
+type TCPAddr struct {
+ IP IP
+ Port int
+}
+
+// Network returns the address's network name, "tcp".
+func (a *TCPAddr) Network() string { return "tcp" }
+
+func (a *TCPAddr) String() string {
+ if a == nil {
+ return "<nil>"
+ }
+ return joinHostPort(a.IP.String(), itoa(a.Port))
+}
+
+func (a *TCPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if ip := a.IP.To4(); ip != nil {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+ return ipToSockaddr(family, a.IP, a.Port)
+}
+
+func (a *TCPAddr) toAddr() sockaddr {
+ if a == nil { // nil *TCPAddr
+ return nil // nil interface
+ }
+ return a
+}
+
+// ResolveTCPAddr parses addr as a TCP address of the form
+// host:port and resolves domain names or port names to
+// numeric addresses. A literal IPv6 host address must be
+// enclosed in square brackets, as in "[::]:80".
+func ResolveTCPAddr(addr string) (*TCPAddr, os.Error) {
+ ip, port, err := hostPortToIP("tcp", addr)
+ if err != nil {
+ return nil, err
+ }
+ return &TCPAddr{ip, port}, nil
+}
+
+// TCPConn is an implementation of the Conn interface
+// for TCP network connections.
+type TCPConn struct {
+ fd *netFD
+}
+
+func newTCPConn(fd *netFD) *TCPConn {
+ c := &TCPConn{fd}
+ c.SetNoDelay(true)
+ return c
+}
+
+func (c *TCPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *TCPConn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Read(b)
+}
+
+// Write implements the net.Conn Write method.
+func (c *TCPConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the TCP connection.
+func (c *TCPConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address, a *TCPAddr.
+func (c *TCPConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *TCPAddr.
+func (c *TCPConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *TCPConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *TCPConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *TCPConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *TCPConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *TCPConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// SetLinger sets the behavior of Close() on a connection
+// which still has data waiting to be sent or to be acknowledged.
+//
+// If sec < 0 (the default), Close returns immediately and
+// the operating system finishes sending the data in the background.
+//
+// If sec == 0, Close returns immediately and the operating system
+// discards any unsent or unacknowledged data.
+//
+// If sec > 0, Close blocks for at most sec seconds waiting for
+// data to be sent and acknowledged.
+func (c *TCPConn) SetLinger(sec int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setLinger(c.fd, sec)
+}
+
+// SetKeepAlive sets whether the operating system should send
+// keepalive messages on the connection.
+func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setKeepAlive(c.fd, keepalive)
+}
+
+// SetNoDelay controls whether the operating system should delay
+// packet transmission in hopes of sending fewer packets
+// (Nagle's algorithm). The default is true (no delay), meaning
+// that data is sent as soon as possible after a Write.
+func (c *TCPConn) SetNoDelay(noDelay bool) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setNoDelay(c.fd, noDelay)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *TCPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
+// DialTCP is like Dial but can only connect to TCP networks
+// and returns a TCPConn structure.
+func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
+ if raddr == nil {
+ return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+ if e != nil {
+ return nil, e
+ }
+ return newTCPConn(fd), nil
+}
+
+// TCPListener is a TCP network listener.
+// Clients should typically use variables of type Listener
+// instead of assuming TCP.
+type TCPListener struct {
+ fd *netFD
+}
+
+// ListenTCP announces on the TCP address laddr and returns a TCP listener.
+// Net must be "tcp", "tcp4", or "tcp6".
+// If laddr has a port of 0, it means to listen on some available port.
+// The caller can use l.Addr() to retrieve the chosen address.
+func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) {
+ fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
+ if err != nil {
+ return nil, err
+ }
+ errno := syscall.Listen(fd.sysfd, listenBacklog())
+ if errno != 0 {
+ closesocket(fd.sysfd)
+ return nil, &OpError{"listen", "tcp", laddr, os.Errno(errno)}
+ }
+ l = new(TCPListener)
+ l.fd = fd
+ return l, nil
+}
+
+// AcceptTCP accepts the next incoming call and returns the new connection
+// and the remote address.
+func (l *TCPListener) AcceptTCP() (c *TCPConn, err os.Error) {
+ if l == nil || l.fd == nil || l.fd.sysfd < 0 {
+ return nil, os.EINVAL
+ }
+ fd, err := l.fd.accept(sockaddrToTCP)
+ if err != nil {
+ return nil, err
+ }
+ return newTCPConn(fd), nil
+}
+
+// Accept implements the Accept method in the Listener interface;
+// it waits for the next call and returns a generic Conn.
+func (l *TCPListener) Accept() (c Conn, err os.Error) {
+ c1, err := l.AcceptTCP()
+ if err != nil {
+ return nil, err
+ }
+ return c1, nil
+}
+
+// Close stops listening on the TCP address.
+// Already Accepted connections are not closed.
+func (l *TCPListener) Close() os.Error {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+ return l.fd.Close()
+}
+
+// Addr returns the listener's network address, a *TCPAddr.
+func (l *TCPListener) Addr() Addr { return l.fd.laddr }
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (l *TCPListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
diff --git a/libgo/go/net/textproto/pipeline.go b/libgo/go/net/textproto/pipeline.go
new file mode 100644
index 000000000..8c25884b3
--- /dev/null
+++ b/libgo/go/net/textproto/pipeline.go
@@ -0,0 +1,117 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+ "sync"
+)
+
+// A Pipeline manages a pipelined in-order request/response sequence.
+//
+// To use a Pipeline p to manage multiple clients on a connection,
+// each client should run:
+//
+// id := p.Next() // take a number
+//
+// p.StartRequest(id) // wait for turn to send request
+// «send request»
+// p.EndRequest(id) // notify Pipeline that request is sent
+//
+// p.StartResponse(id) // wait for turn to read response
+// «read response»
+// p.EndResponse(id) // notify Pipeline that response is read
+//
+// A pipelined server can use the same calls to ensure that
+// responses computed in parallel are written in the correct order.
+type Pipeline struct {
+ mu sync.Mutex
+ id uint
+ request sequencer
+ response sequencer
+}
+
+// Next returns the next id for a request/response pair.
+func (p *Pipeline) Next() uint {
+ p.mu.Lock()
+ id := p.id
+ p.id++
+ p.mu.Unlock()
+ return id
+}
+
+// StartRequest blocks until it is time to send (or, if this is a server, receive)
+// the request with the given id.
+func (p *Pipeline) StartRequest(id uint) {
+ p.request.Start(id)
+}
+
+// EndRequest notifies p that the request with the given id has been sent
+// (or, if this is a server, received).
+func (p *Pipeline) EndRequest(id uint) {
+ p.request.End(id)
+}
+
+// StartResponse blocks until it is time to receive (or, if this is a server, send)
+// the request with the given id.
+func (p *Pipeline) StartResponse(id uint) {
+ p.response.Start(id)
+}
+
+// EndResponse notifies p that the response with the given id has been received
+// (or, if this is a server, sent).
+func (p *Pipeline) EndResponse(id uint) {
+ p.response.End(id)
+}
+
+// A sequencer schedules a sequence of numbered events that must
+// happen in order, one after the other. The event numbering must start
+// at 0 and increment without skipping. The event number wraps around
+// safely as long as there are not 2^32 simultaneous events pending.
+type sequencer struct {
+ mu sync.Mutex
+ id uint
+ wait map[uint]chan uint
+}
+
+// Start waits until it is time for the event numbered id to begin.
+// That is, except for the first event, it waits until End(id-1) has
+// been called.
+func (s *sequencer) Start(id uint) {
+ s.mu.Lock()
+ if s.id == id {
+ s.mu.Unlock()
+ return
+ }
+ c := make(chan uint)
+ if s.wait == nil {
+ s.wait = make(map[uint]chan uint)
+ }
+ s.wait[id] = c
+ s.mu.Unlock()
+ <-c
+}
+
+// End notifies the sequencer that the event numbered id has completed,
+// allowing it to schedule the event numbered id+1. It is a run-time error
+// to call End with an id that is not the number of the active event.
+func (s *sequencer) End(id uint) {
+ s.mu.Lock()
+ if s.id != id {
+ panic("out of sync")
+ }
+ id++
+ s.id = id
+ if s.wait == nil {
+ s.wait = make(map[uint]chan uint)
+ }
+ c, ok := s.wait[id]
+ if ok {
+ s.wait[id] = nil, false
+ }
+ s.mu.Unlock()
+ if ok {
+ c <- 1
+ }
+}
diff --git a/libgo/go/net/textproto/reader.go b/libgo/go/net/textproto/reader.go
new file mode 100644
index 000000000..c8e34b758
--- /dev/null
+++ b/libgo/go/net/textproto/reader.go
@@ -0,0 +1,492 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+ "bufio"
+ "bytes"
+ "container/vector"
+ "io"
+ "io/ioutil"
+ "os"
+ "strconv"
+)
+
+// BUG(rsc): To let callers manage exposure to denial of service
+// attacks, Reader should allow them to set and reset a limit on
+// the number of bytes read from the connection.
+
+// A Reader implements convenience methods for reading requests
+// or responses from a text protocol network connection.
+type Reader struct {
+ R *bufio.Reader
+ dot *dotReader
+}
+
+// NewReader returns a new Reader reading from r.
+func NewReader(r *bufio.Reader) *Reader {
+ return &Reader{R: r}
+}
+
+// ReadLine reads a single line from r,
+// eliding the final \n or \r\n from the returned string.
+func (r *Reader) ReadLine() (string, os.Error) {
+ line, err := r.ReadLineBytes()
+ return string(line), err
+}
+
+// ReadLineBytes is like ReadLine but returns a []byte instead of a string.
+func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
+ r.closeDot()
+ line, err := r.R.ReadBytes('\n')
+ n := len(line)
+ if n > 0 && line[n-1] == '\n' {
+ n--
+ if n > 0 && line[n-1] == '\r' {
+ n--
+ }
+ }
+ return line[0:n], err
+}
+
+// ReadContinuedLine reads a possibly continued line from r,
+// eliding the final trailing ASCII white space.
+// Lines after the first are considered continuations if they
+// begin with a space or tab character. In the returned data,
+// continuation lines are separated from the previous line
+// only by a single space: the newline and leading white space
+// are removed.
+//
+// For example, consider this input:
+//
+// Line 1
+// continued...
+// Line 2
+//
+// The first call to ReadContinuedLine will return "Line 1 continued..."
+// and the second will return "Line 2".
+//
+// A line consisting of only white space is never continued.
+//
+func (r *Reader) ReadContinuedLine() (string, os.Error) {
+ line, err := r.ReadContinuedLineBytes()
+ return string(line), err
+}
+
+// trim returns s with leading and trailing spaces and tabs removed.
+// It does not assume Unicode or UTF-8.
+func trim(s []byte) []byte {
+ i := 0
+ for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
+ i++
+ }
+ n := len(s)
+ for n > i && (s[n-1] == ' ' || s[n-1] == '\t') {
+ n--
+ }
+ return s[i:n]
+}
+
+// ReadContinuedLineBytes is like ReadContinuedLine but
+// returns a []byte instead of a string.
+func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
+ // Read the first line.
+ line, err := r.ReadLineBytes()
+ if err != nil {
+ return line, err
+ }
+ if len(line) == 0 { // blank line - no continuation
+ return line, nil
+ }
+ line = trim(line)
+
+ // Look for a continuation line.
+ c, err := r.R.ReadByte()
+ if err != nil {
+ // Delay err until we read the byte next time.
+ return line, nil
+ }
+ if c != ' ' && c != '\t' {
+ // Not a continuation.
+ r.R.UnreadByte()
+ return line, nil
+ }
+
+ // Read continuation lines.
+ for {
+ // Consume leading spaces; one already gone.
+ for {
+ c, err = r.R.ReadByte()
+ if err != nil {
+ break
+ }
+ if c != ' ' && c != '\t' {
+ r.R.UnreadByte()
+ break
+ }
+ }
+ var cont []byte
+ cont, err = r.ReadLineBytes()
+ cont = trim(cont)
+ line = append(line, ' ')
+ line = append(line, cont...)
+ if err != nil {
+ break
+ }
+
+ // Check for leading space on next line.
+ if c, err = r.R.ReadByte(); err != nil {
+ break
+ }
+ if c != ' ' && c != '\t' {
+ r.R.UnreadByte()
+ break
+ }
+ }
+
+ // Delay error until next call.
+ if len(line) > 0 {
+ err = nil
+ }
+ return line, err
+}
+
+func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message string, err os.Error) {
+ line, err := r.ReadLine()
+ if err != nil {
+ return
+ }
+ if len(line) < 4 || line[3] != ' ' && line[3] != '-' {
+ err = ProtocolError("short response: " + line)
+ return
+ }
+ continued = line[3] == '-'
+ code, err = strconv.Atoi(line[0:3])
+ if err != nil || code < 100 {
+ err = ProtocolError("invalid response code: " + line)
+ return
+ }
+ message = line[4:]
+ if 1 <= expectCode && expectCode < 10 && code/100 != expectCode ||
+ 10 <= expectCode && expectCode < 100 && code/10 != expectCode ||
+ 100 <= expectCode && expectCode < 1000 && code != expectCode {
+ err = &Error{code, message}
+ }
+ return
+}
+
+// ReadCodeLine reads a response code line of the form
+// code message
+// where code is a 3-digit status code and the message
+// extends to the rest of the line. An example of such a line is:
+// 220 plan9.bell-labs.com ESMTP
+//
+// If the prefix of the status does not match the digits in expectCode,
+// ReadCodeLine returns with err set to &Error{code, message}.
+// For example, if expectCode is 31, an error will be returned if
+// the status is not in the range [310,319].
+//
+// If the response is multi-line, ReadCodeLine returns an error.
+//
+// An expectCode <= 0 disables the check of the status code.
+//
+func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err os.Error) {
+ code, continued, message, err := r.readCodeLine(expectCode)
+ if err == nil && continued {
+ err = ProtocolError("unexpected multi-line response: " + message)
+ }
+ return
+}
+
+// ReadResponse reads a multi-line response of the form
+// code-message line 1
+// code-message line 2
+// ...
+// code message line n
+// where code is a 3-digit status code. Each line should have the same code.
+// The response is terminated by a line that uses a space between the code and
+// the message line rather than a dash. Each line in message is separated by
+// a newline (\n).
+//
+// If the prefix of the status does not match the digits in expectCode,
+// ReadResponse returns with err set to &Error{code, message}.
+// For example, if expectCode is 31, an error will be returned if
+// the status is not in the range [310,319].
+//
+// An expectCode <= 0 disables the check of the status code.
+//
+func (r *Reader) ReadResponse(expectCode int) (code int, message string, err os.Error) {
+ code, continued, message, err := r.readCodeLine(expectCode)
+ for err == nil && continued {
+ var code2 int
+ var moreMessage string
+ code2, continued, moreMessage, err = r.readCodeLine(expectCode)
+ if code != code2 {
+ err = ProtocolError("status code mismatch: " + strconv.Itoa(code) + ", " + strconv.Itoa(code2))
+ }
+ message += "\n" + moreMessage
+ }
+ return
+}
+
+// DotReader returns a new Reader that satisfies Reads using the
+// decoded text of a dot-encoded block read from r.
+// The returned Reader is only valid until the next call
+// to a method on r.
+//
+// Dot encoding is a common framing used for data blocks
+// in text protcols like SMTP. The data consists of a sequence
+// of lines, each of which ends in "\r\n". The sequence itself
+// ends at a line containing just a dot: ".\r\n". Lines beginning
+// with a dot are escaped with an additional dot to avoid
+// looking like the end of the sequence.
+//
+// The decoded form returned by the Reader's Read method
+// rewrites the "\r\n" line endings into the simpler "\n",
+// removes leading dot escapes if present, and stops with error os.EOF
+// after consuming (and discarding) the end-of-sequence line.
+func (r *Reader) DotReader() io.Reader {
+ r.closeDot()
+ r.dot = &dotReader{r: r}
+ return r.dot
+}
+
+type dotReader struct {
+ r *Reader
+ state int
+}
+
+// Read satisfies reads by decoding dot-encoded data read from d.r.
+func (d *dotReader) Read(b []byte) (n int, err os.Error) {
+ // Run data through a simple state machine to
+ // elide leading dots, rewrite trailing \r\n into \n,
+ // and detect ending .\r\n line.
+ const (
+ stateBeginLine = iota // beginning of line; initial state; must be zero
+ stateDot // read . at beginning of line
+ stateDotCR // read .\r at beginning of line
+ stateCR // read \r (possibly at end of line)
+ stateData // reading data in middle of line
+ stateEOF // reached .\r\n end marker line
+ )
+ br := d.r.R
+ for n < len(b) && d.state != stateEOF {
+ var c byte
+ c, err = br.ReadByte()
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ break
+ }
+ switch d.state {
+ case stateBeginLine:
+ if c == '.' {
+ d.state = stateDot
+ continue
+ }
+ if c == '\r' {
+ d.state = stateCR
+ continue
+ }
+ d.state = stateData
+
+ case stateDot:
+ if c == '\r' {
+ d.state = stateDotCR
+ continue
+ }
+ if c == '\n' {
+ d.state = stateEOF
+ continue
+ }
+ d.state = stateData
+
+ case stateDotCR:
+ if c == '\n' {
+ d.state = stateEOF
+ continue
+ }
+ // Not part of .\r\n.
+ // Consume leading dot and emit saved \r.
+ br.UnreadByte()
+ c = '\r'
+ d.state = stateData
+
+ case stateCR:
+ if c == '\n' {
+ d.state = stateBeginLine
+ break
+ }
+ // Not part of \r\n. Emit saved \r
+ br.UnreadByte()
+ c = '\r'
+ d.state = stateData
+
+ case stateData:
+ if c == '\r' {
+ d.state = stateCR
+ continue
+ }
+ if c == '\n' {
+ d.state = stateBeginLine
+ }
+ }
+ b[n] = c
+ n++
+ }
+ if err == nil && d.state == stateEOF {
+ err = os.EOF
+ }
+ if err != nil && d.r.dot == d {
+ d.r.dot = nil
+ }
+ return
+}
+
+// closeDot drains the current DotReader if any,
+// making sure that it reads until the ending dot line.
+func (r *Reader) closeDot() {
+ if r.dot == nil {
+ return
+ }
+ buf := make([]byte, 128)
+ for r.dot != nil {
+ // When Read reaches EOF or an error,
+ // it will set r.dot == nil.
+ r.dot.Read(buf)
+ }
+}
+
+// ReadDotBytes reads a dot-encoding and returns the decoded data.
+//
+// See the documentation for the DotReader method for details about dot-encoding.
+func (r *Reader) ReadDotBytes() ([]byte, os.Error) {
+ return ioutil.ReadAll(r.DotReader())
+}
+
+// ReadDotLines reads a dot-encoding and returns a slice
+// containing the decoded lines, with the final \r\n or \n elided from each.
+//
+// See the documentation for the DotReader method for details about dot-encoding.
+func (r *Reader) ReadDotLines() ([]string, os.Error) {
+ // We could use ReadDotBytes and then Split it,
+ // but reading a line at a time avoids needing a
+ // large contiguous block of memory and is simpler.
+ var v vector.StringVector
+ var err os.Error
+ for {
+ var line string
+ line, err = r.ReadLine()
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ break
+ }
+
+ // Dot by itself marks end; otherwise cut one dot.
+ if len(line) > 0 && line[0] == '.' {
+ if len(line) == 1 {
+ break
+ }
+ line = line[1:]
+ }
+ v.Push(line)
+ }
+ return v, err
+}
+
+// ReadMIMEHeader reads a MIME-style header from r.
+// The header is a sequence of possibly continued Key: Value lines
+// ending in a blank line.
+// The returned map m maps CanonicalHeaderKey(key) to a
+// sequence of values in the same order encountered in the input.
+//
+// For example, consider this input:
+//
+// My-Key: Value 1
+// Long-Key: Even
+// Longer Value
+// My-Key: Value 2
+//
+// Given that input, ReadMIMEHeader returns the map:
+//
+// map[string][]string{
+// "My-Key": []string{"Value 1", "Value 2"},
+// "Long-Key": []string{"Even Longer Value"},
+// }
+//
+func (r *Reader) ReadMIMEHeader() (map[string][]string, os.Error) {
+ m := make(map[string][]string)
+ for {
+ kv, err := r.ReadContinuedLineBytes()
+ if len(kv) == 0 {
+ return m, err
+ }
+
+ // Key ends at first colon; must not have spaces.
+ i := bytes.IndexByte(kv, ':')
+ if i < 0 || bytes.IndexByte(kv[0:i], ' ') >= 0 {
+ return m, ProtocolError("malformed MIME header line: " + string(kv))
+ }
+ key := CanonicalHeaderKey(string(kv[0:i]))
+
+ // Skip initial spaces in value.
+ i++ // skip colon
+ for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') {
+ i++
+ }
+ value := string(kv[i:])
+
+ v := vector.StringVector(m[key])
+ v.Push(value)
+ m[key] = v
+
+ if err != nil {
+ return m, err
+ }
+ }
+ panic("unreachable")
+}
+
+// CanonicalHeaderKey returns the canonical format of the
+// MIME header key s. The canonicalization converts the first
+// letter and any letter following a hyphen to upper case;
+// the rest are converted to lowercase. For example, the
+// canonical key for "accept-encoding" is "Accept-Encoding".
+func CanonicalHeaderKey(s string) string {
+ // Quick check for canonical encoding.
+ needUpper := true
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if needUpper && 'a' <= c && c <= 'z' {
+ goto MustRewrite
+ }
+ if !needUpper && 'A' <= c && c <= 'Z' {
+ goto MustRewrite
+ }
+ needUpper = c == '-'
+ }
+ return s
+
+MustRewrite:
+ // Canonicalize: first letter upper case
+ // and upper case after each dash.
+ // (Host, User-Agent, If-Modified-Since).
+ // MIME headers are ASCII only, so no Unicode issues.
+ a := []byte(s)
+ upper := true
+ for i, v := range a {
+ if upper && 'a' <= v && v <= 'z' {
+ a[i] = v + 'A' - 'a'
+ }
+ if !upper && 'A' <= v && v <= 'Z' {
+ a[i] = v + 'a' - 'A'
+ }
+ upper = v == '-'
+ }
+ return string(a)
+}
diff --git a/libgo/go/net/textproto/reader_test.go b/libgo/go/net/textproto/reader_test.go
new file mode 100644
index 000000000..2cecbc75f
--- /dev/null
+++ b/libgo/go/net/textproto/reader_test.go
@@ -0,0 +1,140 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+ "bufio"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type canonicalHeaderKeyTest struct {
+ in, out string
+}
+
+var canonicalHeaderKeyTests = []canonicalHeaderKeyTest{
+ {"a-b-c", "A-B-C"},
+ {"a-1-c", "A-1-C"},
+ {"User-Agent", "User-Agent"},
+ {"uSER-aGENT", "User-Agent"},
+ {"user-agent", "User-Agent"},
+ {"USER-AGENT", "User-Agent"},
+}
+
+func TestCanonicalHeaderKey(t *testing.T) {
+ for _, tt := range canonicalHeaderKeyTests {
+ if s := CanonicalHeaderKey(tt.in); s != tt.out {
+ t.Errorf("CanonicalHeaderKey(%q) = %q, want %q", tt.in, s, tt.out)
+ }
+ }
+}
+
+func reader(s string) *Reader {
+ return NewReader(bufio.NewReader(strings.NewReader(s)))
+}
+
+func TestReadLine(t *testing.T) {
+ r := reader("line1\nline2\n")
+ s, err := r.ReadLine()
+ if s != "line1" || err != nil {
+ t.Fatalf("Line 1: %s, %v", s, err)
+ }
+ s, err = r.ReadLine()
+ if s != "line2" || err != nil {
+ t.Fatalf("Line 2: %s, %v", s, err)
+ }
+ s, err = r.ReadLine()
+ if s != "" || err != os.EOF {
+ t.Fatalf("EOF: %s, %v", s, err)
+ }
+}
+
+func TestReadContinuedLine(t *testing.T) {
+ r := reader("line1\nline\n 2\nline3\n")
+ s, err := r.ReadContinuedLine()
+ if s != "line1" || err != nil {
+ t.Fatalf("Line 1: %s, %v", s, err)
+ }
+ s, err = r.ReadContinuedLine()
+ if s != "line 2" || err != nil {
+ t.Fatalf("Line 2: %s, %v", s, err)
+ }
+ s, err = r.ReadContinuedLine()
+ if s != "line3" || err != nil {
+ t.Fatalf("Line 3: %s, %v", s, err)
+ }
+ s, err = r.ReadContinuedLine()
+ if s != "" || err != os.EOF {
+ t.Fatalf("EOF: %s, %v", s, err)
+ }
+}
+
+func TestReadCodeLine(t *testing.T) {
+ r := reader("123 hi\n234 bye\n345 no way\n")
+ code, msg, err := r.ReadCodeLine(0)
+ if code != 123 || msg != "hi" || err != nil {
+ t.Fatalf("Line 1: %d, %s, %v", code, msg, err)
+ }
+ code, msg, err = r.ReadCodeLine(23)
+ if code != 234 || msg != "bye" || err != nil {
+ t.Fatalf("Line 2: %d, %s, %v", code, msg, err)
+ }
+ code, msg, err = r.ReadCodeLine(346)
+ if code != 345 || msg != "no way" || err == nil {
+ t.Fatalf("Line 3: %d, %s, %v", code, msg, err)
+ }
+ if e, ok := err.(*Error); !ok || e.Code != code || e.Msg != msg {
+ t.Fatalf("Line 3: wrong error %v\n", err)
+ }
+ code, msg, err = r.ReadCodeLine(1)
+ if code != 0 || msg != "" || err != os.EOF {
+ t.Fatalf("EOF: %d, %s, %v", code, msg, err)
+ }
+}
+
+func TestReadDotLines(t *testing.T) {
+ r := reader("dotlines\r\n.foo\r\n..bar\n...baz\nquux\r\n\r\n.\r\nanother\n")
+ s, err := r.ReadDotLines()
+ want := []string{"dotlines", "foo", ".bar", "..baz", "quux", ""}
+ if !reflect.DeepEqual(s, want) || err != nil {
+ t.Fatalf("ReadDotLines: %v, %v", s, err)
+ }
+
+ s, err = r.ReadDotLines()
+ want = []string{"another"}
+ if !reflect.DeepEqual(s, want) || err != io.ErrUnexpectedEOF {
+ t.Fatalf("ReadDotLines2: %v, %v", s, err)
+ }
+}
+
+func TestReadDotBytes(t *testing.T) {
+ r := reader("dotlines\r\n.foo\r\n..bar\n...baz\nquux\r\n\r\n.\r\nanot.her\r\n")
+ b, err := r.ReadDotBytes()
+ want := []byte("dotlines\nfoo\n.bar\n..baz\nquux\n\n")
+ if !reflect.DeepEqual(b, want) || err != nil {
+ t.Fatalf("ReadDotBytes: %q, %v", b, err)
+ }
+
+ b, err = r.ReadDotBytes()
+ want = []byte("anot.her\n")
+ if !reflect.DeepEqual(b, want) || err != io.ErrUnexpectedEOF {
+ t.Fatalf("ReadDotBytes2: %q, %v", b, err)
+ }
+}
+
+func TestReadMIMEHeader(t *testing.T) {
+ r := reader("my-key: Value 1 \r\nLong-key: Even \n Longer Value\r\nmy-Key: Value 2\r\n\n")
+ m, err := r.ReadMIMEHeader()
+ want := map[string][]string{
+ "My-Key": {"Value 1", "Value 2"},
+ "Long-Key": {"Even Longer Value"},
+ }
+ if !reflect.DeepEqual(m, want) || err != nil {
+ t.Fatalf("ReadMIMEHeader: %v, %v; want %v", m, err, want)
+ }
+}
diff --git a/libgo/go/net/textproto/textproto.go b/libgo/go/net/textproto/textproto.go
new file mode 100644
index 000000000..f62009c52
--- /dev/null
+++ b/libgo/go/net/textproto/textproto.go
@@ -0,0 +1,122 @@
+// 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.
+
+// The textproto package implements generic support for
+// text-based request/response protocols in the style of
+// HTTP, NNTP, and SMTP.
+//
+// The package provides:
+//
+// Error, which represents a numeric error response from
+// a server.
+//
+// Pipeline, to manage pipelined requests and responses
+// in a client.
+//
+// Reader, to read numeric response code lines,
+// key: value headers, lines wrapped with leading spaces
+// on continuation lines, and whole text blocks ending
+// with a dot on a line by itself.
+//
+// Writer, to write dot-encoded text blocks.
+//
+package textproto
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "net"
+ "os"
+)
+
+// An Error represents a numeric error response from a server.
+type Error struct {
+ Code int
+ Msg string
+}
+
+func (e *Error) String() string {
+ return fmt.Sprintf("%03d %s", e.Code, e.Msg)
+}
+
+// A ProtocolError describes a protocol violation such
+// as an invalid response or a hung-up connection.
+type ProtocolError string
+
+func (p ProtocolError) String() string {
+ return string(p)
+}
+
+// A Conn represents a textual network protocol connection.
+// It consists of a Reader and Writer to manage I/O
+// and a Pipeline to sequence concurrent requests on the connection.
+// These embedded types carry methods with them;
+// see the documentation of those types for details.
+type Conn struct {
+ Reader
+ Writer
+ Pipeline
+ conn io.ReadWriteCloser
+}
+
+// NewConn returns a new Conn using conn for I/O.
+func NewConn(conn io.ReadWriteCloser) *Conn {
+ return &Conn{
+ Reader: Reader{R: bufio.NewReader(conn)},
+ Writer: Writer{W: bufio.NewWriter(conn)},
+ conn: conn,
+ }
+}
+
+// Close closes the connection.
+func (c *Conn) Close() os.Error {
+ return c.conn.Close()
+}
+
+// Dial connects to the given address on the given network using net.Dial
+// and then returns a new Conn for the connection.
+func Dial(network, addr string) (*Conn, os.Error) {
+ c, err := net.Dial(network, "", addr)
+ if err != nil {
+ return nil, err
+ }
+ return NewConn(c), nil
+}
+
+// Cmd is a convenience method that sends a command after
+// waiting its turn in the pipeline. The command text is the
+// result of formatting format with args and appending \r\n.
+// Cmd returns the id of the command, for use with StartResponse and EndResponse.
+//
+// For example, a client might run a HELP command that returns a dot-body
+// by using:
+//
+// id, err := c.Cmd("HELP")
+// if err != nil {
+// return nil, err
+// }
+//
+// c.StartResponse(id)
+// defer c.EndResponse(id)
+//
+// if _, _, err = c.ReadCodeLine(110); err != nil {
+// return nil, err
+// }
+// text, err := c.ReadDotAll()
+// if err != nil {
+// return nil, err
+// }
+// return c.ReadCodeLine(250)
+//
+func (c *Conn) Cmd(format string, args ...interface{}) (id uint, err os.Error) {
+ id = c.Next()
+ c.StartRequest(id)
+ err = c.PrintfLine(format, args...)
+ c.EndRequest(id)
+ if err != nil {
+ return 0, err
+ }
+ return id, nil
+}
diff --git a/libgo/go/net/textproto/writer.go b/libgo/go/net/textproto/writer.go
new file mode 100644
index 000000000..4e705f6c3
--- /dev/null
+++ b/libgo/go/net/textproto/writer.go
@@ -0,0 +1,119 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+)
+
+// A Writer implements convenience methods for writing
+// requests or responses to a text protocol network connection.
+type Writer struct {
+ W *bufio.Writer
+ dot *dotWriter
+}
+
+// NewWriter returns a new Writer writing to w.
+func NewWriter(w *bufio.Writer) *Writer {
+ return &Writer{W: w}
+}
+
+var crnl = []byte{'\r', '\n'}
+var dotcrnl = []byte{'.', '\r', '\n'}
+
+// PrintfLine writes the formatted output followed by \r\n.
+func (w *Writer) PrintfLine(format string, args ...interface{}) os.Error {
+ w.closeDot()
+ fmt.Fprintf(w.W, format, args...)
+ w.W.Write(crnl)
+ return w.W.Flush()
+}
+
+// DotWriter returns a writer that can be used to write a dot-encoding to w.
+// It takes care of inserting leading dots when necessary,
+// translating line-ending \n into \r\n, and adding the final .\r\n line
+// when the DotWriter is closed. The caller should close the
+// DotWriter before the next call to a method on w.
+//
+// See the documentation for Reader's DotReader method for details about dot-encoding.
+func (w *Writer) DotWriter() io.WriteCloser {
+ w.closeDot()
+ w.dot = &dotWriter{w: w}
+ return w.dot
+}
+
+func (w *Writer) closeDot() {
+ if w.dot != nil {
+ w.dot.Close() // sets w.dot = nil
+ }
+}
+
+type dotWriter struct {
+ w *Writer
+ state int
+}
+
+const (
+ wstateBeginLine = iota // beginning of line; initial state; must be zero
+ wstateCR // wrote \r (possibly at end of line)
+ wstateData // writing data in middle of line
+)
+
+func (d *dotWriter) Write(b []byte) (n int, err os.Error) {
+ bw := d.w.W
+ for n < len(b) {
+ c := b[n]
+ switch d.state {
+ case wstateBeginLine:
+ d.state = wstateData
+ if c == '.' {
+ // escape leading dot
+ bw.WriteByte('.')
+ }
+ fallthrough
+
+ case wstateData:
+ if c == '\r' {
+ d.state = wstateCR
+ }
+ if c == '\n' {
+ bw.WriteByte('\r')
+ d.state = wstateBeginLine
+ }
+
+ case wstateCR:
+ d.state = wstateData
+ if c == '\n' {
+ d.state = wstateBeginLine
+ }
+ }
+ if err = bw.WriteByte(c); err != nil {
+ break
+ }
+ n++
+ }
+ return
+}
+
+func (d *dotWriter) Close() os.Error {
+ if d.w.dot == d {
+ d.w.dot = nil
+ }
+ bw := d.w.W
+ switch d.state {
+ default:
+ bw.WriteByte('\r')
+ fallthrough
+ case wstateCR:
+ bw.WriteByte('\n')
+ fallthrough
+ case wstateBeginLine:
+ bw.Write(dotcrnl)
+ }
+ return bw.Flush()
+}
diff --git a/libgo/go/net/textproto/writer_test.go b/libgo/go/net/textproto/writer_test.go
new file mode 100644
index 000000000..e03ab5e15
--- /dev/null
+++ b/libgo/go/net/textproto/writer_test.go
@@ -0,0 +1,35 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+ "bufio"
+ "bytes"
+ "testing"
+)
+
+func TestPrintfLine(t *testing.T) {
+ var buf bytes.Buffer
+ w := NewWriter(bufio.NewWriter(&buf))
+ err := w.PrintfLine("foo %d", 123)
+ if s := buf.String(); s != "foo 123\r\n" || err != nil {
+ t.Fatalf("s=%q; err=%s", s, err)
+ }
+}
+
+func TestDotWriter(t *testing.T) {
+ var buf bytes.Buffer
+ w := NewWriter(bufio.NewWriter(&buf))
+ d := w.DotWriter()
+ n, err := d.Write([]byte("abc\n.def\n..ghi\n.jkl\n."))
+ if n != 21 || err != nil {
+ t.Fatalf("Write: %d, %s", n, err)
+ }
+ d.Close()
+ want := "abc\r\n..def\r\n...ghi\r\n..jkl\r\n..\r\n.\r\n"
+ if s := buf.String(); s != want {
+ t.Fatalf("wrote %q", s)
+ }
+}
diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go
new file mode 100644
index 000000000..09a257dc8
--- /dev/null
+++ b/libgo/go/net/timeout_test.go
@@ -0,0 +1,57 @@
+// 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 net
+
+import (
+ "os"
+ "testing"
+ "time"
+)
+
+func testTimeout(t *testing.T, network, addr string, readFrom bool) {
+ fd, err := Dial(network, "", addr)
+ if err != nil {
+ t.Errorf("dial %s %s failed: %v", network, addr, err)
+ return
+ }
+ defer fd.Close()
+ t0 := time.Nanoseconds()
+ fd.SetReadTimeout(1e8) // 100ms
+ var b [100]byte
+ var n int
+ var err1 os.Error
+ if readFrom {
+ n, _, err1 = fd.(PacketConn).ReadFrom(b[0:])
+ } else {
+ n, err1 = fd.Read(b[0:])
+ }
+ t1 := time.Nanoseconds()
+ what := "Read"
+ if readFrom {
+ what = "ReadFrom"
+ }
+ if n != 0 || err1 == nil || !err1.(Error).Timeout() {
+ t.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
+ }
+ if t1-t0 < 0.5e8 || t1-t0 > 1.5e8 {
+ t.Errorf("fd.%s on %s %s took %f seconds, expected 0.1", what, network, addr, float64(t1-t0)/1e9)
+ }
+}
+
+func TestTimeoutUDP(t *testing.T) {
+ testTimeout(t, "udp", "127.0.0.1:53", false)
+ testTimeout(t, "udp", "127.0.0.1:53", true)
+}
+
+func TestTimeoutTCP(t *testing.T) {
+ // set up a listener that won't talk back
+ listening := make(chan string)
+ done := make(chan int)
+ go runServe(t, "tcp", "127.0.0.1:0", listening, done)
+ addr := <-listening
+
+ testTimeout(t, "tcp", addr, false)
+ <-done
+}
diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go
new file mode 100644
index 000000000..0270954c1
--- /dev/null
+++ b/libgo/go/net/udpsock.go
@@ -0,0 +1,281 @@
+// 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.
+
+// UDP sockets
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func sockaddrToUDP(sa syscall.Sockaddr) Addr {
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return &UDPAddr{sa.Addr[0:], sa.Port}
+ case *syscall.SockaddrInet6:
+ return &UDPAddr{sa.Addr[0:], sa.Port}
+ }
+ return nil
+}
+
+// UDPAddr represents the address of a UDP end point.
+type UDPAddr struct {
+ IP IP
+ Port int
+}
+
+// Network returns the address's network name, "udp".
+func (a *UDPAddr) Network() string { return "udp" }
+
+func (a *UDPAddr) String() string {
+ if a == nil {
+ return "<nil>"
+ }
+ return joinHostPort(a.IP.String(), itoa(a.Port))
+}
+
+func (a *UDPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if ip := a.IP.To4(); ip != nil {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+ return ipToSockaddr(family, a.IP, a.Port)
+}
+
+func (a *UDPAddr) toAddr() sockaddr {
+ if a == nil { // nil *UDPAddr
+ return nil // nil interface
+ }
+ return a
+}
+
+// ResolveUDPAddr parses addr as a UDP address of the form
+// host:port and resolves domain names or port names to
+// numeric addresses. A literal IPv6 host address must be
+// enclosed in square brackets, as in "[::]:80".
+func ResolveUDPAddr(addr string) (*UDPAddr, os.Error) {
+ ip, port, err := hostPortToIP("udp", addr)
+ if err != nil {
+ return nil, err
+ }
+ return &UDPAddr{ip, port}, nil
+}
+
+// UDPConn is the implementation of the Conn and PacketConn
+// interfaces for UDP network connections.
+type UDPConn struct {
+ fd *netFD
+}
+
+func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{fd} }
+
+func (c *UDPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *UDPConn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Read(b)
+}
+
+// Write implements the net.Conn Write method.
+func (c *UDPConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the UDP connection.
+func (c *UDPConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address.
+func (c *UDPConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *UDPAddr.
+func (c *UDPConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *UDPConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *UDPConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *UDPConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *UDPConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *UDPConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// UDP-specific methods.
+
+// ReadFromUDP reads a UDP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromUDP can be made to time out and return an error with Timeout() == true
+// after a fixed time limit; see SetTimeout and SetReadTimeout.
+func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, sa, err := c.fd.ReadFrom(b)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ addr = &UDPAddr{sa.Addr[0:], sa.Port}
+ case *syscall.SockaddrInet6:
+ addr = &UDPAddr{sa.Addr[0:], sa.Port}
+ }
+ return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, uaddr, err := c.ReadFromUDP(b)
+ return n, uaddr.toAddr(), err
+}
+
+// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
+//
+// WriteToUDP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ sa, err1 := addr.sockaddr(c.fd.family)
+ if err1 != nil {
+ return 0, &OpError{Op: "write", Net: "udp", Addr: addr, Error: err1}
+ }
+ return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ a, ok := addr.(*UDPAddr)
+ if !ok {
+ return 0, &OpError{"writeto", "udp", addr, os.EINVAL}
+ }
+ return c.WriteToUDP(b, a)
+}
+
+// DialUDP connects to the remote address raddr on the network net,
+// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if raddr == nil {
+ return nil, &OpError{"dial", "udp", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
+ if e != nil {
+ return nil, e
+ }
+ return newUDPConn(fd), nil
+}
+
+// ListenUDP listens for incoming UDP packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send UDP
+// packets with per-packet addressing.
+func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr == nil {
+ return nil, &OpError{"listen", "udp", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
+ if e != nil {
+ return nil, e
+ }
+ return newUDPConn(fd), nil
+}
+
+// BindToDevice binds a UDPConn to a network interface.
+func (c *UDPConn) BindToDevice(device string) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ c.fd.incref()
+ defer c.fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UDPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
diff --git a/libgo/go/net/unixsock.go b/libgo/go/net/unixsock.go
new file mode 100644
index 000000000..8c26a7baf
--- /dev/null
+++ b/libgo/go/net/unixsock.go
@@ -0,0 +1,449 @@
+// 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.
+
+// Unix domain sockets
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err os.Error) {
+ var proto int
+ switch net {
+ default:
+ return nil, UnknownNetworkError(net)
+ case "unix":
+ proto = syscall.SOCK_STREAM
+ case "unixgram":
+ proto = syscall.SOCK_DGRAM
+ case "unixpacket":
+ proto = syscall.SOCK_SEQPACKET
+ }
+
+ var la, ra syscall.Sockaddr
+ switch mode {
+ default:
+ panic("unixSocket mode " + mode)
+
+ case "dial":
+ if laddr != nil {
+ la = &syscall.SockaddrUnix{Name: laddr.Name}
+ }
+ if raddr != nil {
+ ra = &syscall.SockaddrUnix{Name: raddr.Name}
+ } else if proto != syscall.SOCK_DGRAM || laddr == nil {
+ return nil, &OpError{Op: mode, Net: net, Error: errMissingAddress}
+ }
+
+ case "listen":
+ if laddr == nil {
+ return nil, &OpError{mode, net, nil, errMissingAddress}
+ }
+ la = &syscall.SockaddrUnix{Name: laddr.Name}
+ if raddr != nil {
+ return nil, &OpError{Op: mode, Net: net, Addr: raddr, Error: &AddrError{Error: "unexpected remote address", Addr: raddr.String()}}
+ }
+ }
+
+ f := sockaddrToUnix
+ if proto == syscall.SOCK_DGRAM {
+ f = sockaddrToUnixgram
+ } else if proto == syscall.SOCK_SEQPACKET {
+ f = sockaddrToUnixpacket
+ }
+
+ fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f)
+ if oserr != nil {
+ goto Error
+ }
+ return fd, nil
+
+Error:
+ addr := raddr
+ if mode == "listen" {
+ addr = laddr
+ }
+ return nil, &OpError{Op: mode, Net: net, Addr: addr, Error: oserr}
+}
+
+// UnixAddr represents the address of a Unix domain socket end point.
+type UnixAddr struct {
+ Name string
+ Net string
+}
+
+func sockaddrToUnix(sa syscall.Sockaddr) Addr {
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
+ return &UnixAddr{s.Name, "unix"}
+ }
+ return nil
+}
+
+func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
+ return &UnixAddr{s.Name, "unixgram"}
+ }
+ return nil
+}
+
+func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
+ return &UnixAddr{s.Name, "unixpacket"}
+ }
+ return nil
+}
+
+func protoToNet(proto int) string {
+ switch proto {
+ case syscall.SOCK_STREAM:
+ return "unix"
+ case syscall.SOCK_SEQPACKET:
+ return "unixpacket"
+ case syscall.SOCK_DGRAM:
+ return "unixgram"
+ default:
+ panic("protoToNet unknown protocol")
+ }
+ return ""
+}
+
+// Network returns the address's network name, "unix" or "unixgram".
+func (a *UnixAddr) Network() string {
+ return a.Net
+}
+
+func (a *UnixAddr) String() string {
+ if a == nil {
+ return "<nil>"
+ }
+ return a.Name
+}
+
+func (a *UnixAddr) toAddr() Addr {
+ if a == nil { // nil *UnixAddr
+ return nil // nil interface
+ }
+ return a
+}
+
+// ResolveUnixAddr parses addr as a Unix domain socket address.
+// The string net gives the network name, "unix", "unixgram" or
+// "unixpacket".
+func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) {
+ switch net {
+ case "unix":
+ case "unixpacket":
+ case "unixgram":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ return &UnixAddr{addr, net}, nil
+}
+
+// UnixConn is an implementation of the Conn interface
+// for connections to Unix domain sockets.
+type UnixConn struct {
+ fd *netFD
+}
+
+func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{fd} }
+
+func (c *UnixConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *UnixConn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Read(b)
+}
+
+// Write implements the net.Conn Write method.
+func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the Unix domain connection.
+func (c *UnixConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address, a *UnixAddr.
+// Unlike in other protocols, LocalAddr is usually nil for dialed connections.
+func (c *UnixConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *UnixAddr.
+// Unlike in other protocols, RemoteAddr is usually nil for connections
+// accepted by a listener.
+func (c *UnixConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *UnixConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *UnixConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *UnixConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// ReadFromUnix reads a packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromUnix can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetReadTimeout.
+func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, sa, err := c.fd.ReadFrom(b)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrUnix:
+ addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
+ }
+ return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, uaddr, err := c.ReadFromUnix(b)
+ return n, uaddr.toAddr(), err
+}
+
+// WriteToUnix writes a packet to addr via c, copying the payload from b.
+//
+// WriteToUnix can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ if addr.Net != protoToNet(c.fd.proto) {
+ return 0, os.EAFNOSUPPORT
+ }
+ sa := &syscall.SockaddrUnix{Name: addr.Name}
+ return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ a, ok := addr.(*UnixAddr)
+ if !ok {
+ return 0, &OpError{"writeto", "unix", addr, os.EINVAL}
+ }
+ return c.WriteToUnix(b, a)
+}
+
+func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err os.Error) {
+ if !c.ok() {
+ return 0, 0, 0, nil, os.EINVAL
+ }
+ n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrUnix:
+ addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
+ }
+ return
+}
+
+func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err os.Error) {
+ if !c.ok() {
+ return 0, 0, os.EINVAL
+ }
+ if addr != nil {
+ if addr.Net != protoToNet(c.fd.proto) {
+ return 0, 0, os.EAFNOSUPPORT
+ }
+ sa := &syscall.SockaddrUnix{Name: addr.Name}
+ return c.fd.WriteMsg(b, oob, sa)
+ }
+ return c.fd.WriteMsg(b, oob, nil)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UnixConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
+// DialUnix connects to the remote address raddr on the network net,
+// which must be "unix" or "unixgram". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err os.Error) {
+ fd, e := unixSocket(net, laddr, raddr, "dial")
+ if e != nil {
+ return nil, e
+ }
+ return newUnixConn(fd), nil
+}
+
+// UnixListener is a Unix domain socket listener.
+// Clients should typically use variables of type Listener
+// instead of assuming Unix domain sockets.
+type UnixListener struct {
+ fd *netFD
+ path string
+}
+
+// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
+// Net must be "unix" (stream sockets).
+func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
+ if net != "unix" && net != "unixgram" && net != "unixpacket" {
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr != nil {
+ laddr = &UnixAddr{laddr.Name, net} // make our own copy
+ }
+ fd, err := unixSocket(net, laddr, nil, "listen")
+ if err != nil {
+ return nil, err
+ }
+ e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
+ if e1 != 0 {
+ closesocket(fd.sysfd)
+ return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Error: os.Errno(e1)}
+ }
+ return &UnixListener{fd, laddr.Name}, nil
+}
+
+// AcceptUnix accepts the next incoming call and returns the new connection
+// and the remote address.
+func (l *UnixListener) AcceptUnix() (c *UnixConn, err os.Error) {
+ if l == nil || l.fd == nil {
+ return nil, os.EINVAL
+ }
+ fd, e := l.fd.accept(sockaddrToUnix)
+ if e != nil {
+ return nil, e
+ }
+ c = newUnixConn(fd)
+ return c, nil
+}
+
+// Accept implements the Accept method in the Listener interface;
+// it waits for the next call and returns a generic Conn.
+func (l *UnixListener) Accept() (c Conn, err os.Error) {
+ c1, err := l.AcceptUnix()
+ if err != nil {
+ return nil, err
+ }
+ return c1, nil
+}
+
+// Close stops listening on the Unix address.
+// Already accepted connections are not closed.
+func (l *UnixListener) Close() os.Error {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+
+ // The operating system doesn't clean up
+ // the file that announcing created, so
+ // we have to clean it up ourselves.
+ // There's a race here--we can't know for
+ // sure whether someone else has come along
+ // and replaced our socket name already--
+ // but this sequence (remove then close)
+ // is at least compatible with the auto-remove
+ // sequence in ListenUnix. It's only non-Go
+ // programs that can mess us up.
+ if l.path[0] != '@' {
+ syscall.Unlink(l.path)
+ }
+ err := l.fd.Close()
+ l.fd = nil
+ return err
+}
+
+// Addr returns the listener's network address.
+func (l *UnixListener) Addr() Addr { return l.fd.laddr }
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (l *UnixListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
+
+// ListenUnixgram listens for incoming Unix datagram packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send UDP
+// packets with per-packet addressing. The network net must be "unixgram".
+func ListenUnixgram(net string, laddr *UnixAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "unixgram":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr == nil {
+ return nil, &OpError{"listen", "unixgram", nil, errMissingAddress}
+ }
+ fd, e := unixSocket(net, laddr, nil, "listen")
+ if e != nil {
+ return nil, e
+ }
+ return newUDPConn(fd), nil
+}
diff --git a/libgo/go/netchan/common.go b/libgo/go/netchan/common.go
new file mode 100644
index 000000000..56c0b2519
--- /dev/null
+++ b/libgo/go/netchan/common.go
@@ -0,0 +1,325 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package netchan
+
+import (
+ "gob"
+ "net"
+ "os"
+ "reflect"
+ "sync"
+ "time"
+)
+
+// The direction of a connection from the client's perspective.
+type Dir int
+
+const (
+ Recv Dir = iota
+ Send
+)
+
+func (dir Dir) String() string {
+ switch dir {
+ case Recv:
+ return "Recv"
+ case Send:
+ return "Send"
+ }
+ return "???"
+}
+
+// Payload types
+const (
+ payRequest = iota // request structure follows
+ payError // error structure follows
+ payData // user payload follows
+ payAck // acknowledgement; no payload
+ payClosed // channel is now closed
+ payAckSend // payload has been delivered.
+)
+
+// A header is sent as a prefix to every transmission. It will be followed by
+// a request structure, an error structure, or an arbitrary user payload structure.
+type header struct {
+ Id int
+ PayloadType int
+ SeqNum int64
+}
+
+// Sent with a header once per channel from importer to exporter to report
+// that it wants to bind to a channel with the specified direction for count
+// messages, with space for size buffered values. If count is -1, it means unlimited.
+type request struct {
+ Name string
+ Count int64
+ Size int
+ Dir Dir
+}
+
+// Sent with a header to report an error.
+type error struct {
+ Error string
+}
+
+// Used to unify management of acknowledgements for import and export.
+type unackedCounter interface {
+ unackedCount() int64
+ ack() int64
+ seq() int64
+}
+
+// A channel and its direction.
+type chanDir struct {
+ ch *reflect.ChanValue
+ dir Dir
+}
+
+// clientSet contains the objects and methods needed for tracking
+// clients of an exporter and draining outstanding messages.
+type clientSet struct {
+ mu sync.Mutex // protects access to channel and client maps
+ names map[string]*chanDir
+ clients map[unackedCounter]bool
+}
+
+// Mutex-protected encoder and decoder pair.
+type encDec struct {
+ decLock sync.Mutex
+ dec *gob.Decoder
+ encLock sync.Mutex
+ enc *gob.Encoder
+}
+
+func newEncDec(conn net.Conn) *encDec {
+ return &encDec{
+ dec: gob.NewDecoder(conn),
+ enc: gob.NewEncoder(conn),
+ }
+}
+
+// Decode an item from the connection.
+func (ed *encDec) decode(value reflect.Value) os.Error {
+ ed.decLock.Lock()
+ err := ed.dec.DecodeValue(value)
+ if err != nil {
+ // TODO: tear down connection?
+ }
+ ed.decLock.Unlock()
+ return err
+}
+
+// Encode a header and payload onto the connection.
+func (ed *encDec) encode(hdr *header, payloadType int, payload interface{}) os.Error {
+ ed.encLock.Lock()
+ hdr.PayloadType = payloadType
+ err := ed.enc.Encode(hdr)
+ if err == nil {
+ if payload != nil {
+ err = ed.enc.Encode(payload)
+ }
+ }
+ if err != nil {
+ // TODO: tear down connection if there is an error?
+ }
+ ed.encLock.Unlock()
+ return err
+}
+
+// See the comment for Exporter.Drain.
+func (cs *clientSet) drain(timeout int64) os.Error {
+ startTime := time.Nanoseconds()
+ for {
+ pending := false
+ cs.mu.Lock()
+ // Any messages waiting for a client?
+ for _, chDir := range cs.names {
+ if chDir.ch.Len() > 0 {
+ pending = true
+ }
+ }
+ // Any unacknowledged messages?
+ for client := range cs.clients {
+ n := client.unackedCount()
+ if n > 0 { // Check for > rather than != just to be safe.
+ pending = true
+ break
+ }
+ }
+ cs.mu.Unlock()
+ if !pending {
+ break
+ }
+ if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+ return os.ErrorString("timeout")
+ }
+ time.Sleep(100 * 1e6) // 100 milliseconds
+ }
+ return nil
+}
+
+// See the comment for Exporter.Sync.
+func (cs *clientSet) sync(timeout int64) os.Error {
+ startTime := time.Nanoseconds()
+ // seq remembers the clients and their seqNum at point of entry.
+ seq := make(map[unackedCounter]int64)
+ for client := range cs.clients {
+ seq[client] = client.seq()
+ }
+ for {
+ pending := false
+ cs.mu.Lock()
+ // Any unacknowledged messages? Look only at clients that existed
+ // when we started and are still in this client set.
+ for client := range seq {
+ if _, ok := cs.clients[client]; ok {
+ if client.ack() < seq[client] {
+ pending = true
+ break
+ }
+ }
+ }
+ cs.mu.Unlock()
+ if !pending {
+ break
+ }
+ if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+ return os.ErrorString("timeout")
+ }
+ time.Sleep(100 * 1e6) // 100 milliseconds
+ }
+ return nil
+}
+
+// A netChan represents a channel imported or exported
+// on a single connection. Flow is controlled by the receiving
+// side by sending payAckSend messages when values
+// are delivered into the local channel.
+type netChan struct {
+ *chanDir
+ name string
+ id int
+ size int // buffer size of channel.
+
+ // sender-specific state
+ ackCh chan bool // buffered with space for all the acks we need
+ space int // available space.
+
+ // receiver-specific state
+ sendCh chan reflect.Value // buffered channel of values received from other end.
+ ed *encDec // so that we can send acks.
+ count int64 // number of values still to receive.
+}
+
+// Create a new netChan with the given name (only used for
+// messages), id, direction, buffer size, and count.
+// The connection to the other side is represented by ed.
+func newNetChan(name string, id int, ch *chanDir, ed *encDec, size int, count int64) *netChan {
+ c := &netChan{chanDir: ch, name: name, id: id, size: size, ed: ed, count: count}
+ if c.dir == Send {
+ c.ackCh = make(chan bool, size)
+ c.space = size
+ }
+ return c
+}
+
+// Close the channel.
+func (nch *netChan) close() {
+ if nch.dir == Recv {
+ if nch.sendCh != nil {
+ // If the sender goroutine is active, close the channel to it.
+ // It will close nch.ch when it can.
+ close(nch.sendCh)
+ } else {
+ nch.ch.Close()
+ }
+ } else {
+ nch.ch.Close()
+ close(nch.ackCh)
+ }
+}
+
+// Send message from remote side to local receiver.
+func (nch *netChan) send(val reflect.Value) {
+ if nch.dir != Recv {
+ panic("send on wrong direction of channel")
+ }
+ if nch.sendCh == nil {
+ // If possible, do local send directly and ack immediately.
+ if nch.ch.TrySend(val) {
+ nch.sendAck()
+ return
+ }
+ // Start sender goroutine to manage delayed delivery of values.
+ nch.sendCh = make(chan reflect.Value, nch.size)
+ go nch.sender()
+ }
+ if ok := nch.sendCh <- val; !ok {
+ // TODO: should this be more resilient?
+ panic("netchan: remote sender sent more values than allowed")
+ }
+}
+
+// sendAck sends an acknowledgment that a message has left
+// the channel's buffer. If the messages remaining to be sent
+// will fit in the channel's buffer, then we don't
+// need to send an ack.
+func (nch *netChan) sendAck() {
+ if nch.count < 0 || nch.count > int64(nch.size) {
+ nch.ed.encode(&header{Id: nch.id}, payAckSend, nil)
+ }
+ if nch.count > 0 {
+ nch.count--
+ }
+}
+
+// The sender process forwards items from the sending queue
+// to the destination channel, acknowledging each item.
+func (nch *netChan) sender() {
+ if nch.dir != Recv {
+ panic("sender on wrong direction of channel")
+ }
+ // When Exporter.Hangup is called, the underlying channel is closed,
+ // and so we may get a "too many operations on closed channel" error
+ // if there are outstanding messages in sendCh.
+ // Make sure that this doesn't panic the whole program.
+ defer func() {
+ if r := recover(); r != nil {
+ // TODO check that r is "too many operations", otherwise re-panic.
+ }
+ }()
+ for v := range nch.sendCh {
+ nch.ch.Send(v)
+ nch.sendAck()
+ }
+ nch.ch.Close()
+}
+
+// Receive value from local side for sending to remote side.
+func (nch *netChan) recv() (val reflect.Value, closed bool) {
+ if nch.dir != Send {
+ panic("recv on wrong direction of channel")
+ }
+
+ if nch.space == 0 {
+ // Wait for buffer space.
+ <-nch.ackCh
+ nch.space++
+ }
+ nch.space--
+ return nch.ch.Recv(), nch.ch.Closed()
+}
+
+// acked is called when the remote side indicates that
+// a value has been delivered.
+func (nch *netChan) acked() {
+ if nch.dir != Send {
+ panic("recv on wrong direction of channel")
+ }
+ if ok := nch.ackCh <- true; !ok {
+ panic("netchan: remote receiver sent too many acks")
+ // TODO: should this be more resilient?
+ }
+}
diff --git a/libgo/go/netchan/export.go b/libgo/go/netchan/export.go
new file mode 100644
index 000000000..0f72ca7a9
--- /dev/null
+++ b/libgo/go/netchan/export.go
@@ -0,0 +1,390 @@
+// 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.
+
+/*
+ The netchan package implements type-safe networked channels:
+ it allows the two ends of a channel to appear on different
+ computers connected by a network. It does this by transporting
+ data sent to a channel on one machine so it can be recovered
+ by a receive of a channel of the same type on the other.
+
+ An exporter publishes a set of channels by name. An importer
+ connects to the exporting machine and imports the channels
+ by name. After importing the channels, the two machines can
+ use the channels in the usual way.
+
+ Networked channels are not synchronized; they always behave
+ as if they are buffered channels of at least one element.
+*/
+package netchan
+
+// BUG: can't use range clause to receive when using ImportNValues to limit the count.
+
+import (
+ "log"
+ "net"
+ "os"
+ "reflect"
+ "strconv"
+ "sync"
+)
+
+// Export
+
+// expLog is a logging convenience function. The first argument must be a string.
+func expLog(args ...interface{}) {
+ args[0] = "netchan export: " + args[0].(string)
+ log.Print(args...)
+}
+
+// An Exporter allows a set of channels to be published on a single
+// network port. A single machine may have multiple Exporters
+// but they must use different ports.
+type Exporter struct {
+ *clientSet
+ listener net.Listener
+}
+
+type expClient struct {
+ *encDec
+ exp *Exporter
+ chans map[int]*netChan // channels in use by client
+ mu sync.Mutex // protects remaining fields
+ errored bool // client has been sent an error
+ seqNum int64 // sequences messages sent to client; has value of highest sent
+ ackNum int64 // highest sequence number acknowledged
+ seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
+}
+
+func newClient(exp *Exporter, conn net.Conn) *expClient {
+ client := new(expClient)
+ client.exp = exp
+ client.encDec = newEncDec(conn)
+ client.seqNum = 0
+ client.ackNum = 0
+ client.chans = make(map[int]*netChan)
+ return client
+}
+
+func (client *expClient) sendError(hdr *header, err string) {
+ error := &error{err}
+ expLog("sending error to client:", error.Error)
+ client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
+ client.mu.Lock()
+ client.errored = true
+ client.mu.Unlock()
+}
+
+func (client *expClient) newChan(hdr *header, dir Dir, name string, size int, count int64) *netChan {
+ exp := client.exp
+ exp.mu.Lock()
+ ech, ok := exp.names[name]
+ exp.mu.Unlock()
+ if !ok {
+ client.sendError(hdr, "no such channel: "+name)
+ return nil
+ }
+ if ech.dir != dir {
+ client.sendError(hdr, "wrong direction for channel: "+name)
+ return nil
+ }
+ nch := newNetChan(name, hdr.Id, ech, client.encDec, size, count)
+ client.chans[hdr.Id] = nch
+ return nch
+}
+
+func (client *expClient) getChan(hdr *header, dir Dir) *netChan {
+ nch := client.chans[hdr.Id]
+ if nch == nil {
+ return nil
+ }
+ if nch.dir != dir {
+ client.sendError(hdr, "wrong direction for channel: "+nch.name)
+ }
+ return nch
+}
+
+// The function run manages sends and receives for a single client. For each
+// (client Recv) request, this will launch a serveRecv goroutine to deliver
+// the data for that channel, while (client Send) requests are handled as
+// data arrives from the client.
+func (client *expClient) run() {
+ hdr := new(header)
+ hdrValue := reflect.NewValue(hdr)
+ req := new(request)
+ reqValue := reflect.NewValue(req)
+ error := new(error)
+ for {
+ *hdr = header{}
+ if err := client.decode(hdrValue); err != nil {
+ expLog("error decoding client header:", err)
+ break
+ }
+ switch hdr.PayloadType {
+ case payRequest:
+ *req = request{}
+ if err := client.decode(reqValue); err != nil {
+ expLog("error decoding client request:", err)
+ break
+ }
+ if req.Size < 1 {
+ panic("netchan: remote requested " + strconv.Itoa(req.Size) + " values")
+ }
+ switch req.Dir {
+ case Recv:
+ // look up channel before calling serveRecv to
+ // avoid a lock around client.chans.
+ if nch := client.newChan(hdr, Send, req.Name, req.Size, req.Count); nch != nil {
+ go client.serveRecv(nch, *hdr, req.Count)
+ }
+ case Send:
+ client.newChan(hdr, Recv, req.Name, req.Size, req.Count)
+ // The actual sends will have payload type payData.
+ // TODO: manage the count?
+ default:
+ error.Error = "request: can't handle channel direction"
+ expLog(error.Error, req.Dir)
+ client.encode(hdr, payError, error)
+ }
+ case payData:
+ client.serveSend(*hdr)
+ case payClosed:
+ client.serveClosed(*hdr)
+ case payAck:
+ client.mu.Lock()
+ if client.ackNum != hdr.SeqNum-1 {
+ // Since the sequence number is incremented and the message is sent
+ // in a single instance of locking client.mu, the messages are guaranteed
+ // to be sent in order. Therefore receipt of acknowledgement N means
+ // all messages <=N have been seen by the recipient. We check anyway.
+ expLog("sequence out of order:", client.ackNum, hdr.SeqNum)
+ }
+ if client.ackNum < hdr.SeqNum { // If there has been an error, don't back up the count.
+ client.ackNum = hdr.SeqNum
+ }
+ client.mu.Unlock()
+ case payAckSend:
+ if nch := client.getChan(hdr, Send); nch != nil {
+ nch.acked()
+ }
+ default:
+ log.Exit("netchan export: unknown payload type", hdr.PayloadType)
+ }
+ }
+ client.exp.delClient(client)
+}
+
+// Send all the data on a single channel to a client asking for a Recv.
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveRecv(nch *netChan, hdr header, count int64) {
+ for {
+ val, closed := nch.recv()
+ if closed {
+ if err := client.encode(&hdr, payClosed, nil); err != nil {
+ expLog("error encoding server closed message:", err)
+ }
+ break
+ }
+ // We hold the lock during transmission to guarantee messages are
+ // sent in sequence number order. Also, we increment first so the
+ // value of client.SeqNum is the value of the highest used sequence
+ // number, not one beyond.
+ client.mu.Lock()
+ client.seqNum++
+ hdr.SeqNum = client.seqNum
+ client.seqLock.Lock() // guarantee ordering of messages
+ client.mu.Unlock()
+ err := client.encode(&hdr, payData, val.Interface())
+ client.seqLock.Unlock()
+ if err != nil {
+ expLog("error encoding client response:", err)
+ client.sendError(&hdr, err.String())
+ break
+ }
+ // Negative count means run forever.
+ if count >= 0 {
+ if count--; count <= 0 {
+ break
+ }
+ }
+ }
+}
+
+// Receive and deliver locally one item from a client asking for a Send
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveSend(hdr header) {
+ nch := client.getChan(&hdr, Recv)
+ if nch == nil {
+ return
+ }
+ // Create a new value for each received item.
+ val := reflect.MakeZero(nch.ch.Type().(*reflect.ChanType).Elem())
+ if err := client.decode(val); err != nil {
+ expLog("value decode:", err, "; type ", nch.ch.Type())
+ return
+ }
+ nch.send(val)
+}
+
+// Report that client has closed the channel that is sending to us.
+// The header is passed by value to avoid issues of overwriting.
+func (client *expClient) serveClosed(hdr header) {
+ nch := client.getChan(&hdr, Recv)
+ if nch == nil {
+ return
+ }
+ nch.close()
+}
+
+func (client *expClient) unackedCount() int64 {
+ client.mu.Lock()
+ n := client.seqNum - client.ackNum
+ client.mu.Unlock()
+ return n
+}
+
+func (client *expClient) seq() int64 {
+ client.mu.Lock()
+ n := client.seqNum
+ client.mu.Unlock()
+ return n
+}
+
+func (client *expClient) ack() int64 {
+ client.mu.Lock()
+ n := client.seqNum
+ client.mu.Unlock()
+ return n
+}
+
+// Wait for incoming connections, start a new runner for each
+func (exp *Exporter) listen() {
+ for {
+ conn, err := exp.listener.Accept()
+ if err != nil {
+ expLog("listen:", err)
+ break
+ }
+ client := exp.addClient(conn)
+ go client.run()
+ }
+}
+
+// NewExporter creates a new Exporter to export channels
+// on the network and local address defined as in net.Listen.
+func NewExporter(network, localaddr string) (*Exporter, os.Error) {
+ listener, err := net.Listen(network, localaddr)
+ if err != nil {
+ return nil, err
+ }
+ e := &Exporter{
+ listener: listener,
+ clientSet: &clientSet{
+ names: make(map[string]*chanDir),
+ clients: make(map[unackedCounter]bool),
+ },
+ }
+ go e.listen()
+ return e, nil
+}
+
+// addClient creates a new expClient and records its existence
+func (exp *Exporter) addClient(conn net.Conn) *expClient {
+ client := newClient(exp, conn)
+ exp.mu.Lock()
+ exp.clients[client] = true
+ exp.mu.Unlock()
+ return client
+}
+
+// delClient forgets the client existed
+func (exp *Exporter) delClient(client *expClient) {
+ exp.mu.Lock()
+ exp.clients[client] = false, false
+ exp.mu.Unlock()
+}
+
+// Drain waits until all messages sent from this exporter/importer, including
+// those not yet sent to any client and possibly including those sent while
+// Drain was executing, have been received by the importer. In short, it
+// waits until all the exporter's messages have been received by a client.
+// If the timeout (measured in nanoseconds) is positive and Drain takes
+// longer than that to complete, an error is returned.
+func (exp *Exporter) Drain(timeout int64) os.Error {
+ // This wrapper function is here so the method's comment will appear in godoc.
+ return exp.clientSet.drain(timeout)
+}
+
+// Sync waits until all clients of the exporter have received the messages
+// that were sent at the time Sync was invoked. Unlike Drain, it does not
+// wait for messages sent while it is running or messages that have not been
+// dispatched to any client. If the timeout (measured in nanoseconds) is
+// positive and Sync takes longer than that to complete, an error is
+// returned.
+func (exp *Exporter) Sync(timeout int64) os.Error {
+ // This wrapper function is here so the method's comment will appear in godoc.
+ return exp.clientSet.sync(timeout)
+}
+
+// Addr returns the Exporter's local network address.
+func (exp *Exporter) Addr() net.Addr { return exp.listener.Addr() }
+
+func checkChan(chT interface{}, dir Dir) (*reflect.ChanValue, os.Error) {
+ chanType, ok := reflect.Typeof(chT).(*reflect.ChanType)
+ if !ok {
+ return nil, os.ErrorString("not a channel")
+ }
+ if dir != Send && dir != Recv {
+ return nil, os.ErrorString("unknown channel direction")
+ }
+ switch chanType.Dir() {
+ case reflect.BothDir:
+ case reflect.SendDir:
+ if dir != Recv {
+ return nil, os.ErrorString("to import/export with Send, must provide <-chan")
+ }
+ case reflect.RecvDir:
+ if dir != Send {
+ return nil, os.ErrorString("to import/export with Recv, must provide chan<-")
+ }
+ }
+ return reflect.NewValue(chT).(*reflect.ChanValue), nil
+}
+
+// Export exports a channel of a given type and specified direction. The
+// channel to be exported is provided in the call and may be of arbitrary
+// channel type.
+// Despite the literal signature, the effective signature is
+// Export(name string, chT chan T, dir Dir)
+func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
+ ch, err := checkChan(chT, dir)
+ if err != nil {
+ return err
+ }
+ exp.mu.Lock()
+ defer exp.mu.Unlock()
+ _, present := exp.names[name]
+ if present {
+ return os.ErrorString("channel name already being exported:" + name)
+ }
+ exp.names[name] = &chanDir{ch, dir}
+ return nil
+}
+
+// Hangup disassociates the named channel from the Exporter and closes
+// the channel. Messages in flight for the channel may be dropped.
+func (exp *Exporter) Hangup(name string) os.Error {
+ exp.mu.Lock()
+ chDir, ok := exp.names[name]
+ if ok {
+ exp.names[name] = nil, false
+ }
+ // TODO drop all instances of channel from client sets
+ exp.mu.Unlock()
+ if !ok {
+ return os.ErrorString("netchan export: hangup: no such channel: " + name)
+ }
+ chDir.ch.Close()
+ return nil
+}
diff --git a/libgo/go/netchan/import.go b/libgo/go/netchan/import.go
new file mode 100644
index 000000000..22b0f69ba
--- /dev/null
+++ b/libgo/go/netchan/import.go
@@ -0,0 +1,243 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package netchan
+
+import (
+ "log"
+ "net"
+ "os"
+ "reflect"
+ "sync"
+)
+
+// Import
+
+// impLog is a logging convenience function. The first argument must be a string.
+func impLog(args ...interface{}) {
+ args[0] = "netchan import: " + args[0].(string)
+ log.Print(args...)
+}
+
+// An Importer allows a set of channels to be imported from a single
+// remote machine/network port. A machine may have multiple
+// importers, even from the same machine/network port.
+type Importer struct {
+ *encDec
+ conn net.Conn
+ chanLock sync.Mutex // protects access to channel map
+ names map[string]*netChan
+ chans map[int]*netChan
+ errors chan os.Error
+ maxId int
+}
+
+// NewImporter creates a new Importer object to import channels
+// from an Exporter at the network and remote address as defined in net.Dial.
+// The Exporter must be available and serving when the Importer is
+// created.
+func NewImporter(network, remoteaddr string) (*Importer, os.Error) {
+ conn, err := net.Dial(network, "", remoteaddr)
+ if err != nil {
+ return nil, err
+ }
+ imp := new(Importer)
+ imp.encDec = newEncDec(conn)
+ imp.conn = conn
+ imp.chans = make(map[int]*netChan)
+ imp.names = make(map[string]*netChan)
+ imp.errors = make(chan os.Error, 10)
+ go imp.run()
+ return imp, nil
+}
+
+// shutdown closes all channels for which we are receiving data from the remote side.
+func (imp *Importer) shutdown() {
+ imp.chanLock.Lock()
+ for _, ich := range imp.chans {
+ if ich.dir == Recv {
+ ich.close()
+ }
+ }
+ imp.chanLock.Unlock()
+}
+
+// Handle the data from a single imported data stream, which will
+// have the form
+// (response, data)*
+// The response identifies by name which channel is transmitting data.
+func (imp *Importer) run() {
+ // Loop on responses; requests are sent by ImportNValues()
+ hdr := new(header)
+ hdrValue := reflect.NewValue(hdr)
+ ackHdr := new(header)
+ err := new(error)
+ errValue := reflect.NewValue(err)
+ for {
+ *hdr = header{}
+ if e := imp.decode(hdrValue); e != nil {
+ impLog("header:", e)
+ imp.shutdown()
+ return
+ }
+ switch hdr.PayloadType {
+ case payData:
+ // done lower in loop
+ case payError:
+ if e := imp.decode(errValue); e != nil {
+ impLog("error:", e)
+ return
+ }
+ if err.Error != "" {
+ impLog("response error:", err.Error)
+ if sent := imp.errors <- os.ErrorString(err.Error); !sent {
+ imp.shutdown()
+ return
+ }
+ continue // errors are not acknowledged.
+ }
+ case payClosed:
+ nch := imp.getChan(hdr.Id, false)
+ if nch != nil {
+ nch.close()
+ }
+ continue // closes are not acknowledged.
+ case payAckSend:
+ // we can receive spurious acks if the channel is
+ // hung up, so we ask getChan to ignore any errors.
+ nch := imp.getChan(hdr.Id, true)
+ if nch != nil {
+ nch.acked()
+ }
+ continue
+ default:
+ impLog("unexpected payload type:", hdr.PayloadType)
+ return
+ }
+ nch := imp.getChan(hdr.Id, false)
+ if nch == nil {
+ continue
+ }
+ if nch.dir != Recv {
+ impLog("cannot happen: receive from non-Recv channel")
+ return
+ }
+ // Acknowledge receipt
+ ackHdr.Id = hdr.Id
+ ackHdr.SeqNum = hdr.SeqNum
+ imp.encode(ackHdr, payAck, nil)
+ // Create a new value for each received item.
+ value := reflect.MakeZero(nch.ch.Type().(*reflect.ChanType).Elem())
+ if e := imp.decode(value); e != nil {
+ impLog("importer value decode:", e)
+ return
+ }
+ nch.send(value)
+ }
+}
+
+func (imp *Importer) getChan(id int, errOk bool) *netChan {
+ imp.chanLock.Lock()
+ ich := imp.chans[id]
+ imp.chanLock.Unlock()
+ if ich == nil {
+ if !errOk {
+ impLog("unknown id in netchan request: ", id)
+ }
+ return nil
+ }
+ return ich
+}
+
+// Errors returns a channel from which transmission and protocol errors
+// can be read. Clients of the importer are not required to read the error
+// channel for correct execution. However, if too many errors occur
+// without being read from the error channel, the importer will shut down.
+func (imp *Importer) Errors() chan os.Error {
+ return imp.errors
+}
+
+// Import imports a channel of the given type, size and specified direction.
+// It is equivalent to ImportNValues with a count of -1, meaning unbounded.
+func (imp *Importer) Import(name string, chT interface{}, dir Dir, size int) os.Error {
+ return imp.ImportNValues(name, chT, dir, size, -1)
+}
+
+// ImportNValues imports a channel of the given type and specified
+// direction and then receives or transmits up to n values on that
+// channel. A value of n==-1 implies an unbounded number of values. The
+// channel will have buffer space for size values, or 1 value if size < 1.
+// The channel to be bound to the remote site's channel is provided
+// in the call and may be of arbitrary channel type.
+// Despite the literal signature, the effective signature is
+// ImportNValues(name string, chT chan T, dir Dir, n int) os.Error
+// Example usage:
+// imp, err := NewImporter("tcp", "netchanserver.mydomain.com:1234")
+// if err != nil { log.Exit(err) }
+// ch := make(chan myType)
+// err = imp.ImportNValues("name", ch, Recv, 1)
+// if err != nil { log.Exit(err) }
+// fmt.Printf("%+v\n", <-ch)
+func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, size, n int) os.Error {
+ ch, err := checkChan(chT, dir)
+ if err != nil {
+ return err
+ }
+ imp.chanLock.Lock()
+ defer imp.chanLock.Unlock()
+ _, present := imp.names[name]
+ if present {
+ return os.ErrorString("channel name already being imported:" + name)
+ }
+ if size < 1 {
+ size = 1
+ }
+ id := imp.maxId
+ imp.maxId++
+ nch := newNetChan(name, id, &chanDir{ch, dir}, imp.encDec, size, int64(n))
+ imp.names[name] = nch
+ imp.chans[id] = nch
+ // Tell the other side about this channel.
+ hdr := &header{Id: id}
+ req := &request{Name: name, Count: int64(n), Dir: dir, Size: size}
+ if err = imp.encode(hdr, payRequest, req); err != nil {
+ impLog("request encode:", err)
+ return err
+ }
+ if dir == Send {
+ go func() {
+ for i := 0; n == -1 || i < n; i++ {
+ val, closed := nch.recv()
+ if closed {
+ if err = imp.encode(hdr, payClosed, nil); err != nil {
+ impLog("error encoding client closed message:", err)
+ }
+ return
+ }
+ if err = imp.encode(hdr, payData, val.Interface()); err != nil {
+ impLog("error encoding client send:", err)
+ return
+ }
+ }
+ }()
+ }
+ return nil
+}
+
+// Hangup disassociates the named channel from the Importer and closes
+// the channel. Messages in flight for the channel may be dropped.
+func (imp *Importer) Hangup(name string) os.Error {
+ imp.chanLock.Lock()
+ nc, ok := imp.names[name]
+ if ok {
+ imp.names[name] = nil, false
+ imp.chans[nc.id] = nil, false
+ }
+ imp.chanLock.Unlock()
+ if !ok {
+ return os.ErrorString("netchan import: hangup: no such channel: " + name)
+ }
+ nc.close()
+ return nil
+}
diff --git a/libgo/go/netchan/netchan_test.go b/libgo/go/netchan/netchan_test.go
new file mode 100644
index 000000000..6d7d63f98
--- /dev/null
+++ b/libgo/go/netchan/netchan_test.go
@@ -0,0 +1,515 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package netchan
+
+import (
+ "strings"
+ "testing"
+ "time"
+)
+
+const count = 10 // number of items in most tests
+const closeCount = 5 // number of items when sender closes early
+
+const base = 23
+
+func exportSend(exp *Exporter, n int, t *testing.T, done chan bool) {
+ ch := make(chan int)
+ err := exp.Export("exportedSend", ch, Send)
+ if err != nil {
+ t.Fatal("exportSend:", err)
+ }
+ go func() {
+ for i := 0; i < n; i++ {
+ ch <- base+i
+ }
+ close(ch)
+ if done != nil {
+ done <- true
+ }
+ }()
+}
+
+func exportReceive(exp *Exporter, t *testing.T, expDone chan bool) {
+ ch := make(chan int)
+ err := exp.Export("exportedRecv", ch, Recv)
+ expDone <- true
+ if err != nil {
+ t.Fatal("exportReceive:", err)
+ }
+ for i := 0; i < count; i++ {
+ v := <-ch
+ if closed(ch) {
+ if i != closeCount {
+ t.Errorf("exportReceive expected close at %d; got one at %d", closeCount, i)
+ }
+ break
+ }
+ if v != base+i {
+ t.Errorf("export Receive: bad value: expected %d+%d=%d; got %d", base, i, base+i, v)
+ }
+ }
+}
+
+func importSend(imp *Importer, n int, t *testing.T, done chan bool) {
+ ch := make(chan int)
+ err := imp.ImportNValues("exportedRecv", ch, Send, 3, -1)
+ if err != nil {
+ t.Fatal("importSend:", err)
+ }
+ go func() {
+ for i := 0; i < n; i++ {
+ ch <- base+i
+ }
+ close(ch)
+ if done != nil {
+ done <- true
+ }
+ }()
+}
+
+func importReceive(imp *Importer, t *testing.T, done chan bool) {
+ ch := make(chan int)
+ err := imp.ImportNValues("exportedSend", ch, Recv, 3, count)
+ if err != nil {
+ t.Fatal("importReceive:", err)
+ }
+ for i := 0; i < count; i++ {
+ v := <-ch
+ if closed(ch) {
+ if i != closeCount {
+ t.Errorf("importReceive expected close at %d; got one at %d", closeCount, i)
+ }
+ break
+ }
+ if v != base+i {
+ t.Errorf("importReceive: bad value: expected %d+%d=%d; got %+d", base, i, base+i, v)
+ }
+ }
+ if done != nil {
+ done <- true
+ }
+}
+
+func TestExportSendImportReceive(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ exportSend(exp, count, t, nil)
+ importReceive(imp, t, nil)
+}
+
+func TestExportReceiveImportSend(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ expDone := make(chan bool)
+ done := make(chan bool)
+ go func() {
+ exportReceive(exp, t, expDone)
+ done <- true
+ }()
+ <-expDone
+ importSend(imp, count, t, nil)
+ <-done
+}
+
+func TestClosingExportSendImportReceive(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ exportSend(exp, closeCount, t, nil)
+ importReceive(imp, t, nil)
+}
+
+func TestClosingImportSendExportReceive(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ expDone := make(chan bool)
+ done := make(chan bool)
+ go func() {
+ exportReceive(exp, t, expDone)
+ done <- true
+ }()
+ <-expDone
+ importSend(imp, closeCount, t, nil)
+ <-done
+}
+
+func TestErrorForIllegalChannel(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ // Now export a channel.
+ ch := make(chan int, 1)
+ err = exp.Export("aChannel", ch, Send)
+ if err != nil {
+ t.Fatal("export:", err)
+ }
+ ch <- 1234
+ close(ch)
+ // Now try to import a different channel.
+ ch = make(chan int)
+ err = imp.Import("notAChannel", ch, Recv, 1)
+ if err != nil {
+ t.Fatal("import:", err)
+ }
+ // Expect an error now. Start a timeout.
+ timeout := make(chan bool, 1) // buffered so closure will not hang around.
+ go func() {
+ time.Sleep(10e9) // very long, to give even really slow machines a chance.
+ timeout <- true
+ }()
+ select {
+ case err = <-imp.Errors():
+ if strings.Index(err.String(), "no such channel") < 0 {
+ t.Error("wrong error for nonexistent channel:", err)
+ }
+ case <-timeout:
+ t.Error("import of nonexistent channel did not receive an error")
+ }
+}
+
+// Not a great test but it does at least invoke Drain.
+func TestExportDrain(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ done := make(chan bool)
+ go func() {
+ exportSend(exp, closeCount, t, nil)
+ done <- true
+ }()
+ <-done
+ go importReceive(imp, t, done)
+ exp.Drain(0)
+ <-done
+}
+
+// Not a great test but it does at least invoke Sync.
+func TestExportSync(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ done := make(chan bool)
+ exportSend(exp, closeCount, t, nil)
+ go importReceive(imp, t, done)
+ exp.Sync(0)
+ <-done
+}
+
+// Test hanging up the send side of an export.
+// TODO: test hanging up the receive side of an export.
+func TestExportHangup(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ ech := make(chan int)
+ err = exp.Export("exportedSend", ech, Send)
+ if err != nil {
+ t.Fatal("export:", err)
+ }
+ // Prepare to receive two values. We'll actually deliver only one.
+ ich := make(chan int)
+ err = imp.ImportNValues("exportedSend", ich, Recv, 1, 2)
+ if err != nil {
+ t.Fatal("import exportedSend:", err)
+ }
+ // Send one value, receive it.
+ const Value = 1234
+ ech <- Value
+ v := <-ich
+ if v != Value {
+ t.Fatal("expected", Value, "got", v)
+ }
+ // Now hang up the channel. Importer should see it close.
+ exp.Hangup("exportedSend")
+ v = <-ich
+ if !closed(ich) {
+ t.Fatal("expected channel to be closed; got value", v)
+ }
+}
+
+// Test hanging up the send side of an import.
+// TODO: test hanging up the receive side of an import.
+func TestImportHangup(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ ech := make(chan int)
+ err = exp.Export("exportedRecv", ech, Recv)
+ if err != nil {
+ t.Fatal("export:", err)
+ }
+ // Prepare to Send two values. We'll actually deliver only one.
+ ich := make(chan int)
+ err = imp.ImportNValues("exportedRecv", ich, Send, 1, 2)
+ if err != nil {
+ t.Fatal("import exportedRecv:", err)
+ }
+ // Send one value, receive it.
+ const Value = 1234
+ ich <- Value
+ v := <-ech
+ if v != Value {
+ t.Fatal("expected", Value, "got", v)
+ }
+ // Now hang up the channel. Exporter should see it close.
+ imp.Hangup("exportedRecv")
+ v = <-ech
+ if !closed(ech) {
+ t.Fatal("expected channel to be closed; got value", v)
+ }
+}
+
+// loop back exportedRecv to exportedSend,
+// but receive a value from ctlch before starting the loop.
+func exportLoopback(exp *Exporter, t *testing.T) {
+ inch := make(chan int)
+ if err := exp.Export("exportedRecv", inch, Recv); err != nil {
+ t.Fatal("exportRecv")
+ }
+
+ outch := make(chan int)
+ if err := exp.Export("exportedSend", outch, Send); err != nil {
+ t.Fatal("exportSend")
+ }
+
+ ctlch := make(chan int)
+ if err := exp.Export("exportedCtl", ctlch, Recv); err != nil {
+ t.Fatal("exportRecv")
+ }
+
+ go func() {
+ <-ctlch
+ for i := 0; i < count; i++ {
+ x := <-inch
+ if x != base+i {
+ t.Errorf("exportLoopback expected %d; got %d", i, x)
+ }
+ outch <- x
+ }
+ }()
+}
+
+// This test checks that channel operations can proceed
+// even when other concurrent operations are blocked.
+func TestIndependentSends(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+
+ exportLoopback(exp, t)
+
+ importSend(imp, count, t, nil)
+ done := make(chan bool)
+ go importReceive(imp, t, done)
+
+ // wait for export side to try to deliver some values.
+ time.Sleep(0.25e9)
+
+ ctlch := make(chan int)
+ if err := imp.ImportNValues("exportedCtl", ctlch, Send, 1, 1); err != nil {
+ t.Fatal("importSend:", err)
+ }
+ ctlch <- 0
+
+ <-done
+}
+
+// This test cross-connects a pair of exporter/importer pairs.
+type value struct {
+ I int
+ Source string
+}
+
+func TestCrossConnect(t *testing.T) {
+ e1, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ i1, err := NewImporter("tcp", e1.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+
+ e2, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ i2, err := NewImporter("tcp", e2.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+
+ crossExport(e1, e2, t)
+ crossImport(i1, i2, t)
+}
+
+// Export side of cross-traffic.
+func crossExport(e1, e2 *Exporter, t *testing.T) {
+ s := make(chan value)
+ err := e1.Export("exportedSend", s, Send)
+ if err != nil {
+ t.Fatal("exportSend:", err)
+ }
+
+ r := make(chan value)
+ err = e2.Export("exportedReceive", r, Recv)
+ if err != nil {
+ t.Fatal("exportReceive:", err)
+ }
+
+ go crossLoop("export", s, r, t)
+}
+
+// Import side of cross-traffic.
+func crossImport(i1, i2 *Importer, t *testing.T) {
+ s := make(chan value)
+ err := i2.Import("exportedReceive", s, Send, 2)
+ if err != nil {
+ t.Fatal("import of exportedReceive:", err)
+ }
+
+ r := make(chan value)
+ err = i1.Import("exportedSend", r, Recv, 2)
+ if err != nil {
+ t.Fatal("import of exported Send:", err)
+ }
+
+ crossLoop("import", s, r, t)
+}
+
+// Cross-traffic: send and receive 'count' numbers.
+func crossLoop(name string, s, r chan value, t *testing.T) {
+ for si, ri := 0, 0; si < count && ri < count; {
+ select {
+ case s <- value{si, name}:
+ si++
+ case v := <-r:
+ if v.I != ri {
+ t.Errorf("loop: bad value: expected %d, hello; got %+v", ri, v)
+ }
+ ri++
+ }
+ }
+}
+
+const flowCount = 100
+
+// test flow control from exporter to importer.
+func TestExportFlowControl(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+
+ sendDone := make(chan bool, 1)
+ exportSend(exp, flowCount, t, sendDone)
+
+ ch := make(chan int)
+ err = imp.ImportNValues("exportedSend", ch, Recv, 20, -1)
+ if err != nil {
+ t.Fatal("importReceive:", err)
+ }
+
+ testFlow(sendDone, ch, flowCount, t)
+}
+
+// test flow control from importer to exporter.
+func TestImportFlowControl(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+
+ ch := make(chan int)
+ err = exp.Export("exportedRecv", ch, Recv)
+ if err != nil {
+ t.Fatal("importReceive:", err)
+ }
+
+ sendDone := make(chan bool, 1)
+ importSend(imp, flowCount, t, sendDone)
+ testFlow(sendDone, ch, flowCount, t)
+}
+
+func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) {
+ go func() {
+ time.Sleep(1e9)
+ sendDone <- false
+ }()
+
+ if <-sendDone {
+ t.Fatal("send did not block")
+ }
+ n := 0
+ for i := range ch {
+ t.Log("after blocking, got value ", i)
+ n++
+ }
+ if n != N {
+ t.Fatalf("expected %d values; got %d", N, n)
+ }
+}
diff --git a/libgo/go/os/dir.go b/libgo/go/os/dir.go
new file mode 100644
index 000000000..b3b5d3e37
--- /dev/null
+++ b/libgo/go/os/dir.go
@@ -0,0 +1,72 @@
+// 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
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func libc_dup(fd int) int __asm__ ("dup")
+func libc_opendir(*byte) *syscall.DIR __asm__ ("opendir")
+func libc_closedir(*syscall.DIR) int __asm__ ("closedir")
+
+// FIXME: pathconf returns long, not int.
+func libc_pathconf(*byte, int) int __asm__ ("pathconf")
+
+func clen(n []byte) int {
+ for i := 0; i < len(n); i++ {
+ if n[i] == 0 {
+ return i
+ }
+ }
+ return len(n)
+}
+
+var elen int;
+
+// Negative count means read until EOF.
+func (file *File) Readdirnames(count int) (names []string, err Error) {
+ if elen == 0 {
+ var dummy syscall.Dirent;
+ elen = (unsafe.Offsetof(dummy.Name) +
+ libc_pathconf(syscall.StringBytePtr(file.name), syscall.PC_NAME_MAX) +
+ 1);
+ }
+
+ if file.dirinfo == nil {
+ file.dirinfo = new(dirInfo)
+ file.dirinfo.buf = make([]byte, elen)
+ file.dirinfo.dir = libc_opendir(syscall.StringBytePtr(file.name))
+ }
+
+ entry_dirent := unsafe.Pointer(&file.dirinfo.buf[0]).(*syscall.Dirent)
+
+ size := count
+ if size < 0 {
+ size = 100
+ }
+ names = make([]string, 0, size) // Empty with room to grow.
+
+ dir := file.dirinfo.dir
+ if dir == nil {
+ return names, NewSyscallError("opendir", syscall.GetErrno())
+ }
+
+ for count != 0 {
+ var result *syscall.Dirent
+ i := libc_readdir_r(dir, entry_dirent, &result)
+ if result == nil {
+ break
+ }
+ var name = string(result.Name[0:clen(result.Name[0:])])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ count--
+ names = append(names, name)
+ }
+ return names, nil
+}
diff --git a/libgo/go/os/dir_largefile.go b/libgo/go/os/dir_largefile.go
new file mode 100644
index 000000000..c723ec924
--- /dev/null
+++ b/libgo/go/os/dir_largefile.go
@@ -0,0 +1,12 @@
+// dir_largefile.go -- For systems which use the large file interface for
+// readdir_r.
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) int __asm__ ("readdir64_r")
diff --git a/libgo/go/os/dir_regfile.go b/libgo/go/os/dir_regfile.go
new file mode 100644
index 000000000..22fb5febb
--- /dev/null
+++ b/libgo/go/os/dir_regfile.go
@@ -0,0 +1,12 @@
+// dir_regfile.go -- For systems which do not use the large file interface
+// for readdir_r.
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) int __asm__ ("readdir_r")
diff --git a/libgo/go/os/env.go b/libgo/go/os/env.go
new file mode 100644
index 000000000..3a6d79dd0
--- /dev/null
+++ b/libgo/go/os/env.go
@@ -0,0 +1,73 @@
+// 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.
+
+// General environment variables.
+
+package os
+
+// Expand replaces ${var} or $var in the string based on the mapping function.
+// Invocations of undefined variables are replaced with the empty string.
+func Expand(s string, mapping func(string) string) string {
+ buf := make([]byte, 0, 2*len(s))
+ // ${} is all ASCII, so bytes are fine for this operation.
+ i := 0
+ for j := 0; j < len(s); j++ {
+ if s[j] == '$' && j+1 < len(s) {
+ buf = append(buf, []byte(s[i:j])...)
+ name, w := getShellName(s[j+1:])
+ buf = append(buf, []byte(mapping(name))...)
+ j += w
+ i = j + 1
+ }
+ }
+ return string(buf) + s[i:]
+}
+
+// ShellExpand replaces ${var} or $var in the string according to the values
+// of the operating system's environment variables. References to undefined
+// variables are replaced by the empty string.
+func ShellExpand(s string) string {
+ return Expand(s, Getenv)
+}
+
+// isSpellSpecialVar reports whether the character identifies a special
+// shell variable such as $*.
+func isShellSpecialVar(c uint8) bool {
+ switch c {
+ case '*', '#', '$', '@', '!', '?', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return true
+ }
+ return false
+}
+
+// isAlphaNum reports whether the byte is an ASCII letter, number, or underscore
+func isAlphaNum(c uint8) bool {
+ return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
+}
+
+// getName returns the name that begins the string and the number of bytes
+// consumed to extract it. If the name is enclosed in {}, it's part of a ${}
+// expansion and two more bytes are needed than the length of the name.
+func getShellName(s string) (string, int) {
+ switch {
+ case s[0] == '{':
+ if len(s) > 2 && isShellSpecialVar(s[1]) && s[2] == '}' {
+ return s[1:2], 3
+ }
+ // Scan to closing brace
+ for i := 1; i < len(s); i++ {
+ if s[i] == '}' {
+ return s[1:i], i + 1
+ }
+ }
+ return "", 1 // Bad syntax; just eat the brace.
+ case isShellSpecialVar(s[0]):
+ return s[0:1], 1
+ }
+ // Scan alphanumerics.
+ var i int
+ for i = 0; i < len(s) && isAlphaNum(s[i]); i++ {
+ }
+ return s[:i], i
+}
diff --git a/libgo/go/os/env_test.go b/libgo/go/os/env_test.go
new file mode 100644
index 000000000..04ff39072
--- /dev/null
+++ b/libgo/go/os/env_test.go
@@ -0,0 +1,59 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+ . "os"
+ "testing"
+)
+
+// testGetenv gives us a controlled set of variables for testing Expand.
+func testGetenv(s string) string {
+ switch s {
+ case "*":
+ return "all the args"
+ case "#":
+ return "NARGS"
+ case "$":
+ return "PID"
+ case "1":
+ return "ARGUMENT1"
+ case "HOME":
+ return "/usr/gopher"
+ case "H":
+ return "(Value of H)"
+ case "home_1":
+ return "/usr/foo"
+ case "_":
+ return "underscore"
+ }
+ return ""
+}
+
+var expandTests = []struct {
+ in, out string
+}{
+ {"", ""},
+ {"$*", "all the args"},
+ {"$$", "PID"},
+ {"${*}", "all the args"},
+ {"$1", "ARGUMENT1"},
+ {"${1}", "ARGUMENT1"},
+ {"now is the time", "now is the time"},
+ {"$HOME", "/usr/gopher"},
+ {"$home_1", "/usr/foo"},
+ {"${HOME}", "/usr/gopher"},
+ {"${H}OME", "(Value of H)OME"},
+ {"A$$$#$1$H$home_1*B", "APIDNARGSARGUMENT1(Value of H)/usr/foo*B"},
+}
+
+func TestExpand(t *testing.T) {
+ for _, test := range expandTests {
+ result := Expand(test.in, testGetenv)
+ if result != test.out {
+ t.Errorf("Expand(%q)=%q; expected %q", test.in, result, test.out)
+ }
+ }
+}
diff --git a/libgo/go/os/env_unix.go b/libgo/go/os/env_unix.go
new file mode 100644
index 000000000..e7e1c3b90
--- /dev/null
+++ b/libgo/go/os/env_unix.go
@@ -0,0 +1,96 @@
+// 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.
+
+// Unix environment variables.
+
+package os
+
+import (
+ "sync"
+)
+
+// ENOENV is the Error indicating that an environment variable does not exist.
+var ENOENV = NewError("no such environment variable")
+
+var env map[string]string
+var once sync.Once
+
+
+func copyenv() {
+ env = make(map[string]string)
+ for _, s := range Envs {
+ for j := 0; j < len(s); j++ {
+ if s[j] == '=' {
+ env[s[0:j]] = s[j+1:]
+ break
+ }
+ }
+ }
+}
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err Error) {
+ once.Do(copyenv)
+
+ if len(key) == 0 {
+ return "", EINVAL
+ }
+ v, ok := env[key]
+ if !ok {
+ return "", ENOENV
+ }
+ return v, nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+ v, _ := Getenverror(key)
+ return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an Error, if any.
+func Setenv(key, value string) Error {
+ once.Do(copyenv)
+
+ if len(key) == 0 {
+ return EINVAL
+ }
+ env[key] = value
+ return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+ once.Do(copyenv) // prevent copyenv in Getenv/Setenv
+ env = make(map[string]string)
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+ once.Do(copyenv)
+ a := make([]string, len(env))
+ i := 0
+ for k, v := range env {
+ // check i < len(a) for safety,
+ // in case env is changing underfoot.
+ if i < len(a) {
+ a[i] = k + "=" + v
+ i++
+ }
+ }
+ return a[0:i]
+}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+ dir := Getenv("TMPDIR")
+ if dir == "" {
+ dir = "/tmp"
+ }
+ return dir
+}
diff --git a/libgo/go/os/env_windows.go b/libgo/go/os/env_windows.go
new file mode 100644
index 000000000..d2b159dfb
--- /dev/null
+++ b/libgo/go/os/env_windows.go
@@ -0,0 +1,127 @@
+// 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.
+
+// Windows environment variables.
+
+package os
+
+import (
+ "syscall"
+ "utf16"
+ "unsafe"
+)
+
+// ENOENV is the Error indicating that an environment variable does not exist.
+var ENOENV = NewError("no such environment variable")
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err Error) {
+ b := make([]uint16, 100)
+ n, e := syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+ if n == 0 && e == syscall.ERROR_ENVVAR_NOT_FOUND {
+ return "", ENOENV
+ }
+ if n > uint32(len(b)) {
+ b = make([]uint16, n)
+ n, e = syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+ if n > uint32(len(b)) {
+ n = 0
+ }
+ }
+ if n == 0 {
+ return "", NewSyscallError("GetEnvironmentVariable", e)
+ }
+ return string(utf16.Decode(b[0:n])), nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+ v, _ := Getenverror(key)
+ return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an Error, if any.
+func Setenv(key, value string) Error {
+ var v *uint16
+ if len(value) > 0 {
+ v = syscall.StringToUTF16Ptr(value)
+ }
+ ok, e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
+ if !ok {
+ return NewSyscallError("SetEnvironmentVariable", e)
+ }
+ return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+ for _, s := range Environ() {
+ // Environment variables can begin with =
+ // so start looking for the separator = at j=1.
+ // http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
+ for j := 1; j < len(s); j++ {
+ if s[j] == '=' {
+ Setenv(s[0:j], "")
+ break
+ }
+ }
+ }
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+ s, e := syscall.GetEnvironmentStrings()
+ if e != 0 {
+ return nil
+ }
+ defer syscall.FreeEnvironmentStrings(s)
+ r := make([]string, 0, 50) // Empty with room to grow.
+ for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
+ if p[i] == 0 {
+ // empty string marks the end
+ if i <= from {
+ break
+ }
+ r = append(r, string(utf16.Decode(p[from:i])))
+ from = i + 1
+ }
+ }
+ return r
+}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+ const pathSep = '\\'
+ dirw := make([]uint16, syscall.MAX_PATH)
+ n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+ if n > uint32(len(dirw)) {
+ dirw = make([]uint16, n)
+ n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+ if n > uint32(len(dirw)) {
+ n = 0
+ }
+ }
+ if n > 0 && dirw[n-1] == pathSep {
+ n--
+ }
+ return string(utf16.Decode(dirw[0:n]))
+}
+
+func init() {
+ var argc int32
+ cmd := syscall.GetCommandLine()
+ argv, e := syscall.CommandLineToArgv(cmd, &argc)
+ if e != 0 {
+ return
+ }
+ defer syscall.LocalFree(uint32(uintptr(unsafe.Pointer(argv))))
+ Args = make([]string, argc)
+ for i, v := range (*argv)[:argc] {
+ Args[i] = string(syscall.UTF16ToString((*v)[:]))
+ }
+}
diff --git a/libgo/go/os/error.go b/libgo/go/os/error.go
new file mode 100644
index 000000000..8cdf53254
--- /dev/null
+++ b/libgo/go/os/error.go
@@ -0,0 +1,113 @@
+// 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
+
+import syscall "syscall"
+
+// An Error can represent any printable error condition.
+type Error interface {
+ String() string
+}
+
+// A helper type that can be embedded or wrapped to simplify satisfying
+// Error.
+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 }
+
+// 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) }
+
+// Errno is the Unix error number. Names such as EINVAL are simple
+// wrappers to convert the error number into an Error.
+type Errno int64
+
+func (e Errno) String() string { return syscall.Errstr(int(e)) }
+
+func (e Errno) Temporary() bool {
+ return e == Errno(syscall.EINTR) || e.Timeout()
+}
+
+func (e Errno) Timeout() bool {
+ return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK)
+}
+
+// Commonly known Unix errors.
+var (
+ EPERM Error = Errno(syscall.EPERM)
+ ENOENT Error = Errno(syscall.ENOENT)
+ ESRCH Error = Errno(syscall.ESRCH)
+ EINTR Error = Errno(syscall.EINTR)
+ EIO Error = Errno(syscall.EIO)
+ ENXIO Error = Errno(syscall.ENXIO)
+ E2BIG Error = Errno(syscall.E2BIG)
+ ENOEXEC Error = Errno(syscall.ENOEXEC)
+ EBADF Error = Errno(syscall.EBADF)
+ ECHILD Error = Errno(syscall.ECHILD)
+ EDEADLK Error = Errno(syscall.EDEADLK)
+ ENOMEM Error = Errno(syscall.ENOMEM)
+ EACCES Error = Errno(syscall.EACCES)
+ EFAULT Error = Errno(syscall.EFAULT)
+ EBUSY Error = Errno(syscall.EBUSY)
+ EEXIST Error = Errno(syscall.EEXIST)
+ EXDEV Error = Errno(syscall.EXDEV)
+ ENODEV Error = Errno(syscall.ENODEV)
+ ENOTDIR Error = Errno(syscall.ENOTDIR)
+ EISDIR Error = Errno(syscall.EISDIR)
+ EINVAL Error = Errno(syscall.EINVAL)
+ ENFILE Error = Errno(syscall.ENFILE)
+ EMFILE Error = Errno(syscall.EMFILE)
+ ENOTTY Error = Errno(syscall.ENOTTY)
+ EFBIG Error = Errno(syscall.EFBIG)
+ ENOSPC Error = Errno(syscall.ENOSPC)
+ ESPIPE Error = Errno(syscall.ESPIPE)
+ EROFS Error = Errno(syscall.EROFS)
+ EMLINK Error = Errno(syscall.EMLINK)
+ EPIPE Error = Errno(syscall.EPIPE)
+ EAGAIN Error = Errno(syscall.EAGAIN)
+ EDOM Error = Errno(syscall.EDOM)
+ ERANGE Error = Errno(syscall.ERANGE)
+ EADDRINUSE Error = Errno(syscall.EADDRINUSE)
+ ECONNREFUSED Error = Errno(syscall.ECONNREFUSED)
+ ENAMETOOLONG Error = Errno(syscall.ENAMETOOLONG)
+ EAFNOSUPPORT Error = Errno(syscall.EAFNOSUPPORT)
+)
+
+// PathError records an error and the operation and file path that caused it.
+type PathError struct {
+ Op string
+ Path string
+ Error Error
+}
+
+func (e *PathError) String() string { return e.Op + " " + e.Path + ": " + e.Error.String() }
+
+// SyscallError records an error from a specific system call.
+type SyscallError struct {
+ Syscall string
+ Errno Errno
+}
+
+func (e *SyscallError) String() string { return e.Syscall + ": " + e.Errno.String() }
+
+// Note: If the name of the function NewSyscallError changes,
+// pkg/go/doc/doc.go should be adjusted since it hardwires
+// this name in a heuristic.
+
+// NewSyscallError returns, as an Error, a new SyscallError
+// with the given system call name and error number.
+// As a convenience, if errno is 0, NewSyscallError returns nil.
+func NewSyscallError(syscall string, errno int) Error {
+ if errno == 0 {
+ return nil
+ }
+ return &SyscallError{syscall, Errno(errno)}
+}
diff --git a/libgo/go/os/exec.go b/libgo/go/os/exec.go
new file mode 100644
index 000000000..100d984d1
--- /dev/null
+++ b/libgo/go/os/exec.go
@@ -0,0 +1,154 @@
+// 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
+
+import (
+ "syscall"
+)
+
+// ForkExec forks the current process and invokes Exec with the program, arguments,
+// and environment specified by name, argv, and envv. It returns the process
+// id of the forked process and an Error, if any. The fd array specifies the
+// file descriptors to be set up in the new process: fd[0] will be Unix file
+// descriptor 0 (standard input), fd[1] descriptor 1, and so on. A nil entry
+// will cause the child to have no open file descriptor with that index.
+// If dir is not empty, the child chdirs into the directory before execing the program.
+func ForkExec(name string, argv []string, envv []string, dir string, fd []*File) (pid int, err Error) {
+ if envv == nil {
+ envv = Environ()
+ }
+ // Create array of integer (system) fds.
+ intfd := make([]int, len(fd))
+ for i, f := range fd {
+ if f == nil {
+ intfd[i] = -1
+ } else {
+ intfd[i] = f.Fd()
+ }
+ }
+
+ p, e := syscall.ForkExec(name, argv, envv, dir, intfd)
+ if e != 0 {
+ return 0, &PathError{"fork/exec", name, Errno(e)}
+ }
+ return p, nil
+}
+
+// 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.
+// ForkExec is almost always a better way to execute a program.
+func Exec(name string, argv []string, envv []string) Error {
+ if envv == nil {
+ envv = Environ()
+ }
+ e := syscall.Exec(name, argv, envv)
+ if e != 0 {
+ return &PathError{"exec", name, Errno(e)}
+ }
+ return nil
+}
+
+// TODO(rsc): Should os implement its own syscall.WaitStatus
+// wrapper with the methods, or is exposing the underlying one enough?
+//
+// TODO(rsc): Certainly need to have Rusage struct,
+// since syscall one might have different field types across
+// different OS.
+
+// Waitmsg stores the information about an exited process as reported by Wait.
+type Waitmsg struct {
+ Pid int // The process's id.
+ syscall.WaitStatus // System-dependent status info.
+ Rusage *syscall.Rusage // System-dependent resource usage info.
+}
+
+// Options for Wait.
+const (
+ WNOHANG = syscall.WNOHANG // Don't wait if no process has exited.
+ WSTOPPED = syscall.WSTOPPED // If set, status of stopped subprocesses is also reported.
+ WUNTRACED = syscall.WUNTRACED // Usually an alias for WSTOPPED.
+ WRUSAGE = 1 << 20 // Record resource usage.
+)
+
+// WRUSAGE must not be too high a bit, to avoid clashing with Linux's
+// WCLONE, WALL, and WNOTHREAD flags, which sit in the top few bits of
+// the options
+
+// Wait waits for process pid to exit or stop, and then returns a
+// Waitmsg describing its status and an Error, if any. The options
+// (WNOHANG etc.) affect the behavior of the Wait call.
+func Wait(pid int, options int) (w *Waitmsg, err Error) {
+ var status syscall.WaitStatus
+ var rusage *syscall.Rusage
+ if options&WRUSAGE != 0 {
+ rusage = new(syscall.Rusage)
+ options ^= WRUSAGE
+ }
+ pid1, e := syscall.Wait4(pid, &status, options, rusage)
+ if e != 0 {
+ return nil, NewSyscallError("wait", e)
+ }
+ w = new(Waitmsg)
+ w.Pid = pid1
+ w.WaitStatus = status
+ w.Rusage = rusage
+ return w, nil
+}
+
+// Convert i to decimal string.
+func itod(i int) string {
+ if i == 0 {
+ return "0"
+ }
+
+ u := uint64(i)
+ if i < 0 {
+ u = -u
+ }
+
+ // Assemble decimal in reverse order.
+ var b [32]byte
+ bp := len(b)
+ for ; u > 0; u /= 10 {
+ bp--
+ b[bp] = byte(u%10) + '0'
+ }
+
+ if i < 0 {
+ bp--
+ b[bp] = '-'
+ }
+
+ return string(b[bp:])
+}
+
+func (w Waitmsg) String() string {
+ // TODO(austin) Use signal names when possible?
+ res := ""
+ switch {
+ case w.Exited():
+ res = "exit status " + itod(w.ExitStatus())
+ case w.Signaled():
+ res = "signal " + itod(w.Signal())
+ case w.Stopped():
+ res = "stop signal " + itod(w.StopSignal())
+ if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 {
+ res += " (trap " + itod(w.TrapCause()) + ")"
+ }
+ case w.Continued():
+ res = "continued"
+ }
+ if w.CoreDump() {
+ res += " (core dumped)"
+ }
+ return res
+}
+
+// Getpid returns the process id of the caller.
+func Getpid() int { return syscall.Getpid() }
+
+// Getppid returns the process id of the caller's parent.
+func Getppid() int { return syscall.Getppid() }
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go
new file mode 100644
index 000000000..3f73f1dff
--- /dev/null
+++ b/libgo/go/os/file.go
@@ -0,0 +1,438 @@
+// 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.
+
+// The os package provides a platform-independent interface to operating
+// system functionality. The design is Unix-like.
+package os
+
+import (
+ "runtime"
+ "syscall"
+)
+
+// File represents an open file descriptor.
+type File struct {
+ fd int
+ name string
+ dirinfo *dirInfo // nil unless directory being read
+ nepipe int // number of consecutive EPIPE in Write
+}
+
+// Fd returns the integer Unix file descriptor referencing the open file.
+func (file *File) Fd() int { return file.fd }
+
+// Name returns the name of the file as presented to Open.
+func (file *File) Name() string { return file.name }
+
+// NewFile returns a new File with the given file descriptor and name.
+func NewFile(fd int, name string) *File {
+ if fd < 0 {
+ return nil
+ }
+ f := &File{fd, name, nil, 0}
+ runtime.SetFinalizer(f, (*File).Close)
+ return f
+}
+
+// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
+// standard output, and standard error file descriptors.
+var (
+ Stdin = NewFile(syscall.Stdin, "/dev/stdin")
+ Stdout = NewFile(syscall.Stdout, "/dev/stdout")
+ Stderr = NewFile(syscall.Stderr, "/dev/stderr")
+)
+
+// Flags to Open wrapping those of the underlying system. Not all flags
+// may be implemented on a given system.
+const (
+ O_RDONLY int = syscall.O_RDONLY // open the file read-only.
+ O_WRONLY int = syscall.O_WRONLY // open the file write-only.
+ O_RDWR int = syscall.O_RDWR // open the file read-write.
+ O_APPEND int = syscall.O_APPEND // append data to the file when writing.
+ O_ASYNC int = syscall.O_ASYNC // generate a signal when I/O is available.
+ O_CREAT int = syscall.O_CREAT // create a new file if none exists.
+ O_EXCL int = syscall.O_EXCL // used with O_CREAT, file must not exist
+ O_NOCTTY int = syscall.O_NOCTTY // do not make file the controlling tty.
+ O_NONBLOCK int = syscall.O_NONBLOCK // open in non-blocking mode.
+ O_NDELAY int = O_NONBLOCK // synonym for O_NONBLOCK
+ O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
+ O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
+ O_CREATE int = O_CREAT // create a new file if none exists.
+)
+
+type eofError int
+
+func (eofError) String() string { return "EOF" }
+
+// EOF is the Error returned by Read when no more input is available.
+// Functions should return EOF only to signal a graceful end of input.
+// If the EOF occurs unexpectedly in a structured data stream,
+// the appropriate error is either io.ErrUnexpectedEOF or some other error
+// giving more detail.
+var EOF Error = eofError(0)
+
+// Read reads up to len(b) bytes from the File.
+// It returns the number of bytes read and an Error, if any.
+// EOF is signaled by a zero count with err set to EOF.
+func (file *File) Read(b []byte) (n int, err Error) {
+ if file == nil {
+ return 0, EINVAL
+ }
+ n, e := syscall.Read(file.fd, b)
+ if n < 0 {
+ n = 0
+ }
+ if n == 0 && e == 0 {
+ return 0, EOF
+ }
+ if e != 0 {
+ err = &PathError{"read", file.name, Errno(e)}
+ }
+ return n, err
+}
+
+// ReadAt reads len(b) bytes from the File starting at byte offset off.
+// It returns the number of bytes read and the Error, if any.
+// EOF is signaled by a zero count with err set to EOF.
+// ReadAt always returns a non-nil Error when n != len(b).
+func (file *File) ReadAt(b []byte, off int64) (n int, err Error) {
+ if file == nil {
+ return 0, EINVAL
+ }
+ for len(b) > 0 {
+ m, e := syscall.Pread(file.fd, b, off)
+ if m == 0 && e == 0 {
+ return n, EOF
+ }
+ if e != 0 {
+ err = &PathError{"read", file.name, Errno(e)}
+ break
+ }
+ n += m
+ b = b[m:]
+ off += int64(m)
+ }
+ return
+}
+
+// Write writes len(b) bytes to the File.
+// It returns the number of bytes written and an Error, if any.
+// Write returns a non-nil Error when n != len(b).
+func (file *File) Write(b []byte) (n int, err Error) {
+ if file == nil {
+ return 0, EINVAL
+ }
+ n, e := syscall.Write(file.fd, b)
+ if n < 0 {
+ n = 0
+ }
+ if e == syscall.EPIPE {
+ file.nepipe++
+ if file.nepipe >= 10 {
+ Exit(syscall.EPIPE)
+ }
+ } else {
+ file.nepipe = 0
+ }
+ if e != 0 {
+ err = &PathError{"write", file.name, Errno(e)}
+ }
+ return n, err
+}
+
+// WriteAt writes len(b) bytes to the File starting at byte offset off.
+// It returns the number of bytes written and an Error, if any.
+// WriteAt returns a non-nil Error when n != len(b).
+func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
+ if file == nil {
+ return 0, EINVAL
+ }
+ for len(b) > 0 {
+ m, e := syscall.Pwrite(file.fd, b, off)
+ if e != 0 {
+ err = &PathError{"write", file.name, Errno(e)}
+ break
+ }
+ n += m
+ b = b[m:]
+ off += int64(m)
+ }
+ return
+}
+
+// Seek sets the offset for the next Read or Write on file to offset, interpreted
+// according to whence: 0 means relative to the origin of the file, 1 means
+// relative to the current offset, and 2 means relative to the end.
+// It returns the new offset and an Error, if any.
+func (file *File) Seek(offset int64, whence int) (ret int64, err Error) {
+ r, e := syscall.Seek(file.fd, offset, whence)
+ if e == 0 && file.dirinfo != nil && r != 0 {
+ e = syscall.EISDIR
+ }
+ if e != 0 {
+ return 0, &PathError{"seek", file.name, Errno(e)}
+ }
+ return r, nil
+}
+
+// WriteString is like Write, but writes the contents of string s rather than
+// an array of bytes.
+func (file *File) WriteString(s string) (ret int, err Error) {
+ if file == nil {
+ return 0, EINVAL
+ }
+ b := syscall.StringByteSlice(s)
+ b = b[0 : len(b)-1]
+ return file.Write(b)
+}
+
+// Pipe returns a connected pair of Files; reads from r return bytes written to w.
+// It returns the files and an Error, if any.
+func Pipe() (r *File, w *File, err Error) {
+ var p [2]int
+
+ // See ../syscall/exec.go for description of lock.
+ syscall.ForkLock.RLock()
+ e := syscall.Pipe(p[0:])
+ if e != 0 {
+ syscall.ForkLock.RUnlock()
+ return nil, nil, NewSyscallError("pipe", e)
+ }
+ syscall.CloseOnExec(p[0])
+ syscall.CloseOnExec(p[1])
+ syscall.ForkLock.RUnlock()
+
+ return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
+}
+
+// Mkdir creates a new directory with the specified name and permission bits.
+// It returns an error, if any.
+func Mkdir(name string, perm uint32) Error {
+ e := syscall.Mkdir(name, perm)
+ if e != 0 {
+ return &PathError{"mkdir", name, Errno(e)}
+ }
+ return nil
+}
+
+// Stat returns a FileInfo structure describing the named file and an error, if any.
+// If name names a valid symbolic link, the returned FileInfo describes
+// the file pointed at by the link and has fi.FollowedSymlink set to true.
+// If name names an invalid symbolic link, the returned FileInfo describes
+// the link itself and has fi.FollowedSymlink set to false.
+func Stat(name string) (fi *FileInfo, err Error) {
+ var lstat, stat syscall.Stat_t
+ e := syscall.Lstat(name, &lstat)
+ if e != 0 {
+ return nil, &PathError{"stat", name, Errno(e)}
+ }
+ statp := &lstat
+ if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
+ e := syscall.Stat(name, &stat)
+ if e == 0 {
+ statp = &stat
+ }
+ }
+ return fileInfoFromStat(name, new(FileInfo), &lstat, statp), nil
+}
+
+// Lstat returns the FileInfo structure describing the named file and an
+// error, if any. If the file is a symbolic link, the returned FileInfo
+// describes the symbolic link. Lstat makes no attempt to follow the link.
+func Lstat(name string) (fi *FileInfo, err Error) {
+ var stat syscall.Stat_t
+ e := syscall.Lstat(name, &stat)
+ if e != 0 {
+ return nil, &PathError{"lstat", name, Errno(e)}
+ }
+ return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil
+}
+
+// Chdir changes the current working directory to the named directory.
+func Chdir(dir string) Error {
+ if e := syscall.Chdir(dir); e != 0 {
+ return &PathError{"chdir", dir, Errno(e)}
+ }
+ return nil
+}
+
+// Chdir changes the current working directory to the file,
+// which must be a directory.
+func (f *File) Chdir() Error {
+ if e := syscall.Fchdir(f.fd); e != 0 {
+ return &PathError{"chdir", f.name, Errno(e)}
+ }
+ return nil
+}
+
+// Remove removes the named file or directory.
+func Remove(name string) Error {
+ // System call interface forces us to know
+ // whether name is a file or directory.
+ // Try both: it is cheaper on average than
+ // doing a Stat plus the right one.
+ e := syscall.Unlink(name)
+ if e == 0 {
+ return nil
+ }
+ e1 := syscall.Rmdir(name)
+ if e1 == 0 {
+ return nil
+ }
+
+ // Both failed: figure out which error to return.
+ // OS X and Linux differ on whether unlink(dir)
+ // returns EISDIR, so can't use that. However,
+ // both agree that rmdir(file) returns ENOTDIR,
+ // so we can use that to decide which error is real.
+ // Rmdir might also return ENOTDIR if given a bad
+ // file path, like /etc/passwd/foo, but in that case,
+ // both errors will be ENOTDIR, so it's okay to
+ // use the error from unlink.
+ // For windows syscall.ENOTDIR is set
+ // to syscall.ERROR_DIRECTORY, hopefully it should
+ // do the trick.
+ if e1 != syscall.ENOTDIR {
+ e = e1
+ }
+ return &PathError{"remove", name, Errno(e)}
+}
+
+// LinkError records an error during a link or symlink or rename
+// system call and the paths that caused it.
+type LinkError struct {
+ Op string
+ Old string
+ New string
+ Error Error
+}
+
+func (e *LinkError) String() string {
+ return e.Op + " " + e.Old + " " + e.New + ": " + e.Error.String()
+}
+
+// Link creates a hard link.
+func Link(oldname, newname string) Error {
+ e := syscall.Link(oldname, newname)
+ if e != 0 {
+ return &LinkError{"link", oldname, newname, Errno(e)}
+ }
+ return nil
+}
+
+// Symlink creates a symbolic link.
+func Symlink(oldname, newname string) Error {
+ e := syscall.Symlink(oldname, newname)
+ if e != 0 {
+ return &LinkError{"symlink", oldname, newname, Errno(e)}
+ }
+ return nil
+}
+
+// Readlink reads the contents of a symbolic link: the destination of
+// the link. It returns the contents and an Error, if any.
+func Readlink(name string) (string, Error) {
+ for len := 128; ; len *= 2 {
+ b := make([]byte, len)
+ n, e := syscall.Readlink(name, b)
+ if e != 0 {
+ return "", &PathError{"readlink", name, Errno(e)}
+ }
+ if n < len {
+ return string(b[0:n]), nil
+ }
+ }
+ // Silence 6g.
+ return "", nil
+}
+
+// Rename renames a file.
+func Rename(oldname, newname string) Error {
+ e := syscall.Rename(oldname, newname)
+ if e != 0 {
+ return &LinkError{"rename", oldname, newname, Errno(e)}
+ }
+ return nil
+}
+
+// Chmod changes the mode of the named file to mode.
+// If the file is a symbolic link, it changes the mode of the link's target.
+func Chmod(name string, mode uint32) Error {
+ if e := syscall.Chmod(name, mode); e != 0 {
+ return &PathError{"chmod", name, Errno(e)}
+ }
+ return nil
+}
+
+// Chmod changes the mode of the file to mode.
+func (f *File) Chmod(mode uint32) Error {
+ if e := syscall.Fchmod(f.fd, mode); e != 0 {
+ return &PathError{"chmod", f.name, Errno(e)}
+ }
+ return nil
+}
+
+// Chown changes the numeric uid and gid of the named file.
+// If the file is a symbolic link, it changes the uid and gid of the link's target.
+func Chown(name string, uid, gid int) Error {
+ if e := syscall.Chown(name, uid, gid); e != 0 {
+ return &PathError{"chown", name, Errno(e)}
+ }
+ return nil
+}
+
+// Lchown changes the numeric uid and gid of the named file.
+// If the file is a symbolic link, it changes the uid and gid of the link itself.
+func Lchown(name string, uid, gid int) Error {
+ if e := syscall.Lchown(name, uid, gid); e != 0 {
+ return &PathError{"lchown", name, Errno(e)}
+ }
+ return nil
+}
+
+// Chown changes the numeric uid and gid of the named file.
+func (f *File) Chown(uid, gid int) Error {
+ if e := syscall.Fchown(f.fd, uid, gid); e != 0 {
+ return &PathError{"chown", f.name, Errno(e)}
+ }
+ return nil
+}
+
+// Truncate changes the size of the file.
+// It does not change the I/O offset.
+func (f *File) Truncate(size int64) Error {
+ if e := syscall.Ftruncate(f.fd, size); e != 0 {
+ return &PathError{"truncate", f.name, Errno(e)}
+ }
+ return nil
+}
+
+// Sync commits the current contents of the file to stable storage.
+// Typically, this means flushing the file system's in-memory copy
+// of recently written data to disk.
+func (file *File) Sync() (err Error) {
+ if file == nil {
+ return EINVAL
+ }
+ if e := syscall.Fsync(file.fd); e != 0 {
+ return NewSyscallError("fsync", e)
+ }
+ return nil
+}
+
+// Chtimes changes the access and modification times of the named
+// file, similar to the Unix utime() or utimes() functions.
+//
+// The argument times are in nanoseconds, although the underlying
+// filesystem may truncate or round the values to a more
+// coarse time unit.
+func Chtimes(name string, atime_ns int64, mtime_ns int64) Error {
+ var utimes [2]syscall.Timeval
+ utimes[0] = syscall.NsecToTimeval(atime_ns)
+ utimes[1] = syscall.NsecToTimeval(mtime_ns)
+ if e := syscall.Utimes(name, utimes[0:]); e != 0 {
+ return &PathError{"chtimes", name, Errno(e)}
+ }
+ return nil
+}
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
new file mode 100644
index 000000000..57d4a477f
--- /dev/null
+++ b/libgo/go/os/file_unix.go
@@ -0,0 +1,110 @@
+// 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
+
+import (
+ "runtime"
+ "syscall"
+)
+
+// Auxiliary information if the File describes a directory
+type dirInfo struct {
+ buf []byte // buffer for directory I/O
+ dir *syscall.DIR // from opendir
+}
+
+// DevNull is the name of the operating system's ``null device.''
+// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
+const DevNull = "/dev/null"
+
+// Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.)
+// if applicable. If successful, methods on the returned File can be used for I/O.
+// It returns the File and an Error, if any.
+func Open(name string, flag int, perm uint32) (file *File, err Error) {
+ r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
+ if e != 0 {
+ return nil, &PathError{"open", name, Errno(e)}
+ }
+
+ // There's a race here with fork/exec, which we are
+ // content to live with. See ../syscall/exec.go
+ if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
+ syscall.CloseOnExec(r)
+ }
+
+ return NewFile(r, name), nil
+}
+
+// Close closes the File, rendering it unusable for I/O.
+// It returns an Error, if any.
+func (file *File) Close() Error {
+ if file == nil || file.fd < 0 {
+ return EINVAL
+ }
+ var err Error
+ if e := syscall.Close(file.fd); e != 0 {
+ err = &PathError{"close", file.name, Errno(e)}
+ }
+
+ if file.dirinfo != nil {
+ if libc_closedir(file.dirinfo.dir) < 0 && err == nil {
+ err = &PathError{"closedir", file.name, Errno(syscall.GetErrno())}
+ }
+ }
+
+ file.fd = -1 // so it can't be closed again
+
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(file, nil)
+ return err
+}
+
+// Stat returns the FileInfo structure describing file.
+// It returns the FileInfo and an error, if any.
+func (file *File) Stat() (fi *FileInfo, err Error) {
+ var stat syscall.Stat_t
+ e := syscall.Fstat(file.fd, &stat)
+ if e != 0 {
+ return nil, &PathError{"stat", file.name, Errno(e)}
+ }
+ return fileInfoFromStat(file.name, new(FileInfo), &stat, &stat), nil
+}
+
+// Readdir reads the contents of the directory associated with file and
+// returns an array of up to count FileInfo structures, as would be returned
+// by Lstat, in directory order. Subsequent calls on the same file will yield
+// further FileInfos.
+// A negative count means to read until EOF.
+// Readdir returns the array and an Error, if any.
+func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
+ dirname := file.name
+ if dirname == "" {
+ dirname = "."
+ }
+ dirname += "/"
+ names, err1 := file.Readdirnames(count)
+ if err1 != nil {
+ return nil, err1
+ }
+ fi = make([]FileInfo, len(names))
+ for i, filename := range names {
+ fip, err := Lstat(dirname + filename)
+ if fip == nil || err != nil {
+ fi[i].Name = filename // rest is already zeroed out
+ } else {
+ fi[i] = *fip
+ }
+ }
+ return
+}
+
+// Truncate changes the size of the named file.
+// If the file is a symbolic link, it changes the size of the link's target.
+func Truncate(name string, size int64) Error {
+ if e := syscall.Truncate(name, size); e != 0 {
+ return &PathError{"truncate", name, Errno(e)}
+ }
+ return nil
+}
diff --git a/libgo/go/os/getwd.go b/libgo/go/os/getwd.go
new file mode 100644
index 000000000..49aaea865
--- /dev/null
+++ b/libgo/go/os/getwd.go
@@ -0,0 +1,92 @@
+// 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
+
+import (
+ "syscall"
+)
+
+// Getwd returns a rooted path name corresponding to the
+// current directory. If the current directory can be
+// reached via multiple paths (due to symbolic links),
+// Getwd may return any one of them.
+func Getwd() (string, Error) {
+ // If the operating system provides a Getwd call, use it.
+ if syscall.ImplementsGetwd {
+ s, e := syscall.Getwd()
+ return s, NewSyscallError("getwd", e)
+ }
+
+ // Otherwise, we're trying to find our way back to ".".
+ dot, err := Stat(".")
+ if err != nil {
+ return "", err
+ }
+
+ // Clumsy but widespread kludge:
+ // if $PWD is set and matches ".", use it.
+ pwd := Getenv("PWD")
+ if len(pwd) > 0 && pwd[0] == '/' {
+ d, err := Stat(pwd)
+ if err == nil && d.Dev == dot.Dev && d.Ino == dot.Ino {
+ return pwd, nil
+ }
+ }
+
+ // Root is a special case because it has no parent
+ // and ends in a slash.
+ root, err := Stat("/")
+ if err != nil {
+ // Can't stat root - no hope.
+ return "", err
+ }
+ if root.Dev == dot.Dev && root.Ino == dot.Ino {
+ return "/", nil
+ }
+
+ // General algorithm: find name in parent
+ // and then find name of parent. Each iteration
+ // adds /name to the beginning of pwd.
+ pwd = ""
+ for parent := ".."; ; parent = "../" + parent {
+ if len(parent) >= 1024 { // Sanity check
+ return "", ENAMETOOLONG
+ }
+ fd, err := Open(parent, O_RDONLY, 0)
+ if err != nil {
+ return "", err
+ }
+
+ for {
+ names, err := fd.Readdirnames(100)
+ if err != nil {
+ fd.Close()
+ return "", err
+ }
+ for _, name := range names {
+ d, _ := Lstat(parent + "/" + name)
+ if d.Dev == dot.Dev && d.Ino == dot.Ino {
+ pwd = "/" + name + pwd
+ goto Found
+ }
+ }
+ }
+ fd.Close()
+ return "", ENOENT
+
+ Found:
+ pd, err := fd.Stat()
+ if err != nil {
+ return "", err
+ }
+ fd.Close()
+ if pd.Dev == root.Dev && pd.Ino == root.Ino {
+ break
+ }
+ // Set up for next round.
+ dot = pd
+ }
+ return pwd, nil
+}
diff --git a/libgo/go/os/inotify/inotify_linux.go b/libgo/go/os/inotify/inotify_linux.go
new file mode 100644
index 000000000..1e74c7fbc
--- /dev/null
+++ b/libgo/go/os/inotify/inotify_linux.go
@@ -0,0 +1,291 @@
+// 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.
+
+/*
+This package implements a wrapper for the Linux inotify system.
+
+Example:
+ watcher, err := inotify.NewWatcher()
+ if err != nil {
+ log.Exit(err)
+ }
+ err = watcher.Watch("/tmp")
+ if err != nil {
+ log.Exit(err)
+ }
+ for {
+ select {
+ case ev := <-watcher.Event:
+ log.Println("event:", ev)
+ case err := <-watcher.Error:
+ log.Println("error:", err)
+ }
+ }
+
+*/
+package inotify
+
+import (
+ "fmt"
+ "os"
+ "strings"
+ "syscall"
+ "unsafe"
+)
+
+
+type Event struct {
+ Mask uint32 // Mask of events
+ Cookie uint32 // Unique cookie associating related events (for rename(2))
+ Name string // File name (optional)
+}
+
+type watch struct {
+ wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
+ flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
+}
+
+type Watcher struct {
+ fd int // File descriptor (as returned by the inotify_init() syscall)
+ watches map[string]*watch // Map of inotify watches (key: path)
+ paths map[int]string // Map of watched paths (key: watch descriptor)
+ Error chan os.Error // Errors are sent on this channel
+ Event chan *Event // Events are returned on this channel
+ done chan bool // Channel for sending a "quit message" to the reader goroutine
+ isClosed bool // Set to true when Close() is first called
+}
+
+
+// NewWatcher creates and returns a new inotify instance using inotify_init(2)
+func NewWatcher() (*Watcher, os.Error) {
+ fd, errno := syscall.InotifyInit()
+ if fd == -1 {
+ return nil, os.NewSyscallError("inotify_init", errno)
+ }
+ w := &Watcher{
+ fd: fd,
+ watches: make(map[string]*watch),
+ paths: make(map[int]string),
+ Event: make(chan *Event),
+ Error: make(chan os.Error),
+ done: make(chan bool, 1),
+ }
+
+ go w.readEvents()
+ return w, nil
+}
+
+
+// Close closes an inotify watcher instance
+// It sends a message to the reader goroutine to quit and removes all watches
+// associated with the inotify instance
+func (w *Watcher) Close() os.Error {
+ if w.isClosed {
+ return nil
+ }
+ w.isClosed = true
+
+ // Send "quit" message to the reader goroutine
+ w.done <- true
+ for path := range w.watches {
+ w.RemoveWatch(path)
+ }
+
+ return nil
+}
+
+// AddWatch adds path to the watched file set.
+// The flags are interpreted as described in inotify_add_watch(2).
+func (w *Watcher) AddWatch(path string, flags uint32) os.Error {
+ if w.isClosed {
+ return os.NewError("inotify instance already closed")
+ }
+
+ watchEntry, found := w.watches[path]
+ if found {
+ watchEntry.flags |= flags
+ flags |= syscall.IN_MASK_ADD
+ }
+ wd, errno := syscall.InotifyAddWatch(w.fd, path, flags)
+ if wd == -1 {
+ return os.NewSyscallError("inotify_add_watch", errno)
+ }
+
+ if !found {
+ w.watches[path] = &watch{wd: uint32(wd), flags: flags}
+ w.paths[wd] = path
+ }
+ return nil
+}
+
+
+// Watch adds path to the watched file set, watching all events.
+func (w *Watcher) Watch(path string) os.Error {
+ return w.AddWatch(path, IN_ALL_EVENTS)
+}
+
+
+// RemoveWatch removes path from the watched file set.
+func (w *Watcher) RemoveWatch(path string) os.Error {
+ watch, ok := w.watches[path]
+ if !ok {
+ return os.NewError(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path))
+ }
+ success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
+ if success == -1 {
+ return os.NewSyscallError("inotify_rm_watch", errno)
+ }
+ w.watches[path] = nil, false
+ return nil
+}
+
+
+// readEvents reads from the inotify file descriptor, converts the
+// received events into Event objects and sends them via the Event channel
+func (w *Watcher) readEvents() {
+ var (
+ buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
+ n int // Number of bytes read with read()
+ errno int // Syscall errno
+ )
+
+ for {
+ n, errno = syscall.Read(w.fd, buf[0:])
+ // See if there is a message on the "done" channel
+ _, done := <-w.done
+
+ // If EOF or a "done" message is received
+ if n == 0 || done {
+ errno := syscall.Close(w.fd)
+ if errno == -1 {
+ w.Error <- os.NewSyscallError("close", errno)
+ }
+ close(w.Event)
+ close(w.Error)
+ return
+ }
+ if n < 0 {
+ w.Error <- os.NewSyscallError("read", errno)
+ continue
+ }
+ if n < syscall.SizeofInotifyEvent {
+ w.Error <- os.NewError("inotify: short read in readEvents()")
+ continue
+ }
+
+ var offset uint32 = 0
+ // We don't know how many events we just read into the buffer
+ // While the offset points to at least one whole event...
+ for offset <= uint32(n-syscall.SizeofInotifyEvent) {
+ // Point "raw" to the event in the buffer
+ raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
+ event := new(Event)
+ event.Mask = uint32(raw.Mask)
+ event.Cookie = uint32(raw.Cookie)
+ nameLen := uint32(raw.Len)
+ // If the event happened to the watched directory or the watched file, the kernel
+ // doesn't append the filename to the event, but we would like to always fill the
+ // the "Name" field with a valid filename. We retrieve the path of the watch from
+ // the "paths" map.
+ event.Name = w.paths[int(raw.Wd)]
+ if nameLen > 0 {
+ // Point "bytes" at the first byte of the filename
+ bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent]))
+ // The filename is padded with NUL bytes. TrimRight() gets rid of those.
+ event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
+ }
+ // Send the event on the events channel
+ w.Event <- event
+
+ // Move to the next event in the buffer
+ offset += syscall.SizeofInotifyEvent + nameLen
+ }
+ }
+}
+
+
+// String formats the event e in the form
+// "filename: 0xEventMask = IN_ACCESS|IN_ATTRIB_|..."
+func (e *Event) String() string {
+ var events string = ""
+
+ m := e.Mask
+ for _, b := range eventBits {
+ if m&b.Value != 0 {
+ m &^= b.Value
+ events += "|" + b.Name
+ }
+ }
+
+ if m != 0 {
+ events += fmt.Sprintf("|%#x", m)
+ }
+ if len(events) > 0 {
+ events = " == " + events[1:]
+ }
+
+ return fmt.Sprintf("%q: %#x%s", e.Name, e.Mask, events)
+}
+
+const (
+ // Options for inotify_init() are not exported
+ // IN_CLOEXEC uint32 = syscall.IN_CLOEXEC
+ // IN_NONBLOCK uint32 = syscall.IN_NONBLOCK
+
+ // Options for AddWatch
+ IN_DONT_FOLLOW uint32 = syscall.IN_DONT_FOLLOW
+ IN_ONESHOT uint32 = syscall.IN_ONESHOT
+ IN_ONLYDIR uint32 = syscall.IN_ONLYDIR
+
+ // The "IN_MASK_ADD" option is not exported, as AddWatch
+ // adds it automatically, if there is already a watch for the given path
+ // IN_MASK_ADD uint32 = syscall.IN_MASK_ADD
+
+ // Events
+ IN_ACCESS uint32 = syscall.IN_ACCESS
+ IN_ALL_EVENTS uint32 = syscall.IN_ALL_EVENTS
+ IN_ATTRIB uint32 = syscall.IN_ATTRIB
+ IN_CLOSE uint32 = syscall.IN_CLOSE
+ IN_CLOSE_NOWRITE uint32 = syscall.IN_CLOSE_NOWRITE
+ IN_CLOSE_WRITE uint32 = syscall.IN_CLOSE_WRITE
+ IN_CREATE uint32 = syscall.IN_CREATE
+ IN_DELETE uint32 = syscall.IN_DELETE
+ IN_DELETE_SELF uint32 = syscall.IN_DELETE_SELF
+ IN_MODIFY uint32 = syscall.IN_MODIFY
+ IN_MOVE uint32 = syscall.IN_MOVE
+ IN_MOVED_FROM uint32 = syscall.IN_MOVED_FROM
+ IN_MOVED_TO uint32 = syscall.IN_MOVED_TO
+ IN_MOVE_SELF uint32 = syscall.IN_MOVE_SELF
+ IN_OPEN uint32 = syscall.IN_OPEN
+
+ // Special events
+ IN_ISDIR uint32 = syscall.IN_ISDIR
+ IN_IGNORED uint32 = syscall.IN_IGNORED
+ IN_Q_OVERFLOW uint32 = syscall.IN_Q_OVERFLOW
+ IN_UNMOUNT uint32 = syscall.IN_UNMOUNT
+)
+
+var eventBits = []struct {
+ Value uint32
+ Name string
+}{
+ {IN_ACCESS, "IN_ACCESS"},
+ {IN_ATTRIB, "IN_ATTRIB"},
+ {IN_CLOSE, "IN_CLOSE"},
+ {IN_CLOSE_NOWRITE, "IN_CLOSE_NOWRITE"},
+ {IN_CLOSE_WRITE, "IN_CLOSE_WRITE"},
+ {IN_CREATE, "IN_CREATE"},
+ {IN_DELETE, "IN_DELETE"},
+ {IN_DELETE_SELF, "IN_DELETE_SELF"},
+ {IN_MODIFY, "IN_MODIFY"},
+ {IN_MOVE, "IN_MOVE"},
+ {IN_MOVED_FROM, "IN_MOVED_FROM"},
+ {IN_MOVED_TO, "IN_MOVED_TO"},
+ {IN_MOVE_SELF, "IN_MOVE_SELF"},
+ {IN_OPEN, "IN_OPEN"},
+ {IN_ISDIR, "IN_ISDIR"},
+ {IN_IGNORED, "IN_IGNORED"},
+ {IN_Q_OVERFLOW, "IN_Q_OVERFLOW"},
+ {IN_UNMOUNT, "IN_UNMOUNT"},
+}
diff --git a/libgo/go/os/inotify/inotify_linux_test.go b/libgo/go/os/inotify/inotify_linux_test.go
new file mode 100644
index 000000000..332edcb64
--- /dev/null
+++ b/libgo/go/os/inotify/inotify_linux_test.go
@@ -0,0 +1,99 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package inotify
+
+import (
+ "os"
+ "time"
+ "testing"
+)
+
+func TestInotifyEvents(t *testing.T) {
+ // Create an inotify watcher instance and initialize it
+ watcher, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("NewWatcher() failed: %s", err)
+ }
+
+ // Add a watch for "_obj"
+ err = watcher.Watch("_obj")
+ if err != nil {
+ t.Fatalf("Watcher.Watch() failed: %s", err)
+ }
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Error {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ const testFile string = "_obj/TestInotifyEvents.testfile"
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Event
+ var eventsReceived = 0
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == testFile {
+ eventsReceived++
+ t.Logf("event received: %s", event)
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ }()
+
+ // Create a file
+ // This should add at least one event to the inotify event queue
+ _, err = os.Open(testFile, os.O_WRONLY|os.O_CREAT, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+
+ // We expect this event to be received almost immediately, but let's wait 1 s to be sure
+ time.Sleep(1000e6) // 1000 ms
+ if eventsReceived == 0 {
+ t.Fatal("inotify event hasn't been received after 1 second")
+ }
+
+ // Try closing the inotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ var i = 0
+ for !closed(eventstream) {
+ if i >= 20 {
+ t.Fatal("event stream was not closed after 1 second, as expected")
+ }
+ t.Log("waiting for 50 ms...")
+ time.Sleep(50e6) // 50 ms
+ i++
+ }
+ t.Log("event channel closed")
+}
+
+
+func TestInotifyClose(t *testing.T) {
+ watcher, _ := NewWatcher()
+ watcher.Close()
+
+ done := false
+ go func() {
+ watcher.Close()
+ done = true
+ }()
+
+ time.Sleep(50e6) // 50 ms
+ if !done {
+ t.Fatal("double Close() test failed: second Close() call didn't return")
+ }
+
+ err := watcher.Watch("_obj")
+ if err == nil {
+ t.Fatal("expected error on Watch() after Close(), got nil")
+ }
+}
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
new file mode 100644
index 000000000..5b577065a
--- /dev/null
+++ b/libgo/go/os/os_test.go
@@ -0,0 +1,882 @@
+// 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_test
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ . "os"
+ "strings"
+ "syscall"
+ "testing"
+)
+
+var dot = []string{
+ "env_unix.go",
+ "error.go",
+ "file.go",
+ "os_test.go",
+ "time.go",
+ "types.go",
+}
+
+type sysDir struct {
+ name string
+ files []string
+}
+
+var sysdir = func() (sd *sysDir) {
+ switch syscall.OS {
+ case "windows":
+ sd = &sysDir{
+ Getenv("SystemRoot") + "\\system32\\drivers\\etc",
+ []string{
+ "hosts",
+ "networks",
+ "protocol",
+ "services",
+ },
+ }
+ default:
+ sd = &sysDir{
+ "/etc",
+ []string{
+ "group",
+ "hosts",
+ "passwd",
+ },
+ }
+ }
+ return
+}()
+
+func size(name string, t *testing.T) int64 {
+ file, err := Open(name, O_RDONLY, 0)
+ defer file.Close()
+ if err != nil {
+ t.Fatal("open failed:", err)
+ }
+ var buf [100]byte
+ len := 0
+ for {
+ n, e := file.Read(buf[0:])
+ len += n
+ if e == EOF {
+ break
+ }
+ if e != nil {
+ t.Fatal("read failed:", err)
+ }
+ }
+ return int64(len)
+}
+
+func equal(name1, name2 string) (r bool) {
+ switch syscall.OS {
+ case "windows":
+ r = strings.ToLower(name1) == strings.ToLower(name2)
+ default:
+ r = name1 == name2
+ }
+ return
+}
+
+func newFile(testName string, t *testing.T) (f *File) {
+ // Use a local file system, not NFS.
+ // On Unix, override $TMPDIR in case the user
+ // has it set to an NFS-mounted directory.
+ dir := ""
+ if syscall.OS != "windows" {
+ dir = "/tmp"
+ }
+ f, err := ioutil.TempFile(dir, "_Go_"+testName)
+ if err != nil {
+ t.Fatalf("open %s: %s", testName, err)
+ }
+ return
+}
+
+var sfdir = sysdir.name
+var sfname = sysdir.files[0]
+
+func TestStat(t *testing.T) {
+ path := sfdir + "/" + sfname
+ dir, err := Stat(path)
+ if err != nil {
+ t.Fatal("stat failed:", err)
+ }
+ if !equal(sfname, dir.Name) {
+ t.Error("name should be ", sfname, "; is", dir.Name)
+ }
+ filesize := size(path, t)
+ if dir.Size != filesize {
+ t.Error("size should be", filesize, "; is", dir.Size)
+ }
+}
+
+func TestFstat(t *testing.T) {
+ path := sfdir + "/" + sfname
+ file, err1 := Open(path, O_RDONLY, 0)
+ defer file.Close()
+ if err1 != nil {
+ t.Fatal("open failed:", err1)
+ }
+ dir, err2 := file.Stat()
+ if err2 != nil {
+ t.Fatal("fstat failed:", err2)
+ }
+ if !equal(sfname, dir.Name) {
+ t.Error("name should be ", sfname, "; is", dir.Name)
+ }
+ filesize := size(path, t)
+ if dir.Size != filesize {
+ t.Error("size should be", filesize, "; is", dir.Size)
+ }
+}
+
+func TestLstat(t *testing.T) {
+ path := sfdir + "/" + sfname
+ dir, err := Lstat(path)
+ if err != nil {
+ t.Fatal("lstat failed:", err)
+ }
+ if !equal(sfname, dir.Name) {
+ t.Error("name should be ", sfname, "; is", dir.Name)
+ }
+ filesize := size(path, t)
+ if dir.Size != filesize {
+ t.Error("size should be", filesize, "; is", dir.Size)
+ }
+}
+
+func testReaddirnames(dir string, contents []string, t *testing.T) {
+ file, err := Open(dir, O_RDONLY, 0)
+ defer file.Close()
+ if err != nil {
+ t.Fatalf("open %q failed: %v", dir, err)
+ }
+ s, err2 := file.Readdirnames(-1)
+ if err2 != nil {
+ t.Fatalf("readdirnames %q failed: %v", dir, err2)
+ }
+ for _, m := range contents {
+ found := false
+ for _, n := range s {
+ if n == "." || n == ".." {
+ t.Errorf("got %s in directory", n)
+ }
+ if equal(m, n) {
+ if found {
+ t.Error("present twice:", m)
+ }
+ found = true
+ }
+ }
+ if !found {
+ t.Error("could not find", m)
+ }
+ }
+}
+
+func testReaddir(dir string, contents []string, t *testing.T) {
+ file, err := Open(dir, O_RDONLY, 0)
+ defer file.Close()
+ if err != nil {
+ t.Fatalf("open %q failed: %v", dir, err)
+ }
+ s, err2 := file.Readdir(-1)
+ if err2 != nil {
+ t.Fatalf("readdir %q failed: %v", dir, err2)
+ }
+ for _, m := range contents {
+ found := false
+ for _, n := range s {
+ if equal(m, n.Name) {
+ if found {
+ t.Error("present twice:", m)
+ }
+ found = true
+ }
+ }
+ if !found {
+ t.Error("could not find", m)
+ }
+ }
+}
+
+func TestReaddirnames(t *testing.T) {
+ testReaddirnames(".", dot, t)
+ testReaddirnames(sysdir.name, sysdir.files, t)
+}
+
+func TestReaddir(t *testing.T) {
+ testReaddir(".", dot, t)
+ testReaddir(sysdir.name, sysdir.files, t)
+}
+
+// Read the directory one entry at a time.
+func smallReaddirnames(file *File, length int, t *testing.T) []string {
+ names := make([]string, length)
+ count := 0
+ for {
+ d, err := file.Readdirnames(1)
+ if err != nil {
+ t.Fatalf("readdir %q failed: %v", file.Name(), err)
+ }
+ if len(d) == 0 {
+ break
+ }
+ names[count] = d[0]
+ count++
+ }
+ return names[0:count]
+}
+
+// Check that reading a directory one entry at a time gives the same result
+// as reading it all at once.
+func TestReaddirnamesOneAtATime(t *testing.T) {
+ // big directory that doesn't change often.
+ dir := "/usr/bin"
+ if syscall.OS == "windows" {
+ dir = Getenv("SystemRoot") + "\\system32"
+ }
+ file, err := Open(dir, O_RDONLY, 0)
+ defer file.Close()
+ if err != nil {
+ t.Fatalf("open %q failed: %v", dir, err)
+ }
+ all, err1 := file.Readdirnames(-1)
+ if err1 != nil {
+ t.Fatalf("readdirnames %q failed: %v", dir, err1)
+ }
+ file1, err2 := Open(dir, O_RDONLY, 0)
+ if err2 != nil {
+ t.Fatalf("open %q failed: %v", dir, err2)
+ }
+ small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up
+ for i, n := range all {
+ if small[i] != n {
+ t.Errorf("small read %q mismatch: %v", small[i], n)
+ }
+ }
+}
+
+func TestHardLink(t *testing.T) {
+ // Hardlinks are not supported under windows.
+ if syscall.OS == "windows" {
+ return
+ }
+ from, to := "hardlinktestfrom", "hardlinktestto"
+ Remove(from) // Just in case.
+ file, err := Open(to, O_CREAT|O_WRONLY, 0666)
+ if err != nil {
+ t.Fatalf("open %q failed: %v", to, err)
+ }
+ defer Remove(to)
+ if err = file.Close(); err != nil {
+ t.Errorf("close %q failed: %v", to, err)
+ }
+ err = Link(to, from)
+ if err != nil {
+ t.Fatalf("link %q, %q failed: %v", to, from, err)
+ }
+ defer Remove(from)
+ tostat, err := Stat(to)
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", to, err)
+ }
+ fromstat, err := Stat(from)
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", from, err)
+ }
+ if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+ t.Errorf("link %q, %q did not create hard link", to, from)
+ }
+}
+
+func TestSymLink(t *testing.T) {
+ // Symlinks are not supported under windows.
+ if syscall.OS == "windows" {
+ return
+ }
+ from, to := "symlinktestfrom", "symlinktestto"
+ Remove(from) // Just in case.
+ file, err := Open(to, O_CREAT|O_WRONLY, 0666)
+ if err != nil {
+ t.Fatalf("open %q failed: %v", to, err)
+ }
+ defer Remove(to)
+ if err = file.Close(); err != nil {
+ t.Errorf("close %q failed: %v", to, err)
+ }
+ err = Symlink(to, from)
+ if err != nil {
+ t.Fatalf("symlink %q, %q failed: %v", to, from, err)
+ }
+ defer Remove(from)
+ tostat, err := Stat(to)
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", to, err)
+ }
+ if tostat.FollowedSymlink {
+ t.Fatalf("stat %q claims to have followed a symlink", to)
+ }
+ fromstat, err := Stat(from)
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", from, err)
+ }
+ if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+ t.Errorf("symlink %q, %q did not create symlink", to, from)
+ }
+ fromstat, err = Lstat(from)
+ if err != nil {
+ t.Fatalf("lstat %q failed: %v", from, err)
+ }
+ if !fromstat.IsSymlink() {
+ t.Fatalf("symlink %q, %q did not create symlink", to, from)
+ }
+ fromstat, err = Stat(from)
+ if err != nil {
+ t.Fatalf("stat %q failed: %v", from, err)
+ }
+ if !fromstat.FollowedSymlink {
+ t.Fatalf("stat %q did not follow symlink", from)
+ }
+ s, err := Readlink(from)
+ if err != nil {
+ t.Fatalf("readlink %q failed: %v", from, err)
+ }
+ if s != to {
+ t.Fatalf("after symlink %q != %q", s, to)
+ }
+ file, err = Open(from, O_RDONLY, 0)
+ if err != nil {
+ t.Fatalf("open %q failed: %v", from, err)
+ }
+ file.Close()
+}
+
+func TestLongSymlink(t *testing.T) {
+ // Symlinks are not supported under windows.
+ if syscall.OS == "windows" {
+ return
+ }
+ s := "0123456789abcdef"
+ // Long, but not too long: a common limit is 255.
+ s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
+ from := "longsymlinktestfrom"
+ Remove(from) // Just in case.
+ err := Symlink(s, from)
+ if err != nil {
+ t.Fatalf("symlink %q, %q failed: %v", s, from, err)
+ }
+ defer Remove(from)
+ r, err := Readlink(from)
+ if err != nil {
+ t.Fatalf("readlink %q failed: %v", from, err)
+ }
+ if r != s {
+ t.Fatalf("after symlink %q != %q", r, s)
+ }
+}
+
+func TestRename(t *testing.T) {
+ from, to := "renamefrom", "renameto"
+ Remove(to) // Just in case.
+ file, err := Open(from, O_CREAT|O_WRONLY, 0666)
+ if err != nil {
+ t.Fatalf("open %q failed: %v", to, err)
+ }
+ if err = file.Close(); err != nil {
+ t.Errorf("close %q failed: %v", to, err)
+ }
+ err = Rename(from, to)
+ if err != nil {
+ t.Fatalf("rename %q, %q failed: %v", to, from, err)
+ }
+ defer Remove(to)
+ _, err = Stat(to)
+ if err != nil {
+ t.Errorf("stat %q failed: %v", to, err)
+ }
+}
+
+func TestForkExec(t *testing.T) {
+ var cmd, adir, expect string
+ var args []string
+ r, w, err := Pipe()
+ if err != nil {
+ t.Fatalf("Pipe: %v", err)
+ }
+ if syscall.OS == "windows" {
+ cmd = Getenv("COMSPEC")
+ args = []string{Getenv("COMSPEC"), "/c cd"}
+ adir = Getenv("SystemRoot")
+ expect = Getenv("SystemRoot") + "\r\n"
+ } else {
+ cmd = "/bin/pwd"
+ args = []string{"pwd"}
+ adir = "/"
+ expect = "/\n"
+ }
+ pid, err := ForkExec(cmd, args, nil, adir, []*File{nil, w, Stderr})
+ if err != nil {
+ t.Fatalf("ForkExec: %v", err)
+ }
+ w.Close()
+
+ var b bytes.Buffer
+ io.Copy(&b, r)
+ output := b.String()
+ if output != expect {
+ args[0] = cmd
+ t.Errorf("exec %q returned %q wanted %q", strings.Join(args, " "), output, expect)
+ }
+ Wait(pid, 0)
+}
+
+func checkMode(t *testing.T, path string, mode uint32) {
+ dir, err := Stat(path)
+ if err != nil {
+ t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
+ }
+ if dir.Mode&0777 != mode {
+ t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode, mode)
+ }
+}
+
+func TestChmod(t *testing.T) {
+ // Chmod is not supported under windows.
+ if syscall.OS == "windows" {
+ return
+ }
+ f := newFile("TestChmod", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ if err := Chmod(f.Name(), 0456); err != nil {
+ t.Fatalf("chmod %s 0456: %s", f.Name(), err)
+ }
+ checkMode(t, f.Name(), 0456)
+
+ if err := f.Chmod(0123); err != nil {
+ t.Fatalf("chmod %s 0123: %s", f.Name(), err)
+ }
+ checkMode(t, f.Name(), 0123)
+}
+
+func checkUidGid(t *testing.T, path string, uid, gid int) {
+ dir, err := Stat(path)
+ if err != nil {
+ t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
+ }
+ if dir.Uid != uid {
+ t.Errorf("Stat %q: uid %d want %d", path, dir.Uid, uid)
+ }
+ if dir.Gid != gid {
+ t.Errorf("Stat %q: gid %d want %d", path, dir.Gid, gid)
+ }
+}
+
+func TestChown(t *testing.T) {
+ // Chown is not supported under windows.
+ if syscall.OS == "windows" {
+ return
+ }
+ // Use TempDir() to make sure we're on a local file system,
+ // so that the group ids returned by Getgroups will be allowed
+ // on the file. On NFS, the Getgroups groups are
+ // basically useless.
+ f := newFile("TestChown", t)
+ defer Remove(f.Name())
+ defer f.Close()
+ dir, err := f.Stat()
+ if err != nil {
+ t.Fatalf("stat %s: %s", f.Name(), err)
+ }
+
+ // Can't change uid unless root, but can try
+ // changing the group id. First try our current group.
+ gid := Getgid()
+ t.Log("gid:", gid)
+ if err = Chown(f.Name(), -1, gid); err != nil {
+ t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
+ }
+ checkUidGid(t, f.Name(), dir.Uid, gid)
+
+ // Then try all the auxiliary groups.
+ groups, err := Getgroups()
+ if err != nil {
+ t.Fatalf("getgroups: %s", err)
+ }
+ t.Log("groups: ", groups)
+ for _, g := range groups {
+ if err = Chown(f.Name(), -1, g); err != nil {
+ t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err)
+ }
+ checkUidGid(t, f.Name(), dir.Uid, g)
+
+ // change back to gid to test fd.Chown
+ if err = f.Chown(-1, gid); err != nil {
+ t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
+ }
+ checkUidGid(t, f.Name(), dir.Uid, gid)
+ }
+}
+
+func checkSize(t *testing.T, f *File, size int64) {
+ dir, err := f.Stat()
+ if err != nil {
+ t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
+ }
+ if dir.Size != size {
+ t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size, size)
+ }
+}
+
+func TestTruncate(t *testing.T) {
+ f := newFile("TestTruncate", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ checkSize(t, f, 0)
+ f.Write([]byte("hello, world\n"))
+ checkSize(t, f, 13)
+ f.Truncate(10)
+ checkSize(t, f, 10)
+ f.Truncate(1024)
+ checkSize(t, f, 1024)
+ f.Truncate(0)
+ checkSize(t, f, 0)
+ f.Write([]byte("surprise!"))
+ checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+}
+
+// Use TempDir() to make sure we're on a local file system,
+// so that timings are not distorted by latency and caching.
+// On NFS, timings can be off due to caching of meta-data on
+// NFS servers (Issue 848).
+func TestChtimes(t *testing.T) {
+ f := newFile("TestChtimes", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ f.Write([]byte("hello, world\n"))
+ f.Close()
+
+ preStat, err := Stat(f.Name())
+ if err != nil {
+ t.Fatalf("Stat %s: %s", f.Name(), err)
+ }
+
+ // Move access and modification time back a second
+ const OneSecond = 1e9 // in nanoseconds
+ err = Chtimes(f.Name(), preStat.Atime_ns-OneSecond, preStat.Mtime_ns-OneSecond)
+ if err != nil {
+ t.Fatalf("Chtimes %s: %s", f.Name(), err)
+ }
+
+ postStat, err := Stat(f.Name())
+ if err != nil {
+ t.Fatalf("second Stat %s: %s", f.Name(), err)
+ }
+
+ if postStat.Atime_ns >= preStat.Atime_ns {
+ t.Errorf("Atime_ns didn't go backwards; was=%d, after=%d",
+ preStat.Atime_ns,
+ postStat.Atime_ns)
+ }
+
+ if postStat.Mtime_ns >= preStat.Mtime_ns {
+ t.Errorf("Mtime_ns didn't go backwards; was=%d, after=%d",
+ preStat.Mtime_ns,
+ postStat.Mtime_ns)
+ }
+}
+
+func TestChdirAndGetwd(t *testing.T) {
+ // TODO(brainman): file.Chdir() is not implemented on windows.
+ if syscall.OS == "windows" {
+ return
+ }
+ fd, err := Open(".", O_RDONLY, 0)
+ if err != nil {
+ t.Fatalf("Open .: %s", err)
+ }
+ // These are chosen carefully not to be symlinks on a Mac
+ // (unlike, say, /var, /etc, and /tmp).
+ dirs := []string{"/", "/usr/bin"}
+ for mode := 0; mode < 2; mode++ {
+ for _, d := range dirs {
+ if mode == 0 {
+ err = Chdir(d)
+ } else {
+ fd1, err := Open(d, O_RDONLY, 0)
+ if err != nil {
+ t.Errorf("Open %s: %s", d, err)
+ continue
+ }
+ err = fd1.Chdir()
+ fd1.Close()
+ }
+ pwd, err1 := Getwd()
+ err2 := fd.Chdir()
+ if err2 != nil {
+ // We changed the current directory and cannot go back.
+ // Don't let the tests continue; they'll scribble
+ // all over some other directory.
+ fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2)
+ Exit(1)
+ }
+ if err != nil {
+ fd.Close()
+ t.Fatalf("Chdir %s: %s", d, err)
+ }
+ if err1 != nil {
+ fd.Close()
+ t.Fatalf("Getwd in %s: %s", d, err1)
+ }
+ if pwd != d {
+ fd.Close()
+ t.Fatalf("Getwd returned %q want %q", pwd, d)
+ }
+ }
+ }
+ fd.Close()
+}
+
+func TestTime(t *testing.T) {
+ // Just want to check that Time() is getting something.
+ // A common failure mode on Darwin is to get 0, 0,
+ // because it returns the time in registers instead of
+ // filling in the structure passed to the system call.
+ // Too bad the compiler doesn't know that
+ // 365.24*86400 is an integer.
+ sec, nsec, err := Time()
+ if sec < (2009-1970)*36524*864 {
+ t.Errorf("Time() = %d, %d, %s; not plausible", sec, nsec, err)
+ }
+}
+
+func TestSeek(t *testing.T) {
+ f := newFile("TestSeek", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ const data = "hello, world\n"
+ io.WriteString(f, data)
+
+ type test struct {
+ in int64
+ whence int
+ out int64
+ }
+ var tests = []test{
+ {0, 1, int64(len(data))},
+ {0, 0, 0},
+ {5, 0, 5},
+ {0, 2, int64(len(data))},
+ {0, 0, 0},
+ {-1, 2, int64(len(data)) - 1},
+ {1 << 33, 0, 1 << 33},
+ {1 << 33, 2, 1<<33 + int64(len(data))},
+ }
+ for i, tt := range tests {
+ off, err := f.Seek(tt.in, tt.whence)
+ if off != tt.out || err != nil {
+ if e, ok := err.(*PathError); ok && e.Error == EINVAL && tt.out > 1<<32 {
+ // Reiserfs rejects the big seeks.
+ // http://code.google.com/p/go/issues/detail?id=91
+ break
+ }
+ t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
+ }
+ }
+}
+
+type openErrorTest struct {
+ path string
+ mode int
+ error Error
+}
+
+var openErrorTests = []openErrorTest{
+ {
+ sfdir + "/no-such-file",
+ O_RDONLY,
+ ENOENT,
+ },
+ {
+ sfdir,
+ O_WRONLY,
+ EISDIR,
+ },
+ {
+ sfdir + "/" + sfname + "/no-such-file",
+ O_WRONLY,
+ ENOTDIR,
+ },
+}
+
+func TestOpenError(t *testing.T) {
+ for _, tt := range openErrorTests {
+ f, err := Open(tt.path, tt.mode, 0)
+ if err == nil {
+ t.Errorf("Open(%q, %d) succeeded", tt.path, tt.mode)
+ f.Close()
+ continue
+ }
+ perr, ok := err.(*PathError)
+ if !ok {
+ 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())
+ }
+ }
+}
+
+func run(t *testing.T, cmd []string) string {
+ // Run /bin/hostname and collect output.
+ r, w, err := Pipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ pid, err := ForkExec("/bin/hostname", []string{"hostname"}, nil, "/", []*File{nil, w, Stderr})
+ if err != nil {
+ t.Fatal(err)
+ }
+ w.Close()
+
+ var b bytes.Buffer
+ io.Copy(&b, r)
+ Wait(pid, 0)
+ output := b.String()
+ if n := len(output); n > 0 && output[n-1] == '\n' {
+ output = output[0 : n-1]
+ }
+ if output == "" {
+ t.Fatalf("%v produced no output", cmd)
+ }
+
+ return output
+}
+
+
+func TestHostname(t *testing.T) {
+ // There is no other way to fetch hostname on windows, but via winapi.
+ if syscall.OS == "windows" {
+ return
+ }
+ // Check internal Hostname() against the output of /bin/hostname.
+ // Allow that the internal Hostname returns a Fully Qualified Domain Name
+ // and the /bin/hostname only returns the first component
+ hostname, err := Hostname()
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ want := run(t, []string{"/bin/hostname"})
+ if hostname != want {
+ i := strings.Index(hostname, ".")
+ if i < 0 || hostname[0:i] != want {
+ t.Errorf("Hostname() = %q, want %q", hostname, want)
+ }
+ }
+}
+
+func TestReadAt(t *testing.T) {
+ f := newFile("TestReadAt", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ const data = "hello, world\n"
+ io.WriteString(f, data)
+
+ b := make([]byte, 5)
+ n, err := f.ReadAt(b, 7)
+ if err != nil || n != len(b) {
+ t.Fatalf("ReadAt 7: %d, %r", n, err)
+ }
+ if string(b) != "world" {
+ t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
+ }
+}
+
+func TestWriteAt(t *testing.T) {
+ f := newFile("TestWriteAt", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ const data = "hello, world\n"
+ io.WriteString(f, data)
+
+ n, err := f.WriteAt([]byte("WORLD"), 7)
+ if err != nil || n != 5 {
+ t.Fatalf("WriteAt 7: %d, %v", n, err)
+ }
+
+ b, err := ioutil.ReadFile(f.Name())
+ if err != nil {
+ t.Fatalf("ReadFile %s: %v", f.Name(), err)
+ }
+ if string(b) != "hello, WORLD\n" {
+ t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
+ }
+}
+
+func writeFile(t *testing.T, fname string, flag int, text string) string {
+ f, err := Open(fname, flag, 0666)
+ if err != nil {
+ t.Fatalf("Open: %v", err)
+ }
+ n, err := io.WriteString(f, text)
+ if err != nil {
+ t.Fatalf("WriteString: %d, %v", n, err)
+ }
+ f.Close()
+ data, err := ioutil.ReadFile(fname)
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+ return string(data)
+}
+
+func TestAppend(t *testing.T) {
+ const f = "append.txt"
+ defer Remove(f)
+ s := writeFile(t, f, O_CREAT|O_TRUNC|O_RDWR, "new")
+ if s != "new" {
+ t.Fatalf("writeFile: have %q want %q", s, "new")
+ }
+ s = writeFile(t, f, O_APPEND|O_RDWR, "|append")
+ if s != "new|append" {
+ t.Fatalf("writeFile: have %q want %q", s, "new|append")
+ }
+}
+
+func TestStatDirWithTrailingSlash(t *testing.T) {
+ // Create new dir, in _test so it will get
+ // cleaned up by make if not by us.
+ path := "_test/_TestStatDirWithSlash_"
+ err := MkdirAll(path, 0777)
+ if err != nil {
+ t.Fatalf("MkdirAll %q: %s", path, err)
+ }
+ defer RemoveAll(path)
+
+ // Stat of path should succeed.
+ _, err = Stat(path)
+ if err != nil {
+ t.Fatal("stat failed:", err)
+ }
+
+ // Stat of path+"/" should succeed too.
+ _, err = Stat(path + "/")
+ if err != nil {
+ t.Fatal("stat failed:", err)
+ }
+}
diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go
new file mode 100644
index 000000000..b762971d9
--- /dev/null
+++ b/libgo/go/os/path.go
@@ -0,0 +1,116 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+
+// MkdirAll creates a directory named path,
+// along with any necessary parents, and returns nil,
+// or else returns an error.
+// The permission bits perm are used for all
+// directories that MkdirAll creates.
+// If path is already a directory, MkdirAll does nothing
+// and returns nil.
+func MkdirAll(path string, perm uint32) Error {
+ // If path exists, stop with success or error.
+ dir, err := Stat(path)
+ if err == nil {
+ if dir.IsDirectory() {
+ return nil
+ }
+ return &PathError{"mkdir", path, ENOTDIR}
+ }
+
+ // Doesn't already exist; make sure parent does.
+ i := len(path)
+ for i > 0 && path[i-1] == '/' { // Skip trailing slashes.
+ i--
+ }
+
+ j := i
+ for j > 0 && path[j-1] != '/' { // Scan backward over element.
+ j--
+ }
+
+ if j > 0 {
+ // Create parent
+ err = MkdirAll(path[0:j-1], perm)
+ if err != nil {
+ return err
+ }
+ }
+
+ // Now parent exists, try to create.
+ err = Mkdir(path, perm)
+ if err != nil {
+ // Handle arguments like "foo/." by
+ // double-checking that directory doesn't exist.
+ dir, err1 := Lstat(path)
+ if err1 == nil && dir.IsDirectory() {
+ return nil
+ }
+ return err
+ }
+ return nil
+}
+
+// RemoveAll removes path and any children it contains.
+// It removes everything it can but returns the first error
+// it encounters. If the path does not exist, RemoveAll
+// returns nil (no error).
+func RemoveAll(path string) Error {
+ // Simple case: if Remove works, we're done.
+ err := Remove(path)
+ if err == nil {
+ return nil
+ }
+
+ // Otherwise, is this a directory we need to recurse into?
+ dir, serr := Lstat(path)
+ if serr != nil {
+ if serr, ok := serr.(*PathError); ok && serr.Error == ENOENT {
+ return nil
+ }
+ return serr
+ }
+ if !dir.IsDirectory() {
+ // Not a directory; return the error from Remove.
+ return err
+ }
+
+ // Directory.
+ fd, err := Open(path, O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+
+ // Remove contents & return first error.
+ err = nil
+ for {
+ names, err1 := fd.Readdirnames(100)
+ for _, name := range names {
+ err1 := RemoveAll(path + "/" + name)
+ if err == nil {
+ err = err1
+ }
+ }
+ // If Readdirnames returned an error, use it.
+ if err == nil {
+ err = err1
+ }
+ if len(names) == 0 {
+ break
+ }
+ }
+
+ // Close directory, because windows won't remove opened directory.
+ fd.Close()
+
+ // Remove directory.
+ err1 := Remove(path)
+ if err == nil {
+ err = err1
+ }
+ return err
+}
diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go
new file mode 100644
index 000000000..799e3ec2f
--- /dev/null
+++ b/libgo/go/os/path_test.go
@@ -0,0 +1,181 @@
+// 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_test
+
+import (
+ . "os"
+ "testing"
+ "runtime"
+ "syscall"
+)
+
+func TestMkdirAll(t *testing.T) {
+ // Create new dir, in _test so it will get
+ // cleaned up by make if not by us.
+ path := "_test/_TestMkdirAll_/dir/./dir2"
+ err := MkdirAll(path, 0777)
+ if err != nil {
+ t.Fatalf("MkdirAll %q: %s", path, err)
+ }
+ defer RemoveAll("_test/_TestMkdirAll_")
+
+ // Already exists, should succeed.
+ err = MkdirAll(path, 0777)
+ if err != nil {
+ t.Fatalf("MkdirAll %q (second time): %s", path, err)
+ }
+
+ // Make file.
+ fpath := path + "/file"
+ _, err = Open(fpath, O_WRONLY|O_CREAT, 0666)
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+
+ // Can't make directory named after file.
+ err = MkdirAll(fpath, 0777)
+ if err == nil {
+ t.Fatalf("MkdirAll %q: no error", fpath)
+ }
+ perr, ok := err.(*PathError)
+ if !ok {
+ t.Fatalf("MkdirAll %q returned %T, not *PathError", fpath, err)
+ }
+ if perr.Path != fpath {
+ t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, perr.Path, fpath)
+ }
+
+ // Can't make subdirectory of file.
+ ffpath := fpath + "/subdir"
+ err = MkdirAll(ffpath, 0777)
+ if err == nil {
+ t.Fatalf("MkdirAll %q: no error", ffpath)
+ }
+ perr, ok = err.(*PathError)
+ if !ok {
+ t.Fatalf("MkdirAll %q returned %T, not *PathError", ffpath, err)
+ }
+ if perr.Path != fpath {
+ t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, perr.Path, fpath)
+ }
+}
+
+func TestRemoveAll(t *testing.T) {
+ // Work directory.
+ path := "_test/_TestRemoveAll_"
+ fpath := path + "/file"
+ dpath := path + "/dir"
+
+ // Make directory with 1 file and remove.
+ if err := MkdirAll(path, 0777); err != nil {
+ t.Fatalf("MkdirAll %q: %s", path, err)
+ }
+ fd, err := Open(fpath, O_WRONLY|O_CREAT, 0666)
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+ fd.Close()
+ if err = RemoveAll(path); err != nil {
+ t.Fatalf("RemoveAll %q (first): %s", path, err)
+ }
+ if _, err := Lstat(path); err == nil {
+ t.Fatalf("Lstat %q succeeded after RemoveAll (first)", path)
+ }
+
+ // Make directory with file and subdirectory and remove.
+ if err = MkdirAll(dpath, 0777); err != nil {
+ t.Fatalf("MkdirAll %q: %s", dpath, err)
+ }
+ fd, err = Open(fpath, O_WRONLY|O_CREAT, 0666)
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+ fd.Close()
+ fd, err = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+ fd.Close()
+ if err = RemoveAll(path); err != nil {
+ t.Fatalf("RemoveAll %q (second): %s", path, err)
+ }
+ if _, err := Lstat(path); err == nil {
+ t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
+ }
+
+ // Determine if we should run the following test.
+ testit := true
+ if syscall.OS == "windows" {
+ // Chmod is not supported under windows.
+ testit = false
+ } else {
+ // Test fails as root.
+ testit = Getuid() != 0
+ }
+ if testit {
+ // Make directory with file and subdirectory and trigger error.
+ if err = MkdirAll(dpath, 0777); err != nil {
+ t.Fatalf("MkdirAll %q: %s", dpath, err)
+ }
+
+ for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
+ fd, err = Open(s, O_WRONLY|O_CREAT, 0666)
+ if err != nil {
+ t.Fatalf("create %q: %s", s, err)
+ }
+ fd.Close()
+ }
+ if err = Chmod(dpath, 0); err != nil {
+ t.Fatalf("Chmod %q 0: %s", dpath, err)
+ }
+
+ // No error checking here: either RemoveAll
+ // will or won't be able to remove dpath;
+ // either way we want to see if it removes fpath
+ // and path/zzz. Reasons why RemoveAll might
+ // succeed in removing dpath as well include:
+ // * running as root
+ // * running on a file system without permissions (FAT)
+ RemoveAll(path)
+ Chmod(dpath, 0777)
+
+ for _, s := range []string{fpath, path + "/zzz"} {
+ if _, err := Lstat(s); err == nil {
+ t.Fatalf("Lstat %q succeeded after partial RemoveAll", s)
+ }
+ }
+ }
+ if err = RemoveAll(path); err != nil {
+ t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err)
+ }
+ if _, err := Lstat(path); err == nil {
+ t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path)
+ }
+}
+
+func TestMkdirAllWithSymlink(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Log("Skipping test: symlinks don't exist under Windows")
+ return
+ }
+
+ err := Mkdir("_test/dir", 0755)
+ if err != nil {
+ t.Fatal(`Mkdir "_test/dir":`, err)
+ }
+ defer RemoveAll("_test/dir")
+
+ err = Symlink("dir", "_test/link")
+ if err != nil {
+ t.Fatal(`Symlink "dir", "_test/link":`, err)
+ }
+ defer RemoveAll("_test/link")
+
+ path := "_test/link/foo"
+ err = MkdirAll(path, 0755)
+ if err != nil {
+ t.Errorf("MkdirAll %q: %s", path, err)
+ }
+}
diff --git a/libgo/go/os/proc.go b/libgo/go/os/proc.go
new file mode 100644
index 000000000..dfddab6cb
--- /dev/null
+++ b/libgo/go/os/proc.go
@@ -0,0 +1,35 @@
+// 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.
+
+// Process etc.
+
+package os
+
+import "syscall"
+
+var Args []string // provided by runtime
+var Envs []string // provided by runtime
+
+
+// Getuid returns the numeric user id of the caller.
+func Getuid() int { return syscall.Getuid() }
+
+// Geteuid returns the numeric effective user id of the caller.
+func Geteuid() int { return syscall.Geteuid() }
+
+// Getgid returns the numeric group id of the caller.
+func Getgid() int { return syscall.Getgid() }
+
+// Getegid returns the numeric effective group id of the caller.
+func Getegid() int { return syscall.Getegid() }
+
+// Getgroups returns a list of the numeric ids of groups that the caller belongs to.
+func Getgroups() ([]int, Error) {
+ gids, errno := syscall.Getgroups()
+ return gids, NewSyscallError("getgroups", errno)
+}
+
+// Exit causes the current program to exit with the given status code.
+// Conventionally, code zero indicates success, non-zero an error.
+func Exit(code int) { syscall.Exit(code) }
diff --git a/libgo/go/os/signal/mkunix.sh b/libgo/go/os/signal/mkunix.sh
new file mode 100644
index 000000000..ec5c9d680
--- /dev/null
+++ b/libgo/go/os/signal/mkunix.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+# 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.
+
+echo '// ./mkunix.sh' "$1"
+echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
+echo
+
+cat <<EOH
+package signal
+
+import (
+ "syscall"
+)
+
+var _ = syscall.Syscall // in case there are zero signals
+
+const (
+EOH
+
+sed -n 's/^const[ ]*\(SIG[A-Z0-9][A-Z0-9]*\)[ ].*/ \1 = UnixSignal(syscall.\1)/p' "$1"
+
+echo ")"
diff --git a/libgo/go/os/signal/signal.go b/libgo/go/os/signal/signal.go
new file mode 100644
index 000000000..666c03e73
--- /dev/null
+++ b/libgo/go/os/signal/signal.go
@@ -0,0 +1,48 @@
+// 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 signal implements operating system-independent signal handling.
+package signal
+
+import (
+ "runtime"
+ "strconv"
+)
+
+// A Signal can represent any operating system signal.
+type Signal interface {
+ String() string
+}
+
+type UnixSignal int32
+
+func (sig UnixSignal) String() string {
+ s := runtime.Signame(int32(sig))
+ if len(s) > 0 {
+ return s
+ }
+ return "Signal " + strconv.Itoa(int(sig))
+}
+
+// Incoming is the global signal channel.
+// All signals received by the program will be delivered to this channel.
+var Incoming <-chan Signal
+
+func process(ch chan<- Signal) {
+ for {
+ var mask uint32 = runtime.Sigrecv()
+ for sig := uint(0); sig < 32; sig++ {
+ if mask&(1<<sig) != 0 {
+ ch <- UnixSignal(sig)
+ }
+ }
+ }
+}
+
+func init() {
+ runtime.Siginit()
+ ch := make(chan Signal) // Done here so Incoming can have type <-chan Signal
+ Incoming = ch
+ go process(ch)
+}
diff --git a/libgo/go/os/signal/signal_test.go b/libgo/go/os/signal/signal_test.go
new file mode 100644
index 000000000..f2679f14d
--- /dev/null
+++ b/libgo/go/os/signal/signal_test.go
@@ -0,0 +1,19 @@
+// 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 signal
+
+import (
+ "syscall"
+ "testing"
+)
+
+func TestSignal(t *testing.T) {
+ // Send this process a SIGHUP.
+ syscall.Syscall(syscall.SYS_KILL, uintptr(syscall.Getpid()), syscall.SIGHUP, 0)
+
+ if sig := (<-Incoming).(UnixSignal); sig != SIGHUP {
+ t.Errorf("signal was %v, want %v", sig, SIGHUP)
+ }
+}
diff --git a/libgo/go/os/stat.go b/libgo/go/os/stat.go
new file mode 100644
index 000000000..d6c7a54ed
--- /dev/null
+++ b/libgo/go/os/stat.go
@@ -0,0 +1,40 @@
+// 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.
+
+// AMD64, Linux
+
+package os
+
+import syscall "syscall"
+
+func isSymlink(stat *syscall.Stat_t) bool {
+ return stat.Mode & syscall.S_IFMT == syscall.S_IFLNK
+}
+
+func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
+ fi.Dev = uint64(stat.Dev)
+ fi.Ino = uint64(stat.Ino)
+ fi.Nlink = uint64(stat.Nlink)
+ fi.Mode = uint32(stat.Mode)
+ fi.Uid = int(stat.Uid)
+ fi.Gid = int(stat.Gid)
+ fi.Rdev = uint64(stat.Rdev)
+ fi.Size = int64(stat.Size)
+ fi.Blksize = int64(stat.Blksize)
+ fi.Blocks = int64(stat.Blocks)
+ fi.Atime_ns = int64(stat.Atime.Sec)*1e9 + int64(stat.Atime.Nsec)
+ fi.Mtime_ns = int64(stat.Mtime.Sec)*1e9 + int64(stat.Mtime.Nsec)
+ fi.Ctime_ns = int64(stat.Ctime.Sec)*1e9 + int64(stat.Atime.Nsec)
+ for i := len(name)-1; i >= 0; i-- {
+ if name[i] == '/' {
+ name = name[i+1:]
+ break
+ }
+ }
+ fi.Name = name
+ if isSymlink(lstat) && !isSymlink(stat) {
+ fi.FollowedSymlink = true
+ }
+ return fi
+}
diff --git a/libgo/go/os/sys_bsd.go b/libgo/go/os/sys_bsd.go
new file mode 100644
index 000000000..188993b69
--- /dev/null
+++ b/libgo/go/os/sys_bsd.go
@@ -0,0 +1,19 @@
+// 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.
+
+// os code shared between *BSD systems including OS X (Darwin)
+// and FreeBSD.
+
+package os
+
+import "syscall"
+
+func Hostname() (name string, err Error) {
+ var errno int
+ name, errno = syscall.Sysctl("kern.hostname")
+ if errno != 0 {
+ return "", NewSyscallError("sysctl kern.hostname", errno)
+ }
+ return name, nil
+}
diff --git a/libgo/go/os/sys_linux.go b/libgo/go/os/sys_linux.go
new file mode 100644
index 000000000..b82d295d3
--- /dev/null
+++ b/libgo/go/os/sys_linux.go
@@ -0,0 +1,28 @@
+// 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.
+
+// Linux-specific
+
+package os
+
+
+// Hostname returns the host name reported by the kernel.
+func Hostname() (name string, err Error) {
+ f, err := Open("/proc/sys/kernel/hostname", O_RDONLY, 0)
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+
+ var buf [512]byte // Enough for a DNS name.
+ n, err := f.Read(buf[0:])
+ if err != nil {
+ return "", err
+ }
+
+ if n > 0 && buf[n-1] == '\n' {
+ n--
+ }
+ return string(buf[0:n]), nil
+}
diff --git a/libgo/go/os/sys_uname.go b/libgo/go/os/sys_uname.go
new file mode 100644
index 000000000..ea46ad01e
--- /dev/null
+++ b/libgo/go/os/sys_uname.go
@@ -0,0 +1,25 @@
+// 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.
+
+// For systems which only store the hostname in uname (Solaris).
+
+package os
+
+import "syscall"
+
+func Hostname() (name string, err Error) {
+ var u syscall.Utsname
+ if errno := syscall.Uname(&u); errno != 0 {
+ return "", NewSyscallError("uname", errno)
+ }
+ b := make([]byte, len(u.Nodename))
+ i := 0
+ for ; i < len(u.Nodename); i++ {
+ if u.Nodename[i] == 0 {
+ break
+ }
+ b[i] = byte(u.Nodename[i])
+ }
+ return string(b[:i]), nil
+}
diff --git a/libgo/go/os/time.go b/libgo/go/os/time.go
new file mode 100644
index 000000000..380345f1b
--- /dev/null
+++ b/libgo/go/os/time.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
+
+import "syscall"
+
+
+// Time returns the current time, in whole seconds and
+// fractional nanoseconds, plus an Error if any. The current
+// time is thus 1e9*sec+nsec, in nanoseconds. The zero of
+// time is the Unix epoch.
+func Time() (sec int64, nsec int64, err Error) {
+ var tv syscall.Timeval
+ if errno := syscall.Gettimeofday(&tv); errno != 0 {
+ return 0, 0, NewSyscallError("gettimeofday", errno)
+ }
+ return int64(tv.Sec), int64(tv.Usec) * 1000, err
+}
diff --git a/libgo/go/os/types.go b/libgo/go/os/types.go
new file mode 100644
index 000000000..79f6e9d49
--- /dev/null
+++ b/libgo/go/os/types.go
@@ -0,0 +1,56 @@
+// 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
+
+import "syscall"
+
+// An operating-system independent representation of Unix data structures.
+// OS-specific routines in this directory convert the OS-local versions to these.
+
+// Getpagesize returns the underlying system's memory page size.
+func Getpagesize() int { return syscall.Getpagesize() }
+
+// A FileInfo describes a file and is returned by Stat, Fstat, and Lstat
+type FileInfo struct {
+ Dev uint64 // device number of file system holding file.
+ Ino uint64 // inode number.
+ Nlink uint64 // number of hard links.
+ Mode uint32 // permission and mode bits.
+ Uid int // user id of owner.
+ Gid int // group id of owner.
+ Rdev uint64 // device type for special file.
+ Size int64 // length in bytes.
+ Blksize int64 // size of blocks, in bytes.
+ Blocks int64 // number of blocks allocated for file.
+ Atime_ns int64 // access time; nanoseconds since epoch.
+ Mtime_ns int64 // modified time; nanoseconds since epoch.
+ Ctime_ns int64 // status change time; nanoseconds since epoch.
+ Name string // name of file as presented to Open.
+ FollowedSymlink bool // followed a symlink to get this information
+}
+
+// IsFifo reports whether the FileInfo describes a FIFO file.
+func (f *FileInfo) IsFifo() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFIFO }
+
+// IsChar reports whether the FileInfo describes a character special file.
+func (f *FileInfo) IsChar() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFCHR }
+
+// IsDirectory reports whether the FileInfo describes a directory.
+func (f *FileInfo) IsDirectory() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFDIR }
+
+// IsBlock reports whether the FileInfo describes a block special file.
+func (f *FileInfo) IsBlock() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFBLK }
+
+// IsRegular reports whether the FileInfo describes a regular file.
+func (f *FileInfo) IsRegular() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFREG }
+
+// IsSymlink reports whether the FileInfo describes a symbolic link.
+func (f *FileInfo) IsSymlink() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFLNK }
+
+// IsSocket reports whether the FileInfo describes a socket.
+func (f *FileInfo) IsSocket() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFSOCK }
+
+// Permission returns the file permission bits.
+func (f *FileInfo) Permission() uint32 { return f.Mode & 0777 }
diff --git a/libgo/go/patch/apply.go b/libgo/go/patch/apply.go
new file mode 100644
index 000000000..0dd9080bf
--- /dev/null
+++ b/libgo/go/patch/apply.go
@@ -0,0 +1,54 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package patch
+
+import "os"
+
+// An Op is a single operation to execute to apply a patch.
+type Op struct {
+ Verb Verb // action
+ Src string // source file
+ Dst string // destination file
+ Mode int // mode for destination (if non-zero)
+ Data []byte // data for destination (if non-nil)
+}
+
+// Apply applies the patch set to the files named in the patch set,
+// constructing an in-memory copy of the new file state.
+// It is the client's job to write the changes to the file system
+// if desired.
+//
+// The function readFile should return the contents of the named file.
+// Typically this function will be io.ReadFile.
+//
+func (set *Set) Apply(readFile func(string) ([]byte, os.Error)) ([]Op, os.Error) {
+ op := make([]Op, len(set.File))
+
+ for i, f := range set.File {
+ o := &op[i]
+ o.Verb = f.Verb
+ o.Src = f.Src
+ o.Dst = f.Dst
+ o.Mode = f.NewMode
+ if f.Diff != NoDiff || o.Verb != Edit {
+ // Clients assume o.Data == nil means no data diff.
+ // Start with a non-nil data.
+ var old []byte = make([]byte, 0) // not nil
+ var err os.Error
+ if f.Src != "" {
+ old, err = readFile(f.Src)
+ if err != nil {
+ return nil, &os.PathError{string(f.Verb), f.Src, err}
+ }
+ }
+ o.Data, err = f.Diff.Apply(old)
+ if err != nil {
+ return nil, &os.PathError{string(f.Verb), f.Src, err}
+ }
+ }
+ }
+
+ return op, nil
+}
diff --git a/libgo/go/patch/git.go b/libgo/go/patch/git.go
new file mode 100644
index 000000000..651609726
--- /dev/null
+++ b/libgo/go/patch/git.go
@@ -0,0 +1,121 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package patch
+
+import (
+ "bytes"
+ "compress/zlib"
+ "crypto/sha1"
+ "encoding/git85"
+ "fmt"
+ "io"
+ "os"
+)
+
+func gitSHA1(data []byte) []byte {
+ if len(data) == 0 {
+ // special case: 0 length is all zeros sum
+ return make([]byte, 20)
+ }
+ h := sha1.New()
+ fmt.Fprintf(h, "blob %d\x00", len(data))
+ h.Write(data)
+ return h.Sum()
+}
+
+// BUG(rsc): The Git binary delta format is not implemented, only Git binary literals.
+
+// GitBinaryLiteral represents a Git binary literal diff.
+type GitBinaryLiteral struct {
+ OldSHA1 []byte // if non-empty, the SHA1 hash of the original
+ New []byte // the new contents
+}
+
+// Apply implements the Diff interface's Apply method.
+func (d *GitBinaryLiteral) Apply(old []byte) ([]byte, os.Error) {
+ if sum := gitSHA1(old); !bytes.HasPrefix(sum, d.OldSHA1) {
+ return nil, ErrPatchFailure
+ }
+ return d.New, nil
+}
+
+func unhex(c byte) uint8 {
+ switch {
+ case '0' <= c && c <= '9':
+ return c - '0'
+ case 'a' <= c && c <= 'f':
+ return c - 'a' + 10
+ case 'A' <= c && c <= 'F':
+ return c - 'A' + 10
+ }
+ return 255
+}
+
+func getHex(s []byte) (data []byte, rest []byte) {
+ n := 0
+ for n < len(s) && unhex(s[n]) != 255 {
+ n++
+ }
+ n &^= 1 // Only take an even number of hex digits.
+ data = make([]byte, n/2)
+ for i := range data {
+ data[i] = unhex(s[2*i])<<4 | unhex(s[2*i+1])
+ }
+ rest = s[n:]
+ return
+}
+
+// ParseGitBinary parses raw as a Git binary patch.
+func ParseGitBinary(raw []byte) (Diff, os.Error) {
+ var oldSHA1, newSHA1 []byte
+ var sawBinary bool
+
+ for {
+ var first []byte
+ first, raw, _ = getLine(raw, 1)
+ first = bytes.TrimSpace(first)
+ if s, ok := skip(first, "index "); ok {
+ oldSHA1, s = getHex(s)
+ if s, ok = skip(s, ".."); !ok {
+ continue
+ }
+ newSHA1, s = getHex(s)
+ continue
+ }
+ if _, ok := skip(first, "GIT binary patch"); ok {
+ sawBinary = true
+ continue
+ }
+ if n, _, ok := atoi(first, "literal ", 10); ok && sawBinary {
+ data := make([]byte, n)
+ d := git85.NewDecoder(bytes.NewBuffer(raw))
+ z, err := zlib.NewReader(d)
+ if err != nil {
+ return nil, err
+ }
+ defer z.Close()
+ if _, err = io.ReadFull(z, data); err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return nil, err
+ }
+ var buf [1]byte
+ m, err := z.Read(buf[0:])
+ if m != 0 || err != os.EOF {
+ return nil, os.NewError("Git binary literal longer than expected")
+ }
+
+ if sum := gitSHA1(data); !bytes.HasPrefix(sum, newSHA1) {
+ return nil, os.NewError("Git binary literal SHA1 mismatch")
+ }
+ return &GitBinaryLiteral{oldSHA1, data}, nil
+ }
+ if !sawBinary {
+ return nil, os.NewError("unexpected Git patch header: " + string(first))
+ }
+ }
+ panic("unreachable")
+}
diff --git a/libgo/go/patch/patch.go b/libgo/go/patch/patch.go
new file mode 100644
index 000000000..d4977dc99
--- /dev/null
+++ b/libgo/go/patch/patch.go
@@ -0,0 +1,322 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package patch implements parsing and execution of the textual and
+// binary patch descriptions used by version control tools such as
+// CVS, Git, Mercurial, and Subversion.
+package patch
+
+import (
+ "bytes"
+ "os"
+ "path"
+ "strings"
+)
+
+// A Set represents a set of patches to be applied as a single atomic unit.
+// Patch sets are often preceded by a descriptive header.
+type Set struct {
+ Header string // free-form text
+ File []*File
+}
+
+// A File represents a collection of changes to be made to a single file.
+type File struct {
+ Verb Verb
+ Src string // source for Verb == Copy, Verb == Rename
+ Dst string
+ OldMode, NewMode int // 0 indicates not used
+ Diff // changes to data; == NoDiff if operation does not edit file
+}
+
+// A Verb is an action performed on a file.
+type Verb string
+
+const (
+ Add Verb = "add"
+ Copy Verb = "copy"
+ Delete Verb = "delete"
+ Edit Verb = "edit"
+ Rename Verb = "rename"
+)
+
+// A Diff is any object that describes changes to transform
+// an old byte stream to a new one.
+type Diff interface {
+ // Apply applies the changes listed in the diff
+ // to the string s, returning the new version of the string.
+ // Note that the string s need not be a text string.
+ Apply(old []byte) (new []byte, err os.Error)
+}
+
+// NoDiff is a no-op Diff implementation: it passes the
+// old data through unchanged.
+var NoDiff Diff = noDiffType(0)
+
+type noDiffType int
+
+func (noDiffType) Apply(old []byte) ([]byte, os.Error) {
+ return old, nil
+}
+
+// A SyntaxError represents a syntax error encountered while parsing a patch.
+type SyntaxError string
+
+func (e SyntaxError) String() string { return string(e) }
+
+var newline = []byte{'\n'}
+
+// Parse patches the patch text to create a patch Set.
+// The patch text typically comprises a textual header and a sequence
+// of file patches, as would be generated by CVS, Subversion,
+// Mercurial, or Git.
+func Parse(text []byte) (*Set, os.Error) {
+ // Split text into files.
+ // CVS and Subversion begin new files with
+ // Index: file name.
+ // ==================
+ // diff -u blah blah
+ //
+ // Mercurial and Git use
+ // diff [--git] a/file/path b/file/path.
+ //
+ // First look for Index: lines. If none, fall back on diff lines.
+ text, files := sections(text, "Index: ")
+ if len(files) == 0 {
+ text, files = sections(text, "diff ")
+ }
+
+ set := &Set{string(text), make([]*File, len(files))}
+
+ // Parse file header and then
+ // parse files into patch chunks.
+ // Each chunk begins with @@.
+ for i, raw := range files {
+ p := new(File)
+ set.File[i] = p
+
+ // First line of hdr is the Index: that
+ // begins the section. After that is the file name.
+ s, raw, _ := getLine(raw, 1)
+ if hasPrefix(s, "Index: ") {
+ p.Dst = string(bytes.TrimSpace(s[7:]))
+ goto HaveName
+ } else if hasPrefix(s, "diff ") {
+ str := string(bytes.TrimSpace(s))
+ i := strings.LastIndex(str, " b/")
+ if i >= 0 {
+ p.Dst = str[i+3:]
+ goto HaveName
+ }
+ }
+ return nil, SyntaxError("unexpected patch header line: " + string(s))
+ HaveName:
+ p.Dst = path.Clean(p.Dst)
+ if strings.HasPrefix(p.Dst, "../") || strings.HasPrefix(p.Dst, "/") {
+ return nil, SyntaxError("invalid path: " + p.Dst)
+ }
+
+ // Parse header lines giving file information:
+ // new file mode %o - file created
+ // deleted file mode %o - file deleted
+ // old file mode %o - file mode changed
+ // new file mode %o - file mode changed
+ // rename from %s - file renamed from other file
+ // rename to %s
+ // copy from %s - file copied from other file
+ // copy to %s
+ p.Verb = Edit
+ for len(raw) > 0 {
+ oldraw := raw
+ var l []byte
+ l, raw, _ = getLine(raw, 1)
+ l = bytes.TrimSpace(l)
+ if m, s, ok := atoi(l, "new file mode ", 8); ok && len(s) == 0 {
+ p.NewMode = m
+ p.Verb = Add
+ continue
+ }
+ if m, s, ok := atoi(l, "deleted file mode ", 8); ok && len(s) == 0 {
+ p.OldMode = m
+ p.Verb = Delete
+ p.Src = p.Dst
+ p.Dst = ""
+ continue
+ }
+ if m, s, ok := atoi(l, "old file mode ", 8); ok && len(s) == 0 {
+ // usually implies p.Verb = "rename" or "copy"
+ // but we'll get that from the rename or copy line.
+ p.OldMode = m
+ continue
+ }
+ if m, s, ok := atoi(l, "old mode ", 8); ok && len(s) == 0 {
+ p.OldMode = m
+ continue
+ }
+ if m, s, ok := atoi(l, "new mode ", 8); ok && len(s) == 0 {
+ p.NewMode = m
+ continue
+ }
+ if s, ok := skip(l, "rename from "); ok && len(s) > 0 {
+ p.Src = string(s)
+ p.Verb = Rename
+ continue
+ }
+ if s, ok := skip(l, "rename to "); ok && len(s) > 0 {
+ p.Verb = Rename
+ continue
+ }
+ if s, ok := skip(l, "copy from "); ok && len(s) > 0 {
+ p.Src = string(s)
+ p.Verb = Copy
+ continue
+ }
+ if s, ok := skip(l, "copy to "); ok && len(s) > 0 {
+ p.Verb = Copy
+ continue
+ }
+ if s, ok := skip(l, "Binary file "); ok && len(s) > 0 {
+ // Hg prints
+ // Binary file foo has changed
+ // when deleting a binary file.
+ continue
+ }
+ if s, ok := skip(l, "RCS file: "); ok && len(s) > 0 {
+ // CVS prints
+ // RCS file: /cvs/plan9/bin/yesterday,v
+ // retrieving revision 1.1
+ // for each file.
+ continue
+ }
+ if s, ok := skip(l, "retrieving revision "); ok && len(s) > 0 {
+ // CVS prints
+ // RCS file: /cvs/plan9/bin/yesterday,v
+ // retrieving revision 1.1
+ // for each file.
+ continue
+ }
+ if hasPrefix(l, "===") || hasPrefix(l, "---") || hasPrefix(l, "+++") || hasPrefix(l, "diff ") {
+ continue
+ }
+ if hasPrefix(l, "@@ -") {
+ diff, err := ParseTextDiff(oldraw)
+ if err != nil {
+ return nil, err
+ }
+ p.Diff = diff
+ break
+ }
+ if hasPrefix(l, "GIT binary patch") || (hasPrefix(l, "index ") && !hasPrefix(raw, "--- ")) {
+ diff, err := ParseGitBinary(oldraw)
+ if err != nil {
+ return nil, err
+ }
+ p.Diff = diff
+ break
+ }
+ if hasPrefix(l, "index ") {
+ continue
+ }
+ return nil, SyntaxError("unexpected patch header line: " + string(l))
+ }
+ if p.Diff == nil {
+ p.Diff = NoDiff
+ }
+ if p.Verb == Edit {
+ p.Src = p.Dst
+ }
+ }
+
+ return set, nil
+}
+
+// getLine returns the first n lines of data and the remainder.
+// If data has no newline, getLine returns data, nil, false
+func getLine(data []byte, n int) (first []byte, rest []byte, ok bool) {
+ rest = data
+ ok = true
+ for ; n > 0; n-- {
+ nl := bytes.Index(rest, newline)
+ if nl < 0 {
+ rest = nil
+ ok = false
+ break
+ }
+ rest = rest[nl+1:]
+ }
+ first = data[0 : len(data)-len(rest)]
+ return
+}
+
+// sections returns a collection of file sections,
+// each of which begins with a line satisfying prefix.
+// text before the first instance of such a line is
+// returned separately.
+func sections(text []byte, prefix string) ([]byte, [][]byte) {
+ n := 0
+ for b := text; ; {
+ if hasPrefix(b, prefix) {
+ n++
+ }
+ nl := bytes.Index(b, newline)
+ if nl < 0 {
+ break
+ }
+ b = b[nl+1:]
+ }
+
+ sect := make([][]byte, n+1)
+ n = 0
+ for b := text; ; {
+ if hasPrefix(b, prefix) {
+ sect[n] = text[0 : len(text)-len(b)]
+ n++
+ text = b
+ }
+ nl := bytes.Index(b, newline)
+ if nl < 0 {
+ sect[n] = text
+ break
+ }
+ b = b[nl+1:]
+ }
+ return sect[0], sect[1:]
+}
+
+// if s begins with the prefix t, skip returns
+// s with that prefix removed and ok == true.
+func skip(s []byte, t string) (ss []byte, ok bool) {
+ if len(s) < len(t) || string(s[0:len(t)]) != t {
+ return nil, false
+ }
+ return s[len(t):], true
+}
+
+// if s begins with the prefix t and then is a sequence
+// of digits in the given base, atoi returns the number
+// represented by the digits and s with the
+// prefix and the digits removed.
+func atoi(s []byte, t string, base int) (n int, ss []byte, ok bool) {
+ if s, ok = skip(s, t); !ok {
+ return
+ }
+ var i int
+ for i = 0; i < len(s) && '0' <= s[i] && s[i] <= byte('0'+base-1); i++ {
+ n = n*base + int(s[i]-'0')
+ }
+ if i == 0 {
+ return
+ }
+ return n, s[i:], true
+}
+
+// hasPrefix returns true if s begins with t.
+func hasPrefix(s []byte, t string) bool {
+ _, ok := skip(s, t)
+ return ok
+}
+
+// splitLines returns the result of splitting s into lines.
+// The \n on each line is preserved.
+func splitLines(s []byte) [][]byte { return bytes.SplitAfter(s, newline, -1) }
diff --git a/libgo/go/patch/patch_test.go b/libgo/go/patch/patch_test.go
new file mode 100644
index 000000000..0a4aef7ea
--- /dev/null
+++ b/libgo/go/patch/patch_test.go
@@ -0,0 +1,390 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package patch
+
+// TODO(rsc): test Apply
+
+import "testing"
+
+type Test struct {
+ in string
+ out string
+ diff string
+}
+
+func TestFileApply(t *testing.T) {
+ for i, test := range tests {
+ set, err := Parse([]byte(test.diff))
+ if err != nil {
+ t.Errorf("#%d: Parse: %s", i, err)
+ continue
+ }
+ if len(set.File) != 1 {
+ t.Errorf("#%d: Parse returned %d patches, want 1", i, len(set.File))
+ continue
+ }
+ new, err := set.File[0].Apply([]byte(test.in))
+ if err != nil {
+ t.Errorf("#%d: Apply: %s", i, err)
+ continue
+ }
+ if s := string(new); s != test.out {
+ t.Errorf("#%d:\n--- have\n%s--- want\n%s", i, s, test.out)
+ }
+ }
+}
+
+var tests = []Test{
+ {
+ "hello, world\n",
+ "goodbye, world\n",
+ "Index: a\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1 +1 @@\n" +
+ "-hello, world\n" +
+ "+goodbye, world\n",
+ },
+ {
+ "hello, world\n",
+ "goodbye, world\n",
+ "Index: a\n" +
+ "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1 +1 @@\n" +
+ "-hello, world\n" +
+ "+goodbye, world\n",
+ },
+ {
+ "hello, world\n",
+ "goodbye, world\n",
+ "diff a/a b/b\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1,1 +1,1 @@\n" +
+ "-hello, world\n" +
+ "+goodbye, world\n",
+ },
+ {
+ "hello, world",
+ "goodbye, world\n",
+ "diff --git a/a b/b\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1 +1 @@\n" +
+ "-hello, world\n" +
+ "\\ No newline at end of file\n" +
+ "+goodbye, world\n",
+ },
+ {
+ "hello, world\n",
+ "goodbye, world",
+ "Index: a\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1 +1 @@\n" +
+ "-hello, world\n" +
+ "+goodbye, world\n" +
+ "\\ No newline at end of file\n",
+ },
+ {
+ "hello, world",
+ "goodbye, world",
+ "Index: a\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1 +1 @@\n" +
+ "-hello, world\n" +
+ "\\ No newline at end of file\n" +
+ "+goodbye, world\n" +
+ "\\ No newline at end of file\n",
+ },
+ {
+ "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\n",
+ "a\nB\nC\nD\ne\nf\ng\nj\nk\nl\nm\nN\n",
+ "Index: a\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1,14 +1,12 @@\n" +
+ " a\n" +
+ "-b\n" +
+ "-c\n" +
+ "-d\n" +
+ "+B\n" +
+ "+C\n" +
+ "+D\n" +
+ " e\n" +
+ " f\n" +
+ " g\n" +
+ "-h\n" +
+ "-i\n" +
+ " j\n" +
+ " k\n" +
+ " l\n" +
+ " m\n" +
+ "-n\n" +
+ "+N\n",
+ },
+ {
+ "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+ "a\nb\nc\ng\nh\ni\nj\nk\nl\nm\nN\nO\np\nq\nr\ns\nt\nu\nv\nw\nd\ne\nf\nx\n",
+ "Index: a\n" +
+ "--- a/a\n" +
+ "+++ b/b\n" +
+ "@@ -1,9 +1,6 @@\n" +
+ " a\n" +
+ " b\n" +
+ " c\n" +
+ "-d\n" +
+ "-e\n" +
+ "-f\n" +
+ " g\n" +
+ " h\n" +
+ " i\n" +
+ "@@ -11,8 +8,8 @@ j\n" +
+ " k\n" +
+ " l\n" +
+ " m\n" +
+ "-n\n" +
+ "-o\n" +
+ "+N\n" +
+ "+O\n" +
+ " p\n" +
+ " q\n" +
+ " r\n" +
+ "\n" +
+ "@@ -21,6 +18,7 @@ t\n" +
+ " u\n" +
+ " v\n" +
+ " w\n" +
+ "+d\n" +
+ "+e\n" +
+ "+f\n" +
+ " x\n" +
+ "-y\n" +
+ "-z\n",
+ },
+ {
+ "a\nb\nc\ng\nh\ni\nj\nk\nl\nm\nN\nO\np\nq\nr\ns\nt\nu\nv\nw\nd\ne\nf\nx\n",
+ "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+ "Index: a\n" +
+ "--- a/b\n" +
+ "+++ b/a\n" +
+ "@@ -1,6 +1,9 @@\n" +
+ " a\n" +
+ " b\n" +
+ " c\n" +
+ "+d\n" +
+ "+e\n" +
+ "+f\n" +
+ " g\n" +
+ " h\n" +
+ " i\n" +
+ "@@ -8,8 +11,8 @@ j\n" +
+ " k\n" +
+ " l\n" +
+ " m\n" +
+ "-N\n" +
+ "-O\n" +
+ "+n\n" +
+ "+o\n" +
+ " p\n" +
+ " q\n" +
+ " r\n" +
+ "@@ -18,7 +21,6 @@ t\n" +
+ " u\n" +
+ " v\n" +
+ " w\n" +
+ "-d\n" +
+ "-e\n" +
+ "-f\n" +
+ " x\n" +
+ "+y\n" +
+ "+z\n",
+ },
+ {
+ "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+ "",
+ "Index: a\n" +
+ "deleted file mode 100644\n" +
+ "--- a/a\n" +
+ "+++ /dev/null\n" +
+ "@@ -1,26 +0,0 @@\n" +
+ "-a\n" +
+ "-b\n" +
+ "-c\n" +
+ "-d\n" +
+ "-e\n" +
+ "-f\n" +
+ "-g\n" +
+ "-h\n" +
+ "-i\n" +
+ "-j\n" +
+ "-k\n" +
+ "-l\n" +
+ "-m\n" +
+ "-n\n" +
+ "-o\n" +
+ "-p\n" +
+ "-q\n" +
+ "-r\n" +
+ "-s\n" +
+ "-t\n" +
+ "-u\n" +
+ "-v\n" +
+ "-w\n" +
+ "-x\n" +
+ "-y\n" +
+ "-z\n",
+ },
+ {
+ "",
+ "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
+ "Index: a\n" +
+ "new file mode 100644\n" +
+ "--- /dev/null\n" +
+ "+++ b/a\n" +
+ "@@ -0,0 +1,26 @@\n" +
+ "+a\n" +
+ "+b\n" +
+ "+c\n" +
+ "+d\n" +
+ "+e\n" +
+ "+f\n" +
+ "+g\n" +
+ "+h\n" +
+ "+i\n" +
+ "+j\n" +
+ "+k\n" +
+ "+l\n" +
+ "+m\n" +
+ "+n\n" +
+ "+o\n" +
+ "+p\n" +
+ "+q\n" +
+ "+r\n" +
+ "+s\n" +
+ "+t\n" +
+ "+u\n" +
+ "+v\n" +
+ "+w\n" +
+ "+x\n" +
+ "+y\n" +
+ "+z\n",
+ },
+ {
+ "\xc2\xd8\xf9\x63\x8c\xf7\xc6\x9b\xb0\x3c\x39\xfa\x08\x8e\x42\x8f" +
+ "\x1c\x7c\xaf\x54\x22\x87\xc3\xc5\x68\x9b\xe1\xbd\xbc\xc3\xe0\xda" +
+ "\xcc\xe3\x96\xda\xc2\xaf\xbb\x75\x79\x64\x86\x60\x8a\x43\x9e\x07" +
+ "\x9c\xaa\x92\x88\xd4\x30\xb9\x8b\x95\x04\x60\x71\xc7\xbb\x2d\x93" +
+ "\x66\x73\x01\x24\xf3\x63\xbf\xe6\x1d\x38\x15\x56\x98\xc4\x1f\x85" +
+ "\xc3\x60\x39\x3a\x0d\x57\x53\x0c\x29\x3f\xbb\x44\x7e\x56\x56\x9d" +
+ "\x87\xcf\xf6\x88\xe8\x98\x05\x85\xf8\xfe\x44\x21\xfa\x33\xc9\xa4" +
+ "\x22\xbe\x89\x05\x8b\x82\x76\xc9\x7c\xaf\x48\x28\xc4\x86\x15\x89" +
+ "\xb9\x98\xfa\x41\xfc\x3d\x8d\x80\x29\x33\x17\x45\xa5\x7f\x67\x79" +
+ "\x7f\x92\x3b\x2e\x4c\xc1\xd2\x1b\x9e\xcf\xed\x53\x56\xb2\x49\x58" +
+ "\xd8\xe9\x9f\x98\xa3\xfe\x78\xe1\xe8\x74\x71\x04\x1a\x87\xd9\x68" +
+ "\x18\x68\xd0\xae\x7b\xa4\x25\xe3\x06\x03\x7e\x8b\xd3\x50\x1f\xb1" +
+ "\x67\x08\xe3\x93\xf4\x4f\xa1\xfb\x31\xcf\x99\x5a\x43\x9f\x4b\xc4" +
+ "\xaa\x68\x1a\xf9\x8e\x97\x02\x80\x17\xf1\x25\x21\xdf\x94\xbf\x41" +
+ "\x08\x59\x3d\xea\x36\x23\x03\xb5\x62\x4d\xb6\x8f\x9e\xdf\x1f\x03" +
+ "\x7d\x70\xe0\x6f\x46\x08\x96\x79\x72\xb7\xae\x41\x2b\xbd\x2a\x95",
+
+ "\x8e\x5f\xf8\x79\x36\x8d\xbe\x68\xc4\x2c\x78\x8a\x46\x28\x40\x3e" +
+ "\xcf\x3b\xb9\x14\xaf\xfa\x04\x9e\x4b\xa2\x52\x51\x51\xf0\xad\xd3" +
+ "\x03\x1c\x03\x79\x5f\x53\xc7\x1a\xd5\x28\xe2\xd9\x19\x37\xa4\xfa" +
+ "\xdd\xff\xac\xb5\xa9\x42\x4e\x17\xeb\xb4\x0d\x20\x67\x08\x43\x21" +
+ "\x7d\x12\x27\xfa\x96\x7a\x85\xf8\x04\x5f\xf4\xfe\xda\x9f\x66\xf2" +
+ "\xba\x04\x39\x00\xab\x3f\x23\x20\x84\x53\xb4\x88\xb6\xee\xa2\x9e" +
+ "\xc1\xca\xd4\x09\x2a\x27\x89\x2f\xcb\xba\xa6\x41\xb6\xe9\xc5\x08" +
+ "\xff\xf5\x95\x35\xab\xbb\x5c\x62\x96\xe7\x7c\x8f\xf2\x40\x12\xc9" +
+ "\x2d\xfe\xff\x75\x4f\x70\x47\xc9\xcd\x15\x0a\x1c\x23\xe7\x0f\x15" +
+ "\x95\x75\x30\x8f\x6e\x9f\x7e\xa5\x9d\xd1\x65\x1c\x4d\x4e\xf4\x32" +
+ "\x49\x9b\xa1\x30\x44\x62\x6f\xe2\xe6\x69\x09\xf8\x7c\x7c\xbe\x07" +
+ "\xa9\xb6\x14\x7a\x6b\x85\xe4\xbf\x48\xbe\x5b\x3b\x70\xb3\x79\x3b" +
+ "\xc4\x35\x9d\x86\xf1\xfe\x2b\x6f\x80\x74\x50\xf3\x96\x59\x53\x1a" +
+ "\x75\x46\x9d\x57\x72\xb3\xb1\x26\xf5\x81\xcd\x96\x08\xbc\x2b\x10" +
+ "\xdc\x80\xbd\xd0\xdf\x03\x6d\x8d\xec\x30\x2b\x4c\xdb\x4d\x3b\xef" +
+ "\x7d\x3a\x39\xc8\x5a\xc4\xcc\x24\x37\xde\xe2\x95\x2b\x04\x97\xb0",
+
+ // From git diff --binary
+ "Index: a\n" +
+ "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f 100644\n" +
+ "GIT binary patch\n" +
+ "literal 256\n" +
+ "zcmV+b0ssDvU-)@8jlO8aEO?4WC_p~XJGm6E`UIX!qEb;&@U7DW90Pe@Q^y+BDB{@}\n" +
+ "zH>CRA|E#sCLQWU!v<)C<2ty%#5-0kWdWHA|U-bUkpJwv91UUe!KO-Q7Q?!V-?xLQ-\n" +
+ "z%G3!eCy6i1x~4(4>BR{D^_4ZNyIf+H=X{UyKoZF<{{MAPa7W3_6$%_9=MNQ?buf=^\n" +
+ "zpMIsC(PbP>PV_QKo1rj7VsGN+X$kmze7*;%wiJ46h2+0TzFRwRvw1tjHJyg>{wr^Q\n" +
+ "zbWrn_SyLKyMx9r3v#}=ifz6f(yekmgfW6S)18t4$Fe^;kO*`*>IyuN%#LOf&-r|)j\n" +
+ "G1edVN^?m&S\n" +
+ "\n" +
+ "literal 256\n" +
+ "zcmV+b0ssEO*!g3O_r{yBJURLZjzW(de6Lg@hr`8ao8i5@!{FM?<CfaOue)`5WQJgh\n" +
+ "zL!Jkms*;G*Fu9AB1YmK;yDgJua{(mtW54DdI2Bfy#2<yjU^zMsS5pirKf6SJR#u&d\n" +
+ "z&-RGum<5IS{zM`AGs&bPzKI2kf_BM#uSh7wh82mqnEFBdJ&k}VGZ#gre`k4rk~=O;\n" +
+ "z!O|O^&+SuIvPoFj>7SUR{&?Z&ba4b4huLTtXwa^Eq$T491AdFsP#>{p2;-CVPoeuU\n" +
+ "z&zV|7pG(B5Xd3yBmjZwn@g*VOl)pg;Sv~4DBLlT!O}3Ao-yZ{gaNuu72$p$rx2{1e\n" +
+ "Gy(*Pb;D3Ms\n" +
+ "\n",
+ },
+ {
+ "\xc2\xd8\xf9\x63\x8c\xf7\xc6\x9b\xb0\x3c\x39\xfa\x08\x8e\x42\x8f" +
+ "\x1c\x7c\xaf\x54\x22\x87\xc3\xc5\x68\x9b\xe1\xbd\xbc\xc3\xe0\xda" +
+ "\xcc\xe3\x96\xda\xc2\xaf\xbb\x75\x79\x64\x86\x60\x8a\x43\x9e\x07" +
+ "\x9c\xaa\x92\x88\xd4\x30\xb9\x8b\x95\x04\x60\x71\xc7\xbb\x2d\x93" +
+ "\x66\x73\x01\x24\xf3\x63\xbf\xe6\x1d\x38\x15\x56\x98\xc4\x1f\x85" +
+ "\xc3\x60\x39\x3a\x0d\x57\x53\x0c\x29\x3f\xbb\x44\x7e\x56\x56\x9d" +
+ "\x87\xcf\xf6\x88\xe8\x98\x05\x85\xf8\xfe\x44\x21\xfa\x33\xc9\xa4" +
+ "\x22\xbe\x89\x05\x8b\x82\x76\xc9\x7c\xaf\x48\x28\xc4\x86\x15\x89" +
+ "\xb9\x98\xfa\x41\xfc\x3d\x8d\x80\x29\x33\x17\x45\xa5\x7f\x67\x79" +
+ "\x7f\x92\x3b\x2e\x4c\xc1\xd2\x1b\x9e\xcf\xed\x53\x56\xb2\x49\x58" +
+ "\xd8\xe9\x9f\x98\xa3\xfe\x78\xe1\xe8\x74\x71\x04\x1a\x87\xd9\x68" +
+ "\x18\x68\xd0\xae\x7b\xa4\x25\xe3\x06\x03\x7e\x8b\xd3\x50\x1f\xb1" +
+ "\x67\x08\xe3\x93\xf4\x4f\xa1\xfb\x31\xcf\x99\x5a\x43\x9f\x4b\xc4" +
+ "\xaa\x68\x1a\xf9\x8e\x97\x02\x80\x17\xf1\x25\x21\xdf\x94\xbf\x41" +
+ "\x08\x59\x3d\xea\x36\x23\x03\xb5\x62\x4d\xb6\x8f\x9e\xdf\x1f\x03" +
+ "\x7d\x70\xe0\x6f\x46\x08\x96\x79\x72\xb7\xae\x41\x2b\xbd\x2a\x95",
+
+ "\x8e\x5f\xf8\x79\x36\x8d\xbe\x68\xc4\x2c\x78\x8a\x46\x28\x40\x3e" +
+ "\xcf\x3b\xb9\x14\xaf\xfa\x04\x9e\x4b\xa2\x52\x51\x51\xf0\xad\xd3" +
+ "\x03\x1c\x03\x79\x5f\x53\xc7\x1a\xd5\x28\xe2\xd9\x19\x37\xa4\xfa" +
+ "\xdd\xff\xac\xb5\xa9\x42\x4e\x17\xeb\xb4\x0d\x20\x67\x08\x43\x21" +
+ "\x7d\x12\x27\xfa\x96\x7a\x85\xf8\x04\x5f\xf4\xfe\xda\x9f\x66\xf2" +
+ "\xba\x04\x39\x00\xab\x3f\x23\x20\x84\x53\xb4\x88\xb6\xee\xa2\x9e" +
+ "\xc1\xca\xd4\x09\x2a\x27\x89\x2f\xcb\xba\xa6\x41\xb6\xe9\xc5\x08" +
+ "\xff\xf5\x95\x35\xab\xbb\x5c\x62\x96\xe7\x7c\x8f\xf2\x40\x12\xc9" +
+ "\x2d\xfe\xff\x75\x4f\x70\x47\xc9\xcd\x15\x0a\x1c\x23\xe7\x0f\x15" +
+ "\x95\x75\x30\x8f\x6e\x9f\x7e\xa5\x9d\xd1\x65\x1c\x4d\x4e\xf4\x32" +
+ "\x49\x9b\xa1\x30\x44\x62\x6f\xe2\xe6\x69\x09\xf8\x7c\x7c\xbe\x07" +
+ "\xa9\xb6\x14\x7a\x6b\x85\xe4\xbf\x48\xbe\x5b\x3b\x70\xb3\x79\x3b" +
+ "\xc4\x35\x9d\x86\xf1\xfe\x2b\x6f\x80\x74\x50\xf3\x96\x59\x53\x1a" +
+ "\x75\x46\x9d\x57\x72\xb3\xb1\x26\xf5\x81\xcd\x96\x08\xbc\x2b\x10" +
+ "\xdc\x80\xbd\xd0\xdf\x03\x6d\x8d\xec\x30\x2b\x4c\xdb\x4d\x3b\xef" +
+ "\x7d\x3a\x39\xc8\x5a\xc4\xcc\x24\x37\xde\xe2\x95\x2b\x04\x97\xb0",
+
+ // From hg diff --git
+ "Index: a\n" +
+ "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f\n" +
+ "GIT binary patch\n" +
+ "literal 256\n" +
+ "zc$@(M0ssDvU-)@8jlO8aEO?4WC_p~XJGm6E`UIX!qEb;&@U7DW90Pe@Q^y+BDB{@}\n" +
+ "zH>CRA|E#sCLQWU!v<)C<2ty%#5-0kWdWHA|U-bUkpJwv91UUe!KO-Q7Q?!V-?xLQ-\n" +
+ "z%G3!eCy6i1x~4(4>BR{D^_4ZNyIf+H=X{UyKoZF<{{MAPa7W3_6$%_9=MNQ?buf=^\n" +
+ "zpMIsC(PbP>PV_QKo1rj7VsGN+X$kmze7*;%wiJ46h2+0TzFRwRvw1tjHJyg>{wr^Q\n" +
+ "zbWrn_SyLKyMx9r3v#}=ifz6f(yekmgfW6S)18t4$Fe^;kO*`*>IyuN%#LOf&-r|)j\n" +
+ "G1edVN^?m&S\n" +
+ "\n",
+ },
+ {
+ "",
+ "",
+ "Index: hello\n" +
+ "===================================================================\n" +
+ "old mode 100644\n" +
+ "new mode 100755\n",
+ },
+}
diff --git a/libgo/go/patch/textdiff.go b/libgo/go/patch/textdiff.go
new file mode 100644
index 000000000..c7e693fc6
--- /dev/null
+++ b/libgo/go/patch/textdiff.go
@@ -0,0 +1,171 @@
+package patch
+
+import (
+ "bytes"
+ "os"
+)
+
+type TextDiff []TextChunk
+
+// A TextChunk specifies an edit to a section of a file:
+// the text beginning at Line, which should be exactly Old,
+// is to be replaced with New.
+type TextChunk struct {
+ Line int
+ Old []byte
+ New []byte
+}
+
+func ParseTextDiff(raw []byte) (TextDiff, os.Error) {
+ // Copy raw so it is safe to keep references to slices.
+ _, chunks := sections(raw, "@@ -")
+ delta := 0
+ diff := make(TextDiff, len(chunks))
+ for i, raw := range chunks {
+ c := &diff[i]
+
+ // Parse start line: @@ -oldLine,oldCount +newLine,newCount @@ junk
+ chunk := splitLines(raw)
+ 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))
+ }
+ if len(s) == 0 || s[0] != ',' {
+ oldCount = 1
+ } else if oldCount, s, ok = atoi(s, ",", 10); !ok {
+ goto ErrChunkHdr
+ }
+ if newLine, s, ok = atoi(s, " +", 10); !ok {
+ goto ErrChunkHdr
+ }
+ if len(s) == 0 || s[0] != ',' {
+ newCount = 1
+ } else if newCount, s, ok = atoi(s, ",", 10); !ok {
+ goto ErrChunkHdr
+ }
+ if !hasPrefix(s, " @@") {
+ goto ErrChunkHdr
+ }
+
+ // Special case: for created or deleted files, the empty half
+ // is given as starting at line 0. Translate to line 1.
+ if oldCount == 0 && oldLine == 0 {
+ oldLine = 1
+ }
+ if newCount == 0 && newLine == 0 {
+ newLine = 1
+ }
+
+ // Count lines in text
+ var dropOldNL, dropNewNL bool
+ var nold, nnew int
+ var lastch byte
+ chunk = chunk[1:]
+ for _, l := range chunk {
+ if nold == oldCount && nnew == newCount && (len(l) == 0 || l[0] != '\\') {
+ if len(bytes.TrimSpace(l)) != 0 {
+ return nil, SyntaxError("too many chunk lines")
+ }
+ continue
+ }
+ if len(l) == 0 {
+ return nil, SyntaxError("empty chunk line")
+ }
+ switch l[0] {
+ case '+':
+ nnew++
+ case '-':
+ nold++
+ case ' ':
+ nnew++
+ nold++
+ case '\\':
+ if _, ok := skip(l, "\\ No newline at end of file"); ok {
+ switch lastch {
+ case '-':
+ dropOldNL = true
+ case '+':
+ dropNewNL = true
+ case ' ':
+ dropOldNL = true
+ dropNewNL = true
+ default:
+ return nil, SyntaxError("message `\\ No newline at end of file' out of context")
+ }
+ break
+ }
+ fallthrough
+ default:
+ return nil, SyntaxError("unexpected chunk line: " + string(l))
+ }
+ lastch = l[0]
+ }
+
+ // Does it match the header?
+ if nold != oldCount || nnew != newCount {
+ return nil, SyntaxError("chunk header does not match line count: " + string(chunkHeader))
+ }
+ if oldLine+delta != newLine {
+ return nil, SyntaxError("chunk delta is out of sync with previous chunks")
+ }
+ delta += nnew - nold
+ c.Line = oldLine
+
+ var old, new bytes.Buffer
+ nold = 0
+ nnew = 0
+ for _, l := range chunk {
+ if nold == oldCount && nnew == newCount {
+ break
+ }
+ ch, l := l[0], l[1:]
+ if ch == '\\' {
+ continue
+ }
+ if ch != '+' {
+ old.Write(l)
+ nold++
+ }
+ if ch != '-' {
+ new.Write(l)
+ nnew++
+ }
+ }
+ c.Old = old.Bytes()
+ c.New = new.Bytes()
+ if dropOldNL {
+ c.Old = c.Old[0 : len(c.Old)-1]
+ }
+ if dropNewNL {
+ c.New = c.New[0 : len(c.New)-1]
+ }
+ }
+ return diff, nil
+}
+
+var ErrPatchFailure = os.NewError("patch did not apply cleanly")
+
+// Apply applies the changes listed in the diff
+// to the data, returning the new version.
+func (d TextDiff) Apply(data []byte) ([]byte, os.Error) {
+ var buf bytes.Buffer
+ line := 1
+ for _, c := range d {
+ var ok bool
+ var prefix []byte
+ prefix, data, ok = getLine(data, c.Line-line)
+ if !ok || !bytes.HasPrefix(data, c.Old) {
+ return nil, ErrPatchFailure
+ }
+ buf.Write(prefix)
+ data = data[len(c.Old):]
+ buf.Write(c.New)
+ line = c.Line + bytes.Count(c.Old, newline)
+ }
+ buf.Write(data)
+ return buf.Bytes(), nil
+}
diff --git a/libgo/go/path/match.go b/libgo/go/path/match.go
new file mode 100644
index 000000000..dd3422c42
--- /dev/null
+++ b/libgo/go/path/match.go
@@ -0,0 +1,278 @@
+package path
+
+import (
+ "os"
+ "sort"
+ "strings"
+ "utf8"
+)
+
+var ErrBadPattern = os.NewError("syntax error in pattern")
+
+// Match returns true if name matches the shell file name pattern.
+// The syntax used by pattern is:
+//
+// pattern:
+// { term }
+// term:
+// '*' matches any sequence of non-/ characters
+// '?' matches any single non-/ character
+// '[' [ '^' ] { character-range } ']'
+// character class (must be non-empty)
+// c matches character c (c != '*', '?', '\\', '[')
+// '\\' c matches character c
+//
+// character-range:
+// c matches character c (c != '\\', '-', ']')
+// '\\' c matches character c
+// lo '-' hi matches character c for lo <= c <= hi
+//
+// Match requires pattern to match all of name, not just a substring.
+// The only possible error return is when pattern is malformed.
+//
+func Match(pattern, name string) (matched bool, err os.Error) {
+Pattern:
+ for len(pattern) > 0 {
+ var star bool
+ var chunk string
+ star, chunk, pattern = scanChunk(pattern)
+ if star && chunk == "" {
+ // Trailing * matches rest of string unless it has a /.
+ return strings.Index(name, "/") < 0, nil
+ }
+ // Look for match at current position.
+ t, ok, err := matchChunk(chunk, name)
+ // if we're the last chunk, make sure we've exhausted the name
+ // otherwise we'll give a false result even if we could still match
+ // using the star
+ if ok && (len(t) == 0 || len(pattern) > 0) {
+ name = t
+ continue
+ }
+ if err != nil {
+ return false, err
+ }
+ if star {
+ // Look for match skipping i+1 bytes.
+ // Cannot skip /.
+ for i := 0; i < len(name) && name[i] != '/'; i++ {
+ t, ok, err := matchChunk(chunk, name[i+1:])
+ if ok {
+ // if we're the last chunk, make sure we exhausted the name
+ if len(pattern) == 0 && len(t) > 0 {
+ continue
+ }
+ name = t
+ continue Pattern
+ }
+ if err != nil {
+ return false, err
+ }
+ }
+ }
+ return false, nil
+ }
+ return len(name) == 0, nil
+}
+
+// scanChunk gets the next section of pattern, which is a non-star string
+// possibly preceded by a star.
+func scanChunk(pattern string) (star bool, chunk, rest string) {
+ for len(pattern) > 0 && pattern[0] == '*' {
+ pattern = pattern[1:]
+ star = true
+ }
+ inrange := false
+ var i int
+Scan:
+ for i = 0; i < len(pattern); i++ {
+ switch pattern[i] {
+ case '\\':
+ // error check handled in matchChunk: bad pattern.
+ if i+1 < len(pattern) {
+ i++
+ }
+ continue
+ case '[':
+ inrange = true
+ case ']':
+ inrange = false
+ case '*':
+ if !inrange {
+ break Scan
+ }
+ }
+ }
+ return star, pattern[0:i], pattern[i:]
+}
+
+// matchChunk checks whether chunk matches the beginning of s.
+// If so, it returns the remainder of s (after the match).
+// Chunk is all single-character operators: literals, char classes, and ?.
+func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
+ for len(chunk) > 0 {
+ if len(s) == 0 {
+ return
+ }
+ switch chunk[0] {
+ case '[':
+ // character class
+ r, n := utf8.DecodeRuneInString(s)
+ s = s[n:]
+ chunk = chunk[1:]
+ // possibly negated
+ notNegated := true
+ if len(chunk) > 0 && chunk[0] == '^' {
+ notNegated = false
+ chunk = chunk[1:]
+ }
+ // parse all ranges
+ match := false
+ nrange := 0
+ for {
+ if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 {
+ chunk = chunk[1:]
+ break
+ }
+ var lo, hi int
+ if lo, chunk, err = getEsc(chunk); err != nil {
+ return
+ }
+ hi = lo
+ if chunk[0] == '-' {
+ if hi, chunk, err = getEsc(chunk[1:]); err != nil {
+ return
+ }
+ }
+ if lo <= r && r <= hi {
+ match = true
+ }
+ nrange++
+ }
+ if match != notNegated {
+ return
+ }
+
+ case '?':
+ if s[0] == '/' {
+ return
+ }
+ _, n := utf8.DecodeRuneInString(s)
+ s = s[n:]
+ chunk = chunk[1:]
+
+ case '\\':
+ chunk = chunk[1:]
+ if len(chunk) == 0 {
+ err = ErrBadPattern
+ return
+ }
+ fallthrough
+
+ default:
+ if chunk[0] != s[0] {
+ return
+ }
+ s = s[1:]
+ chunk = chunk[1:]
+ }
+ }
+ return s, true, nil
+}
+
+// getEsc gets a possibly-escaped character from chunk, for a character class.
+func getEsc(chunk string) (r int, nchunk string, err os.Error) {
+ if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
+ err = ErrBadPattern
+ return
+ }
+ if chunk[0] == '\\' {
+ chunk = chunk[1:]
+ if len(chunk) == 0 {
+ err = ErrBadPattern
+ return
+ }
+ }
+ r, n := utf8.DecodeRuneInString(chunk)
+ if r == utf8.RuneError && n == 1 {
+ err = ErrBadPattern
+ }
+ nchunk = chunk[n:]
+ if len(nchunk) == 0 {
+ err = ErrBadPattern
+ }
+ return
+}
+
+// Glob returns the names of all files matching pattern or nil
+// if there is no matching file. The syntax of patterns is the same
+// as in Match. The pattern may describe hierarchical names such as
+// /usr/*/bin/ed.
+//
+func Glob(pattern string) (matches []string) {
+ if !hasMeta(pattern) {
+ if _, err := os.Stat(pattern); err == nil {
+ return []string{pattern}
+ }
+ return nil
+ }
+
+ dir, file := Split(pattern)
+ switch dir {
+ case "":
+ dir = "."
+ case "/":
+ // nothing
+ default:
+ dir = dir[0 : len(dir)-1] // chop off trailing '/'
+ }
+
+ if hasMeta(dir) {
+ for _, d := range Glob(dir) {
+ matches = glob(d, file, matches)
+ }
+ } else {
+ return glob(dir, file, nil)
+ }
+ return matches
+}
+
+// glob searches for files matching pattern in the directory dir
+// and appends them to matches.
+func glob(dir, pattern string, matches []string) []string {
+ fi, err := os.Stat(dir)
+ if err != nil {
+ return nil
+ }
+ if !fi.IsDirectory() {
+ return matches
+ }
+ d, err := os.Open(dir, os.O_RDONLY, 0666)
+ if err != nil {
+ return nil
+ }
+ defer d.Close()
+
+ names, err := d.Readdirnames(-1)
+ if err != nil {
+ return nil
+ }
+ sort.SortStrings(names)
+
+ for _, n := range names {
+ matched, err := Match(pattern, n)
+ if err != nil {
+ return matches
+ }
+ if matched {
+ matches = append(matches, Join(dir, n))
+ }
+ }
+ return matches
+}
+
+// hasMeta returns true if path contains any of the magic characters
+// recognized by Match.
+func hasMeta(path string) bool {
+ return strings.IndexAny(path, "*?[") != -1
+}
diff --git a/libgo/go/path/match_test.go b/libgo/go/path/match_test.go
new file mode 100644
index 000000000..141cff7da
--- /dev/null
+++ b/libgo/go/path/match_test.go
@@ -0,0 +1,106 @@
+// 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 path
+
+import (
+ "os"
+ "testing"
+)
+
+type MatchTest struct {
+ pattern, s string
+ match bool
+ err os.Error
+}
+
+var matchTests = []MatchTest{
+ {"abc", "abc", true, nil},
+ {"*", "abc", true, nil},
+ {"*c", "abc", true, nil},
+ {"a*", "a", true, nil},
+ {"a*", "abc", true, nil},
+ {"a*", "ab/c", false, nil},
+ {"a*/b", "abc/b", true, nil},
+ {"a*/b", "a/c/b", false, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
+ {"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
+ {"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
+ {"ab[c]", "abc", true, nil},
+ {"ab[b-d]", "abc", true, nil},
+ {"ab[e-g]", "abc", false, nil},
+ {"ab[^c]", "abc", false, nil},
+ {"ab[^b-d]", "abc", false, nil},
+ {"ab[^e-g]", "abc", true, nil},
+ {"a\\*b", "a*b", true, nil},
+ {"a\\*b", "ab", false, nil},
+ {"a?b", "a☺b", true, nil},
+ {"a[^a]b", "a☺b", true, nil},
+ {"a???b", "a☺b", false, nil},
+ {"a[^a][^a][^a]b", "a☺b", false, nil},
+ {"[a-ζ]*", "α", true, nil},
+ {"*[a-ζ]", "A", false, nil},
+ {"a?b", "a/b", false, nil},
+ {"a*b", "a/b", false, nil},
+ {"[\\]a]", "]", true, nil},
+ {"[\\-]", "-", true, nil},
+ {"[x\\-]", "x", true, nil},
+ {"[x\\-]", "-", true, nil},
+ {"[x\\-]", "z", false, nil},
+ {"[\\-x]", "x", true, nil},
+ {"[\\-x]", "-", true, nil},
+ {"[\\-x]", "a", false, nil},
+ {"[]a]", "]", false, ErrBadPattern},
+ {"[-]", "-", false, ErrBadPattern},
+ {"[x-]", "x", false, ErrBadPattern},
+ {"[x-]", "-", false, ErrBadPattern},
+ {"[x-]", "z", false, ErrBadPattern},
+ {"[-x]", "x", false, ErrBadPattern},
+ {"[-x]", "-", false, ErrBadPattern},
+ {"[-x]", "a", false, ErrBadPattern},
+ {"\\", "a", false, ErrBadPattern},
+ {"[a-b-c]", "a", false, ErrBadPattern},
+ {"*x", "xxx", true, nil},
+}
+
+func TestMatch(t *testing.T) {
+ for _, tt := range matchTests {
+ ok, err := Match(tt.pattern, tt.s)
+ if ok != tt.match || err != tt.err {
+ t.Errorf("Match(%#q, %#q) = %v, %v want %v, nil", tt.pattern, tt.s, ok, err, tt.match)
+ }
+ }
+}
+
+// contains returns true if vector contains the string s.
+func contains(vector []string, s string) bool {
+ for _, elem := range vector {
+ if elem == s {
+ return true
+ }
+ }
+ return false
+}
+
+var globTests = []struct {
+ pattern, result string
+}{
+ {"match.go", "match.go"},
+ {"mat?h.go", "match.go"},
+ {"*", "match.go"},
+ // Fails in the gccgo test environment.
+ // {"../*/match.go", "../path/match.go"},
+}
+
+func TestGlob(t *testing.T) {
+ for _, tt := range globTests {
+ matches := Glob(tt.pattern)
+ if !contains(matches, tt.result) {
+ t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result)
+ }
+ }
+}
diff --git a/libgo/go/path/path.go b/libgo/go/path/path.go
new file mode 100644
index 000000000..61eea8858
--- /dev/null
+++ b/libgo/go/path/path.go
@@ -0,0 +1,212 @@
+// 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.
+
+// The path package implements utility routines for manipulating
+// slash-separated filename paths.
+package path
+
+import (
+ "io/ioutil"
+ "os"
+ "strings"
+)
+
+// Clean returns the shortest path name equivalent to path
+// by purely lexical processing. It applies the following rules
+// iteratively until no further processing can be done:
+//
+// 1. Replace multiple slashes with a single slash.
+// 2. Eliminate each . path name element (the current directory).
+// 3. Eliminate each inner .. path name element (the parent directory)
+// along with the non-.. element that precedes it.
+// 4. Eliminate .. elements that begin a rooted path:
+// that is, replace "/.." by "/" at the beginning of a path.
+//
+// If the result of this process is an empty string, Clean
+// returns the string ".".
+//
+// See also Rob Pike, ``Lexical File Names in Plan 9 or
+// Getting Dot-Dot right,''
+// http://plan9.bell-labs.com/sys/doc/lexnames.html
+func Clean(path string) string {
+ if path == "" {
+ return "."
+ }
+
+ rooted := path[0] == '/'
+ n := len(path)
+
+ // Invariants:
+ // reading from path; r is index of next byte to process.
+ // writing to buf; w is index of next byte to write.
+ // dotdot is index in buf where .. must stop, either because
+ // it is the leading slash or it is a leading ../../.. prefix.
+ buf := []byte(path)
+ r, w, dotdot := 0, 0, 0
+ if rooted {
+ r, w, dotdot = 1, 1, 1
+ }
+
+ for r < n {
+ switch {
+ case path[r] == '/':
+ // empty path element
+ r++
+ case path[r] == '.' && (r+1 == n || path[r+1] == '/'):
+ // . element
+ r++
+ case path[r] == '.' && path[r+1] == '.' && (r+2 == n || path[r+2] == '/'):
+ // .. element: remove to last /
+ r += 2
+ switch {
+ case w > dotdot:
+ // can backtrack
+ w--
+ for w > dotdot && buf[w] != '/' {
+ w--
+ }
+ case !rooted:
+ // cannot backtrack, but not rooted, so append .. element.
+ if w > 0 {
+ buf[w] = '/'
+ w++
+ }
+ buf[w] = '.'
+ w++
+ buf[w] = '.'
+ w++
+ dotdot = w
+ }
+ default:
+ // real path element.
+ // add slash if needed
+ if rooted && w != 1 || !rooted && w != 0 {
+ buf[w] = '/'
+ w++
+ }
+ // copy element
+ for ; r < n && path[r] != '/'; r++ {
+ buf[w] = path[r]
+ w++
+ }
+ }
+ }
+
+ // Turn empty string into "."
+ if w == 0 {
+ buf[w] = '.'
+ w++
+ }
+
+ return string(buf[0:w])
+}
+
+// Split splits path immediately following the final path separator,
+// separating it into a directory and file name component.
+// If there is no separator in path, Split returns an empty dir and
+// file set to path.
+func Split(path string) (dir, file string) {
+ i := strings.LastIndexAny(path, PathSeps)
+ return path[:i+1], path[i+1:]
+}
+
+// Join joins any number of path elements into a single path, adding a
+// separating slash if necessary. All empty strings are ignored.
+func Join(elem ...string) string {
+ for i, e := range elem {
+ if e != "" {
+ return Clean(strings.Join(elem[i:], "/"))
+ }
+ }
+ return ""
+}
+
+// Ext returns the file name extension used by path.
+// The extension is the suffix beginning at the final dot
+// in the final slash-separated element of path;
+// it is empty if there is no dot.
+func Ext(path string) string {
+ for i := len(path) - 1; i >= 0 && path[i] != '/'; i-- {
+ if path[i] == '.' {
+ return path[i:]
+ }
+ }
+ return ""
+}
+
+// Visitor methods are invoked for corresponding file tree entries
+// visited by Walk. The parameter path is the full path of f relative
+// to root.
+type Visitor interface {
+ VisitDir(path string, f *os.FileInfo) bool
+ VisitFile(path string, f *os.FileInfo)
+}
+
+func walk(path string, f *os.FileInfo, v Visitor, errors chan<- os.Error) {
+ if !f.IsDirectory() {
+ v.VisitFile(path, f)
+ return
+ }
+
+ if !v.VisitDir(path, f) {
+ return // skip directory entries
+ }
+
+ list, err := ioutil.ReadDir(path)
+ if err != nil {
+ if errors != nil {
+ errors <- err
+ }
+ }
+
+ for _, e := range list {
+ walk(Join(path, e.Name), e, v, errors)
+ }
+}
+
+// Walk walks the file tree rooted at root, calling v.VisitDir or
+// v.VisitFile for each directory or file in the tree, including root.
+// If v.VisitDir returns false, Walk skips the directory's entries;
+// otherwise it invokes itself for each directory entry in sorted order.
+// An error reading a directory does not abort the Walk.
+// If errors != nil, Walk sends each directory read error
+// to the channel. Otherwise Walk discards the error.
+func Walk(root string, v Visitor, errors chan<- os.Error) {
+ f, err := os.Lstat(root)
+ if err != nil {
+ if errors != nil {
+ errors <- err
+ }
+ return // can't progress
+ }
+ walk(root, f, v, errors)
+}
+
+// Base returns the last path element of the slash-separated name.
+// Trailing slashes are removed before extracting the last element. If the name is
+// empty, "." is returned. If it consists entirely of slashes, "/" is returned.
+func Base(name string) string {
+ if name == "" {
+ return "."
+ }
+ // Strip trailing slashes.
+ for len(name) > 0 && name[len(name)-1] == '/' {
+ name = name[0 : len(name)-1]
+ }
+ // Find the last element
+ if i := strings.LastIndex(name, "/"); i >= 0 {
+ name = name[i+1:]
+ }
+ // If empty now, it had only slashes.
+ if name == "" {
+ return "/"
+ }
+ return name
+}
+
+// IsAbs returns true if the path is absolute.
+func IsAbs(path string) bool {
+ // TODO: Add Windows support
+ return strings.HasPrefix(path, "/")
+}
diff --git a/libgo/go/path/path_test.go b/libgo/go/path/path_test.go
new file mode 100644
index 000000000..6b4be07a9
--- /dev/null
+++ b/libgo/go/path/path_test.go
@@ -0,0 +1,345 @@
+// 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 path
+
+import (
+ "os"
+ "runtime"
+ "testing"
+)
+
+type CleanTest struct {
+ path, clean string
+}
+
+var cleantests = []CleanTest{
+ // Already clean
+ {"", "."},
+ {"abc", "abc"},
+ {"abc/def", "abc/def"},
+ {"a/b/c", "a/b/c"},
+ {".", "."},
+ {"..", ".."},
+ {"../..", "../.."},
+ {"../../abc", "../../abc"},
+ {"/abc", "/abc"},
+ {"/", "/"},
+
+ // Remove trailing slash
+ {"abc/", "abc"},
+ {"abc/def/", "abc/def"},
+ {"a/b/c/", "a/b/c"},
+ {"./", "."},
+ {"../", ".."},
+ {"../../", "../.."},
+ {"/abc/", "/abc"},
+
+ // Remove doubled slash
+ {"abc//def//ghi", "abc/def/ghi"},
+ {"//abc", "/abc"},
+ {"///abc", "/abc"},
+ {"//abc//", "/abc"},
+ {"abc//", "abc"},
+
+ // Remove . elements
+ {"abc/./def", "abc/def"},
+ {"/./abc/def", "/abc/def"},
+ {"abc/.", "abc"},
+
+ // Remove .. elements
+ {"abc/def/ghi/../jkl", "abc/def/jkl"},
+ {"abc/def/../ghi/../jkl", "abc/jkl"},
+ {"abc/def/..", "abc"},
+ {"abc/def/../..", "."},
+ {"/abc/def/../..", "/"},
+ {"abc/def/../../..", ".."},
+ {"/abc/def/../../..", "/"},
+ {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
+
+ // Combinations
+ {"abc/./../def", "def"},
+ {"abc//./../def", "def"},
+ {"abc/../../././../def", "../../def"},
+}
+
+func TestClean(t *testing.T) {
+ for _, test := range cleantests {
+ if s := Clean(test.path); s != test.clean {
+ t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.clean)
+ }
+ }
+}
+
+type SplitTest struct {
+ path, dir, file string
+}
+
+var splittests = []SplitTest{
+ {"a/b", "a/", "b"},
+ {"a/b/", "a/b/", ""},
+ {"a/", "a/", ""},
+ {"a", "", "a"},
+ {"/", "/", ""},
+}
+
+var winsplittests = []SplitTest{
+ {`C:\Windows\System32`, `C:\Windows\`, `System32`},
+ {`C:\Windows\`, `C:\Windows\`, ``},
+ {`C:\Windows`, `C:\`, `Windows`},
+ {`C:Windows`, `C:`, `Windows`},
+ {`\\?\c:\`, `\\?\c:\`, ``},
+}
+
+func TestSplit(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ splittests = append(splittests, winsplittests...)
+ }
+ for _, test := range splittests {
+ if d, f := Split(test.path); d != test.dir || f != test.file {
+ t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
+ }
+ }
+}
+
+type JoinTest struct {
+ elem []string
+ path string
+}
+
+var jointests = []JoinTest{
+ // zero parameters
+ {[]string{}, ""},
+
+ // one parameter
+ {[]string{""}, ""},
+ {[]string{"a"}, "a"},
+
+ // two parameters
+ {[]string{"a", "b"}, "a/b"},
+ {[]string{"a", ""}, "a"},
+ {[]string{"", "b"}, "b"},
+ {[]string{"/", "a"}, "/a"},
+ {[]string{"/", ""}, "/"},
+ {[]string{"a/", "b"}, "a/b"},
+ {[]string{"a/", ""}, "a"},
+ {[]string{"", ""}, ""},
+}
+
+// join takes a []string and passes it to Join.
+func join(elem []string, args ...string) string {
+ args = elem
+ return Join(args...)
+}
+
+func TestJoin(t *testing.T) {
+ for _, test := range jointests {
+ if p := join(test.elem); p != test.path {
+ t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
+ }
+ }
+}
+
+type ExtTest struct {
+ path, ext string
+}
+
+var exttests = []ExtTest{
+ {"path.go", ".go"},
+ {"path.pb.go", ".go"},
+ {"a.dir/b", ""},
+ {"a.dir/b.go", ".go"},
+ {"a.dir/", ""},
+}
+
+func TestExt(t *testing.T) {
+ for _, test := range exttests {
+ if x := Ext(test.path); x != test.ext {
+ t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext)
+ }
+ }
+}
+
+type Node struct {
+ name string
+ entries []*Node // nil if the entry is a file
+ mark int
+}
+
+var tree = &Node{
+ "testdata",
+ []*Node{
+ &Node{"a", nil, 0},
+ &Node{"b", []*Node{}, 0},
+ &Node{"c", nil, 0},
+ &Node{
+ "d",
+ []*Node{
+ &Node{"x", nil, 0},
+ &Node{"y", []*Node{}, 0},
+ &Node{
+ "z",
+ []*Node{
+ &Node{"u", nil, 0},
+ &Node{"v", nil, 0},
+ },
+ 0,
+ },
+ },
+ 0,
+ },
+ },
+ 0,
+}
+
+func walkTree(n *Node, path string, f func(path string, n *Node)) {
+ f(path, n)
+ for _, e := range n.entries {
+ walkTree(e, Join(path, e.name), f)
+ }
+}
+
+func makeTree(t *testing.T) {
+ walkTree(tree, tree.name, func(path string, n *Node) {
+ if n.entries == nil {
+ fd, err := os.Open(path, os.O_CREAT, 0660)
+ if err != nil {
+ t.Errorf("makeTree: %v", err)
+ }
+ fd.Close()
+ } else {
+ os.Mkdir(path, 0770)
+ }
+ })
+}
+
+func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
+
+func checkMarks(t *testing.T) {
+ walkTree(tree, tree.name, func(path string, n *Node) {
+ if n.mark != 1 {
+ t.Errorf("node %s mark = %d; expected 1", path, n.mark)
+ }
+ n.mark = 0
+ })
+}
+
+// Assumes that each node name is unique. Good enough for a test.
+func mark(name string) {
+ walkTree(tree, tree.name, func(path string, n *Node) {
+ if n.name == name {
+ n.mark++
+ }
+ })
+}
+
+type TestVisitor struct{}
+
+func (v *TestVisitor) VisitDir(path string, f *os.FileInfo) bool {
+ mark(f.Name)
+ return true
+}
+
+func (v *TestVisitor) VisitFile(path string, f *os.FileInfo) {
+ mark(f.Name)
+}
+
+func TestWalk(t *testing.T) {
+ makeTree(t)
+
+ // 1) ignore error handling, expect none
+ v := &TestVisitor{}
+ Walk(tree.name, v, nil)
+ checkMarks(t)
+
+ // 2) handle errors, expect none
+ errors := make(chan os.Error, 64)
+ Walk(tree.name, v, errors)
+ if err, ok := <-errors; ok {
+ t.Errorf("no error expected, found: %s", err)
+ }
+ checkMarks(t)
+
+ if os.Getuid() != 0 {
+ // introduce 2 errors: chmod top-level directories to 0
+ os.Chmod(Join(tree.name, tree.entries[1].name), 0)
+ os.Chmod(Join(tree.name, tree.entries[3].name), 0)
+ // mark respective subtrees manually
+ markTree(tree.entries[1])
+ markTree(tree.entries[3])
+ // correct double-marking of directory itself
+ tree.entries[1].mark--
+ tree.entries[3].mark--
+
+ // 3) handle errors, expect two
+ errors = make(chan os.Error, 64)
+ os.Chmod(Join(tree.name, tree.entries[1].name), 0)
+ Walk(tree.name, v, errors)
+ for i := 1; i <= 2; i++ {
+ if _, ok := <-errors; !ok {
+ t.Errorf("%d. error expected, none found", i)
+ break
+ }
+ }
+ if err, ok := <-errors; ok {
+ t.Errorf("only two errors expected, found 3rd: %v", err)
+ }
+ // the inaccessible subtrees were marked manually
+ checkMarks(t)
+ }
+
+ // cleanup
+ os.Chmod(Join(tree.name, tree.entries[1].name), 0770)
+ os.Chmod(Join(tree.name, tree.entries[3].name), 0770)
+ if err := os.RemoveAll(tree.name); err != nil {
+ t.Errorf("removeTree: %v", err)
+ }
+}
+
+var basetests = []CleanTest{
+ // Already clean
+ {"", "."},
+ {".", "."},
+ {"/.", "."},
+ {"/", "/"},
+ {"////", "/"},
+ {"x/", "x"},
+ {"abc", "abc"},
+ {"abc/def", "def"},
+ {"a/b/.x", ".x"},
+ {"a/b/c.", "c."},
+ {"a/b/c.x", "c.x"},
+}
+
+func TestBase(t *testing.T) {
+ for _, test := range basetests {
+ if s := Base(test.path); s != test.clean {
+ t.Errorf("Base(%q) = %q, want %q", test.path, s, test.clean)
+ }
+ }
+}
+
+type IsAbsTest struct {
+ path string
+ isAbs bool
+}
+
+var isAbsTests = []IsAbsTest{
+ {"", false},
+ {"/", true},
+ {"/usr/bin/gcc", true},
+ {"..", false},
+ {"/a/../bb", true},
+ {".", false},
+ {"./", false},
+ {"lala", false},
+}
+
+func TestIsAbs(t *testing.T) {
+ for _, test := range isAbsTests {
+ if r := IsAbs(test.path); r != test.isAbs {
+ t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
+ }
+ }
+}
diff --git a/libgo/go/path/path_unix.go b/libgo/go/path/path_unix.go
new file mode 100644
index 000000000..7e8c5eb8b
--- /dev/null
+++ b/libgo/go/path/path_unix.go
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package path
+
+const (
+ DirSeps = `/` // directory separators
+ VolumeSeps = `` // volume separators
+ PathSeps = DirSeps + VolumeSeps // all path separators
+)
diff --git a/libgo/go/path/path_windows.go b/libgo/go/path/path_windows.go
new file mode 100644
index 000000000..966eb49fb
--- /dev/null
+++ b/libgo/go/path/path_windows.go
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package path
+
+const (
+ DirSeps = `\/` // directory separators
+ VolumeSeps = `:` // volume separators
+ PathSeps = DirSeps + VolumeSeps // all path separators
+)
diff --git a/libgo/go/rand/exp.go b/libgo/go/rand/exp.go
new file mode 100644
index 000000000..85da49521
--- /dev/null
+++ b/libgo/go/rand/exp.go
@@ -0,0 +1,223 @@
+// 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 rand
+
+import (
+ "math"
+)
+
+/*
+ * Exponential distribution
+ *
+ * See "The Ziggurat Method for Generating Random Variables"
+ * (Marsaglia & Tsang, 2000)
+ * http://www.jstatsoft.org/v05/i08/paper [pdf]
+ */
+
+const (
+ re = 7.69711747013104972
+)
+
+// ExpFloat64 returns an exponentially distributed float64 in the range
+// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
+// (lambda) is 1 and whose mean is 1/lambda (1).
+// To produce a distribution with a different rate parameter,
+// callers can adjust the output using:
+//
+// sample = ExpFloat64() / desiredRateParameter
+//
+func (r *Rand) ExpFloat64() float64 {
+ for {
+ j := r.Uint32()
+ i := j & 0xFF
+ x := float64(j) * float64(we[i])
+ if j < ke[i] {
+ return x
+ }
+ if i == 0 {
+ return re - math.Log(r.Float64())
+ }
+ if fe[i]+float32(r.Float64())*(fe[i-1]-fe[i]) < float32(math.Exp(-x)) {
+ return x
+ }
+ }
+ panic("unreachable")
+}
+
+var ke = [256]uint32{
+ 0xe290a139, 0x0, 0x9beadebc, 0xc377ac71, 0xd4ddb990,
+ 0xde893fb8, 0xe4a8e87c, 0xe8dff16a, 0xebf2deab, 0xee49a6e8,
+ 0xf0204efd, 0xf19bdb8e, 0xf2d458bb, 0xf3da104b, 0xf4b86d78,
+ 0xf577ad8a, 0xf61de83d, 0xf6afb784, 0xf730a573, 0xf7a37651,
+ 0xf80a5bb6, 0xf867189d, 0xf8bb1b4f, 0xf9079062, 0xf94d70ca,
+ 0xf98d8c7d, 0xf9c8928a, 0xf9ff175b, 0xfa319996, 0xfa6085f8,
+ 0xfa8c3a62, 0xfab5084e, 0xfadb36c8, 0xfaff0410, 0xfb20a6ea,
+ 0xfb404fb4, 0xfb5e2951, 0xfb7a59e9, 0xfb95038c, 0xfbae44ba,
+ 0xfbc638d8, 0xfbdcf892, 0xfbf29a30, 0xfc0731df, 0xfc1ad1ed,
+ 0xfc2d8b02, 0xfc3f6c4d, 0xfc5083ac, 0xfc60ddd1, 0xfc708662,
+ 0xfc7f8810, 0xfc8decb4, 0xfc9bbd62, 0xfca9027c, 0xfcb5c3c3,
+ 0xfcc20864, 0xfccdd70a, 0xfcd935e3, 0xfce42ab0, 0xfceebace,
+ 0xfcf8eb3b, 0xfd02c0a0, 0xfd0c3f59, 0xfd156b7b, 0xfd1e48d6,
+ 0xfd26daff, 0xfd2f2552, 0xfd372af7, 0xfd3eeee5, 0xfd4673e7,
+ 0xfd4dbc9e, 0xfd54cb85, 0xfd5ba2f2, 0xfd62451b, 0xfd68b415,
+ 0xfd6ef1da, 0xfd750047, 0xfd7ae120, 0xfd809612, 0xfd8620b4,
+ 0xfd8b8285, 0xfd90bcf5, 0xfd95d15e, 0xfd9ac10b, 0xfd9f8d36,
+ 0xfda43708, 0xfda8bf9e, 0xfdad2806, 0xfdb17141, 0xfdb59c46,
+ 0xfdb9a9fd, 0xfdbd9b46, 0xfdc170f6, 0xfdc52bd8, 0xfdc8ccac,
+ 0xfdcc542d, 0xfdcfc30b, 0xfdd319ef, 0xfdd6597a, 0xfdd98245,
+ 0xfddc94e5, 0xfddf91e6, 0xfde279ce, 0xfde54d1f, 0xfde80c52,
+ 0xfdeab7de, 0xfded5034, 0xfdefd5be, 0xfdf248e3, 0xfdf4aa06,
+ 0xfdf6f984, 0xfdf937b6, 0xfdfb64f4, 0xfdfd818d, 0xfdff8dd0,
+ 0xfe018a08, 0xfe03767a, 0xfe05536c, 0xfe07211c, 0xfe08dfc9,
+ 0xfe0a8fab, 0xfe0c30fb, 0xfe0dc3ec, 0xfe0f48b1, 0xfe10bf76,
+ 0xfe122869, 0xfe1383b4, 0xfe14d17c, 0xfe1611e7, 0xfe174516,
+ 0xfe186b2a, 0xfe19843e, 0xfe1a9070, 0xfe1b8fd6, 0xfe1c8289,
+ 0xfe1d689b, 0xfe1e4220, 0xfe1f0f26, 0xfe1fcfbc, 0xfe2083ed,
+ 0xfe212bc3, 0xfe21c745, 0xfe225678, 0xfe22d95f, 0xfe234ffb,
+ 0xfe23ba4a, 0xfe241849, 0xfe2469f2, 0xfe24af3c, 0xfe24e81e,
+ 0xfe25148b, 0xfe253474, 0xfe2547c7, 0xfe254e70, 0xfe25485a,
+ 0xfe25356a, 0xfe251586, 0xfe24e88f, 0xfe24ae64, 0xfe2466e1,
+ 0xfe2411df, 0xfe23af34, 0xfe233eb4, 0xfe22c02c, 0xfe22336b,
+ 0xfe219838, 0xfe20ee58, 0xfe20358c, 0xfe1f6d92, 0xfe1e9621,
+ 0xfe1daef0, 0xfe1cb7ac, 0xfe1bb002, 0xfe1a9798, 0xfe196e0d,
+ 0xfe1832fd, 0xfe16e5fe, 0xfe15869d, 0xfe141464, 0xfe128ed3,
+ 0xfe10f565, 0xfe0f478c, 0xfe0d84b1, 0xfe0bac36, 0xfe09bd73,
+ 0xfe07b7b5, 0xfe059a40, 0xfe03644c, 0xfe011504, 0xfdfeab88,
+ 0xfdfc26e9, 0xfdf98629, 0xfdf6c83b, 0xfdf3ec01, 0xfdf0f04a,
+ 0xfdedd3d1, 0xfdea953d, 0xfde7331e, 0xfde3abe9, 0xfddffdfb,
+ 0xfddc2791, 0xfdd826cd, 0xfdd3f9a8, 0xfdcf9dfc, 0xfdcb1176,
+ 0xfdc65198, 0xfdc15bb3, 0xfdbc2ce2, 0xfdb6c206, 0xfdb117be,
+ 0xfdab2a63, 0xfda4f5fd, 0xfd9e7640, 0xfd97a67a, 0xfd908192,
+ 0xfd8901f2, 0xfd812182, 0xfd78d98e, 0xfd7022bb, 0xfd66f4ed,
+ 0xfd5d4732, 0xfd530f9c, 0xfd48432b, 0xfd3cd59a, 0xfd30b936,
+ 0xfd23dea4, 0xfd16349e, 0xfd07a7a3, 0xfcf8219b, 0xfce7895b,
+ 0xfcd5c220, 0xfcc2aadb, 0xfcae1d5e, 0xfc97ed4e, 0xfc7fe6d4,
+ 0xfc65ccf3, 0xfc495762, 0xfc2a2fc8, 0xfc07ee19, 0xfbe213c1,
+ 0xfbb8051a, 0xfb890078, 0xfb5411a5, 0xfb180005, 0xfad33482,
+ 0xfa839276, 0xfa263b32, 0xf9b72d1c, 0xf930a1a2, 0xf889f023,
+ 0xf7b577d2, 0xf69c650c, 0xf51530f0, 0xf2cb0e3c, 0xeeefb15d,
+ 0xe6da6ecf,
+}
+var we = [256]float32{
+ 2.0249555e-09, 1.486674e-11, 2.4409617e-11, 3.1968806e-11,
+ 3.844677e-11, 4.4228204e-11, 4.9516443e-11, 5.443359e-11,
+ 5.905944e-11, 6.344942e-11, 6.7643814e-11, 7.1672945e-11,
+ 7.556032e-11, 7.932458e-11, 8.298079e-11, 8.654132e-11,
+ 9.0016515e-11, 9.3415074e-11, 9.674443e-11, 1.0001099e-10,
+ 1.03220314e-10, 1.06377254e-10, 1.09486115e-10, 1.1255068e-10,
+ 1.1557435e-10, 1.1856015e-10, 1.2151083e-10, 1.2442886e-10,
+ 1.2731648e-10, 1.3017575e-10, 1.3300853e-10, 1.3581657e-10,
+ 1.3860142e-10, 1.4136457e-10, 1.4410738e-10, 1.4683108e-10,
+ 1.4953687e-10, 1.5222583e-10, 1.54899e-10, 1.5755733e-10,
+ 1.6020171e-10, 1.6283301e-10, 1.6545203e-10, 1.6805951e-10,
+ 1.7065617e-10, 1.732427e-10, 1.7581973e-10, 1.7838787e-10,
+ 1.8094774e-10, 1.8349985e-10, 1.8604476e-10, 1.8858298e-10,
+ 1.9111498e-10, 1.9364126e-10, 1.9616223e-10, 1.9867835e-10,
+ 2.0119004e-10, 2.0369768e-10, 2.0620168e-10, 2.087024e-10,
+ 2.1120022e-10, 2.136955e-10, 2.1618855e-10, 2.1867974e-10,
+ 2.2116936e-10, 2.2365775e-10, 2.261452e-10, 2.2863202e-10,
+ 2.311185e-10, 2.3360494e-10, 2.360916e-10, 2.3857874e-10,
+ 2.4106667e-10, 2.4355562e-10, 2.4604588e-10, 2.485377e-10,
+ 2.5103128e-10, 2.5352695e-10, 2.560249e-10, 2.585254e-10,
+ 2.6102867e-10, 2.6353494e-10, 2.6604446e-10, 2.6855745e-10,
+ 2.7107416e-10, 2.7359479e-10, 2.761196e-10, 2.7864877e-10,
+ 2.8118255e-10, 2.8372119e-10, 2.8626485e-10, 2.888138e-10,
+ 2.9136826e-10, 2.939284e-10, 2.9649452e-10, 2.9906677e-10,
+ 3.016454e-10, 3.0423064e-10, 3.0682268e-10, 3.0942177e-10,
+ 3.1202813e-10, 3.1464195e-10, 3.1726352e-10, 3.19893e-10,
+ 3.2253064e-10, 3.251767e-10, 3.2783135e-10, 3.3049485e-10,
+ 3.3316744e-10, 3.3584938e-10, 3.3854083e-10, 3.4124212e-10,
+ 3.4395342e-10, 3.46675e-10, 3.4940711e-10, 3.5215003e-10,
+ 3.5490397e-10, 3.5766917e-10, 3.6044595e-10, 3.6323455e-10,
+ 3.660352e-10, 3.6884823e-10, 3.7167386e-10, 3.745124e-10,
+ 3.773641e-10, 3.802293e-10, 3.8310827e-10, 3.860013e-10,
+ 3.8890866e-10, 3.918307e-10, 3.9476775e-10, 3.9772008e-10,
+ 4.0068804e-10, 4.0367196e-10, 4.0667217e-10, 4.09689e-10,
+ 4.1272286e-10, 4.1577405e-10, 4.1884296e-10, 4.2192994e-10,
+ 4.250354e-10, 4.281597e-10, 4.313033e-10, 4.3446652e-10,
+ 4.3764986e-10, 4.408537e-10, 4.4407847e-10, 4.4732465e-10,
+ 4.5059267e-10, 4.5388301e-10, 4.571962e-10, 4.6053267e-10,
+ 4.6389292e-10, 4.6727755e-10, 4.70687e-10, 4.741219e-10,
+ 4.7758275e-10, 4.810702e-10, 4.845848e-10, 4.8812715e-10,
+ 4.9169796e-10, 4.9529775e-10, 4.989273e-10, 5.0258725e-10,
+ 5.0627835e-10, 5.100013e-10, 5.1375687e-10, 5.1754584e-10,
+ 5.21369e-10, 5.2522725e-10, 5.2912136e-10, 5.330522e-10,
+ 5.370208e-10, 5.4102806e-10, 5.45075e-10, 5.491625e-10,
+ 5.532918e-10, 5.5746385e-10, 5.616799e-10, 5.6594107e-10,
+ 5.7024857e-10, 5.746037e-10, 5.7900773e-10, 5.834621e-10,
+ 5.8796823e-10, 5.925276e-10, 5.971417e-10, 6.018122e-10,
+ 6.065408e-10, 6.113292e-10, 6.1617933e-10, 6.2109295e-10,
+ 6.260722e-10, 6.3111916e-10, 6.3623595e-10, 6.4142497e-10,
+ 6.4668854e-10, 6.5202926e-10, 6.5744976e-10, 6.6295286e-10,
+ 6.6854156e-10, 6.742188e-10, 6.79988e-10, 6.858526e-10,
+ 6.9181616e-10, 6.978826e-10, 7.04056e-10, 7.103407e-10,
+ 7.167412e-10, 7.2326256e-10, 7.2990985e-10, 7.366886e-10,
+ 7.4360473e-10, 7.5066453e-10, 7.5787476e-10, 7.6524265e-10,
+ 7.7277595e-10, 7.80483e-10, 7.883728e-10, 7.9645507e-10,
+ 8.047402e-10, 8.1323964e-10, 8.219657e-10, 8.309319e-10,
+ 8.401528e-10, 8.496445e-10, 8.594247e-10, 8.6951274e-10,
+ 8.799301e-10, 8.9070046e-10, 9.018503e-10, 9.134092e-10,
+ 9.254101e-10, 9.378904e-10, 9.508923e-10, 9.644638e-10,
+ 9.786603e-10, 9.935448e-10, 1.0091913e-09, 1.025686e-09,
+ 1.0431306e-09, 1.0616465e-09, 1.08138e-09, 1.1025096e-09,
+ 1.1252564e-09, 1.1498986e-09, 1.1767932e-09, 1.206409e-09,
+ 1.2393786e-09, 1.276585e-09, 1.3193139e-09, 1.3695435e-09,
+ 1.4305498e-09, 1.508365e-09, 1.6160854e-09, 1.7921248e-09,
+}
+var fe = [256]float32{
+ 1, 0.9381437, 0.90046996, 0.87170434, 0.8477855, 0.8269933,
+ 0.8084217, 0.7915276, 0.77595687, 0.7614634, 0.7478686,
+ 0.7350381, 0.72286767, 0.71127474, 0.70019263, 0.6895665,
+ 0.67935055, 0.6695063, 0.66000086, 0.65080583, 0.6418967,
+ 0.63325197, 0.6248527, 0.6166822, 0.60872537, 0.60096896,
+ 0.5934009, 0.58601034, 0.5787874, 0.57172304, 0.5648092,
+ 0.5580383, 0.5514034, 0.5448982, 0.5385169, 0.53225386,
+ 0.5261042, 0.52006316, 0.5141264, 0.50828975, 0.5025495,
+ 0.496902, 0.49134386, 0.485872, 0.48048335, 0.4751752,
+ 0.46994483, 0.46478975, 0.45970762, 0.45469615, 0.44975325,
+ 0.44487688, 0.44006512, 0.43531612, 0.43062815, 0.42599955,
+ 0.42142874, 0.4169142, 0.41245446, 0.40804818, 0.403694,
+ 0.3993907, 0.39513698, 0.39093173, 0.38677382, 0.38266218,
+ 0.37859577, 0.37457356, 0.37059465, 0.3666581, 0.362763,
+ 0.35890847, 0.35509375, 0.351318, 0.3475805, 0.34388044,
+ 0.34021714, 0.3365899, 0.33299807, 0.32944095, 0.32591796,
+ 0.3224285, 0.3189719, 0.31554767, 0.31215525, 0.30879408,
+ 0.3054636, 0.3021634, 0.29889292, 0.2956517, 0.29243928,
+ 0.28925523, 0.28609908, 0.28297043, 0.27986884, 0.27679393,
+ 0.2737453, 0.2707226, 0.2677254, 0.26475343, 0.26180625,
+ 0.25888354, 0.25598502, 0.2531103, 0.25025907, 0.24743107,
+ 0.24462597, 0.24184346, 0.23908329, 0.23634516, 0.23362878,
+ 0.23093392, 0.2282603, 0.22560766, 0.22297576, 0.22036438,
+ 0.21777324, 0.21520215, 0.21265087, 0.21011916, 0.20760682,
+ 0.20511365, 0.20263945, 0.20018397, 0.19774707, 0.19532852,
+ 0.19292815, 0.19054577, 0.1881812, 0.18583426, 0.18350479,
+ 0.1811926, 0.17889754, 0.17661946, 0.17435817, 0.17211354,
+ 0.1698854, 0.16767362, 0.16547804, 0.16329853, 0.16113494,
+ 0.15898713, 0.15685499, 0.15473837, 0.15263714, 0.15055119,
+ 0.14848037, 0.14642459, 0.14438373, 0.14235765, 0.14034624,
+ 0.13834943, 0.13636707, 0.13439907, 0.13244532, 0.13050574,
+ 0.1285802, 0.12666863, 0.12477092, 0.12288698, 0.12101672,
+ 0.119160056, 0.1173169, 0.115487166, 0.11367077, 0.11186763,
+ 0.11007768, 0.10830083, 0.10653701, 0.10478614, 0.10304816,
+ 0.101323, 0.09961058, 0.09791085, 0.09622374, 0.09454919,
+ 0.09288713, 0.091237515, 0.08960028, 0.087975375, 0.08636274,
+ 0.08476233, 0.083174095, 0.081597984, 0.08003395, 0.07848195,
+ 0.076941945, 0.07541389, 0.07389775, 0.072393484, 0.07090106,
+ 0.069420435, 0.06795159, 0.066494495, 0.06504912, 0.063615434,
+ 0.062193416, 0.060783047, 0.059384305, 0.057997175,
+ 0.05662164, 0.05525769, 0.053905312, 0.052564494, 0.051235236,
+ 0.049917534, 0.048611384, 0.047316793, 0.046033762, 0.0447623,
+ 0.043502413, 0.042254124, 0.041017443, 0.039792392,
+ 0.038578995, 0.037377283, 0.036187284, 0.035009038,
+ 0.033842582, 0.032687962, 0.031545233, 0.030414443, 0.02929566,
+ 0.02818895, 0.027094385, 0.026012046, 0.024942026, 0.023884421,
+ 0.022839336, 0.021806888, 0.020787204, 0.019780423, 0.0187867,
+ 0.0178062, 0.016839107, 0.015885621, 0.014945968, 0.014020392,
+ 0.013109165, 0.012212592, 0.011331013, 0.01046481, 0.009614414,
+ 0.008780315, 0.007963077, 0.0071633533, 0.006381906,
+ 0.0056196423, 0.0048776558, 0.004157295, 0.0034602648,
+ 0.0027887989, 0.0021459677, 0.0015362998, 0.0009672693,
+ 0.00045413437,
+}
diff --git a/libgo/go/rand/normal.go b/libgo/go/rand/normal.go
new file mode 100644
index 000000000..9ab46db9f
--- /dev/null
+++ b/libgo/go/rand/normal.go
@@ -0,0 +1,158 @@
+// 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 rand
+
+import (
+ "math"
+)
+
+/*
+ * Normal distribution
+ *
+ * See "The Ziggurat Method for Generating Random Variables"
+ * (Marsaglia & Tsang, 2000)
+ * http://www.jstatsoft.org/v05/i08/paper [pdf]
+ */
+
+const (
+ rn = 3.442619855899
+)
+
+func absInt32(i int32) uint32 {
+ if i < 0 {
+ return uint32(-i)
+ }
+ return uint32(i)
+}
+
+// NormFloat64 returns a normally distributed float64 in the range
+// [-math.MaxFloat64, +math.MaxFloat64] with
+// standard normal distribution (mean = 0, stddev = 1).
+// To produce a different normal distribution, callers can
+// adjust the output using:
+//
+// sample = NormFloat64() * desiredStdDev + desiredMean
+//
+func (r *Rand) NormFloat64() float64 {
+ for {
+ j := int32(r.Uint32()) // Possibly negative
+ i := j & 0x7F
+ x := float64(j) * float64(wn[i])
+ if absInt32(j) < kn[i] {
+ // This case should be hit better than 99% of the time.
+ return x
+ }
+
+ if i == 0 {
+ // This extra work is only required for the base strip.
+ for {
+ x = -math.Log(r.Float64()) * (1.0 / rn)
+ y := -math.Log(r.Float64())
+ if y+y >= x*x {
+ break
+ }
+ }
+ if j > 0 {
+ return rn + x
+ }
+ return -rn - x
+ }
+ if fn[i]+float32(r.Float64())*(fn[i-1]-fn[i]) < float32(math.Exp(-.5*x*x)) {
+ return x
+ }
+ }
+ panic("unreachable")
+}
+
+var kn = [128]uint32{
+ 0x76ad2212, 0x0, 0x600f1b53, 0x6ce447a6, 0x725b46a2,
+ 0x7560051d, 0x774921eb, 0x789a25bd, 0x799045c3, 0x7a4bce5d,
+ 0x7adf629f, 0x7b5682a6, 0x7bb8a8c6, 0x7c0ae722, 0x7c50cce7,
+ 0x7c8cec5b, 0x7cc12cd6, 0x7ceefed2, 0x7d177e0b, 0x7d3b8883,
+ 0x7d5bce6c, 0x7d78dd64, 0x7d932886, 0x7dab0e57, 0x7dc0dd30,
+ 0x7dd4d688, 0x7de73185, 0x7df81cea, 0x7e07c0a3, 0x7e163efa,
+ 0x7e23b587, 0x7e303dfd, 0x7e3beec2, 0x7e46db77, 0x7e51155d,
+ 0x7e5aabb3, 0x7e63abf7, 0x7e6c222c, 0x7e741906, 0x7e7b9a18,
+ 0x7e82adfa, 0x7e895c63, 0x7e8fac4b, 0x7e95a3fb, 0x7e9b4924,
+ 0x7ea0a0ef, 0x7ea5b00d, 0x7eaa7ac3, 0x7eaf04f3, 0x7eb3522a,
+ 0x7eb765a5, 0x7ebb4259, 0x7ebeeafd, 0x7ec2620a, 0x7ec5a9c4,
+ 0x7ec8c441, 0x7ecbb365, 0x7ece78ed, 0x7ed11671, 0x7ed38d62,
+ 0x7ed5df12, 0x7ed80cb4, 0x7eda175c, 0x7edc0005, 0x7eddc78e,
+ 0x7edf6ebf, 0x7ee0f647, 0x7ee25ebe, 0x7ee3a8a9, 0x7ee4d473,
+ 0x7ee5e276, 0x7ee6d2f5, 0x7ee7a620, 0x7ee85c10, 0x7ee8f4cd,
+ 0x7ee97047, 0x7ee9ce59, 0x7eea0eca, 0x7eea3147, 0x7eea3568,
+ 0x7eea1aab, 0x7ee9e071, 0x7ee98602, 0x7ee90a88, 0x7ee86d08,
+ 0x7ee7ac6a, 0x7ee6c769, 0x7ee5bc9c, 0x7ee48a67, 0x7ee32efc,
+ 0x7ee1a857, 0x7edff42f, 0x7ede0ffa, 0x7edbf8d9, 0x7ed9ab94,
+ 0x7ed7248d, 0x7ed45fae, 0x7ed1585c, 0x7ece095f, 0x7eca6ccb,
+ 0x7ec67be2, 0x7ec22eee, 0x7ebd7d1a, 0x7eb85c35, 0x7eb2c075,
+ 0x7eac9c20, 0x7ea5df27, 0x7e9e769f, 0x7e964c16, 0x7e8d44ba,
+ 0x7e834033, 0x7e781728, 0x7e6b9933, 0x7e5d8a1a, 0x7e4d9ded,
+ 0x7e3b737a, 0x7e268c2f, 0x7e0e3ff5, 0x7df1aa5d, 0x7dcf8c72,
+ 0x7da61a1e, 0x7d72a0fb, 0x7d30e097, 0x7cd9b4ab, 0x7c600f1a,
+ 0x7ba90bdc, 0x7a722176, 0x77d664e5,
+}
+var wn = [128]float32{
+ 1.7290405e-09, 1.2680929e-10, 1.6897518e-10, 1.9862688e-10,
+ 2.2232431e-10, 2.4244937e-10, 2.601613e-10, 2.7611988e-10,
+ 2.9073963e-10, 3.042997e-10, 3.1699796e-10, 3.289802e-10,
+ 3.4035738e-10, 3.5121603e-10, 3.616251e-10, 3.7164058e-10,
+ 3.8130857e-10, 3.9066758e-10, 3.9975012e-10, 4.08584e-10,
+ 4.1719309e-10, 4.2559822e-10, 4.338176e-10, 4.418672e-10,
+ 4.497613e-10, 4.5751258e-10, 4.651324e-10, 4.7263105e-10,
+ 4.8001775e-10, 4.87301e-10, 4.944885e-10, 5.015873e-10,
+ 5.0860405e-10, 5.155446e-10, 5.2241467e-10, 5.2921934e-10,
+ 5.359635e-10, 5.426517e-10, 5.4928817e-10, 5.5587696e-10,
+ 5.624219e-10, 5.6892646e-10, 5.753941e-10, 5.818282e-10,
+ 5.882317e-10, 5.946077e-10, 6.00959e-10, 6.072884e-10,
+ 6.135985e-10, 6.19892e-10, 6.2617134e-10, 6.3243905e-10,
+ 6.386974e-10, 6.449488e-10, 6.511956e-10, 6.5744005e-10,
+ 6.6368433e-10, 6.699307e-10, 6.7618144e-10, 6.824387e-10,
+ 6.8870465e-10, 6.949815e-10, 7.012715e-10, 7.075768e-10,
+ 7.1389966e-10, 7.202424e-10, 7.266073e-10, 7.329966e-10,
+ 7.394128e-10, 7.4585826e-10, 7.5233547e-10, 7.58847e-10,
+ 7.653954e-10, 7.719835e-10, 7.7861395e-10, 7.852897e-10,
+ 7.920138e-10, 7.987892e-10, 8.0561924e-10, 8.125073e-10,
+ 8.194569e-10, 8.2647167e-10, 8.3355556e-10, 8.407127e-10,
+ 8.479473e-10, 8.55264e-10, 8.6266755e-10, 8.7016316e-10,
+ 8.777562e-10, 8.8545243e-10, 8.932582e-10, 9.0117996e-10,
+ 9.09225e-10, 9.174008e-10, 9.2571584e-10, 9.341788e-10,
+ 9.427997e-10, 9.515889e-10, 9.605579e-10, 9.697193e-10,
+ 9.790869e-10, 9.88676e-10, 9.985036e-10, 1.0085882e-09,
+ 1.0189509e-09, 1.0296151e-09, 1.0406069e-09, 1.0519566e-09,
+ 1.063698e-09, 1.0758702e-09, 1.0885183e-09, 1.1016947e-09,
+ 1.1154611e-09, 1.1298902e-09, 1.1450696e-09, 1.1611052e-09,
+ 1.1781276e-09, 1.1962995e-09, 1.2158287e-09, 1.2369856e-09,
+ 1.2601323e-09, 1.2857697e-09, 1.3146202e-09, 1.347784e-09,
+ 1.3870636e-09, 1.4357403e-09, 1.5008659e-09, 1.6030948e-09,
+}
+var fn = [128]float32{
+ 1, 0.9635997, 0.9362827, 0.9130436, 0.89228165, 0.87324303,
+ 0.8555006, 0.8387836, 0.8229072, 0.8077383, 0.793177,
+ 0.7791461, 0.7655842, 0.7524416, 0.73967725, 0.7272569,
+ 0.7151515, 0.7033361, 0.69178915, 0.68049186, 0.6694277,
+ 0.658582, 0.6479418, 0.63749546, 0.6272325, 0.6171434,
+ 0.6072195, 0.5974532, 0.58783704, 0.5783647, 0.56903,
+ 0.5598274, 0.5507518, 0.54179835, 0.5329627, 0.52424055,
+ 0.5156282, 0.50712204, 0.49871865, 0.49041483, 0.48220766,
+ 0.4740943, 0.46607214, 0.4581387, 0.45029163, 0.44252872,
+ 0.43484783, 0.427247, 0.41972435, 0.41227803, 0.40490642,
+ 0.39760786, 0.3903808, 0.3832238, 0.37613547, 0.36911446,
+ 0.3621595, 0.35526937, 0.34844297, 0.34167916, 0.33497685,
+ 0.3283351, 0.3217529, 0.3152294, 0.30876362, 0.30235484,
+ 0.29600215, 0.28970486, 0.2834622, 0.2772735, 0.27113807,
+ 0.2650553, 0.25902456, 0.2530453, 0.24711695, 0.241239,
+ 0.23541094, 0.22963232, 0.2239027, 0.21822165, 0.21258877,
+ 0.20700371, 0.20146611, 0.19597565, 0.19053204, 0.18513499,
+ 0.17978427, 0.17447963, 0.1692209, 0.16400786, 0.15884037,
+ 0.15371831, 0.14864157, 0.14361008, 0.13862377, 0.13368265,
+ 0.12878671, 0.12393598, 0.119130544, 0.11437051, 0.10965602,
+ 0.104987256, 0.10036444, 0.095787846, 0.0912578, 0.08677467,
+ 0.0823389, 0.077950984, 0.073611505, 0.06932112, 0.06508058,
+ 0.06089077, 0.056752663, 0.0526674, 0.048636295, 0.044660863,
+ 0.040742867, 0.03688439, 0.033087887, 0.029356318,
+ 0.025693292, 0.022103304, 0.018592102, 0.015167298,
+ 0.011839478, 0.008624485, 0.005548995, 0.0026696292,
+}
diff --git a/libgo/go/rand/rand.go b/libgo/go/rand/rand.go
new file mode 100644
index 000000000..459aed1db
--- /dev/null
+++ b/libgo/go/rand/rand.go
@@ -0,0 +1,179 @@
+// 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 rand implements pseudo-random number generators.
+package rand
+
+import "sync"
+
+// A Source represents a source of uniformly-distributed
+// pseudo-random int64 values in the range [0, 1<<63).
+type Source interface {
+ Int63() int64
+ Seed(seed int64)
+}
+
+// NewSource returns a new pseudo-random Source seeded with the given value.
+func NewSource(seed int64) Source {
+ var rng rngSource
+ rng.Seed(seed)
+ return &rng
+}
+
+// A Rand is a source of random numbers.
+type Rand struct {
+ src Source
+}
+
+// New returns a new Rand that uses random values from src
+// to generate other random values.
+func New(src Source) *Rand { return &Rand{src} }
+
+// Seed uses the provided seed value to initialize the generator to a deterministic state.
+func (r *Rand) Seed(seed int64) { r.src.Seed(seed) }
+
+// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
+func (r *Rand) Int63() int64 { return r.src.Int63() }
+
+// Uint32 returns a pseudo-random 32-bit value as a uint32.
+func (r *Rand) Uint32() uint32 { return uint32(r.Int63() >> 31) }
+
+// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
+func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) }
+
+// Int returns a non-negative pseudo-random int.
+func (r *Rand) Int() int {
+ u := uint(r.Int63())
+ return int(u << 1 >> 1) // clear sign bit if int == int32
+}
+
+// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+func (r *Rand) Int63n(n int64) int64 {
+ if n <= 0 {
+ return 0
+ }
+ max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
+ v := r.Int63()
+ for v > max {
+ v = r.Int63()
+ }
+ return v % n
+}
+
+// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+func (r *Rand) Int31n(n int32) int32 {
+ if n <= 0 {
+ return 0
+ }
+ max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
+ v := r.Int31()
+ for v > max {
+ v = r.Int31()
+ }
+ return v % n
+}
+
+// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+func (r *Rand) Intn(n int) int {
+ if n <= 1<<31-1 {
+ return int(r.Int31n(int32(n)))
+ }
+ return int(r.Int63n(int64(n)))
+}
+
+// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
+func (r *Rand) Float64() float64 { return float64(r.Int63()) / (1 << 63) }
+
+// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
+func (r *Rand) Float32() float32 { return float32(r.Float64()) }
+
+// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
+func (r *Rand) Perm(n int) []int {
+ m := make([]int, n)
+ for i := 0; i < n; i++ {
+ m[i] = i
+ }
+ for i := 0; i < n; i++ {
+ j := r.Intn(i + 1)
+ m[i], m[j] = m[j], m[i]
+ }
+ return m
+}
+
+/*
+ * Top-level convenience functions
+ */
+
+var globalRand = New(&lockedSource{src: NewSource(1)})
+
+// Seed uses the provided seed value to initialize the generator to a deterministic state.
+func Seed(seed int64) { globalRand.Seed(seed) }
+
+// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
+func Int63() int64 { return globalRand.Int63() }
+
+// Uint32 returns a pseudo-random 32-bit value as a uint32.
+func Uint32() uint32 { return globalRand.Uint32() }
+
+// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
+func Int31() int32 { return globalRand.Int31() }
+
+// Int returns a non-negative pseudo-random int.
+func Int() int { return globalRand.Int() }
+
+// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+func Int63n(n int64) int64 { return globalRand.Int63n(n) }
+
+// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+func Int31n(n int32) int32 { return globalRand.Int31n(n) }
+
+// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+func Intn(n int) int { return globalRand.Intn(n) }
+
+// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
+func Float64() float64 { return globalRand.Float64() }
+
+// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
+func Float32() float32 { return globalRand.Float32() }
+
+// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
+func Perm(n int) []int { return globalRand.Perm(n) }
+
+// NormFloat64 returns a normally distributed float64 in the range
+// [-math.MaxFloat64, +math.MaxFloat64] with
+// standard normal distribution (mean = 0, stddev = 1).
+// To produce a different normal distribution, callers can
+// adjust the output using:
+//
+// sample = NormFloat64() * desiredStdDev + desiredMean
+//
+func NormFloat64() float64 { return globalRand.NormFloat64() }
+
+// ExpFloat64 returns an exponentially distributed float64 in the range
+// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter
+// (lambda) is 1 and whose mean is 1/lambda (1).
+// To produce a distribution with a different rate parameter,
+// callers can adjust the output using:
+//
+// sample = ExpFloat64() / desiredRateParameter
+//
+func ExpFloat64() float64 { return globalRand.ExpFloat64() }
+
+type lockedSource struct {
+ lk sync.Mutex
+ src Source
+}
+
+func (r *lockedSource) Int63() (n int64) {
+ r.lk.Lock()
+ n = r.src.Int63()
+ r.lk.Unlock()
+ return
+}
+
+func (r *lockedSource) Seed(seed int64) {
+ r.lk.Lock()
+ r.src.Seed(seed)
+ r.lk.Unlock()
+}
diff --git a/libgo/go/rand/rand_test.go b/libgo/go/rand/rand_test.go
new file mode 100644
index 000000000..2476ebaf6
--- /dev/null
+++ b/libgo/go/rand/rand_test.go
@@ -0,0 +1,350 @@
+// 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 rand
+
+import (
+ "math"
+ "fmt"
+ "os"
+ "testing"
+)
+
+const (
+ numTestSamples = 10000
+)
+
+type statsResults struct {
+ mean float64
+ stddev float64
+ closeEnough float64
+ maxError float64
+}
+
+func max(a, b float64) float64 {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+func nearEqual(a, b, closeEnough, maxError float64) bool {
+ absDiff := math.Fabs(a - b)
+ if absDiff < closeEnough { // Necessary when one value is zero and one value is close to zero.
+ return true
+ }
+ return absDiff/max(math.Fabs(a), math.Fabs(b)) < maxError
+}
+
+var testSeeds = []int64{1, 1754801282, 1698661970, 1550503961}
+
+// checkSimilarDistribution returns success if the mean and stddev of the
+// two statsResults are similar.
+func (this *statsResults) checkSimilarDistribution(expected *statsResults) os.Error {
+ 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)
+ }
+ 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 nil
+}
+
+func getStatsResults(samples []float64) *statsResults {
+ res := new(statsResults)
+ var sum float64
+ for i := range samples {
+ sum += samples[i]
+ }
+ res.mean = sum / float64(len(samples))
+ var devsum float64
+ for i := range samples {
+ devsum += math.Pow(samples[i]-res.mean, 2)
+ }
+ res.stddev = math.Sqrt(devsum / float64(len(samples)))
+ return res
+}
+
+func checkSampleDistribution(t *testing.T, samples []float64, expected *statsResults) {
+ actual := getStatsResults(samples)
+ err := actual.checkSimilarDistribution(expected)
+ if err != nil {
+ t.Errorf(err.String())
+ }
+}
+
+func checkSampleSliceDistributions(t *testing.T, samples []float64, nslices int, expected *statsResults) {
+ chunk := len(samples) / nslices
+ for i := 0; i < nslices; i++ {
+ low := i * chunk
+ var high int
+ if i == nslices-1 {
+ high = len(samples) - 1
+ } else {
+ high = (i + 1) * chunk
+ }
+ checkSampleDistribution(t, samples[low:high], expected)
+ }
+}
+
+//
+// Normal distribution tests
+//
+
+func generateNormalSamples(nsamples int, mean, stddev float64, seed int64) []float64 {
+ r := New(NewSource(seed))
+ samples := make([]float64, nsamples)
+ for i := range samples {
+ samples[i] = r.NormFloat64()*stddev + mean
+ }
+ return samples
+}
+
+func testNormalDistribution(t *testing.T, nsamples int, mean, stddev float64, seed int64) {
+ //fmt.Printf("testing nsamples=%v mean=%v stddev=%v seed=%v\n", nsamples, mean, stddev, seed);
+
+ samples := generateNormalSamples(nsamples, mean, stddev, seed)
+ errorScale := max(1.0, stddev) // Error scales with stddev
+ expected := &statsResults{mean, stddev, 0.10 * errorScale, 0.08 * errorScale}
+
+ // Make sure that the entire set matches the expected distribution.
+ checkSampleDistribution(t, samples, expected)
+
+ // Make sure that each half of the set matches the expected distribution.
+ checkSampleSliceDistributions(t, samples, 2, expected)
+
+ // Make sure that each 7th of the set matches the expected distribution.
+ checkSampleSliceDistributions(t, samples, 7, expected)
+}
+
+// Actual tests
+
+func TestStandardNormalValues(t *testing.T) {
+ for _, seed := range testSeeds {
+ testNormalDistribution(t, numTestSamples, 0, 1, seed)
+ }
+}
+
+func TestNonStandardNormalValues(t *testing.T) {
+ for sd := 0.5; sd < 1000; sd *= 2 {
+ for m := 0.5; m < 1000; m *= 2 {
+ for _, seed := range testSeeds {
+ testNormalDistribution(t, numTestSamples, m, sd, seed)
+ }
+ }
+ }
+}
+
+//
+// Exponential distribution tests
+//
+
+func generateExponentialSamples(nsamples int, rate float64, seed int64) []float64 {
+ r := New(NewSource(seed))
+ samples := make([]float64, nsamples)
+ for i := range samples {
+ samples[i] = r.ExpFloat64() / rate
+ }
+ return samples
+}
+
+func testExponentialDistribution(t *testing.T, nsamples int, rate float64, seed int64) {
+ //fmt.Printf("testing nsamples=%v rate=%v seed=%v\n", nsamples, rate, seed);
+
+ mean := 1 / rate
+ stddev := mean
+
+ samples := generateExponentialSamples(nsamples, rate, seed)
+ errorScale := max(1.0, 1/rate) // Error scales with the inverse of the rate
+ expected := &statsResults{mean, stddev, 0.10 * errorScale, 0.20 * errorScale}
+
+ // Make sure that the entire set matches the expected distribution.
+ checkSampleDistribution(t, samples, expected)
+
+ // Make sure that each half of the set matches the expected distribution.
+ checkSampleSliceDistributions(t, samples, 2, expected)
+
+ // Make sure that each 7th of the set matches the expected distribution.
+ checkSampleSliceDistributions(t, samples, 7, expected)
+}
+
+// Actual tests
+
+func TestStandardExponentialValues(t *testing.T) {
+ for _, seed := range testSeeds {
+ testExponentialDistribution(t, numTestSamples, 1, seed)
+ }
+}
+
+func TestNonStandardExponentialValues(t *testing.T) {
+ for rate := 0.05; rate < 10; rate *= 2 {
+ for _, seed := range testSeeds {
+ testExponentialDistribution(t, numTestSamples, rate, seed)
+ }
+ }
+}
+
+//
+// Table generation tests
+//
+
+func initNorm() (testKn []uint32, testWn, testFn []float32) {
+ const m1 = 1 << 31
+ var (
+ dn float64 = rn
+ tn = dn
+ vn float64 = 9.91256303526217e-3
+ )
+
+ testKn = make([]uint32, 128)
+ testWn = make([]float32, 128)
+ testFn = make([]float32, 128)
+
+ q := vn / math.Exp(-0.5*dn*dn)
+ testKn[0] = uint32((dn / q) * m1)
+ testKn[1] = 0
+ testWn[0] = float32(q / m1)
+ testWn[127] = float32(dn / m1)
+ testFn[0] = 1.0
+ testFn[127] = float32(math.Exp(-0.5 * dn * dn))
+ for i := 126; i >= 1; i-- {
+ dn = math.Sqrt(-2.0 * math.Log(vn/dn+math.Exp(-0.5*dn*dn)))
+ testKn[i+1] = uint32((dn / tn) * m1)
+ tn = dn
+ testFn[i] = float32(math.Exp(-0.5 * dn * dn))
+ testWn[i] = float32(dn / m1)
+ }
+ return
+}
+
+func initExp() (testKe []uint32, testWe, testFe []float32) {
+ const m2 = 1 << 32
+ var (
+ de float64 = re
+ te = de
+ ve float64 = 3.9496598225815571993e-3
+ )
+
+ testKe = make([]uint32, 256)
+ testWe = make([]float32, 256)
+ testFe = make([]float32, 256)
+
+ q := ve / math.Exp(-de)
+ testKe[0] = uint32((de / q) * m2)
+ testKe[1] = 0
+ testWe[0] = float32(q / m2)
+ testWe[255] = float32(de / m2)
+ testFe[0] = 1.0
+ testFe[255] = float32(math.Exp(-de))
+ for i := 254; i >= 1; i-- {
+ de = -math.Log(ve/de + math.Exp(-de))
+ testKe[i+1] = uint32((de / te) * m2)
+ te = de
+ testFe[i] = float32(math.Exp(-de))
+ testWe[i] = float32(de / m2)
+ }
+ return
+}
+
+// compareUint32Slices returns the first index where the two slices
+// disagree, or <0 if the lengths are the same and all elements
+// are identical.
+func compareUint32Slices(s1, s2 []uint32) int {
+ if len(s1) != len(s2) {
+ if len(s1) > len(s2) {
+ return len(s2) + 1
+ }
+ return len(s1) + 1
+ }
+ for i := range s1 {
+ if s1[i] != s2[i] {
+ return i
+ }
+ }
+ return -1
+}
+
+// compareFloat32Slices returns the first index where the two slices
+// disagree, or <0 if the lengths are the same and all elements
+// are identical.
+func compareFloat32Slices(s1, s2 []float32) int {
+ if len(s1) != len(s2) {
+ if len(s1) > len(s2) {
+ return len(s2) + 1
+ }
+ return len(s1) + 1
+ }
+ for i := range s1 {
+ if !nearEqual(float64(s1[i]), float64(s2[i]), 0, 1e-7) {
+ return i
+ }
+ }
+ return -1
+}
+
+func TestNormTables(t *testing.T) {
+ testKn, testWn, testFn := initNorm()
+ if i := compareUint32Slices(kn[0:], testKn); i >= 0 {
+ t.Errorf("kn disagrees at index %v; %v != %v", i, kn[i], testKn[i])
+ }
+ if i := compareFloat32Slices(wn[0:], testWn); i >= 0 {
+ t.Errorf("wn disagrees at index %v; %v != %v", i, wn[i], testWn[i])
+ }
+ if i := compareFloat32Slices(fn[0:], testFn); i >= 0 {
+ t.Errorf("fn disagrees at index %v; %v != %v", i, fn[i], testFn[i])
+ }
+}
+
+func TestExpTables(t *testing.T) {
+ testKe, testWe, testFe := initExp()
+ if i := compareUint32Slices(ke[0:], testKe); i >= 0 {
+ t.Errorf("ke disagrees at index %v; %v != %v", i, ke[i], testKe[i])
+ }
+ if i := compareFloat32Slices(we[0:], testWe); i >= 0 {
+ t.Errorf("we disagrees at index %v; %v != %v", i, we[i], testWe[i])
+ }
+ if i := compareFloat32Slices(fe[0:], testFe); i >= 0 {
+ t.Errorf("fe disagrees at index %v; %v != %v", i, fe[i], testFe[i])
+ }
+}
+
+// Benchmarks
+
+func BenchmarkInt63Threadsafe(b *testing.B) {
+ for n := b.N; n > 0; n-- {
+ Int63()
+ }
+}
+
+func BenchmarkInt63Unthreadsafe(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Int63()
+ }
+}
+
+func BenchmarkIntn1000(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Intn(1000)
+ }
+}
+
+func BenchmarkInt63n1000(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Int63n(1000)
+ }
+}
+
+func BenchmarkInt31n1000(b *testing.B) {
+ r := New(NewSource(1))
+ for n := b.N; n > 0; n-- {
+ r.Int31n(1000)
+ }
+}
diff --git a/libgo/go/rand/rng.go b/libgo/go/rand/rng.go
new file mode 100644
index 000000000..947c49f0f
--- /dev/null
+++ b/libgo/go/rand/rng.go
@@ -0,0 +1,246 @@
+// 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 rand
+
+/*
+ * Uniform distribution
+ *
+ * algorithm by
+ * DP Mitchell and JA Reeds
+ */
+
+const (
+ _LEN = 607
+ _TAP = 273
+ _MAX = 1 << 63
+ _MASK = _MAX - 1
+ _A = 48271
+ _M = (1 << 31) - 1
+ _Q = 44488
+ _R = 3399
+)
+
+var (
+ // cooked random numbers
+ // the state of the rng
+ // after 780e10 iterations
+ rng_cooked [_LEN]int64 = [...]int64{
+ 5041579894721019882, 4646389086726545243, 1395769623340756751, 5333664234075297259,
+ 2875692520355975054, 9033628115061424579, 7143218595135194537, 4812947590706362721,
+ 7937252194349799378, 5307299880338848416, 8209348851763925077, 2115741599318814044,
+ 4593015457530856296, 8140875735541888011, 3319429241265089026, 8619815648190321034,
+ 1727074043483619500, 113108499721038619, 4569519971459345583, 5062833859075314731,
+ 2387618771259064424, 2716131344356686112, 6559392774825876886, 7650093201692370310,
+ 7684323884043752161, 257867835996031390, 6593456519409015164, 271327514973697897,
+ 2789386447340118284, 1065192797246149621, 3344507881999356393, 4459797941780066633,
+ 7465081662728599889, 1014950805555097187, 4449440729345990775, 3481109366438502643,
+ 2418672789110888383, 5796562887576294778, 4484266064449540171, 3738982361971787048,
+ 4523597184512354423, 10530508058128498, 8633833783282346118, 2625309929628791628,
+ 8660405965245884302, 10162832508971942, 6540714680961817391, 7031802312784620857,
+ 6240911277345944669, 831864355460801054, 8004434137542152891, 2116287251661052151,
+ 2202309800992166967, 9161020366945053561, 4069299552407763864, 4936383537992622449,
+ 457351505131524928, 342195045928179354, 2847771682816600509, 2068020115986376518,
+ 4368649989588021065, 887231587095185257, 5563591506886576496, 6816225200251950296,
+ 5616972787034086048, 8471809303394836566, 1686575021641186857, 4045484338074262002,
+ 4244156215201778923, 7848217333783577387, 5632136521049761902, 833283142057835272,
+ 9029726508369077193, 3243583134664087292, 4316371101804477087, 8937849979965997980,
+ 6446940406810434101, 1679342092332374735, 6050638460742422078, 6993520719509581582,
+ 7640877852514293609, 5881353426285907985, 812786550756860885, 4541845584483343330,
+ 2725470216277009086, 4980675660146853729, 5210769080603236061, 8894283318990530821,
+ 6326442804750084282, 1495812843684243920, 7069751578799128019, 7370257291860230865,
+ 6756929275356942261, 4706794511633873654, 7824520467827898663, 8549875090542453214,
+ 33650829478596156, 1328918435751322643, 7297902601803624459, 1011190183918857495,
+ 2238025036817854944, 5147159997473910359, 896512091560522982, 2659470849286379941,
+ 6097729358393448602, 1731725986304753684, 4106255841983812711, 8327155210721535508,
+ 8477511620686074402, 5803876044675762232, 8435417780860221662, 5988852856651071244,
+ 4715837297103951910, 7566171971264485114, 505808562678895611, 5070098180695063370,
+ 842110666775871513, 572156825025677802, 1791881013492340891, 3393267094866038768,
+ 3778721850472236509, 2352769483186201278, 1292459583847367458, 8897907043675088419,
+ 5781809037144163536, 2733958794029492513, 5092019688680754699, 8996124554772526841,
+ 4234737173186232084, 5027558287275472836, 4635198586344772304, 8687338893267139351,
+ 5907508150730407386, 784756255473944452, 972392927514829904, 5422057694808175112,
+ 5158420642969283891, 9048531678558643225, 2407211146698877100, 7583282216521099569,
+ 3940796514530962282, 3341174631045206375, 3095313889586102949, 7405321895688238710,
+ 5832080132947175283, 7890064875145919662, 8184139210799583195, 1149859861409226130,
+ 1464597243840211302, 4641648007187991873, 3516491885471466898, 956288521791657692,
+ 6657089965014657519, 5220884358887979358, 1796677326474620641, 5340761970648932916,
+ 1147977171614181568, 5066037465548252321, 2574765911837859848, 1085848279845204775,
+ 3350107529868390359, 6116438694366558490, 2107701075971293812, 1803294065921269267,
+ 2469478054175558874, 7368243281019965984, 3791908367843677526, 185046971116456637,
+ 2257095756513439648, 7217693971077460129, 909049953079504259, 7196649268545224266,
+ 5637660345400869599, 3955544945427965183, 8057528650917418961, 4139268440301127643,
+ 6621926588513568059, 1373361136802681441, 6527366231383600011, 3507654575162700890,
+ 9202058512774729859, 1954818376891585542, 6640380907130175705, 8299563319178235687,
+ 3901867355218954373, 7046310742295574065, 6847195391333990232, 1572638100518868053,
+ 8850422670118399721, 3631909142291992901, 5158881091950831288, 2882958317343121593,
+ 4763258931815816403, 6280052734341785344, 4243789408204964850, 2043464728020827976,
+ 6545300466022085465, 4562580375758598164, 5495451168795427352, 1738312861590151095,
+ 553004618757816492, 6895160632757959823, 8233623922264685171, 7139506338801360852,
+ 8550891222387991669, 5535668688139305547, 2430933853350256242, 5401941257863201076,
+ 8159640039107728799, 6157493831600770366, 7632066283658143750, 6308328381617103346,
+ 3681878764086140361, 3289686137190109749, 6587997200611086848, 244714774258135476,
+ 4079788377417136100, 8090302575944624335, 2945117363431356361, 864324395848741045,
+ 3009039260312620700, 8430027460082534031, 401084700045993341, 7254622446438694921,
+ 4707864159563588614, 5640248530963493951, 5982507712689997893, 3315098242282210105,
+ 5503847578771918426, 3941971367175193882, 8118566580304798074, 3839261274019871296,
+ 7062410411742090847, 741381002980207668, 6027994129690250817, 2497829994150063930,
+ 6251390334426228834, 1368930247903518833, 8809096399316380241, 6492004350391900708,
+ 2462145737463489636, 404828418920299174, 4153026434231690595, 261785715255475940,
+ 5464715384600071357, 592710404378763017, 6764129236657751224, 8513655718539357449,
+ 5820343663801914208, 385298524683789911, 5224135003438199467, 6303131641338802145,
+ 7150122561309371392, 368107899140673753, 3115186834558311558, 2915636353584281051,
+ 4782583894627718279, 6718292300699989587, 8387085186914375220, 3387513132024756289,
+ 4654329375432538231, 8930667561363381602, 5374373436876319273, 7623042350483453954,
+ 7725442901813263321, 9186225467561587250, 4091027289597503355, 2357631606492579800,
+ 2530936820058611833, 1636551876240043639, 5564664674334965799, 1452244145334316253,
+ 2061642381019690829, 1279580266495294036, 9108481583171221009, 6023278686734049809,
+ 5007630032676973346, 2153168792952589781, 6720334534964750538, 6041546491134794105,
+ 3433922409283786309, 2285479922797300912, 3110614940896576130, 6366559590722842893,
+ 5418791419666136509, 7163298419643543757, 4891138053923696990, 580618510277907015,
+ 1684034065251686769, 4429514767357295841, 330346578555450005, 1119637995812174675,
+ 7177515271653460134, 4589042248470800257, 7693288629059004563, 143607045258444228,
+ 246994305896273627, 866417324803099287, 6473547110565816071, 3092379936208876896,
+ 2058427839513754051, 5133784708526867938, 8785882556301281247, 6149332666841167611,
+ 8585842181454472135, 6137678347805511274, 2070447184436970006, 5708223427705576541,
+ 5999657892458244504, 4358391411789012426, 325123008708389849, 6837621693887290924,
+ 4843721905315627004, 6010651222149276415, 5398352198963874652, 4602025990114250980,
+ 1044646352569048800, 9106614159853161675, 829256115228593269, 4919284369102997000,
+ 2681532557646850893, 3681559472488511871, 5307999518958214035, 6334130388442829274,
+ 2658708232916537604, 1163313865052186287, 581945337509520675, 3648778920718647903,
+ 4423673246306544414, 1620799783996955743, 220828013409515943, 8150384699999389761,
+ 4287360518296753003, 4590000184845883843, 5513660857261085186, 6964829100392774275,
+ 478991688350776035, 8746140185685648781, 228500091334420247, 1356187007457302238,
+ 3019253992034194581, 3152601605678500003, 430152752706002213, 5559581553696971176,
+ 4916432985369275664, 663574931734554391, 3420773838927732076, 2868348622579915573,
+ 1999319134044418520, 3328689518636282723, 2587672709781371173, 1517255313529399333,
+ 3092343956317362483, 3662252519007064108, 972445599196498113, 7664865435875959367,
+ 1708913533482282562, 6917817162668868494, 3217629022545312900, 2570043027221707107,
+ 8739788839543624613, 2488075924621352812, 4694002395387436668, 4559628481798514356,
+ 2997203966153298104, 1282559373026354493, 240113143146674385, 8665713329246516443,
+ 628141331766346752, 4571950817186770476, 1472811188152235408, 7596648026010355826,
+ 6091219417754424743, 7834161864828164065, 7103445518877254909, 4390861237357459201,
+ 4442653864240571734, 8903482404847331368, 622261699494173647, 6037261250297213248,
+ 504404948065709118, 7275215526217113061, 1011176780856001400, 2194750105623461063,
+ 2623071828615234808, 5157313728073836108, 3738405111966602044, 2539767524076729570,
+ 2467284396349269342, 5256026990536851868, 7841086888628396109, 6640857538655893162,
+ 1202087339038317498, 2113514992440715978, 7534350895342931403, 4925284734898484745,
+ 5145623771477493805, 8225140880134972332, 2719520354384050532, 9132346697815513771,
+ 4332154495710163773, 7137789594094346916, 6994721091344268833, 6667228574869048934,
+ 655440045726677499, 59934747298466858, 6124974028078036405, 8957774780655365418,
+ 2332206071942466437, 1701056712286369627, 3154897383618636503, 1637766181387607527,
+ 2460521277767576533, 197309393502684135, 643677854385267315, 2543179307861934850,
+ 4350769010207485119, 4754652089410667672, 2015595502641514512, 7999059458976458608,
+ 4287946071480840813, 8362686366770308971, 6486469209321732151, 3617727845841796026,
+ 7554353525834302244, 4450022655153542367, 1605195740213535749, 5327014565305508387,
+ 4626575813550328320, 2692222020597705149, 241045573717249868, 5098046974627094010,
+ 7916882295460730264, 884817090297530579, 5329160409530630596, 7790979528857726136,
+ 4955070238059373407, 4918537275422674302, 3008076183950404629, 3007769226071157901,
+ 2470346235617803020, 8928702772696731736, 7856187920214445904, 4474874585391974885,
+ 7900176660600710914, 2140571127916226672, 2425445057265199971, 2486055153341847830,
+ 4186670094382025798, 1883939007446035042, 8808666044074867985, 3734134241178479257,
+ 4065968871360089196, 6953124200385847784, 1305686814738899057, 1637739099014457647,
+ 3656125660947993209, 3966759634633167020, 3106378204088556331, 6328899822778449810,
+ 4565385105440252958, 1979884289539493806, 2331793186920865425, 3783206694208922581,
+ 8464961209802336085, 2843963751609577687, 3030678195484896323, 4793717574095772604,
+ 4459239494808162889, 402587895800087237, 8057891408711167515, 4541888170938985079,
+ 1042662272908816815, 5557303057122568958, 2647678726283249984, 2144477441549833761,
+ 5806352215355387087, 7117771003473903623, 5916597177708541638, 462597715452321361,
+ 8833658097025758785, 5970273481425315300, 563813119381731307, 2768349550652697015,
+ 1598828206250873866, 5206393647403558110, 6235043485709261823, 3152217402014639496,
+ 8469693267274066490, 125672920241807416, 5311079624024060938, 6663754932310491587,
+ 8736848295048751716, 4488039774992061878, 5923302823487327109, 140891791083103236,
+ 7414942793393574290, 7990420780896957397, 4317817392807076702, 3625184369705367340,
+ 2740722765288122703, 5743100009702758344, 5997898640509039159, 8854493341352484163,
+ 5242208035432907801, 701338899890987198, 7609280429197514109, 3020985755112334161,
+ 6651322707055512866, 2635195723621160615, 5144520864246028816, 1035086515727829828,
+ 1567242097116389047, 8172389260191636581, 6337820351429292273, 2163012566996458925,
+ 2743190902890262681, 1906367633221323427, 6011544915663598137, 5932255307352610768,
+ 2241128460406315459, 895504896216695588, 3094483003111372717, 4583857460292963101,
+ 9079887171656594975, 8839289181930711403, 5762740387243057873, 4225072055348026230,
+ 1838220598389033063, 3801620336801580414, 8823526620080073856, 1776617605585100335,
+ 7899055018877642622, 5421679761463003041, 5521102963086275121, 4248279443559365898,
+ 8735487530905098534, 1760527091573692978, 7142485049657745894, 8222656872927218123,
+ 4969531564923704323, 3394475942196872480, 6424174453260338141, 359248545074932887,
+ 3273651282831730598, 6797106199797138596, 3030918217665093212, 145600834617314036,
+ 6036575856065626233, 740416251634527158, 7080427635449935582, 6951781370868335478,
+ 399922722363687927, 294902314447253185, 7844950936339178523, 880320858634709042,
+ 6192655680808675579, 411604686384710388, 9026808440365124461, 6440783557497587732,
+ 4615674634722404292, 539897290441580544, 2096238225866883852, 8751955639408182687,
+ 1907224908052289603, 7381039757301768559, 6157238513393239656, 7749994231914157575,
+ 8629571604380892756, 5280433031239081479, 7101611890139813254, 2479018537985767835,
+ 7169176924412769570, 7942066497793203302, 1357759729055557688, 2278447439451174845,
+ 3625338785743880657, 6477479539006708521, 8976185375579272206, 5511371554711836120,
+ 1326024180520890843, 7537449876596048829, 5464680203499696154, 3189671183162196045,
+ 6346751753565857109, 241159987320630307, 3095793449658682053, 8978332846736310159,
+ 2902794662273147216, 7208698530190629697, 7276901792339343736, 1732385229314443140,
+ 4133292154170828382, 2918308698224194548, 1519461397937144458, 5293934712616591764,
+ 4922828954023452664, 2879211533496425641, 5896236396443472108, 8465043815351752425,
+ 7329020396871624740, 8915471717014488588, 2944902635677463047, 7052079073493465134,
+ 8382142935188824023, 9103922860780351547, 4152330101494654406,
+ }
+)
+
+type rngSource struct {
+ tap int // index into vec
+ feed int // index into vec
+ vec [_LEN]int64 // current feedback register
+}
+
+// seed rng x[n+1] = 48271 * x[n] mod (2**31 - 1)
+func seedrand(x int32) int32 {
+ hi := x / _Q
+ lo := x % _Q
+ x = _A*lo - _R*hi
+ if x < 0 {
+ x += _M
+ }
+ return x
+}
+
+// Seed uses the provided seed value to initialize the generator to a deterministic state.
+func (rng *rngSource) Seed(seed int64) {
+ rng.tap = 0
+ rng.feed = _LEN - _TAP
+
+ seed = seed % _M
+ if seed < 0 {
+ seed += _M
+ }
+ if seed == 0 {
+ seed = 89482311
+ }
+
+ x := int32(seed)
+ for i := -20; i < _LEN; i++ {
+ x = seedrand(x)
+ if i >= 0 {
+ var u int64
+ u = int64(x) << 40
+ x = seedrand(x)
+ u ^= int64(x) << 20
+ x = seedrand(x)
+ u ^= int64(x)
+ u ^= rng_cooked[i]
+ rng.vec[i] = u & _MASK
+ }
+ }
+}
+
+// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
+func (rng *rngSource) Int63() int64 {
+ rng.tap--
+ if rng.tap < 0 {
+ rng.tap += _LEN
+ }
+
+ rng.feed--
+ if rng.feed < 0 {
+ rng.feed += _LEN
+ }
+
+ x := (rng.vec[rng.feed] + rng.vec[rng.tap]) & _MASK
+ rng.vec[rng.feed] = x
+ return x
+}
diff --git a/libgo/go/rand/zipf.go b/libgo/go/rand/zipf.go
new file mode 100644
index 000000000..38e8ec516
--- /dev/null
+++ b/libgo/go/rand/zipf.go
@@ -0,0 +1,73 @@
+// 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.
+
+// W.Hormann, G.Derflinger:
+// "Rejection-Inversion to Generate Variates
+// from Monotone Discrete Distributions"
+// http://eeyore.wu-wien.ac.at/papers/96-04-04.wh-der.ps.gz
+
+package rand
+
+import "math"
+
+// A Zipf generates Zipf distributed variates.
+type Zipf struct {
+ r *Rand
+ imax float64
+ v float64
+ q float64
+ s float64
+ oneminusQ float64
+ oneminusQinv float64
+ hxm float64
+ hx0minusHxm float64
+}
+
+func (z *Zipf) h(x float64) float64 {
+ return math.Exp(z.oneminusQ*math.Log(z.v+x)) * z.oneminusQinv
+}
+
+func (z *Zipf) hinv(x float64) float64 {
+ return math.Exp(z.oneminusQinv*math.Log(z.oneminusQ*x)) - z.v
+}
+
+// NewZipf returns a Zipf generating variates p(k) on [0, imax]
+// proportional to (v+k)**(-s) where s>1 and k>=0, and v>=1.
+//
+func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf {
+ z := new(Zipf)
+ if s <= 1.0 || v < 1 {
+ return nil
+ }
+ z.r = r
+ z.imax = float64(imax)
+ z.v = v
+ z.q = s
+ z.oneminusQ = 1.0 - z.q
+ z.oneminusQinv = 1.0 / z.oneminusQ
+ z.hxm = z.h(z.imax + 0.5)
+ z.hx0minusHxm = z.h(0.5) - math.Exp(math.Log(z.v)*(-z.q)) - z.hxm
+ z.s = 1 - z.hinv(z.h(1.5)-math.Exp(-z.q*math.Log(z.v+1.0)))
+ return z
+}
+
+// Uint64 returns a value drawn from the Zipf distributed described
+// by the Zipf object.
+func (z *Zipf) Uint64() uint64 {
+ k := 0.0
+
+ for {
+ r := z.r.Float64() // r on [0,1]
+ ur := z.hxm + r*z.hx0minusHxm
+ x := z.hinv(ur)
+ k = math.Floor(x + 0.5)
+ if k-x <= z.s {
+ break
+ }
+ if ur >= z.h(k+0.5)-math.Exp(-math.Log(k+z.v)*z.q) {
+ break
+ }
+ }
+ return uint64(k)
+}
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
new file mode 100644
index 000000000..320f44203
--- /dev/null
+++ b/libgo/go/reflect/all_test.go
@@ -0,0 +1,1392 @@
+// 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 reflect_test
+
+import (
+ "container/vector"
+ "fmt"
+ "io"
+ "os"
+ . "reflect"
+ "testing"
+ "unsafe"
+)
+
+type integer int
+type T struct {
+ a int
+ b float64
+ c string
+ d *int
+}
+
+type pair struct {
+ i interface{}
+ s string
+}
+
+func isDigit(c uint8) bool { return '0' <= c && c <= '9' }
+
+func assert(t *testing.T, s, want string) {
+ if s != want {
+ t.Errorf("have %#q want %#q", s, want)
+ }
+}
+
+func typestring(i interface{}) string { return Typeof(i).String() }
+
+var typeTests = []pair{
+ {struct{ x int }{}, "int"},
+ {struct{ x int8 }{}, "int8"},
+ {struct{ x int16 }{}, "int16"},
+ {struct{ x int32 }{}, "int32"},
+ {struct{ x int64 }{}, "int64"},
+ {struct{ x uint }{}, "uint"},
+ {struct{ x uint8 }{}, "uint8"},
+ {struct{ x uint16 }{}, "uint16"},
+ {struct{ x uint32 }{}, "uint32"},
+ {struct{ x uint64 }{}, "uint64"},
+ {struct{ x float32 }{}, "float32"},
+ {struct{ x float64 }{}, "float64"},
+ {struct{ x int8 }{}, "int8"},
+ {struct{ x (**int8) }{}, "**int8"},
+ {struct{ x (**integer) }{}, "**reflect_test.integer"},
+ {struct{ x ([32]int32) }{}, "[32]int32"},
+ {struct{ x ([]int8) }{}, "[]int8"},
+ {struct{ x (map[string]int32) }{}, "map[string] int32"},
+ {struct{ x (chan<- string) }{}, "chan<- string"},
+ {struct {
+ x struct {
+ c chan *int32
+ d float32
+ }
+ }{},
+ "struct { c chan *int32; d float32 }",
+ },
+ {struct{ x (func(a int8, b int32)) }{}, "func(int8, int32)"},
+ {struct {
+ x struct {
+ c func(chan *integer, *int8)
+ }
+ }{},
+ "struct { c func(chan *reflect_test.integer, *int8) }",
+ },
+ {struct {
+ x struct {
+ a int8
+ b int32
+ }
+ }{},
+ "struct { a int8; b int32 }",
+ },
+ {struct {
+ x struct {
+ a int8
+ b int8
+ c int32
+ }
+ }{},
+ "struct { a int8; b int8; c int32 }",
+ },
+ {struct {
+ x struct {
+ a int8
+ b int8
+ c int8
+ d int32
+ }
+ }{},
+ "struct { a int8; b int8; c int8; d int32 }",
+ },
+ {struct {
+ x struct {
+ a int8
+ b int8
+ c int8
+ d int8
+ e int32
+ }
+ }{},
+ "struct { a int8; b int8; c int8; d int8; e int32 }",
+ },
+ {struct {
+ x struct {
+ a int8
+ b int8
+ c int8
+ d int8
+ e int8
+ f int32
+ }
+ }{},
+ "struct { a int8; b int8; c int8; d int8; e int8; f int32 }",
+ },
+ {struct {
+ x struct {
+ a int8 "hi there"
+ }
+ }{},
+ `struct { a int8 "hi there" }`,
+ },
+ {struct {
+ x struct {
+ a int8 "hi \x00there\t\n\"\\"
+ }
+ }{},
+ `struct { a int8 "hi \x00there\t\n\"\\" }`,
+ },
+ {struct {
+ x struct {
+ f func(args ...int)
+ }
+ }{},
+ "struct { f func(...int) }",
+ },
+ {struct {
+ x (interface {
+ a(func(func(int) int) func(func(int)) int)
+ b()
+ })
+ }{},
+ "interface { a(func(func(int) int) func(func(int)) int); b() }",
+ },
+}
+
+var valueTests = []pair{
+ {(int8)(0), "8"},
+ {(int16)(0), "16"},
+ {(int32)(0), "32"},
+ {(int64)(0), "64"},
+ {(uint8)(0), "8"},
+ {(uint16)(0), "16"},
+ {(uint32)(0), "32"},
+ {(uint64)(0), "64"},
+ {(float32)(0), "256.25"},
+ {(float64)(0), "512.125"},
+ {(string)(""), "stringy cheese"},
+ {(bool)(false), "true"},
+ {(*int8)(nil), "*int8(0)"},
+ {(**int8)(nil), "**int8(0)"},
+ {[5]int32{}, "[5]int32{0, 0, 0, 0, 0}"},
+ {(**integer)(nil), "**reflect_test.integer(0)"},
+ {(map[string]int32)(nil), "map[string] int32{<can't iterate on maps>}"},
+ {(chan<- string)(nil), "chan<- string"},
+ {struct {
+ c chan *int32
+ d float32
+ }{},
+ "struct { c chan *int32; d float32 }{chan *int32, 0}",
+ },
+ {(func(a int8, b int32))(nil), "func(int8, int32)(0)"},
+ {struct{ c func(chan *integer, *int8) }{},
+ "struct { c func(chan *reflect_test.integer, *int8) }{func(chan *reflect_test.integer, *int8)(0)}",
+ },
+ {struct {
+ a int8
+ b int32
+ }{},
+ "struct { a int8; b int32 }{0, 0}",
+ },
+ {struct {
+ a int8
+ b int8
+ c int32
+ }{},
+ "struct { a int8; b int8; c int32 }{0, 0, 0}",
+ },
+}
+
+func testType(t *testing.T, i int, typ Type, want string) {
+ s := typ.String()
+ if s != want {
+ t.Errorf("#%d: have %#q, want %#q", i, s, want)
+ }
+}
+
+func TestTypes(t *testing.T) {
+ for i, tt := range typeTests {
+ testType(t, i, NewValue(tt.i).(*StructValue).Field(0).Type(), tt.s)
+ }
+}
+
+func TestSet(t *testing.T) {
+ for i, tt := range valueTests {
+ v := NewValue(tt.i)
+ switch v := v.(type) {
+ case *IntValue:
+ switch v.Type().Kind() {
+ case Int:
+ v.Set(132)
+ case Int8:
+ v.Set(8)
+ case Int16:
+ v.Set(16)
+ case Int32:
+ v.Set(32)
+ case Int64:
+ v.Set(64)
+ }
+ case *UintValue:
+ switch v.Type().Kind() {
+ case Uint:
+ v.Set(132)
+ case Uint8:
+ v.Set(8)
+ case Uint16:
+ v.Set(16)
+ case Uint32:
+ v.Set(32)
+ case Uint64:
+ v.Set(64)
+ }
+ case *FloatValue:
+ switch v.Type().Kind() {
+ case Float32:
+ v.Set(256.25)
+ case Float64:
+ v.Set(512.125)
+ }
+ case *ComplexValue:
+ switch v.Type().Kind() {
+ case Complex64:
+ v.Set(532.125 + 10i)
+ case Complex128:
+ v.Set(564.25 + 1i)
+ }
+ case *StringValue:
+ v.Set("stringy cheese")
+ case *BoolValue:
+ v.Set(true)
+ }
+ s := valueToString(v)
+ if s != tt.s {
+ t.Errorf("#%d: have %#q, want %#q", i, s, tt.s)
+ }
+ }
+}
+
+func TestSetValue(t *testing.T) {
+ for i, tt := range valueTests {
+ v := NewValue(tt.i)
+ switch v := v.(type) {
+ case *IntValue:
+ switch v.Type().Kind() {
+ case Int:
+ v.SetValue(NewValue(int(132)))
+ case Int8:
+ v.SetValue(NewValue(int8(8)))
+ case Int16:
+ v.SetValue(NewValue(int16(16)))
+ case Int32:
+ v.SetValue(NewValue(int32(32)))
+ case Int64:
+ v.SetValue(NewValue(int64(64)))
+ }
+ case *UintValue:
+ switch v.Type().Kind() {
+ case Uint:
+ v.SetValue(NewValue(uint(132)))
+ case Uint8:
+ v.SetValue(NewValue(uint8(8)))
+ case Uint16:
+ v.SetValue(NewValue(uint16(16)))
+ case Uint32:
+ v.SetValue(NewValue(uint32(32)))
+ case Uint64:
+ v.SetValue(NewValue(uint64(64)))
+ }
+ case *FloatValue:
+ switch v.Type().Kind() {
+ case Float32:
+ v.SetValue(NewValue(float32(256.25)))
+ case Float64:
+ v.SetValue(NewValue(512.125))
+ }
+ case *ComplexValue:
+ switch v.Type().Kind() {
+ case Complex64:
+ v.SetValue(NewValue(complex64(532.125 + 10i)))
+ case Complex128:
+ v.SetValue(NewValue(complex128(564.25 + 1i)))
+ }
+
+ case *StringValue:
+ v.SetValue(NewValue("stringy cheese"))
+ case *BoolValue:
+ v.SetValue(NewValue(true))
+ }
+ s := valueToString(v)
+ if s != tt.s {
+ t.Errorf("#%d: have %#q, want %#q", i, s, tt.s)
+ }
+ }
+}
+
+var _i = 7
+
+var valueToStringTests = []pair{
+ {123, "123"},
+ {123.5, "123.5"},
+ {byte(123), "123"},
+ {"abc", "abc"},
+ {T{123, 456.75, "hello", &_i}, "reflect_test.T{123, 456.75, hello, *int(&7)}"},
+ {new(chan *T), "*chan *reflect_test.T(&chan *reflect_test.T)"},
+ {[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
+ {&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[10]int(&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
+ {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
+ {&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[]int(&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
+}
+
+func TestValueToString(t *testing.T) {
+ for i, test := range valueToStringTests {
+ s := valueToString(NewValue(test.i))
+ if s != test.s {
+ t.Errorf("#%d: have %#q, want %#q", i, s, test.s)
+ }
+ }
+}
+
+func TestArrayElemSet(t *testing.T) {
+ v := NewValue([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
+ v.(*ArrayValue).Elem(4).(*IntValue).Set(123)
+ s := valueToString(v)
+ const want = "[10]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"
+ if s != want {
+ t.Errorf("[10]int: have %#q want %#q", s, want)
+ }
+
+ v = NewValue([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
+ v.(*SliceValue).Elem(4).(*IntValue).Set(123)
+ s = valueToString(v)
+ const want1 = "[]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"
+ if s != want1 {
+ t.Errorf("[]int: have %#q want %#q", s, want1)
+ }
+}
+
+func TestPtrPointTo(t *testing.T) {
+ var ip *int32
+ var i int32 = 1234
+ vip := NewValue(&ip)
+ vi := NewValue(i)
+ vip.(*PtrValue).Elem().(*PtrValue).PointTo(vi)
+ if *ip != 1234 {
+ t.Errorf("got %d, want 1234", *ip)
+ }
+
+ ip = nil
+ vp := NewValue(ip).(*PtrValue)
+ vp.PointTo(vp.Elem())
+ if ip != nil {
+ t.Errorf("got non-nil (%p), want nil", ip)
+ }
+}
+
+func TestPtrSetNil(t *testing.T) {
+ var i int32 = 1234
+ ip := &i
+ vip := NewValue(&ip)
+ vip.(*PtrValue).Elem().(*PtrValue).Set(nil)
+ if ip != nil {
+ t.Errorf("got non-nil (%d), want nil", *ip)
+ }
+}
+
+func TestMapSetNil(t *testing.T) {
+ m := make(map[string]int)
+ vm := NewValue(&m)
+ vm.(*PtrValue).Elem().(*MapValue).Set(nil)
+ if m != nil {
+ t.Errorf("got non-nil (%p), want nil", m)
+ }
+}
+
+
+func TestAll(t *testing.T) {
+ testType(t, 1, Typeof((int8)(0)), "int8")
+ testType(t, 2, Typeof((*int8)(nil)).(*PtrType).Elem(), "int8")
+
+ typ := Typeof((*struct {
+ c chan *int32
+ d float32
+ })(nil))
+ testType(t, 3, typ, "*struct { c chan *int32; d float32 }")
+ etyp := typ.(*PtrType).Elem()
+ testType(t, 4, etyp, "struct { c chan *int32; d float32 }")
+ styp := etyp.(*StructType)
+ f := styp.Field(0)
+ testType(t, 5, f.Type, "chan *int32")
+
+ f, present := styp.FieldByName("d")
+ if !present {
+ t.Errorf("FieldByName says present field is absent")
+ }
+ testType(t, 6, f.Type, "float32")
+
+ f, present = styp.FieldByName("absent")
+ if present {
+ t.Errorf("FieldByName says absent field is present")
+ }
+
+ typ = Typeof([32]int32{})
+ testType(t, 7, typ, "[32]int32")
+ testType(t, 8, typ.(*ArrayType).Elem(), "int32")
+
+ typ = Typeof((map[string]*int32)(nil))
+ testType(t, 9, typ, "map[string] *int32")
+ mtyp := typ.(*MapType)
+ testType(t, 10, mtyp.Key(), "string")
+ testType(t, 11, mtyp.Elem(), "*int32")
+
+ typ = Typeof((chan<- string)(nil))
+ testType(t, 12, typ, "chan<- string")
+ testType(t, 13, typ.(*ChanType).Elem(), "string")
+
+ // make sure tag strings are not part of element type
+ typ = Typeof(struct {
+ d []uint32 "TAG"
+ }{}).(*StructType).Field(0).Type
+ testType(t, 14, typ, "[]uint32")
+}
+
+func TestInterfaceGet(t *testing.T) {
+ var inter struct {
+ e interface{}
+ }
+ inter.e = 123.456
+ v1 := NewValue(&inter)
+ v2 := v1.(*PtrValue).Elem().(*StructValue).Field(0)
+ assert(t, v2.Type().String(), "interface { }")
+ i2 := v2.(*InterfaceValue).Interface()
+ v3 := NewValue(i2)
+ assert(t, v3.Type().String(), "float64")
+}
+
+func TestInterfaceValue(t *testing.T) {
+ var inter struct {
+ e interface{}
+ }
+ inter.e = 123.456
+ v1 := NewValue(&inter)
+ v2 := v1.(*PtrValue).Elem().(*StructValue).Field(0)
+ assert(t, v2.Type().String(), "interface { }")
+ v3 := v2.(*InterfaceValue).Elem()
+ assert(t, v3.Type().String(), "float64")
+
+ i3 := v2.Interface()
+ if _, ok := i3.(float64); !ok {
+ t.Error("v2.Interface() did not return float64, got ", Typeof(i3))
+ }
+}
+
+func TestFunctionValue(t *testing.T) {
+ v := NewValue(func() {})
+ if v.Interface() != v.Interface() {
+ t.Fatalf("TestFunction != itself")
+ }
+ assert(t, v.Type().String(), "func()")
+}
+
+var appendTests = []struct {
+ orig, extra []int
+}{
+ {make([]int, 2, 4), []int{22}},
+ {make([]int, 2, 4), []int{22, 33, 44}},
+}
+
+func TestAppend(t *testing.T) {
+ for i, test := range appendTests {
+ origLen, extraLen := len(test.orig), len(test.extra)
+ want := append(test.orig, test.extra...)
+ // Convert extra from []int to []Value.
+ e0 := make([]Value, len(test.extra))
+ for j, e := range test.extra {
+ e0[j] = NewValue(e)
+ }
+ // Convert extra from []int to *SliceValue.
+ e1 := NewValue(test.extra).(*SliceValue)
+ // Test Append.
+ a0 := NewValue(test.orig).(*SliceValue)
+ have0 := Append(a0, e0...).Interface().([]int)
+ if !DeepEqual(have0, want) {
+ t.Errorf("Append #%d: have %v, want %v", i, have0, want)
+ }
+ // Check that the orig and extra slices were not modified.
+ if len(test.orig) != origLen {
+ t.Errorf("Append #%d origLen: have %v, want %v", i, len(test.orig), origLen)
+ }
+ if len(test.extra) != extraLen {
+ t.Errorf("Append #%d extraLen: have %v, want %v", i, len(test.extra), extraLen)
+ }
+ // Test AppendSlice.
+ a1 := NewValue(test.orig).(*SliceValue)
+ have1 := AppendSlice(a1, e1).Interface().([]int)
+ if !DeepEqual(have1, want) {
+ t.Errorf("AppendSlice #%d: have %v, want %v", i, have1, want)
+ }
+ // Check that the orig and extra slices were not modified.
+ if len(test.orig) != origLen {
+ t.Errorf("AppendSlice #%d origLen: have %v, want %v", i, len(test.orig), origLen)
+ }
+ if len(test.extra) != extraLen {
+ t.Errorf("AppendSlice #%d extraLen: have %v, want %v", i, len(test.extra), extraLen)
+ }
+ }
+}
+
+func TestCopy(t *testing.T) {
+ a := []int{1, 2, 3, 4, 10, 9, 8, 7}
+ b := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}
+ c := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}
+ for i := 0; i < len(b); i++ {
+ if b[i] != c[i] {
+ t.Fatalf("b != c before test")
+ }
+ }
+ aa := NewValue(a).(*SliceValue)
+ ab := NewValue(b).(*SliceValue)
+ for tocopy := 1; tocopy <= 7; tocopy++ {
+ aa.SetLen(tocopy)
+ Copy(ab, aa)
+ aa.SetLen(8)
+ for i := 0; i < tocopy; i++ {
+ if a[i] != b[i] {
+ t.Errorf("(i) tocopy=%d a[%d]=%d, b[%d]=%d",
+ tocopy, i, a[i], i, b[i])
+ }
+ }
+ for i := tocopy; i < len(b); i++ {
+ if b[i] != c[i] {
+ if i < len(a) {
+ t.Errorf("(ii) tocopy=%d a[%d]=%d, b[%d]=%d, c[%d]=%d",
+ tocopy, i, a[i], i, b[i], i, c[i])
+ } else {
+ t.Errorf("(iii) tocopy=%d b[%d]=%d, c[%d]=%d",
+ tocopy, i, b[i], i, c[i])
+ }
+ } else {
+ t.Logf("tocopy=%d elem %d is okay\n", tocopy, i)
+ }
+ }
+ }
+}
+
+func TestBigUnnamedStruct(t *testing.T) {
+ b := struct{ a, b, c, d int64 }{1, 2, 3, 4}
+ v := NewValue(b)
+ b1 := v.Interface().(struct {
+ a, b, c, d int64
+ })
+ if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d {
+ t.Errorf("NewValue(%v).Interface().(*Big) = %v", b, b1)
+ }
+}
+
+type big struct {
+ a, b, c, d, e int64
+}
+
+func TestBigStruct(t *testing.T) {
+ b := big{1, 2, 3, 4, 5}
+ v := NewValue(b)
+ b1 := v.Interface().(big)
+ if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d || b1.e != b.e {
+ t.Errorf("NewValue(%v).Interface().(big) = %v", b, b1)
+ }
+}
+
+type Basic struct {
+ x int
+ y float32
+}
+
+type NotBasic Basic
+
+type DeepEqualTest struct {
+ a, b interface{}
+ eq bool
+}
+
+var deepEqualTests = []DeepEqualTest{
+ // Equalities
+ {1, 1, true},
+ {int32(1), int32(1), true},
+ {0.5, 0.5, true},
+ {float32(0.5), float32(0.5), true},
+ {"hello", "hello", true},
+ {make([]int, 10), make([]int, 10), true},
+ {&[3]int{1, 2, 3}, &[3]int{1, 2, 3}, true},
+ {Basic{1, 0.5}, Basic{1, 0.5}, true},
+ {os.Error(nil), os.Error(nil), true},
+ {map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true},
+
+ // Inequalities
+ {1, 2, false},
+ {int32(1), int32(2), false},
+ {0.5, 0.6, false},
+ {float32(0.5), float32(0.6), false},
+ {"hello", "hey", false},
+ {make([]int, 10), make([]int, 11), false},
+ {&[3]int{1, 2, 3}, &[3]int{1, 2, 4}, false},
+ {Basic{1, 0.5}, Basic{1, 0.6}, false},
+ {Basic{1, 0}, Basic{2, 0}, false},
+ {map[int]string{1: "one", 3: "two"}, map[int]string{2: "two", 1: "one"}, false},
+ {map[int]string{1: "one", 2: "txo"}, map[int]string{2: "two", 1: "one"}, false},
+ {map[int]string{1: "one"}, map[int]string{2: "two", 1: "one"}, false},
+ {map[int]string{2: "two", 1: "one"}, map[int]string{1: "one"}, false},
+ {nil, 1, false},
+ {1, nil, false},
+
+ // Mismatched types
+ {1, 1.0, false},
+ {int32(1), int64(1), false},
+ {0.5, "hello", false},
+ {[]int{1, 2, 3}, [3]int{1, 2, 3}, false},
+ {&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false},
+ {Basic{1, 0.5}, NotBasic{1, 0.5}, false},
+ {map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false},
+}
+
+func TestDeepEqual(t *testing.T) {
+ for _, test := range deepEqualTests {
+ if r := DeepEqual(test.a, test.b); r != test.eq {
+ t.Errorf("DeepEqual(%v, %v) = %v, want %v", test.a, test.b, r, test.eq)
+ }
+ }
+}
+
+func TestTypeof(t *testing.T) {
+ for _, test := range deepEqualTests {
+ v := NewValue(test.a)
+ if v == nil {
+ continue
+ }
+ typ := Typeof(test.a)
+ if typ != v.Type() {
+ t.Errorf("Typeof(%v) = %v, but NewValue(%v).Type() = %v", test.a, typ, test.a, v.Type())
+ }
+ }
+}
+
+type Recursive struct {
+ x int
+ r *Recursive
+}
+
+func TestDeepEqualRecursiveStruct(t *testing.T) {
+ a, b := new(Recursive), new(Recursive)
+ *a = Recursive{12, a}
+ *b = Recursive{12, b}
+ if !DeepEqual(a, b) {
+ t.Error("DeepEqual(recursive same) = false, want true")
+ }
+}
+
+type _Complex struct {
+ a int
+ b [3]*_Complex
+ c *string
+ d map[float64]float64
+}
+
+func TestDeepEqualComplexStruct(t *testing.T) {
+ m := make(map[float64]float64)
+ stra, strb := "hello", "hello"
+ a, b := new(_Complex), new(_Complex)
+ *a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m}
+ *b = _Complex{5, [3]*_Complex{b, a, a}, &strb, m}
+ if !DeepEqual(a, b) {
+ t.Error("DeepEqual(complex same) = false, want true")
+ }
+}
+
+func TestDeepEqualComplexStructInequality(t *testing.T) {
+ m := make(map[float64]float64)
+ stra, strb := "hello", "helloo" // Difference is here
+ a, b := new(_Complex), new(_Complex)
+ *a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m}
+ *b = _Complex{5, [3]*_Complex{b, a, a}, &strb, m}
+ if DeepEqual(a, b) {
+ t.Error("DeepEqual(complex different) = true, want false")
+ }
+}
+
+
+func check2ndField(x interface{}, offs uintptr, t *testing.T) {
+ s := NewValue(x).(*StructValue)
+ f := s.Type().(*StructType).Field(1)
+ if f.Offset != offs {
+ t.Error("mismatched offsets in structure alignment:", f.Offset, offs)
+ }
+}
+
+// Check that structure alignment & offsets viewed through reflect agree with those
+// from the compiler itself.
+func TestAlignment(t *testing.T) {
+ type T1inner struct {
+ a int
+ }
+ type T1 struct {
+ T1inner
+ f int
+ }
+ type T2inner struct {
+ a, b int
+ }
+ type T2 struct {
+ T2inner
+ f int
+ }
+
+ x := T1{T1inner{2}, 17}
+ check2ndField(x, uintptr(unsafe.Pointer(&x.f))-uintptr(unsafe.Pointer(&x)), t)
+
+ x1 := T2{T2inner{2, 3}, 17}
+ check2ndField(x1, uintptr(unsafe.Pointer(&x1.f))-uintptr(unsafe.Pointer(&x1)), t)
+}
+
+type IsNiller interface {
+ IsNil() bool
+}
+
+func Nil(a interface{}, t *testing.T) {
+ n := NewValue(a).(*StructValue).Field(0).(IsNiller)
+ if !n.IsNil() {
+ t.Errorf("%v should be nil", a)
+ }
+}
+
+func NotNil(a interface{}, t *testing.T) {
+ n := NewValue(a).(*StructValue).Field(0).(IsNiller)
+ if n.IsNil() {
+ t.Errorf("value of type %v should not be nil", NewValue(a).Type().String())
+ }
+}
+
+func TestIsNil(t *testing.T) {
+ // These do not implement IsNil
+ doNotNil := []interface{}{int(0), float32(0), struct{ a int }{}}
+ for _, ts := range doNotNil {
+ ty := Typeof(ts)
+ v := MakeZero(ty)
+ if _, ok := v.(IsNiller); ok {
+ t.Errorf("%s is nilable; should not be", ts)
+ }
+ }
+
+ // These do implement IsNil.
+ // Wrap in extra struct to hide interface type.
+ doNil := []interface{}{
+ struct{ x *int }{},
+ struct{ x interface{} }{},
+ struct{ x map[string]int }{},
+ struct{ x func() bool }{},
+ struct{ x chan int }{},
+ struct{ x []string }{},
+ }
+ for _, ts := range doNil {
+ ty := Typeof(ts).(*StructType).Field(0).Type
+ v := MakeZero(ty)
+ if _, ok := v.(IsNiller); !ok {
+ t.Errorf("%s %T is not nilable; should be", ts, v)
+ }
+ }
+
+ // Check the implementations
+ var pi struct {
+ x *int
+ }
+ Nil(pi, t)
+ pi.x = new(int)
+ NotNil(pi, t)
+
+ var si struct {
+ x []int
+ }
+ Nil(si, t)
+ si.x = make([]int, 10)
+ NotNil(si, t)
+
+ var ci struct {
+ x chan int
+ }
+ Nil(ci, t)
+ ci.x = make(chan int)
+ NotNil(ci, t)
+
+ var mi struct {
+ x map[int]int
+ }
+ Nil(mi, t)
+ mi.x = make(map[int]int)
+ NotNil(mi, t)
+
+ var ii struct {
+ x interface{}
+ }
+ Nil(ii, t)
+ ii.x = 2
+ NotNil(ii, t)
+
+ var fi struct {
+ x func(t *testing.T)
+ }
+ Nil(fi, t)
+ fi.x = TestIsNil
+ NotNil(fi, t)
+}
+
+func TestInterfaceExtraction(t *testing.T) {
+ var s struct {
+ w io.Writer
+ }
+
+ s.w = os.Stdout
+ v := Indirect(NewValue(&s)).(*StructValue).Field(0).Interface()
+ if v != s.w.(interface{}) {
+ t.Error("Interface() on interface: ", v, s.w)
+ }
+}
+
+func TestInterfaceEditing(t *testing.T) {
+ // strings are bigger than one word,
+ // so the interface conversion allocates
+ // memory to hold a string and puts that
+ // pointer in the interface.
+ var i interface{} = "hello"
+
+ // if i pass the interface value by value
+ // to NewValue, i should get a fresh copy
+ // of the value.
+ v := NewValue(i)
+
+ // and setting that copy to "bye" should
+ // not change the value stored in i.
+ v.(*StringValue).Set("bye")
+ if i.(string) != "hello" {
+ t.Errorf(`Set("bye") changed i to %s`, i.(string))
+ }
+
+ // the same should be true of smaller items.
+ i = 123
+ v = NewValue(i)
+ v.(*IntValue).Set(234)
+ if i.(int) != 123 {
+ t.Errorf("Set(234) changed i to %d", i.(int))
+ }
+}
+
+func TestNilPtrValueSub(t *testing.T) {
+ var pi *int
+ if pv := NewValue(pi).(*PtrValue); pv.Elem() != nil {
+ t.Error("NewValue((*int)(nil)).(*PtrValue).Elem() != nil")
+ }
+}
+
+func TestMap(t *testing.T) {
+ m := map[string]int{"a": 1, "b": 2}
+ mv := NewValue(m).(*MapValue)
+ if n := mv.Len(); n != len(m) {
+ t.Errorf("Len = %d, want %d", n, len(m))
+ }
+ keys := mv.Keys()
+ i := 0
+ newmap := MakeMap(mv.Type().(*MapType))
+ for k, v := range m {
+ // Check that returned Keys match keys in range.
+ // These aren't required to be in the same order,
+ // but they are in this implementation, which makes
+ // the test easier.
+ if i >= len(keys) {
+ t.Errorf("Missing key #%d %q", i, k)
+ } else if kv := keys[i].(*StringValue); kv.Get() != k {
+ t.Errorf("Keys[%d] = %q, want %q", i, kv.Get(), k)
+ }
+ i++
+
+ // Check that value lookup is correct.
+ vv := mv.Elem(NewValue(k))
+ if vi := vv.(*IntValue).Get(); vi != int64(v) {
+ t.Errorf("Key %q: have value %d, want %d", k, vi, v)
+ }
+
+ // Copy into new map.
+ newmap.SetElem(NewValue(k), NewValue(v))
+ }
+ vv := mv.Elem(NewValue("not-present"))
+ if vv != nil {
+ t.Errorf("Invalid key: got non-nil value %s", valueToString(vv))
+ }
+
+ newm := newmap.Interface().(map[string]int)
+ if len(newm) != len(m) {
+ t.Errorf("length after copy: newm=%d, m=%d", newm, m)
+ }
+
+ for k, v := range newm {
+ mv, ok := m[k]
+ if mv != v {
+ t.Errorf("newm[%q] = %d, but m[%q] = %d, %v", k, v, k, mv, ok)
+ }
+ }
+
+ newmap.SetElem(NewValue("a"), nil)
+ v, ok := newm["a"]
+ if ok {
+ t.Errorf("newm[\"a\"] = %d after delete", v)
+ }
+
+ mv = NewValue(&m).(*PtrValue).Elem().(*MapValue)
+ mv.Set(nil)
+ if m != nil {
+ t.Errorf("mv.Set(nil) failed")
+ }
+}
+
+func TestChan(t *testing.T) {
+ for loop := 0; loop < 2; loop++ {
+ var c chan int
+ var cv *ChanValue
+
+ // check both ways to allocate channels
+ switch loop {
+ case 1:
+ c = make(chan int, 1)
+ cv = NewValue(c).(*ChanValue)
+ case 0:
+ cv = MakeChan(Typeof(c).(*ChanType), 1)
+ c = cv.Interface().(chan int)
+ }
+
+ // Send
+ cv.Send(NewValue(2))
+ if i := <-c; i != 2 {
+ t.Errorf("reflect Send 2, native recv %d", i)
+ }
+
+ // Recv
+ c <- 3
+ if i := cv.Recv().(*IntValue).Get(); i != 3 {
+ t.Errorf("native send 3, reflect Recv %d", i)
+ }
+
+ // TryRecv fail
+ val := cv.TryRecv()
+ if val != nil {
+ t.Errorf("TryRecv on empty chan: %s", valueToString(val))
+ }
+
+ // TryRecv success
+ c <- 4
+ val = cv.TryRecv()
+ if val == nil {
+ t.Errorf("TryRecv on ready chan got nil")
+ } else if i := val.(*IntValue).Get(); i != 4 {
+ t.Errorf("native send 4, TryRecv %d", i)
+ }
+
+ // TrySend fail
+ c <- 100
+ ok := cv.TrySend(NewValue(5))
+ i := <-c
+ if ok {
+ t.Errorf("TrySend on full chan succeeded: value %d", i)
+ }
+
+ // TrySend success
+ ok = cv.TrySend(NewValue(6))
+ if !ok {
+ t.Errorf("TrySend on empty chan failed")
+ } else {
+ if i = <-c; i != 6 {
+ t.Errorf("TrySend 6, recv %d", i)
+ }
+ }
+
+ // Close
+ c <- 123
+ cv.Close()
+ if cv.Closed() {
+ t.Errorf("closed too soon - 1")
+ }
+ if i := cv.Recv().(*IntValue).Get(); i != 123 {
+ t.Errorf("send 123 then close; Recv %d", i)
+ }
+ if cv.Closed() {
+ t.Errorf("closed too soon - 2")
+ }
+ if i := cv.Recv().(*IntValue).Get(); i != 0 {
+ t.Errorf("after close Recv %d", i)
+ }
+ if !cv.Closed() {
+ t.Errorf("not closed")
+ }
+ }
+
+ // check creation of unbuffered channel
+ var c chan int
+ cv := MakeChan(Typeof(c).(*ChanType), 0)
+ c = cv.Interface().(chan int)
+ if cv.TrySend(NewValue(7)) {
+ t.Errorf("TrySend on sync chan succeeded")
+ }
+ if cv.TryRecv() != nil {
+ t.Errorf("TryRecv on sync chan succeeded")
+ }
+
+ // len/cap
+ cv = MakeChan(Typeof(c).(*ChanType), 10)
+ c = cv.Interface().(chan int)
+ for i := 0; i < 3; i++ {
+ c <- i
+ }
+ if l, m := cv.Len(), cv.Cap(); l != len(c) || m != cap(c) {
+ t.Errorf("Len/Cap = %d/%d want %d/%d", l, m, len(c), cap(c))
+ }
+
+}
+
+// Difficult test for function call because of
+// implicit padding between arguments.
+func dummy(b byte, c int, d byte) (i byte, j int, k byte) {
+ return b, c, d
+}
+
+func TestFunc(t *testing.T) {
+ ret := NewValue(dummy).(*FuncValue).Call([]Value{NewValue(byte(10)), NewValue(20), NewValue(byte(30))})
+ if len(ret) != 3 {
+ t.Fatalf("Call returned %d values, want 3", len(ret))
+ }
+
+ i := ret[0].(*UintValue).Get()
+ j := ret[1].(*IntValue).Get()
+ k := ret[2].(*UintValue).Get()
+ if i != 10 || j != 20 || k != 30 {
+ t.Errorf("Call returned %d, %d, %d; want 10, 20, 30", i, j, k)
+ }
+}
+
+type Point struct {
+ x, y int
+}
+
+func (p Point) Dist(scale int) int { return p.x*p.x*scale + p.y*p.y*scale }
+
+func TestMethod(t *testing.T) {
+ // Non-curried method of type.
+ p := Point{3, 4}
+ i := Typeof(p).Method(0).Func.Call([]Value{NewValue(p), NewValue(10)})[0].(*IntValue).Get()
+ if i != 250 {
+ t.Errorf("Type Method returned %d; want 250", i)
+ }
+
+ i = Typeof(&p).Method(0).Func.Call([]Value{NewValue(&p), NewValue(10)})[0].(*IntValue).Get()
+ if i != 250 {
+ t.Errorf("Pointer Type Method returned %d; want 250", i)
+ }
+
+ // Curried method of value.
+ i = NewValue(p).Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
+ if i != 250 {
+ t.Errorf("Value Method returned %d; want 250", i)
+ }
+
+ // Curried method of interface value.
+ // Have to wrap interface value in a struct to get at it.
+ // Passing it to NewValue directly would
+ // access the underlying Point, not the interface.
+ var s = struct {
+ x interface {
+ Dist(int) int
+ }
+ }{p}
+ pv := NewValue(s).(*StructValue).Field(0)
+ i = pv.Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
+ if i != 250 {
+ t.Errorf("Interface Method returned %d; want 250", i)
+ }
+}
+
+func TestInterfaceSet(t *testing.T) {
+ p := &Point{3, 4}
+
+ var s struct {
+ I interface{}
+ P interface {
+ Dist(int) int
+ }
+ }
+ sv := NewValue(&s).(*PtrValue).Elem().(*StructValue)
+ sv.Field(0).(*InterfaceValue).Set(NewValue(p))
+ if q := s.I.(*Point); q != p {
+ t.Errorf("i: have %p want %p", q, p)
+ }
+
+ pv := sv.Field(1).(*InterfaceValue)
+ pv.Set(NewValue(p))
+ if q := s.P.(*Point); q != p {
+ t.Errorf("i: have %p want %p", q, p)
+ }
+
+ i := pv.Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
+ if i != 250 {
+ t.Errorf("Interface Method returned %d; want 250", i)
+ }
+}
+
+type T1 struct {
+ a string
+ int
+}
+
+func TestAnonymousFields(t *testing.T) {
+ var field StructField
+ var ok bool
+ var t1 T1
+ type1 := Typeof(t1).(*StructType)
+ if field, ok = type1.FieldByName("int"); !ok {
+ t.Error("no field 'int'")
+ }
+ if field.Index[0] != 1 {
+ t.Error("field index should be 1; is", field.Index)
+ }
+}
+
+type FTest struct {
+ s interface{}
+ name string
+ index []int
+ value int
+}
+
+type D1 struct {
+ d int
+}
+type D2 struct {
+ d int
+}
+
+type S0 struct {
+ a, b, c int
+ D1
+ D2
+}
+
+type S1 struct {
+ b int
+ S0
+}
+
+type S2 struct {
+ a int
+ *S1
+}
+
+type S1x struct {
+ S1
+}
+
+type S1y struct {
+ S1
+}
+
+type S3 struct {
+ S1x
+ S2
+ d, e int
+ *S1y
+}
+
+type S4 struct {
+ *S4
+ a int
+}
+
+var fieldTests = []FTest{
+ {struct{}{}, "", nil, 0},
+ {struct{}{}, "foo", nil, 0},
+ {S0{a: 'a'}, "a", []int{0}, 'a'},
+ {S0{}, "d", nil, 0},
+ {S1{S0: S0{a: 'a'}}, "a", []int{1, 0}, 'a'},
+ {S1{b: 'b'}, "b", []int{0}, 'b'},
+ {S1{}, "S0", []int{1}, 0},
+ {S1{S0: S0{c: 'c'}}, "c", []int{1, 2}, 'c'},
+ {S2{a: 'a'}, "a", []int{0}, 'a'},
+ {S2{}, "S1", []int{1}, 0},
+ {S2{S1: &S1{b: 'b'}}, "b", []int{1, 0}, 'b'},
+ {S2{S1: &S1{S0: S0{c: 'c'}}}, "c", []int{1, 1, 2}, 'c'},
+ {S2{}, "d", nil, 0},
+ {S3{}, "S1", nil, 0},
+ {S3{S2: S2{a: 'a'}}, "a", []int{1, 0}, 'a'},
+ {S3{}, "b", nil, 0},
+ {S3{d: 'd'}, "d", []int{2}, 0},
+ {S3{e: 'e'}, "e", []int{3}, 'e'},
+ {S4{a: 'a'}, "a", []int{1}, 'a'},
+ {S4{}, "b", nil, 0},
+}
+
+func TestFieldByIndex(t *testing.T) {
+ for _, test := range fieldTests {
+ s := Typeof(test.s).(*StructType)
+ f := s.FieldByIndex(test.index)
+ if f.Name != "" {
+ if test.index != nil {
+ if f.Name != test.name {
+ t.Errorf("%s.%s found; want %s", s.Name(), f.Name, test.name)
+ }
+ } else {
+ t.Errorf("%s.%s found", s.Name(), f.Name)
+ }
+ } else if len(test.index) > 0 {
+ t.Errorf("%s.%s not found", s.Name(), test.name)
+ }
+
+ if test.value != 0 {
+ v := NewValue(test.s).(*StructValue).FieldByIndex(test.index)
+ if v != nil {
+ if x, ok := v.Interface().(int); ok {
+ if x != test.value {
+ t.Errorf("%s%v is %d; want %d", s.Name(), test.index, x, test.value)
+ }
+ } else {
+ t.Errorf("%s%v value not an int", s.Name(), test.index)
+ }
+ } else {
+ t.Errorf("%s%v value not found", s.Name(), test.index)
+ }
+ }
+ }
+}
+
+func TestFieldByName(t *testing.T) {
+ for _, test := range fieldTests {
+ s := Typeof(test.s).(*StructType)
+ f, found := s.FieldByName(test.name)
+ if found {
+ if test.index != nil {
+ // Verify field depth and index.
+ if len(f.Index) != len(test.index) {
+ t.Errorf("%s.%s depth %d; want %d", s.Name(), test.name, len(f.Index), len(test.index))
+ } else {
+ for i, x := range f.Index {
+ if x != test.index[i] {
+ t.Errorf("%s.%s.Index[%d] is %d; want %d", s.Name(), test.name, i, x, test.index[i])
+ }
+ }
+ }
+ } else {
+ t.Errorf("%s.%s found", s.Name(), f.Name)
+ }
+ } else if len(test.index) > 0 {
+ t.Errorf("%s.%s not found", s.Name(), test.name)
+ }
+
+ if test.value != 0 {
+ v := NewValue(test.s).(*StructValue).FieldByName(test.name)
+ if v != nil {
+ if x, ok := v.Interface().(int); ok {
+ if x != test.value {
+ t.Errorf("%s.%s is %d; want %d", s.Name(), test.name, x, test.value)
+ }
+ } else {
+ t.Errorf("%s.%s value not an int", s.Name(), test.name)
+ }
+ } else {
+ t.Errorf("%s.%s value not found", s.Name(), test.name)
+ }
+ }
+ }
+}
+
+func TestImportPath(t *testing.T) {
+ if path := Typeof(vector.Vector{}).PkgPath(); path != "libgo_container.vector" {
+ t.Errorf("Typeof(vector.Vector{}).PkgPath() = %q, want \"libgo_container.vector\"", path)
+ }
+}
+
+func TestDotDotDot(t *testing.T) {
+ // Test example from FuncType.DotDotDot documentation.
+ var f func(x int, y ...float64)
+ typ := Typeof(f).(*FuncType)
+ if typ.NumIn() == 2 && typ.In(0) == Typeof(int(0)) {
+ sl, ok := typ.In(1).(*SliceType)
+ if ok {
+ if sl.Elem() == Typeof(0.0) {
+ // ok
+ return
+ }
+ }
+ }
+
+ // Failed
+ t.Errorf("want NumIn() = 2, In(0) = int, In(1) = []float64")
+ s := fmt.Sprintf("have NumIn() = %d", typ.NumIn())
+ for i := 0; i < typ.NumIn(); i++ {
+ s += fmt.Sprintf(", In(%d) = %s", i, typ.In(i))
+ }
+ t.Error(s)
+}
+
+type inner struct {
+ x int
+}
+
+type outer struct {
+ y int
+ inner
+}
+
+func (*inner) m() {}
+func (*outer) m() {}
+
+func TestNestedMethods(t *testing.T) {
+ typ := Typeof((*outer)(nil))
+ if typ.NumMethod() != 1 || typ.Method(0).Func.Get() != NewValue((*outer).m).(*FuncValue).Get() {
+ t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m)
+ for i := 0; i < typ.NumMethod(); i++ {
+ m := typ.Method(i)
+ t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Get())
+ }
+ }
+}
+
+type innerInt struct {
+ x int
+}
+
+type outerInt struct {
+ y int
+ innerInt
+}
+
+func (i *innerInt) m() int {
+ return i.x
+}
+
+func TestEmbeddedMethods(t *testing.T) {
+ typ := Typeof((*outerInt)(nil))
+ if typ.NumMethod() != 1 || typ.Method(0).Func.Get() != NewValue((*outerInt).m).(*FuncValue).Get() {
+ t.Errorf("Wrong method table for outerInt: (m=%p)", (*outerInt).m)
+ for i := 0; i < typ.NumMethod(); i++ {
+ m := typ.Method(i)
+ t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Get())
+ }
+ }
+
+ i := &innerInt{3}
+ if v := NewValue(i).Method(0).Call(nil)[0].(*IntValue).Get(); v != 3 {
+ t.Errorf("i.m() = %d, want 3", v)
+ }
+
+ o := &outerInt{1, innerInt{2}}
+ if v := NewValue(o).Method(0).Call(nil)[0].(*IntValue).Get(); v != 2 {
+ t.Errorf("i.m() = %d, want 2", v)
+ }
+
+ f := (*outerInt).m
+ if v := f(o); v != 2 {
+ t.Errorf("f(o) = %d, want 2", v)
+ }
+}
diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go
new file mode 100644
index 000000000..a50925e51
--- /dev/null
+++ b/libgo/go/reflect/deepequal.go
@@ -0,0 +1,135 @@
+// 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.
+
+// Deep equality test via reflection
+
+package reflect
+
+
+// During deepValueEqual, must keep track of checks that are
+// in progress. The comparison algorithm assumes that all
+// checks in progress are true when it reencounters them.
+// Visited are stored in a map indexed by 17 * a1 + a2;
+type visit struct {
+ a1 uintptr
+ a2 uintptr
+ typ Type
+ next *visit
+}
+
+// Tests for deep equality using reflected types. The map argument tracks
+// comparisons that have already been seen, which allows short circuiting on
+// recursive types.
+func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) bool {
+ if v1 == nil || v2 == nil {
+ return v1 == v2
+ }
+ if v1.Type() != v2.Type() {
+ return false
+ }
+
+ // if depth > 10 { panic("deepValueEqual") } // for debugging
+
+ addr1 := v1.Addr()
+ addr2 := v2.Addr()
+ if addr1 > addr2 {
+ // Canonicalize order to reduce number of entries in visited.
+ addr1, addr2 = addr2, addr1
+ }
+
+ // Short circuit if references are identical ...
+ if addr1 == addr2 {
+ return true
+ }
+
+ // ... or already seen
+ h := 17*addr1 + addr2
+ seen := visited[h]
+ typ := v1.Type()
+ for p := seen; p != nil; p = p.next {
+ if p.a1 == addr1 && p.a2 == addr2 && p.typ == typ {
+ return true
+ }
+ }
+
+ // Remember for later.
+ visited[h] = &visit{addr1, addr2, typ, seen}
+
+ switch v := v1.(type) {
+ case *ArrayValue:
+ arr1 := v
+ arr2 := v2.(*ArrayValue)
+ if arr1.Len() != arr2.Len() {
+ return false
+ }
+ for i := 0; i < arr1.Len(); i++ {
+ if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited, depth+1) {
+ return false
+ }
+ }
+ return true
+ case *SliceValue:
+ arr1 := v
+ arr2 := v2.(*SliceValue)
+ if arr1.Len() != arr2.Len() {
+ return false
+ }
+ for i := 0; i < arr1.Len(); i++ {
+ if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited, depth+1) {
+ return false
+ }
+ }
+ return true
+ case *InterfaceValue:
+ i1 := v.Interface()
+ i2 := v2.Interface()
+ if i1 == nil || i2 == nil {
+ return i1 == i2
+ }
+ return deepValueEqual(NewValue(i1), NewValue(i2), visited, depth+1)
+ case *PtrValue:
+ return deepValueEqual(v.Elem(), v2.(*PtrValue).Elem(), visited, depth+1)
+ case *StructValue:
+ struct1 := v
+ struct2 := v2.(*StructValue)
+ for i, n := 0, v.NumField(); i < n; i++ {
+ if !deepValueEqual(struct1.Field(i), struct2.Field(i), visited, depth+1) {
+ return false
+ }
+ }
+ return true
+ case *MapValue:
+ map1 := v
+ map2 := v2.(*MapValue)
+ if map1.Len() != map2.Len() {
+ return false
+ }
+ for _, k := range map1.Keys() {
+ if !deepValueEqual(map1.Elem(k), map2.Elem(k), visited, depth+1) {
+ return false
+ }
+ }
+ return true
+ default:
+ // Normal equality suffices
+ return v1.Interface() == v2.Interface()
+ }
+
+ panic("Not reached")
+}
+
+// DeepEqual tests for deep equality. It uses normal == equality where possible
+// but will scan members of arrays, slices, and fields of structs. It correctly
+// handles recursive types.
+func DeepEqual(a1, a2 interface{}) bool {
+ if a1 == nil || a2 == nil {
+ return a1 == a2
+ }
+ v1 := NewValue(a1)
+ v2 := NewValue(a2)
+ if v1.Type() != v2.Type() {
+ return false
+ }
+ return deepValueEqual(v1, v2, make(map[uintptr]*visit), 0)
+}
diff --git a/libgo/go/reflect/tostring_test.go b/libgo/go/reflect/tostring_test.go
new file mode 100644
index 000000000..a1487fdd2
--- /dev/null
+++ b/libgo/go/reflect/tostring_test.go
@@ -0,0 +1,96 @@
+// 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.
+
+// Formatting of reflection types and values for debugging.
+// Not defined as methods so they do not need to be linked into most binaries;
+// the functions are not used by the library itself, only in tests.
+
+package reflect_test
+
+import (
+ . "reflect"
+ "strconv"
+)
+
+// valueToString returns a textual representation of the reflection value val.
+// For debugging only.
+func valueToString(val Value) string {
+ var str string
+ if val == nil {
+ return "<nil>"
+ }
+ typ := val.Type()
+ switch val := val.(type) {
+ case *IntValue:
+ return strconv.Itoa64(val.Get())
+ case *UintValue:
+ return strconv.Uitoa64(val.Get())
+ case *FloatValue:
+ return strconv.Ftoa64(float64(val.Get()), 'g', -1)
+ case *ComplexValue:
+ c := val.Get()
+ return strconv.Ftoa64(float64(real(c)), 'g', -1) + "+" + strconv.Ftoa64(float64(imag(c)), 'g', -1) + "i"
+ case *StringValue:
+ return val.Get()
+ case *BoolValue:
+ if val.Get() {
+ return "true"
+ } else {
+ return "false"
+ }
+ case *PtrValue:
+ v := val
+ str = typ.String() + "("
+ if v.IsNil() {
+ str += "0"
+ } else {
+ str += "&" + valueToString(v.Elem())
+ }
+ str += ")"
+ return str
+ case ArrayOrSliceValue:
+ v := val
+ str += typ.String()
+ str += "{"
+ for i := 0; i < v.Len(); i++ {
+ if i > 0 {
+ str += ", "
+ }
+ str += valueToString(v.Elem(i))
+ }
+ str += "}"
+ return str
+ case *MapValue:
+ t := typ.(*MapType)
+ str = t.String()
+ str += "{"
+ str += "<can't iterate on maps>"
+ str += "}"
+ return str
+ case *ChanValue:
+ str = typ.String()
+ return str
+ case *StructValue:
+ t := typ.(*StructType)
+ v := val
+ str += t.String()
+ str += "{"
+ for i, n := 0, v.NumField(); i < n; i++ {
+ if i > 0 {
+ str += ", "
+ }
+ str += valueToString(v.Field(i))
+ }
+ str += "}"
+ return str
+ case *InterfaceValue:
+ return typ.String() + "(" + valueToString(val.Elem()) + ")"
+ case *FuncValue:
+ v := val
+ return typ.String() + "(" + strconv.Itoa64(int64(v.Get())) + ")"
+ default:
+ panic("valueToString: can't print type " + typ.String())
+ }
+ return "valueToString: can't happen"
+}
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
new file mode 100644
index 000000000..4ad4c5f2b
--- /dev/null
+++ b/libgo/go/reflect/type.go
@@ -0,0 +1,743 @@
+// 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.
+
+// The reflect package implements run-time reflection, allowing a program to
+// manipulate objects with arbitrary types. The typical use is to take a
+// value with static type interface{} and extract its dynamic type
+// information by calling Typeof, which returns an object with interface
+// type Type. That contains a pointer to a struct of type *StructType,
+// *IntType, etc. representing the details of the underlying type. A type
+// switch or type assertion can reveal which.
+//
+// A call to NewValue creates a Value representing the run-time data; it
+// contains a *StructValue, *IntValue, etc. MakeZero takes a Type and
+// returns a Value representing a zero value for that type.
+package reflect
+
+import (
+ "runtime"
+ "strconv"
+ "sync"
+ "unsafe"
+)
+
+/*
+ * Copy of data structures from ../runtime/type.go.
+ * For comments, see the ones in that file.
+ *
+ * These data structures are known to the compiler and the runtime.
+ *
+ * Putting these types in runtime instead of reflect means that
+ * reflect doesn't need to be autolinked into every binary, which
+ * simplifies bootstrapping and package dependencies.
+ * Unfortunately, it also means that reflect needs its own
+ * copy in order to access the private fields.
+ */
+
+// commonType is the common implementation of most values.
+// It is embedded in other, public struct types, but always
+// with a unique tag like "uint" or "float" so that the client cannot
+// convert from, say, *UintType to *FloatType.
+
+type commonType struct {
+ kind uint8
+ align int8
+ fieldAlign uint8
+ size uintptr
+ hash uint32
+ hashfn func(unsafe.Pointer, uintptr)
+ equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr)
+ string *string
+ *uncommonType
+}
+
+type method struct {
+ name *string
+ pkgPath *string
+ mtyp *runtime.Type
+ typ *runtime.Type
+ tfn unsafe.Pointer
+}
+
+type uncommonType struct {
+ name *string
+ pkgPath *string
+ methods []method
+}
+
+// BoolType represents a boolean type.
+type BoolType struct {
+ commonType "bool"
+}
+
+// FloatType represents a float type.
+type FloatType struct {
+ commonType "float"
+}
+
+// ComplexType represents a complex type.
+type ComplexType struct {
+ commonType "complex"
+}
+
+// IntType represents a signed integer type.
+type IntType struct {
+ commonType "int"
+}
+
+// UintType represents a uint type.
+type UintType struct {
+ commonType "uint"
+}
+
+// StringType represents a string type.
+type StringType struct {
+ commonType "string"
+}
+
+// UnsafePointerType represents an unsafe.Pointer type.
+type UnsafePointerType struct {
+ commonType "unsafe.Pointer"
+}
+
+// ArrayType represents a fixed array type.
+type ArrayType struct {
+ commonType "array"
+ elem *runtime.Type
+ len uintptr
+}
+
+// ChanDir represents a channel type's direction.
+type ChanDir int
+
+const (
+ RecvDir ChanDir = 1 << iota
+ SendDir
+ BothDir = RecvDir | SendDir
+)
+
+// ChanType represents a channel type.
+type ChanType struct {
+ commonType "chan"
+ elem *runtime.Type
+ dir uintptr
+}
+
+// FuncType represents a function type.
+type FuncType struct {
+ commonType "func"
+ dotdotdot bool
+ in []*runtime.Type
+ out []*runtime.Type
+}
+
+// Method on interface type
+type imethod struct {
+ name *string
+ pkgPath *string
+ typ *runtime.Type
+}
+
+// InterfaceType represents an interface type.
+type InterfaceType struct {
+ commonType "interface"
+ methods []imethod
+}
+
+// MapType represents a map type.
+type MapType struct {
+ commonType "map"
+ key *runtime.Type
+ elem *runtime.Type
+}
+
+// PtrType represents a pointer type.
+type PtrType struct {
+ commonType "ptr"
+ elem *runtime.Type
+}
+
+// SliceType represents a slice type.
+type SliceType struct {
+ commonType "slice"
+ elem *runtime.Type
+}
+
+// Struct field
+type structField struct {
+ name *string
+ pkgPath *string
+ typ *runtime.Type
+ tag *string
+ offset uintptr
+}
+
+// StructType represents a struct type.
+type StructType struct {
+ commonType "struct"
+ fields []structField
+}
+
+
+/*
+ * The compiler knows the exact layout of all the data structures above.
+ * The compiler does not know about the data structures and methods below.
+ */
+
+// Method represents a single method.
+type Method struct {
+ PkgPath string // empty for uppercase Name
+ Name string
+ Type *FuncType
+ Func *FuncValue
+}
+
+// Type is the runtime representation of a Go type.
+// Every type implements the methods listed here.
+// Some types implement additional interfaces;
+// use a type switch to find out what kind of type a Type is.
+// Each type in a program has a unique Type, so == on Types
+// corresponds to Go's type equality.
+type Type interface {
+ // PkgPath returns the type's package path.
+ // The package path is a full package import path like "container/vector".
+ // PkgPath returns an empty string for unnamed types.
+ PkgPath() string
+
+ // Name returns the type's name within its package.
+ // Name returns an empty string for unnamed types.
+ Name() string
+
+ // String returns a string representation of the type.
+ // The string representation may use shortened package names
+ // (e.g., vector instead of "container/vector") and is not
+ // guaranteed to be unique among types. To test for equality,
+ // compare the Types directly.
+ String() string
+
+ // Size returns the number of bytes needed to store
+ // a value of the given type; it is analogous to unsafe.Sizeof.
+ Size() uintptr
+
+ // Bits returns the size of the type in bits.
+ // It is intended for use with numeric types and may overflow
+ // when used for composite types.
+ Bits() int
+
+ // Align returns the alignment of a value of this type
+ // when allocated in memory.
+ Align() int
+
+ // FieldAlign returns the alignment of a value of this type
+ // when used as a field in a struct.
+ FieldAlign() int
+
+ // Kind returns the specific kind of this type.
+ Kind() Kind
+
+ // For non-interface types, Method returns the i'th method with receiver T.
+ // For interface types, Method returns the i'th method in the interface.
+ // NumMethod returns the number of such methods.
+ Method(int) Method
+ NumMethod() int
+ uncommon() *uncommonType
+}
+
+// A Kind represents the specific kind of type that a Type represents.
+// For numeric types, the Kind gives more information than the Type's
+// dynamic type. For example, the Type of a float32 is FloatType, but
+// the Kind is Float32.
+//
+// The zero Kind is not a valid kind.
+type Kind uint8
+
+const (
+ Bool Kind = 1 + iota
+ Int
+ Int8
+ Int16
+ Int32
+ Int64
+ Uint
+ Uint8
+ Uint16
+ Uint32
+ Uint64
+ Uintptr
+ Float32
+ Float64
+ Complex64
+ Complex128
+ Array
+ Chan
+ Func
+ Interface
+ Map
+ Ptr
+ Slice
+ String
+ Struct
+ UnsafePointer
+)
+
+// High bit says whether type has
+// embedded pointers,to help garbage collector.
+const kindMask = 0x7f
+
+func (k Kind) String() string {
+ if int(k) < len(kindNames) {
+ return kindNames[k]
+ }
+ return "kind" + strconv.Itoa(int(k))
+}
+
+var kindNames = []string{
+ Bool: "bool",
+ Int: "int",
+ Int8: "int8",
+ Int16: "int16",
+ Int32: "int32",
+ Int64: "int64",
+ Uint: "uint",
+ Uint8: "uint8",
+ Uint16: "uint16",
+ Uint32: "uint32",
+ Uint64: "uint64",
+ Uintptr: "uintptr",
+ Float32: "float32",
+ Float64: "float64",
+ Complex64: "complex64",
+ Complex128: "complex128",
+ Array: "array",
+ Chan: "chan",
+ Func: "func",
+ Interface: "interface",
+ Map: "map",
+ Ptr: "ptr",
+ Slice: "slice",
+ String: "string",
+ Struct: "struct",
+ UnsafePointer: "unsafe.Pointer",
+}
+
+func (t *uncommonType) uncommon() *uncommonType {
+ return t
+}
+
+func (t *uncommonType) PkgPath() string {
+ if t == nil || t.pkgPath == nil {
+ return ""
+ }
+ return *t.pkgPath
+}
+
+func (t *uncommonType) Name() string {
+ if t == nil || t.name == nil {
+ return ""
+ }
+ return *t.name
+}
+
+func (t *commonType) String() string { return *t.string }
+
+func (t *commonType) Size() uintptr { return t.size }
+
+func (t *commonType) Bits() int { return int(t.size * 8) }
+
+func (t *commonType) Align() int { return int(t.align) }
+
+func (t *commonType) FieldAlign() int { return int(t.fieldAlign) }
+
+func (t *commonType) Kind() Kind { return Kind(t.kind & kindMask) }
+
+func (t *uncommonType) Method(i int) (m Method) {
+ if t == nil || i < 0 || i >= len(t.methods) {
+ return
+ }
+ p := &t.methods[i]
+ if p.name != nil {
+ m.Name = *p.name
+ }
+ if p.pkgPath != nil {
+ m.PkgPath = *p.pkgPath
+ }
+ m.Type = runtimeToType(p.typ).(*FuncType)
+ fn := p.tfn
+ m.Func = &FuncValue{value: value{m.Type, addr(&fn), true}}
+ return
+}
+
+func (t *uncommonType) NumMethod() int {
+ if t == nil {
+ return 0
+ }
+ return len(t.methods)
+}
+
+// TODO(rsc): 6g supplies these, but they are not
+// as efficient as they could be: they have commonType
+// as the receiver instead of *commonType.
+func (t *commonType) NumMethod() int { return t.uncommonType.NumMethod() }
+
+func (t *commonType) Method(i int) (m Method) { return t.uncommonType.Method(i) }
+
+func (t *commonType) PkgPath() string { return t.uncommonType.PkgPath() }
+
+func (t *commonType) Name() string { return t.uncommonType.Name() }
+
+// Len returns the number of elements in the array.
+func (t *ArrayType) Len() int { return int(t.len) }
+
+// Elem returns the type of the array's elements.
+func (t *ArrayType) Elem() Type { return runtimeToType(t.elem) }
+
+// Dir returns the channel direction.
+func (t *ChanType) Dir() ChanDir { return ChanDir(t.dir) }
+
+// Elem returns the channel's element type.
+func (t *ChanType) Elem() Type { return runtimeToType(t.elem) }
+
+func (d ChanDir) String() string {
+ switch d {
+ case SendDir:
+ return "chan<-"
+ case RecvDir:
+ return "<-chan"
+ case BothDir:
+ return "chan"
+ }
+ return "ChanDir" + strconv.Itoa(int(d))
+}
+
+// In returns the type of the i'th function input parameter.
+func (t *FuncType) In(i int) Type {
+ if i < 0 || i >= len(t.in) {
+ return nil
+ }
+ return runtimeToType(t.in[i])
+}
+
+// DotDotDot returns true if the final function input parameter
+// is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the
+// parameter's underlying static type []T.
+//
+// For concreteness, if t is func(x int, y ... float), then
+//
+// t.NumIn() == 2
+// t.In(0) is the reflect.Type for "int"
+// t.In(1) is the reflect.Type for "[]float"
+// t.DotDotDot() == true
+//
+func (t *FuncType) DotDotDot() bool { return t.dotdotdot }
+
+// NumIn returns the number of input parameters.
+func (t *FuncType) NumIn() int { return len(t.in) }
+
+// Out returns the type of the i'th function output parameter.
+func (t *FuncType) Out(i int) Type {
+ if i < 0 || i >= len(t.out) {
+ return nil
+ }
+ return runtimeToType(t.out[i])
+}
+
+// NumOut returns the number of function output parameters.
+func (t *FuncType) NumOut() int { return len(t.out) }
+
+// Method returns the i'th interface method.
+func (t *InterfaceType) Method(i int) (m Method) {
+ if i < 0 || i >= len(t.methods) {
+ return
+ }
+ p := &t.methods[i]
+ m.Name = *p.name
+ if p.pkgPath != nil {
+ m.PkgPath = *p.pkgPath
+ }
+ m.Type = runtimeToType(p.typ).(*FuncType)
+ return
+}
+
+// NumMethod returns the number of interface methods.
+func (t *InterfaceType) NumMethod() int { return len(t.methods) }
+
+// Key returns the map key type.
+func (t *MapType) Key() Type { return runtimeToType(t.key) }
+
+// Elem returns the map element type.
+func (t *MapType) Elem() Type { return runtimeToType(t.elem) }
+
+// Elem returns the pointer element type.
+func (t *PtrType) Elem() Type { return runtimeToType(t.elem) }
+
+// Elem returns the type of the slice's elements.
+func (t *SliceType) Elem() Type { return runtimeToType(t.elem) }
+
+type StructField struct {
+ PkgPath string // empty for uppercase Name
+ Name string
+ Type Type
+ Tag string
+ Offset uintptr
+ Index []int
+ Anonymous bool
+}
+
+// Field returns the i'th struct field.
+func (t *StructType) Field(i int) (f StructField) {
+ if i < 0 || i >= len(t.fields) {
+ return
+ }
+ p := t.fields[i]
+ f.Type = runtimeToType(p.typ)
+ if p.name != nil {
+ f.Name = *p.name
+ } else {
+ t := f.Type
+ if pt, ok := t.(*PtrType); ok {
+ t = pt.Elem()
+ }
+ f.Name = t.Name()
+ f.Anonymous = true
+ }
+ if p.pkgPath != nil {
+ f.PkgPath = *p.pkgPath
+ }
+ if p.tag != nil {
+ f.Tag = *p.tag
+ }
+ f.Offset = p.offset
+ f.Index = []int{i}
+ return
+}
+
+// TODO(gri): Should there be an error/bool indicator if the index
+// is wrong for FieldByIndex?
+
+// FieldByIndex returns the nested field corresponding to index.
+func (t *StructType) FieldByIndex(index []int) (f StructField) {
+ for i, x := range index {
+ if i > 0 {
+ ft := f.Type
+ if pt, ok := ft.(*PtrType); ok {
+ ft = pt.Elem()
+ }
+ if st, ok := ft.(*StructType); ok {
+ t = st
+ } else {
+ var f0 StructField
+ f = f0
+ return
+ }
+ }
+ f = t.Field(x)
+ }
+ return
+}
+
+const inf = 1 << 30 // infinity - no struct has that many nesting levels
+
+func (t *StructType) fieldByNameFunc(match func(string) bool, mark map[*StructType]bool, depth int) (ff StructField, fd int) {
+ fd = inf // field depth
+
+ if mark[t] {
+ // Struct already seen.
+ return
+ }
+ mark[t] = true
+
+ var fi int // field index
+ n := 0 // number of matching fields at depth fd
+L:
+ for i := range t.fields {
+ f := t.Field(i)
+ d := inf
+ switch {
+ case match(f.Name):
+ // Matching top-level field.
+ d = depth
+ case f.Anonymous:
+ ft := f.Type
+ if pt, ok := ft.(*PtrType); ok {
+ ft = pt.Elem()
+ }
+ switch {
+ case match(ft.Name()):
+ // Matching anonymous top-level field.
+ d = depth
+ case fd > depth:
+ // No top-level field yet; look inside nested structs.
+ if st, ok := ft.(*StructType); ok {
+ f, d = st.fieldByNameFunc(match, mark, depth+1)
+ }
+ }
+ }
+
+ switch {
+ case d < fd:
+ // Found field at shallower depth.
+ ff, fi, fd = f, i, d
+ n = 1
+ case d == fd:
+ // More than one matching field at the same depth (or d, fd == inf).
+ // Same as no field found at this depth.
+ n++
+ if d == depth {
+ // Impossible to find a field at lower depth.
+ break L
+ }
+ }
+ }
+
+ if n == 1 {
+ // Found matching field.
+ if len(ff.Index) <= depth {
+ ff.Index = make([]int, depth+1)
+ }
+ ff.Index[depth] = fi
+ } else {
+ // None or more than one matching field found.
+ fd = inf
+ }
+
+ mark[t] = false, false
+ return
+}
+
+// FieldByName returns the struct field with the given name
+// and a boolean to indicate if the field was found.
+func (t *StructType) FieldByName(name string) (f StructField, present bool) {
+ return t.FieldByNameFunc(func(s string) bool { return s == name })
+}
+
+// FieldByNameFunc returns the struct field with a name that satisfies the
+// match function and a boolean to indicate if the field was found.
+func (t *StructType) FieldByNameFunc(match func(string) bool) (f StructField, present bool) {
+ if ff, fd := t.fieldByNameFunc(match, make(map[*StructType]bool), 0); fd < inf {
+ ff.Index = ff.Index[0 : fd+1]
+ f, present = ff, true
+ }
+ return
+}
+
+// NumField returns the number of struct fields.
+func (t *StructType) NumField() int { return len(t.fields) }
+
+// Canonicalize a Type.
+var canonicalType = make(map[string]Type)
+
+var canonicalTypeLock sync.Mutex
+
+func canonicalize(t Type) Type {
+ if t == nil {
+ return nil
+ }
+ u := t.uncommon()
+ var s string
+ if u == nil || u.PkgPath() == "" {
+ s = t.String()
+ } else {
+ s = u.PkgPath() + "." + u.Name()
+ }
+ canonicalTypeLock.Lock()
+ if r, ok := canonicalType[s]; ok {
+ canonicalTypeLock.Unlock()
+ return r
+ }
+ canonicalType[s] = t
+ canonicalTypeLock.Unlock()
+ return t
+}
+
+// Convert runtime type to reflect type.
+// Same memory layouts, different method sets.
+func toType(i interface{}) Type {
+ switch v := i.(type) {
+ case nil:
+ return nil
+ case *runtime.BoolType:
+ return (*BoolType)(unsafe.Pointer(v))
+ case *runtime.FloatType:
+ return (*FloatType)(unsafe.Pointer(v))
+ case *runtime.ComplexType:
+ return (*ComplexType)(unsafe.Pointer(v))
+ case *runtime.IntType:
+ return (*IntType)(unsafe.Pointer(v))
+ case *runtime.StringType:
+ return (*StringType)(unsafe.Pointer(v))
+ case *runtime.UintType:
+ return (*UintType)(unsafe.Pointer(v))
+ case *runtime.UnsafePointerType:
+ return (*UnsafePointerType)(unsafe.Pointer(v))
+ case *runtime.ArrayType:
+ return (*ArrayType)(unsafe.Pointer(v))
+ case *runtime.ChanType:
+ return (*ChanType)(unsafe.Pointer(v))
+ case *runtime.FuncType:
+ return (*FuncType)(unsafe.Pointer(v))
+ case *runtime.InterfaceType:
+ return (*InterfaceType)(unsafe.Pointer(v))
+ case *runtime.MapType:
+ return (*MapType)(unsafe.Pointer(v))
+ case *runtime.PtrType:
+ return (*PtrType)(unsafe.Pointer(v))
+ case *runtime.SliceType:
+ return (*SliceType)(unsafe.Pointer(v))
+ case *runtime.StructType:
+ return (*StructType)(unsafe.Pointer(v))
+ }
+ println(i)
+ panic("toType")
+}
+
+// Convert pointer to runtime Type structure to our Type structure.
+func runtimeToType(v *runtime.Type) Type {
+ var r Type
+ switch Kind(v.Kind) {
+ case Bool:
+ r = (*BoolType)(unsafe.Pointer(v))
+ case Int, Int8, Int16, Int32, Int64:
+ r = (*IntType)(unsafe.Pointer(v))
+ case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
+ r = (*UintType)(unsafe.Pointer(v))
+ case Float32, Float64:
+ r = (*FloatType)(unsafe.Pointer(v))
+ case Complex64, Complex128:
+ r = (*ComplexType)(unsafe.Pointer(v))
+ case Array:
+ r = (*ArrayType)(unsafe.Pointer(v))
+ case Chan:
+ r = (*ChanType)(unsafe.Pointer(v))
+ case Func:
+ r = (*FuncType)(unsafe.Pointer(v))
+ case Interface:
+ r = (*InterfaceType)(unsafe.Pointer(v))
+ case Map:
+ r = (*MapType)(unsafe.Pointer(v))
+ case Ptr:
+ r = (*PtrType)(unsafe.Pointer(v))
+ case Slice:
+ r = (*SliceType)(unsafe.Pointer(v))
+ case String:
+ r = (*StringType)(unsafe.Pointer(v))
+ case Struct:
+ r = (*StructType)(unsafe.Pointer(v))
+ case UnsafePointer:
+ r = (*UnsafePointerType)(unsafe.Pointer(v))
+ default:
+ panic("runtimeToType")
+ }
+ return canonicalize(r)
+ panic("runtimeToType")
+}
+
+// ArrayOrSliceType is the common interface implemented
+// by both ArrayType and SliceType.
+type ArrayOrSliceType interface {
+ Type
+ Elem() Type
+}
+
+// Typeof returns the reflection Type of the value in the interface{}.
+func Typeof(i interface{}) Type { return canonicalize(toType(unsafe.Typeof(i))) }
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
new file mode 100644
index 000000000..8ef402bbc
--- /dev/null
+++ b/libgo/go/reflect/value.go
@@ -0,0 +1,1242 @@
+// 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 reflect
+
+import (
+ "math"
+ "runtime"
+ "unsafe"
+)
+
+const ptrSize = uintptr(unsafe.Sizeof((*byte)(nil)))
+const cannotSet = "cannot set value obtained via unexported struct field"
+
+type addr unsafe.Pointer
+
+// TODO: This will have to go away when
+// the new gc goes in.
+func memmove(adst, asrc addr, n uintptr) {
+ dst := uintptr(adst)
+ src := uintptr(asrc)
+ switch {
+ case src < dst && src+n > dst:
+ // byte copy backward
+ // careful: i is unsigned
+ for i := n; i > 0; {
+ i--
+ *(*byte)(addr(dst + i)) = *(*byte)(addr(src + i))
+ }
+ case (n|src|dst)&(ptrSize-1) != 0:
+ // byte copy forward
+ for i := uintptr(0); i < n; i++ {
+ *(*byte)(addr(dst + i)) = *(*byte)(addr(src + i))
+ }
+ default:
+ // word copy forward
+ for i := uintptr(0); i < n; i += ptrSize {
+ *(*uintptr)(addr(dst + i)) = *(*uintptr)(addr(src + i))
+ }
+ }
+}
+
+// Value is the common interface to reflection values.
+// The implementations of Value (e.g., ArrayValue, StructValue)
+// have additional type-specific methods.
+type Value interface {
+ // Type returns the value's type.
+ Type() Type
+
+ // Interface returns the value as an interface{}.
+ Interface() interface{}
+
+ // CanSet returns whether the value can be changed.
+ // Values obtained by the use of non-exported struct fields
+ // can be used in Get but not Set.
+ // If CanSet() returns false, calling the type-specific Set
+ // will cause a crash.
+ CanSet() bool
+
+ // SetValue assigns v to the value; v must have the same type as the value.
+ SetValue(v Value)
+
+ // Addr returns a pointer to the underlying data.
+ // It is for advanced clients that also
+ // import the "unsafe" package.
+ Addr() uintptr
+
+ // Method returns a FuncValue corresponding to the value's i'th method.
+ // The arguments to a Call on the returned FuncValue
+ // should not include a receiver; the FuncValue will use
+ // the value as the receiver.
+ Method(i int) *FuncValue
+
+ getAddr() addr
+}
+
+// value is the common implementation of most values.
+// It is embedded in other, public struct types, but always
+// with a unique tag like "uint" or "float" so that the client cannot
+// convert from, say, *UintValue to *FloatValue.
+type value struct {
+ typ Type
+ addr addr
+ canSet bool
+}
+
+func (v *value) Type() Type { return v.typ }
+
+func (v *value) Addr() uintptr { return uintptr(v.addr) }
+
+func (v *value) getAddr() addr { return v.addr }
+
+func (v *value) Interface() interface{} {
+ if typ, ok := v.typ.(*InterfaceType); ok {
+ // There are two different representations of interface values,
+ // one if the interface type has methods and one if it doesn't.
+ // These two representations require different expressions
+ // to extract correctly.
+ if typ.NumMethod() == 0 {
+ // Extract as interface value without methods.
+ return *(*interface{})(v.addr)
+ }
+ // Extract from v.addr as interface value with methods.
+ return *(*interface {
+ m()
+ })(v.addr)
+ }
+ return unsafe.Unreflect(v.typ, unsafe.Pointer(v.addr))
+}
+
+func (v *value) CanSet() bool { return v.canSet }
+
+/*
+ * basic types
+ */
+
+// BoolValue represents a bool value.
+type BoolValue struct {
+ value "bool"
+}
+
+// Get returns the underlying bool value.
+func (v *BoolValue) Get() bool { return *(*bool)(v.addr) }
+
+// Set sets v to the value x.
+func (v *BoolValue) Set(x bool) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ *(*bool)(v.addr) = x
+}
+
+// Set sets v to the value x.
+func (v *BoolValue) SetValue(x Value) { v.Set(x.(*BoolValue).Get()) }
+
+// FloatValue represents a float value.
+type FloatValue struct {
+ value "float"
+}
+
+// Get returns the underlying int value.
+func (v *FloatValue) Get() float64 {
+ switch v.typ.Kind() {
+ case Float32:
+ return float64(*(*float32)(v.addr))
+ case Float64:
+ return *(*float64)(v.addr)
+ }
+ panic("reflect: invalid float kind")
+}
+
+// Set sets v to the value x.
+func (v *FloatValue) Set(x float64) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ switch v.typ.Kind() {
+ default:
+ panic("reflect: invalid float kind")
+ case Float32:
+ *(*float32)(v.addr) = float32(x)
+ case Float64:
+ *(*float64)(v.addr) = x
+ }
+}
+
+// Overflow returns true if x cannot be represented by the type of v.
+func (v *FloatValue) Overflow(x float64) bool {
+ if v.typ.Size() == 8 {
+ return false
+ }
+ if x < 0 {
+ x = -x
+ }
+ return math.MaxFloat32 < x && x <= math.MaxFloat64
+}
+
+// Set sets v to the value x.
+func (v *FloatValue) SetValue(x Value) { v.Set(x.(*FloatValue).Get()) }
+
+// ComplexValue represents a complex value.
+type ComplexValue struct {
+ value "complex"
+}
+
+// Get returns the underlying complex value.
+func (v *ComplexValue) Get() complex128 {
+ switch v.typ.Kind() {
+ case Complex64:
+ return complex128(*(*complex64)(v.addr))
+ case Complex128:
+ return *(*complex128)(v.addr)
+ }
+ panic("reflect: invalid complex kind")
+}
+
+// Set sets v to the value x.
+func (v *ComplexValue) Set(x complex128) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ switch v.typ.Kind() {
+ default:
+ panic("reflect: invalid complex kind")
+ case Complex64:
+ *(*complex64)(v.addr) = complex64(x)
+ case Complex128:
+ *(*complex128)(v.addr) = x
+ }
+}
+
+// Set sets v to the value x.
+func (v *ComplexValue) SetValue(x Value) { v.Set(x.(*ComplexValue).Get()) }
+
+// IntValue represents an int value.
+type IntValue struct {
+ value "int"
+}
+
+// Get returns the underlying int value.
+func (v *IntValue) Get() int64 {
+ switch v.typ.Kind() {
+ case Int:
+ return int64(*(*int)(v.addr))
+ case Int8:
+ return int64(*(*int8)(v.addr))
+ case Int16:
+ return int64(*(*int16)(v.addr))
+ case Int32:
+ return int64(*(*int32)(v.addr))
+ case Int64:
+ return *(*int64)(v.addr)
+ }
+ panic("reflect: invalid int kind")
+}
+
+// Set sets v to the value x.
+func (v *IntValue) Set(x int64) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ switch v.typ.Kind() {
+ default:
+ panic("reflect: invalid int kind")
+ case Int:
+ *(*int)(v.addr) = int(x)
+ case Int8:
+ *(*int8)(v.addr) = int8(x)
+ case Int16:
+ *(*int16)(v.addr) = int16(x)
+ case Int32:
+ *(*int32)(v.addr) = int32(x)
+ case Int64:
+ *(*int64)(v.addr) = x
+ }
+}
+
+// Set sets v to the value x.
+func (v *IntValue) SetValue(x Value) { v.Set(x.(*IntValue).Get()) }
+
+// Overflow returns true if x cannot be represented by the type of v.
+func (v *IntValue) Overflow(x int64) bool {
+ bitSize := uint(v.typ.Bits())
+ trunc := (x << (64 - bitSize)) >> (64 - bitSize)
+ return x != trunc
+}
+
+// StringHeader is the runtime representation of a string.
+type StringHeader struct {
+ Data uintptr
+ Len int
+}
+
+// StringValue represents a string value.
+type StringValue struct {
+ value "string"
+}
+
+// Get returns the underlying string value.
+func (v *StringValue) Get() string { return *(*string)(v.addr) }
+
+// Set sets v to the value x.
+func (v *StringValue) Set(x string) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ *(*string)(v.addr) = x
+}
+
+// Set sets v to the value x.
+func (v *StringValue) SetValue(x Value) { v.Set(x.(*StringValue).Get()) }
+
+// UintValue represents a uint value.
+type UintValue struct {
+ value "uint"
+}
+
+// Get returns the underlying uuint value.
+func (v *UintValue) Get() uint64 {
+ switch v.typ.Kind() {
+ case Uint:
+ return uint64(*(*uint)(v.addr))
+ case Uint8:
+ return uint64(*(*uint8)(v.addr))
+ case Uint16:
+ return uint64(*(*uint16)(v.addr))
+ case Uint32:
+ return uint64(*(*uint32)(v.addr))
+ case Uint64:
+ return *(*uint64)(v.addr)
+ case Uintptr:
+ return uint64(*(*uintptr)(v.addr))
+ }
+ panic("reflect: invalid uint kind")
+}
+
+// Set sets v to the value x.
+func (v *UintValue) Set(x uint64) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ switch v.typ.Kind() {
+ default:
+ panic("reflect: invalid uint kind")
+ case Uint:
+ *(*uint)(v.addr) = uint(x)
+ case Uint8:
+ *(*uint8)(v.addr) = uint8(x)
+ case Uint16:
+ *(*uint16)(v.addr) = uint16(x)
+ case Uint32:
+ *(*uint32)(v.addr) = uint32(x)
+ case Uint64:
+ *(*uint64)(v.addr) = x
+ case Uintptr:
+ *(*uintptr)(v.addr) = uintptr(x)
+ }
+}
+
+// Overflow returns true if x cannot be represented by the type of v.
+func (v *UintValue) Overflow(x uint64) bool {
+ bitSize := uint(v.typ.Bits())
+ trunc := (x << (64 - bitSize)) >> (64 - bitSize)
+ return x != trunc
+}
+
+// Set sets v to the value x.
+func (v *UintValue) SetValue(x Value) { v.Set(x.(*UintValue).Get()) }
+
+// UnsafePointerValue represents an unsafe.Pointer value.
+type UnsafePointerValue struct {
+ value "unsafe.Pointer"
+}
+
+// Get returns the underlying uintptr value.
+// Get returns uintptr, not unsafe.Pointer, so that
+// programs that do not import "unsafe" cannot
+// obtain a value of unsafe.Pointer type from "reflect".
+func (v *UnsafePointerValue) Get() uintptr { return uintptr(*(*unsafe.Pointer)(v.addr)) }
+
+// Set sets v to the value x.
+func (v *UnsafePointerValue) Set(x unsafe.Pointer) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ *(*unsafe.Pointer)(v.addr) = x
+}
+
+// Set sets v to the value x.
+func (v *UnsafePointerValue) SetValue(x Value) {
+ v.Set(unsafe.Pointer(x.(*UnsafePointerValue).Get()))
+}
+
+func typesMustMatch(t1, t2 Type) {
+ if t1 != t2 {
+ panic("type mismatch: " + t1.String() + " != " + t2.String())
+ }
+}
+
+/*
+ * array
+ */
+
+// ArrayOrSliceValue is the common interface
+// implemented by both ArrayValue and SliceValue.
+type ArrayOrSliceValue interface {
+ Value
+ Len() int
+ Cap() int
+ Elem(i int) Value
+ addr() addr
+}
+
+// grow grows the slice s so that it can hold extra more values, allocating
+// more capacity if needed. It also returns the old and new slice lengths.
+func grow(s *SliceValue, extra int) (*SliceValue, int, int) {
+ i0 := s.Len()
+ i1 := i0 + extra
+ if i1 < i0 {
+ panic("append: slice overflow")
+ }
+ m := s.Cap()
+ if i1 <= m {
+ return s.Slice(0, i1), i0, i1
+ }
+ if m == 0 {
+ m = extra
+ } else {
+ for m < i1 {
+ if i0 < 1024 {
+ m += m
+ } else {
+ m += m / 4
+ }
+ }
+ }
+ t := MakeSlice(s.Type().(*SliceType), i1, m)
+ Copy(t, s)
+ return t, i0, i1
+}
+
+// Append appends the values x to a slice s and returns the resulting slice.
+// Each x must have the same type as s' element type.
+func Append(s *SliceValue, x ...Value) *SliceValue {
+ s, i0, i1 := grow(s, len(x))
+ for i, j := i0, 0; i < i1; i, j = i+1, j+1 {
+ s.Elem(i).SetValue(x[j])
+ }
+ return s
+}
+
+// AppendSlice appends a slice t to a slice s and returns the resulting slice.
+// The slices s and t must have the same element type.
+func AppendSlice(s, t *SliceValue) *SliceValue {
+ s, i0, i1 := grow(s, t.Len())
+ Copy(s.Slice(i0, i1), t)
+ return s
+}
+
+// Copy copies the contents of src into dst until either
+// dst has been filled or src has been exhausted.
+// It returns the number of elements copied.
+// The arrays dst and src must have the same element type.
+func Copy(dst, src ArrayOrSliceValue) int {
+ // TODO: This will have to move into the runtime
+ // once the real gc goes in.
+ de := dst.Type().(ArrayOrSliceType).Elem()
+ se := src.Type().(ArrayOrSliceType).Elem()
+ typesMustMatch(de, se)
+ n := dst.Len()
+ if xn := src.Len(); n > xn {
+ n = xn
+ }
+ memmove(dst.addr(), src.addr(), uintptr(n)*de.Size())
+ return n
+}
+
+// An ArrayValue represents an array.
+type ArrayValue struct {
+ value "array"
+}
+
+// Len returns the length of the array.
+func (v *ArrayValue) Len() int { return v.typ.(*ArrayType).Len() }
+
+// Cap returns the capacity of the array (equal to Len()).
+func (v *ArrayValue) Cap() int { return v.typ.(*ArrayType).Len() }
+
+// addr returns the base address of the data in the array.
+func (v *ArrayValue) addr() addr { return v.value.addr }
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *ArrayValue) Set(x *ArrayValue) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ typesMustMatch(v.typ, x.typ)
+ Copy(v, x)
+}
+
+// Set sets v to the value x.
+func (v *ArrayValue) SetValue(x Value) { v.Set(x.(*ArrayValue)) }
+
+// Elem returns the i'th element of v.
+func (v *ArrayValue) Elem(i int) Value {
+ typ := v.typ.(*ArrayType).Elem()
+ n := v.Len()
+ if i < 0 || i >= n {
+ panic("array index out of bounds")
+ }
+ p := addr(uintptr(v.addr()) + uintptr(i)*typ.Size())
+ return newValue(typ, p, v.canSet)
+}
+
+/*
+ * slice
+ */
+
+// runtime representation of slice
+type SliceHeader struct {
+ Data uintptr
+ Len int
+ Cap int
+}
+
+// A SliceValue represents a slice.
+type SliceValue struct {
+ value "slice"
+}
+
+func (v *SliceValue) slice() *SliceHeader { return (*SliceHeader)(v.value.addr) }
+
+// IsNil returns whether v is a nil slice.
+func (v *SliceValue) IsNil() bool { return v.slice().Data == 0 }
+
+// Len returns the length of the slice.
+func (v *SliceValue) Len() int { return int(v.slice().Len) }
+
+// Cap returns the capacity of the slice.
+func (v *SliceValue) Cap() int { return int(v.slice().Cap) }
+
+// addr returns the base address of the data in the slice.
+func (v *SliceValue) addr() addr { return addr(v.slice().Data) }
+
+// SetLen changes the length of v.
+// The new length n must be between 0 and the capacity, inclusive.
+func (v *SliceValue) SetLen(n int) {
+ s := v.slice()
+ if n < 0 || n > int(s.Cap) {
+ panic("reflect: slice length out of range in SetLen")
+ }
+ s.Len = n
+}
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *SliceValue) Set(x *SliceValue) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ typesMustMatch(v.typ, x.typ)
+ *v.slice() = *x.slice()
+}
+
+// Set sets v to the value x.
+func (v *SliceValue) SetValue(x Value) { v.Set(x.(*SliceValue)) }
+
+// Get returns the uintptr address of the v.Cap()'th element. This gives
+// the same result for all slices of the same array.
+// It is mainly useful for printing.
+func (v *SliceValue) Get() uintptr {
+ typ := v.typ.(*SliceType)
+ return uintptr(v.addr()) + uintptr(v.Cap())*typ.Elem().Size()
+}
+
+// Slice returns a sub-slice of the slice v.
+func (v *SliceValue) Slice(beg, end int) *SliceValue {
+ cap := v.Cap()
+ if beg < 0 || end < beg || end > cap {
+ panic("slice index out of bounds")
+ }
+ typ := v.typ.(*SliceType)
+ s := new(SliceHeader)
+ s.Data = uintptr(v.addr()) + uintptr(beg)*typ.Elem().Size()
+ s.Len = end - beg
+ s.Cap = cap - beg
+ return newValue(typ, addr(s), v.canSet).(*SliceValue)
+}
+
+// Elem returns the i'th element of v.
+func (v *SliceValue) Elem(i int) Value {
+ typ := v.typ.(*SliceType).Elem()
+ n := v.Len()
+ if i < 0 || i >= n {
+ panic("reflect: slice index out of range")
+ }
+ p := addr(uintptr(v.addr()) + uintptr(i)*typ.Size())
+ return newValue(typ, p, v.canSet)
+}
+
+// MakeSlice creates a new zero-initialized slice value
+// for the specified slice type, length, and capacity.
+func MakeSlice(typ *SliceType, len, cap int) *SliceValue {
+ s := &SliceHeader{
+ Data: uintptr(unsafe.NewArray(typ.Elem(), cap)),
+ Len: len,
+ Cap: cap,
+ }
+ return newValue(typ, addr(s), true).(*SliceValue)
+}
+
+/*
+ * chan
+ */
+
+// A ChanValue represents a chan.
+type ChanValue struct {
+ value "chan"
+}
+
+// IsNil returns whether v is a nil channel.
+func (v *ChanValue) IsNil() bool { return *(*uintptr)(v.addr) == 0 }
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *ChanValue) Set(x *ChanValue) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ typesMustMatch(v.typ, x.typ)
+ *(*uintptr)(v.addr) = *(*uintptr)(x.addr)
+}
+
+// Set sets v to the value x.
+func (v *ChanValue) SetValue(x Value) { v.Set(x.(*ChanValue)) }
+
+// Get returns the uintptr value of v.
+// It is mainly useful for printing.
+func (v *ChanValue) Get() uintptr { return *(*uintptr)(v.addr) }
+
+// implemented in ../pkg/runtime/reflect.cgo
+func makechan(typ *runtime.ChanType, size uint32) (ch *byte)
+func chansend(ch, val *byte, pres *bool)
+func chanrecv(ch, val *byte, pres *bool)
+func chanclosed(ch *byte) bool
+func chanclose(ch *byte)
+func chanlen(ch *byte) int32
+func chancap(ch *byte) int32
+
+// Closed returns the result of closed(c) on the underlying channel.
+func (v *ChanValue) Closed() bool {
+ ch := *(**byte)(v.addr)
+ return chanclosed(ch)
+}
+
+// Close closes the channel.
+func (v *ChanValue) Close() {
+ ch := *(**byte)(v.addr)
+ chanclose(ch)
+}
+
+func (v *ChanValue) Len() int {
+ ch := *(**byte)(v.addr)
+ return int(chanlen(ch))
+}
+
+func (v *ChanValue) Cap() int {
+ ch := *(**byte)(v.addr)
+ return int(chancap(ch))
+}
+
+// internal send; non-blocking if b != nil
+func (v *ChanValue) send(x Value, b *bool) {
+ t := v.Type().(*ChanType)
+ if t.Dir()&SendDir == 0 {
+ panic("send on recv-only channel")
+ }
+ typesMustMatch(t.Elem(), x.Type())
+ ch := *(**byte)(v.addr)
+ chansend(ch, (*byte)(x.getAddr()), b)
+}
+
+// internal recv; non-blocking if b != nil
+func (v *ChanValue) recv(b *bool) Value {
+ t := v.Type().(*ChanType)
+ if t.Dir()&RecvDir == 0 {
+ panic("recv on send-only channel")
+ }
+ ch := *(**byte)(v.addr)
+ x := MakeZero(t.Elem())
+ chanrecv(ch, (*byte)(x.getAddr()), b)
+ return x
+}
+
+// Send sends x on the channel v.
+func (v *ChanValue) Send(x Value) { v.send(x, nil) }
+
+// Recv receives and returns a value from the channel v.
+func (v *ChanValue) Recv() Value { return v.recv(nil) }
+
+// TrySend attempts to sends x on the channel v but will not block.
+// It returns true if the value was sent, false otherwise.
+func (v *ChanValue) TrySend(x Value) bool {
+ var ok bool
+ v.send(x, &ok)
+ return ok
+}
+
+// TryRecv attempts to receive a value from the channel v but will not block.
+// It returns the value if one is received, nil otherwise.
+func (v *ChanValue) TryRecv() Value {
+ var ok bool
+ x := v.recv(&ok)
+ if !ok {
+ return nil
+ }
+ return x
+}
+
+// MakeChan creates a new channel with the specified type and buffer size.
+func MakeChan(typ *ChanType, buffer int) *ChanValue {
+ if buffer < 0 {
+ panic("MakeChan: negative buffer size")
+ }
+ if typ.Dir() != BothDir {
+ panic("MakeChan: unidirectional channel type")
+ }
+ v := MakeZero(typ).(*ChanValue)
+ *(**byte)(v.addr) = makechan((*runtime.ChanType)(unsafe.Pointer(typ)), uint32(buffer))
+ return v
+}
+
+/*
+ * func
+ */
+
+// A FuncValue represents a function value.
+type FuncValue struct {
+ value "func"
+ first *value
+ isInterface bool
+}
+
+// IsNil returns whether v is a nil function.
+func (v *FuncValue) IsNil() bool { return *(*uintptr)(v.addr) == 0 }
+
+// Get returns the uintptr value of v.
+// It is mainly useful for printing.
+func (v *FuncValue) Get() uintptr { return *(*uintptr)(v.addr) }
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *FuncValue) Set(x *FuncValue) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ typesMustMatch(v.typ, x.typ)
+ *(*uintptr)(v.addr) = *(*uintptr)(x.addr)
+}
+
+// Set sets v to the value x.
+func (v *FuncValue) SetValue(x Value) { v.Set(x.(*FuncValue)) }
+
+// Method returns a FuncValue corresponding to v's i'th method.
+// The arguments to a Call on the returned FuncValue
+// should not include a receiver; the FuncValue will use v
+// as the receiver.
+func (v *value) Method(i int) *FuncValue {
+ t := v.Type().uncommon()
+ if t == nil || i < 0 || i >= len(t.methods) {
+ return nil
+ }
+ p := &t.methods[i]
+ fn := p.tfn
+ fv := &FuncValue{value: value{runtimeToType(p.typ), addr(&fn), true}, first: v, isInterface: false}
+ return fv
+}
+
+// implemented in ../pkg/runtime/*/asm.s
+func call(typ *FuncType, fnaddr *byte, isInterface bool, params *addr, results *addr)
+
+// Call calls the function fv with input parameters in.
+// It returns the function's output parameters as Values.
+func (fv *FuncValue) Call(in []Value) []Value {
+ t := fv.Type().(*FuncType)
+ nin := len(in)
+ if fv.first != nil && !fv.isInterface {
+ nin++
+ }
+ if nin != t.NumIn() {
+ panic("FuncValue: wrong argument count")
+ }
+ if fv.first != nil && fv.isInterface {
+ nin++
+ }
+ nout := t.NumOut()
+
+ params := make([]addr, nin)
+ delta := 0
+ off := 0
+ if v := fv.first; v != nil {
+ // Hard-wired first argument.
+ if fv.isInterface {
+ // v is a single uninterpreted word
+ params[0] = v.getAddr()
+ } else {
+ // v is a real value
+ tv := v.Type()
+
+ // This is a method, so we need to always pass
+ // a pointer.
+ vAddr := v.getAddr()
+ if ptv, ok := tv.(*PtrType); ok {
+ typesMustMatch(t.In(0), tv)
+ } else {
+ p := addr(new(addr))
+ *(*addr)(p) = vAddr
+ vAddr = p
+ typesMustMatch(t.In(0).(*PtrType).Elem(), tv)
+ }
+
+ params[0] = vAddr
+ delta = 1
+ }
+ off = 1
+ }
+ for i, v := range in {
+ tv := v.Type()
+ tf := t.In(i + delta)
+
+ // If this is really a method, and we are explicitly
+ // passing the object, then we need to pass the address
+ // of the object instead. Unfortunately, we don't
+ // have any way to know that this is a method, so we just
+ // check the type. FIXME: This is ugly.
+ vAddr := v.getAddr()
+ if i == 0 && tf != tv {
+ if ptf, ok := tf.(*PtrType); ok {
+ p := addr(new(addr))
+ *(*addr)(p) = vAddr
+ vAddr = p
+ tf = ptf.Elem()
+ }
+ }
+
+ typesMustMatch(tf, tv)
+ params[i+off] = vAddr
+ }
+
+ ret := make([]Value, nout)
+ results := make([]addr, nout)
+ for i := 0; i < nout; i++ {
+ tv := t.Out(i)
+ v := MakeZero(tv)
+ results[i] = v.getAddr()
+ ret[i] = v
+ }
+
+ call(t, *(**byte)(fv.addr), fv.isInterface, &params[0], &results[0])
+
+ return ret
+}
+
+/*
+ * interface
+ */
+
+// An InterfaceValue represents an interface value.
+type InterfaceValue struct {
+ value "interface"
+}
+
+// IsNil returns whether v is a nil interface value.
+func (v *InterfaceValue) IsNil() bool { return v.Interface() == nil }
+
+// No single uinptr Get because v.Interface() is available.
+
+// Get returns the two words that represent an interface in the runtime.
+// Those words are useful only when playing unsafe games.
+func (v *InterfaceValue) Get() [2]uintptr {
+ return *(*[2]uintptr)(v.addr)
+}
+
+// Elem returns the concrete value stored in the interface value v.
+func (v *InterfaceValue) Elem() Value { return NewValue(v.Interface()) }
+
+// ../runtime/reflect.cgo
+func setiface(typ *InterfaceType, x *interface{}, addr addr)
+
+// Set assigns x to v.
+func (v *InterfaceValue) Set(x Value) {
+ var i interface{}
+ if x != nil {
+ i = x.Interface()
+ }
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ // Two different representations; see comment in Get.
+ // Empty interface is easy.
+ t := v.typ.(*InterfaceType)
+ if t.NumMethod() == 0 {
+ *(*interface{})(v.addr) = i
+ return
+ }
+
+ // Non-empty interface requires a runtime check.
+ setiface(t, &i, v.addr)
+}
+
+// Set sets v to the value x.
+func (v *InterfaceValue) SetValue(x Value) { v.Set(x) }
+
+// Method returns a FuncValue corresponding to v's i'th method.
+// The arguments to a Call on the returned FuncValue
+// should not include a receiver; the FuncValue will use v
+// as the receiver.
+func (v *InterfaceValue) Method(i int) *FuncValue {
+ t := v.Type().(*InterfaceType)
+ if t == nil || i < 0 || i >= len(t.methods) {
+ return nil
+ }
+ p := &t.methods[i]
+
+ // Interface is two words: itable, data.
+ tab := *(**[10000]addr)(v.addr)
+ data := &value{Typeof((*byte)(nil)), addr(uintptr(v.addr) + ptrSize), true}
+
+ fn := tab[i+1]
+ fv := &FuncValue{value: value{runtimeToType(p.typ), addr(&fn), true}, first: data, isInterface: true}
+ return fv
+}
+
+/*
+ * map
+ */
+
+// A MapValue represents a map value.
+type MapValue struct {
+ value "map"
+}
+
+// IsNil returns whether v is a nil map value.
+func (v *MapValue) IsNil() bool { return *(*uintptr)(v.addr) == 0 }
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *MapValue) Set(x *MapValue) {
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ if x == nil {
+ *(**uintptr)(v.addr) = nil
+ return
+ }
+ typesMustMatch(v.typ, x.typ)
+ *(*uintptr)(v.addr) = *(*uintptr)(x.addr)
+}
+
+// Set sets v to the value x.
+func (v *MapValue) SetValue(x Value) {
+ if x == nil {
+ v.Set(nil)
+ return
+ }
+ v.Set(x.(*MapValue))
+}
+
+// Get returns the uintptr value of v.
+// It is mainly useful for printing.
+func (v *MapValue) Get() uintptr { return *(*uintptr)(v.addr) }
+
+// implemented in ../pkg/runtime/reflect.cgo
+func mapaccess(m, key, val *byte) bool
+func mapassign(m, key, val *byte)
+func maplen(m *byte) int32
+func mapiterinit(m *byte) *byte
+func mapiternext(it *byte)
+func mapiterkey(it *byte, key *byte) bool
+func makemap(t *runtime.MapType) *byte
+
+// Elem returns the value associated with key in the map v.
+// It returns nil if key is not found in the map.
+func (v *MapValue) Elem(key Value) Value {
+ t := v.Type().(*MapType)
+ typesMustMatch(t.Key(), key.Type())
+ m := *(**byte)(v.addr)
+ if m == nil {
+ return nil
+ }
+ newval := MakeZero(t.Elem())
+ if !mapaccess(m, (*byte)(key.getAddr()), (*byte)(newval.getAddr())) {
+ return nil
+ }
+ return newval
+}
+
+// SetElem sets the value associated with key in the map v to val.
+// If val is nil, Put deletes the key from map.
+func (v *MapValue) SetElem(key, val Value) {
+ t := v.Type().(*MapType)
+ typesMustMatch(t.Key(), key.Type())
+ var vaddr *byte
+ if val != nil {
+ typesMustMatch(t.Elem(), val.Type())
+ vaddr = (*byte)(val.getAddr())
+ }
+ m := *(**byte)(v.addr)
+ mapassign(m, (*byte)(key.getAddr()), vaddr)
+}
+
+// Len returns the number of keys in the map v.
+func (v *MapValue) Len() int {
+ m := *(**byte)(v.addr)
+ if m == nil {
+ return 0
+ }
+ return int(maplen(m))
+}
+
+// Keys returns a slice containing all the keys present in the map,
+// in unspecified order.
+func (v *MapValue) Keys() []Value {
+ tk := v.Type().(*MapType).Key()
+ m := *(**byte)(v.addr)
+ mlen := int32(0)
+ if m != nil {
+ mlen = maplen(m)
+ }
+ it := mapiterinit(m)
+ a := make([]Value, mlen)
+ var i int
+ for i = 0; i < len(a); i++ {
+ k := MakeZero(tk)
+ if !mapiterkey(it, (*byte)(k.getAddr())) {
+ break
+ }
+ a[i] = k
+ mapiternext(it)
+ }
+ return a[0:i]
+}
+
+// MakeMap creates a new map of the specified type.
+func MakeMap(typ *MapType) *MapValue {
+ v := MakeZero(typ).(*MapValue)
+ *(**byte)(v.addr) = makemap((*runtime.MapType)(unsafe.Pointer(typ)))
+ return v
+}
+
+/*
+ * ptr
+ */
+
+// A PtrValue represents a pointer.
+type PtrValue struct {
+ value "ptr"
+}
+
+// IsNil returns whether v is a nil pointer.
+func (v *PtrValue) IsNil() bool { return *(*uintptr)(v.addr) == 0 }
+
+// Get returns the uintptr value of v.
+// It is mainly useful for printing.
+func (v *PtrValue) Get() uintptr { return *(*uintptr)(v.addr) }
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *PtrValue) Set(x *PtrValue) {
+ if x == nil {
+ *(**uintptr)(v.addr) = nil
+ return
+ }
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ typesMustMatch(v.typ, x.typ)
+ // TODO: This will have to move into the runtime
+ // once the new gc goes in
+ *(*uintptr)(v.addr) = *(*uintptr)(x.addr)
+}
+
+// Set sets v to the value x.
+func (v *PtrValue) SetValue(x Value) {
+ if x == nil {
+ v.Set(nil)
+ return
+ }
+ v.Set(x.(*PtrValue))
+}
+
+// PointTo changes v to point to x.
+// If x is a nil Value, PointTo sets v to nil.
+func (v *PtrValue) PointTo(x Value) {
+ if x == nil {
+ *(**uintptr)(v.addr) = nil
+ return
+ }
+ if !x.CanSet() {
+ panic("cannot set x; cannot point to x")
+ }
+ typesMustMatch(v.typ.(*PtrType).Elem(), x.Type())
+ // TODO: This will have to move into the runtime
+ // once the new gc goes in.
+ *(*uintptr)(v.addr) = x.Addr()
+}
+
+// Elem returns the value that v points to.
+// If v is a nil pointer, Elem returns a nil Value.
+func (v *PtrValue) Elem() Value {
+ if v.IsNil() {
+ return nil
+ }
+ return newValue(v.typ.(*PtrType).Elem(), *(*addr)(v.addr), v.canSet)
+}
+
+// Indirect returns the value that v points to.
+// If v is a nil pointer, Indirect returns a nil Value.
+// If v is not a pointer, Indirect returns v.
+func Indirect(v Value) Value {
+ if pv, ok := v.(*PtrValue); ok {
+ return pv.Elem()
+ }
+ return v
+}
+
+/*
+ * struct
+ */
+
+// A StructValue represents a struct value.
+type StructValue struct {
+ value "struct"
+}
+
+// Set assigns x to v.
+// The new value x must have the same type as v.
+func (v *StructValue) Set(x *StructValue) {
+ // TODO: This will have to move into the runtime
+ // once the gc goes in.
+ if !v.canSet {
+ panic(cannotSet)
+ }
+ typesMustMatch(v.typ, x.typ)
+ memmove(v.addr, x.addr, v.typ.Size())
+}
+
+// Set sets v to the value x.
+func (v *StructValue) SetValue(x Value) { v.Set(x.(*StructValue)) }
+
+// Field returns the i'th field of the struct.
+func (v *StructValue) Field(i int) Value {
+ t := v.typ.(*StructType)
+ if i < 0 || i >= t.NumField() {
+ return nil
+ }
+ f := t.Field(i)
+ return newValue(f.Type, addr(uintptr(v.addr)+f.Offset), v.canSet && f.PkgPath == "")
+}
+
+// FieldByIndex returns the nested field corresponding to index.
+func (t *StructValue) FieldByIndex(index []int) (v Value) {
+ v = t
+ for i, x := range index {
+ if i > 0 {
+ if p, ok := v.(*PtrValue); ok {
+ v = p.Elem()
+ }
+ if s, ok := v.(*StructValue); ok {
+ t = s
+ } else {
+ v = nil
+ return
+ }
+ }
+ v = t.Field(x)
+ }
+ return
+}
+
+// FieldByName returns the struct field with the given name.
+// The result is nil if no field was found.
+func (t *StructValue) FieldByName(name string) Value {
+ if f, ok := t.Type().(*StructType).FieldByName(name); ok {
+ return t.FieldByIndex(f.Index)
+ }
+ return nil
+}
+
+// FieldByNameFunc returns the struct field with a name that satisfies the
+// match function.
+// The result is nil if no field was found.
+func (t *StructValue) FieldByNameFunc(match func(string) bool) Value {
+ if f, ok := t.Type().(*StructType).FieldByNameFunc(match); ok {
+ return t.FieldByIndex(f.Index)
+ }
+ return nil
+}
+
+// NumField returns the number of fields in the struct.
+func (v *StructValue) NumField() int { return v.typ.(*StructType).NumField() }
+
+/*
+ * constructors
+ */
+
+// NewValue returns a new Value initialized to the concrete value
+// stored in the interface i. NewValue(nil) returns nil.
+func NewValue(i interface{}) Value {
+ if i == nil {
+ return nil
+ }
+ t, a := unsafe.Reflect(i)
+ return newValue(canonicalize(toType(t)), addr(a), true)
+}
+
+func newValue(typ Type, addr addr, canSet bool) Value {
+ v := value{typ, addr, canSet}
+ switch typ.(type) {
+ case *ArrayType:
+ return &ArrayValue{v}
+ case *BoolType:
+ return &BoolValue{v}
+ case *ChanType:
+ return &ChanValue{v}
+ case *FloatType:
+ return &FloatValue{v}
+ case *FuncType:
+ return &FuncValue{value: v}
+ case *ComplexType:
+ return &ComplexValue{v}
+ case *IntType:
+ return &IntValue{v}
+ case *InterfaceType:
+ return &InterfaceValue{v}
+ case *MapType:
+ return &MapValue{v}
+ case *PtrType:
+ return &PtrValue{v}
+ case *SliceType:
+ return &SliceValue{v}
+ case *StringType:
+ return &StringValue{v}
+ case *StructType:
+ return &StructValue{v}
+ case *UintType:
+ return &UintValue{v}
+ case *UnsafePointerType:
+ return &UnsafePointerValue{v}
+ }
+ panic("newValue" + typ.String())
+}
+
+// MakeZero returns a zero Value for the specified Type.
+func MakeZero(typ Type) Value {
+ if typ == nil {
+ return nil
+ }
+ return newValue(typ, addr(unsafe.New(typ)), true)
+}
diff --git a/libgo/go/regexp/all_test.go b/libgo/go/regexp/all_test.go
new file mode 100644
index 000000000..aed733064
--- /dev/null
+++ b/libgo/go/regexp/all_test.go
@@ -0,0 +1,426 @@
+// 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 regexp
+
+import (
+ "os"
+ "strings"
+ "testing"
+)
+
+var good_re = []string{
+ ``,
+ `.`,
+ `^.$`,
+ `a`,
+ `a*`,
+ `a+`,
+ `a?`,
+ `a|b`,
+ `a*|b*`,
+ `(a*|b)(c*|d)`,
+ `[a-z]`,
+ `[a-abc-c\-\]\[]`,
+ `[a-z]+`,
+ `[]`,
+ `[abc]`,
+ `[^1234]`,
+ `[^\n]`,
+ `\!\\`,
+}
+
+type stringError struct {
+ re string
+ err os.Error
+}
+
+var bad_re = []stringError{
+ {`*`, ErrBareClosure},
+ {`+`, ErrBareClosure},
+ {`?`, ErrBareClosure},
+ {`(abc`, ErrUnmatchedLpar},
+ {`abc)`, ErrUnmatchedRpar},
+ {`x[a-z`, ErrUnmatchedLbkt},
+ {`abc]`, ErrUnmatchedRbkt},
+ {`[z-a]`, ErrBadRange},
+ {`abc\`, ErrExtraneousBackslash},
+ {`a**`, ErrBadClosure},
+ {`a*+`, ErrBadClosure},
+ {`a??`, ErrBadClosure},
+ {`\x`, ErrBadBackslash},
+}
+
+func compileTest(t *testing.T, expr string, error os.Error) *Regexp {
+ re, err := Compile(expr)
+ if err != error {
+ t.Error("compiling `", expr, "`; unexpected error: ", err.String())
+ }
+ return re
+}
+
+func TestGoodCompile(t *testing.T) {
+ for i := 0; i < len(good_re); i++ {
+ compileTest(t, good_re[i], nil)
+ }
+}
+
+func TestBadCompile(t *testing.T) {
+ for i := 0; i < len(bad_re); i++ {
+ compileTest(t, bad_re[i].re, bad_re[i].err)
+ }
+}
+
+func matchTest(t *testing.T, test *FindTest) {
+ re := compileTest(t, test.pat, nil)
+ if re == nil {
+ return
+ }
+ m := re.MatchString(test.text)
+ if m != (len(test.matches) > 0) {
+ t.Errorf("MatchString failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+ }
+ // now try bytes
+ m = re.Match([]byte(test.text))
+ if m != (len(test.matches) > 0) {
+ t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+ }
+}
+
+func TestMatch(t *testing.T) {
+ for _, test := range findTests {
+ matchTest(t, &test)
+ }
+}
+
+func matchFunctionTest(t *testing.T, test *FindTest) {
+ m, err := MatchString(test.pat, test.text)
+ if err == nil {
+ return
+ }
+ if m != (len(test.matches) > 0) {
+ t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
+ }
+}
+
+func TestMatchFunction(t *testing.T) {
+ for _, test := range findTests {
+ matchFunctionTest(t, &test)
+ }
+}
+
+type ReplaceTest struct {
+ pattern, replacement, input, output string
+}
+
+var replaceTests = []ReplaceTest{
+ // Test empty input and/or replacement, with pattern that matches the empty string.
+ {"", "", "", ""},
+ {"", "x", "", "x"},
+ {"", "", "abc", "abc"},
+ {"", "x", "abc", "xaxbxcx"},
+
+ // Test empty input and/or replacement, with pattern that does not match the empty string.
+ {"b", "", "", ""},
+ {"b", "x", "", ""},
+ {"b", "", "abc", "ac"},
+ {"b", "x", "abc", "axc"},
+ {"y", "", "", ""},
+ {"y", "x", "", ""},
+ {"y", "", "abc", "abc"},
+ {"y", "x", "abc", "abc"},
+
+ // Multibyte characters -- verify that we don't try to match in the middle
+ // of a character.
+ {"[a-c]*", "x", "\u65e5", "x\u65e5x"},
+ {"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
+
+ // Start and end of a string.
+ {"^[a-c]*", "x", "abcdabc", "xdabc"},
+ {"[a-c]*$", "x", "abcdabc", "abcdx"},
+ {"^[a-c]*$", "x", "abcdabc", "abcdabc"},
+ {"^[a-c]*", "x", "abc", "x"},
+ {"[a-c]*$", "x", "abc", "x"},
+ {"^[a-c]*$", "x", "abc", "x"},
+ {"^[a-c]*", "x", "dabce", "xdabce"},
+ {"[a-c]*$", "x", "dabce", "dabcex"},
+ {"^[a-c]*$", "x", "dabce", "dabce"},
+ {"^[a-c]*", "x", "", "x"},
+ {"[a-c]*$", "x", "", "x"},
+ {"^[a-c]*$", "x", "", "x"},
+
+ {"^[a-c]+", "x", "abcdabc", "xdabc"},
+ {"[a-c]+$", "x", "abcdabc", "abcdx"},
+ {"^[a-c]+$", "x", "abcdabc", "abcdabc"},
+ {"^[a-c]+", "x", "abc", "x"},
+ {"[a-c]+$", "x", "abc", "x"},
+ {"^[a-c]+$", "x", "abc", "x"},
+ {"^[a-c]+", "x", "dabce", "dabce"},
+ {"[a-c]+$", "x", "dabce", "dabce"},
+ {"^[a-c]+$", "x", "dabce", "dabce"},
+ {"^[a-c]+", "x", "", ""},
+ {"[a-c]+$", "x", "", ""},
+ {"^[a-c]+$", "x", "", ""},
+
+ // Other cases.
+ {"abc", "def", "abcdefg", "defdefg"},
+ {"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"},
+ {"abc", "", "abcdabc", "d"},
+ {"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"},
+ {"abc", "d", "", ""},
+ {"abc", "d", "abc", "d"},
+ {".+", "x", "abc", "x"},
+ {"[a-c]*", "x", "def", "xdxexfx"},
+ {"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
+ {"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
+}
+
+type ReplaceFuncTest struct {
+ pattern string
+ replacement func(string) string
+ input, output string
+}
+
+var replaceFuncTests = []ReplaceFuncTest{
+ {"[a-c]", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxayxbyxcydef"},
+ {"[a-c]+", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxabcydef"},
+ {"[a-c]*", func(s string) string { return "x" + s + "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"},
+}
+
+func TestReplaceAll(t *testing.T) {
+ for _, tc := range replaceTests {
+ re, err := Compile(tc.pattern)
+ if err != nil {
+ t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+ continue
+ }
+ actual := re.ReplaceAllString(tc.input, tc.replacement)
+ if actual != tc.output {
+ t.Errorf("%q.Replace(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ // now try bytes
+ actual = string(re.ReplaceAll([]byte(tc.input), []byte(tc.replacement)))
+ if actual != tc.output {
+ t.Errorf("%q.Replace(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ }
+}
+
+func TestReplaceAllFunc(t *testing.T) {
+ for _, tc := range replaceFuncTests {
+ re, err := Compile(tc.pattern)
+ if err != nil {
+ t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+ continue
+ }
+ actual := re.ReplaceAllStringFunc(tc.input, tc.replacement)
+ if actual != tc.output {
+ t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ // now try bytes
+ actual = string(re.ReplaceAllFunc([]byte(tc.input), func(s []byte) []byte { return []byte(tc.replacement(string(s))) }))
+ if actual != tc.output {
+ t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ }
+}
+
+type MetaTest struct {
+ pattern, output, literal string
+ isLiteral bool
+}
+
+var metaTests = []MetaTest{
+ {``, ``, ``, true},
+ {`foo`, `foo`, `foo`, true},
+ {`foo\.\$`, `foo\\\.\\\$`, `foo.$`, true}, // has meta but no operator
+ {`foo.\$`, `foo\.\\\$`, `foo`, false}, // has escaped operators and real operators
+ {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[{\]}\\\|,<\.>/\?~`, `!@#`, false},
+}
+
+func TestQuoteMeta(t *testing.T) {
+ for _, tc := range metaTests {
+ // Verify that QuoteMeta returns the expected string.
+ quoted := QuoteMeta(tc.pattern)
+ if quoted != tc.output {
+ t.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`",
+ tc.pattern, quoted, tc.output)
+ continue
+ }
+
+ // Verify that the quoted string is in fact treated as expected
+ // by Compile -- i.e. that it matches the original, unquoted string.
+ if tc.pattern != "" {
+ re, err := Compile(quoted)
+ if err != nil {
+ t.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc.pattern, err)
+ continue
+ }
+ src := "abc" + tc.pattern + "def"
+ repl := "xyz"
+ replaced := re.ReplaceAllString(src, repl)
+ expected := "abcxyzdef"
+ if replaced != expected {
+ t.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`",
+ tc.pattern, src, repl, replaced, expected)
+ }
+ }
+ }
+}
+
+func TestLiteralPrefix(t *testing.T) {
+ for _, tc := range metaTests {
+ // Literal method needs to scan the pattern.
+ re := MustCompile(tc.pattern)
+ str, complete := re.LiteralPrefix()
+ if complete != tc.isLiteral {
+ t.Errorf("LiteralPrefix(`%s`) = %t; want %t", tc.pattern, complete, tc.isLiteral)
+ }
+ if str != tc.literal {
+ t.Errorf("LiteralPrefix(`%s`) = `%s`; want `%s`", tc.pattern, str, tc.literal)
+ }
+ }
+}
+
+type numSubexpCase struct {
+ input string
+ expected int
+}
+
+var numSubexpCases = []numSubexpCase{
+ {``, 0},
+ {`.*`, 0},
+ {`abba`, 0},
+ {`ab(b)a`, 1},
+ {`ab(.*)a`, 1},
+ {`(.*)ab(.*)a`, 2},
+ {`(.*)(ab)(.*)a`, 3},
+ {`(.*)((a)b)(.*)a`, 4},
+ {`(.*)(\(ab)(.*)a`, 3},
+ {`(.*)(\(a\)b)(.*)a`, 3},
+}
+
+func TestNumSubexp(t *testing.T) {
+ for _, c := range numSubexpCases {
+ re := MustCompile(c.input)
+ n := re.NumSubexp()
+ if n != c.expected {
+ t.Errorf("NumSubexp for %q returned %d, expected %d", c.input, n, c.expected)
+ }
+ }
+}
+
+func BenchmarkLiteral(b *testing.B) {
+ x := strings.Repeat("x", 50)
+ b.StopTimer()
+ re := MustCompile(x)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkNotLiteral(b *testing.B) {
+ x := strings.Repeat("x", 49)
+ b.StopTimer()
+ re := MustCompile("^" + x)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkMatchClass(b *testing.B) {
+ b.StopTimer()
+ x := strings.Repeat("xxxx", 20) + "w"
+ re := MustCompile("[abcdw]")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkMatchClass_InRange(b *testing.B) {
+ b.StopTimer()
+ // 'b' is betwen 'a' and 'c', so the charclass
+ // range checking is no help here.
+ x := strings.Repeat("bbbb", 20) + "c"
+ re := MustCompile("[ac]")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if !re.MatchString(x) {
+ println("no match!")
+ break
+ }
+ }
+}
+
+func BenchmarkReplaceAll(b *testing.B) {
+ x := "abcdefghijklmnopqrstuvwxyz"
+ b.StopTimer()
+ re := MustCompile("[cjrw]")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.ReplaceAllString(x, "")
+ }
+}
+
+func BenchmarkAnchoredLiteralShortNonMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ re := MustCompile("^zbc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkAnchoredLiteralLongNonMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ for i := 0; i < 15; i++ {
+ x = append(x, x...)
+ }
+ re := MustCompile("^zbc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkAnchoredShortMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ re := MustCompile("^.bc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
+
+func BenchmarkAnchoredLongMatch(b *testing.B) {
+ b.StopTimer()
+ x := []byte("abcdefghijklmnopqrstuvwxyz")
+ for i := 0; i < 15; i++ {
+ x = append(x, x...)
+ }
+ re := MustCompile("^.bc(d|e)")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ re.Match(x)
+ }
+}
diff --git a/libgo/go/regexp/find_test.go b/libgo/go/regexp/find_test.go
new file mode 100644
index 000000000..1690711dd
--- /dev/null
+++ b/libgo/go/regexp/find_test.go
@@ -0,0 +1,459 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package regexp
+
+import (
+ "fmt"
+ "testing"
+)
+
+// For each pattern/text pair, what is the expected output of each function?
+// We can derive the textual results from the indexed results, the non-submatch
+// results from the submatched results, the single results from the 'all' results,
+// and the byte results from the string results. Therefore the table includes
+// only the FindAllStringSubmatchIndex result.
+type FindTest struct {
+ pat string
+ text string
+ matches [][]int
+}
+
+func (t FindTest) String() string {
+ return fmt.Sprintf("pat: %#q text: %#q", t.pat, t.text)
+}
+
+var findTests = []FindTest{
+ {``, ``, build(1, 0, 0)},
+ {`^abcdefg`, "abcdefg", build(1, 0, 7)},
+ {`a+`, "baaab", build(1, 1, 4)},
+ {"abcd..", "abcdef", build(1, 0, 6)},
+ {`a`, "a", build(1, 0, 1)},
+ {`x`, "y", nil},
+ {`b`, "abc", build(1, 1, 2)},
+ {`.`, "a", build(1, 0, 1)},
+ {`.*`, "abcdef", build(1, 0, 6)},
+ {`^`, "abcde", build(1, 0, 0)},
+ {`$`, "abcde", build(1, 5, 5)},
+ {`^abcd$`, "abcd", build(1, 0, 4)},
+ {`^bcd'`, "abcdef", nil},
+ {`^abcd$`, "abcde", nil},
+ {`a+`, "baaab", build(1, 1, 4)},
+ {`a*`, "baaab", build(3, 0, 0, 1, 4, 5, 5)},
+ {`[a-z]+`, "abcd", build(1, 0, 4)},
+ {`[^a-z]+`, "ab1234cd", build(1, 2, 6)},
+ {`[a\-\]z]+`, "az]-bcz", build(2, 0, 4, 6, 7)},
+ {`[^\n]+`, "abcd\n", build(1, 0, 4)},
+ {`[日本語]+`, "日本語日本語", build(1, 0, 18)},
+ {`日本語+`, "日本語", build(1, 0, 9)},
+ {`日本語+`, "日本語語語語", build(1, 0, 18)},
+ {`()`, "", build(1, 0, 0, 0, 0)},
+ {`(a)`, "a", build(1, 0, 1, 0, 1)},
+ {`(.)(.)`, "日a", build(1, 0, 4, 0, 3, 3, 4)},
+ {`(.*)`, "", build(1, 0, 0, 0, 0)},
+ {`(.*)`, "abcd", build(1, 0, 4, 0, 4)},
+ {`(..)(..)`, "abcd", build(1, 0, 4, 0, 2, 2, 4)},
+ {`(([^xyz]*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 3, 4)},
+ {`((a|b|c)*(d))`, "abcd", build(1, 0, 4, 0, 4, 2, 3, 3, 4)},
+ {`(((a|b|c)*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 2, 3, 3, 4)},
+ {`\a\b\f\n\r\t\v`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
+ {`[\a\b\f\n\r\t\v]+`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
+
+ {`a*(|(b))c*`, "aacc", build(1, 0, 4, 2, 2, -1, -1)},
+ {`(.*).*`, "ab", build(1, 0, 2, 0, 2)},
+ {`[.]`, ".", build(1, 0, 1)},
+ {`/$`, "/abc/", build(1, 4, 5)},
+ {`/$`, "/abc", nil},
+
+ // multiple matches
+ {`.`, "abc", build(3, 0, 1, 1, 2, 2, 3)},
+ {`(.)`, "abc", build(3, 0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3)},
+ {`.(.)`, "abcd", build(2, 0, 2, 1, 2, 2, 4, 3, 4)},
+ {`ab*`, "abbaab", build(3, 0, 3, 3, 4, 4, 6)},
+ {`a(b*)`, "abbaab", build(3, 0, 3, 1, 3, 3, 4, 4, 4, 4, 6, 5, 6)},
+
+ // fixed bugs
+ {`ab$`, "cab", build(1, 1, 3)},
+ {`axxb$`, "axxcb", nil},
+ {`data`, "daXY data", build(1, 5, 9)},
+ {`da(.)a$`, "daXY data", build(1, 5, 9, 7, 8)},
+ {`zx+`, "zzx", build(1, 1, 3)},
+
+ // can backslash-escape any punctuation
+ {`\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~`,
+ `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
+ {`[\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~]+`,
+ `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
+ {"\\`", "`", build(1, 0, 1)},
+ {"[\\`]+", "`", build(1, 0, 1)},
+
+ // long set of matches (longer than startSize)
+ {
+ ".",
+ "qwertyuiopasdfghjklzxcvbnm1234567890",
+ build(36, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
+ 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20,
+ 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30,
+ 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36),
+ },
+}
+
+// build is a helper to construct a [][]int by extracting n sequences from x.
+// This represents n matches with len(x)/n submatches each.
+func build(n int, x ...int) [][]int {
+ ret := make([][]int, n)
+ runLength := len(x) / n
+ j := 0
+ for i := range ret {
+ ret[i] = make([]int, runLength)
+ copy(ret[i], x[j:])
+ j += runLength
+ if j > len(x) {
+ panic("invalid build entry")
+ }
+ }
+ return ret
+}
+
+// First the simple cases.
+
+func TestFind(t *testing.T) {
+ for _, test := range findTests {
+ re := MustCompile(test.pat)
+ if re.String() != test.pat {
+ t.Errorf("String() = `%s`; should be `%s`", re.String(), test.pat)
+ }
+ result := re.Find([]byte(test.text))
+ switch {
+ case len(test.matches) == 0 && len(result) == 0:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ expect := test.text[test.matches[0][0]:test.matches[0][1]]
+ if expect != string(result) {
+ t.Errorf("expected %q got %q: %s", expect, result, test)
+ }
+ }
+ }
+}
+
+func TestFindString(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindString(test.text)
+ switch {
+ case len(test.matches) == 0 && len(result) == 0:
+ // ok
+ case test.matches == nil && result != "":
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == "":
+ // Tricky because an empty result has two meanings: no match or empty match.
+ if test.matches[0][0] != test.matches[0][1] {
+ t.Errorf("expected match; got none: %s", test)
+ }
+ case test.matches != nil && result != "":
+ expect := test.text[test.matches[0][0]:test.matches[0][1]]
+ if expect != result {
+ t.Errorf("expected %q got %q: %s", expect, result, test)
+ }
+ }
+ }
+}
+
+func testFindIndex(test *FindTest, result []int, t *testing.T) {
+ switch {
+ case len(test.matches) == 0 && len(result) == 0:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ expect := test.matches[0]
+ if expect[0] != result[0] || expect[1] != result[1] {
+ t.Errorf("expected %v got %v: %s", expect, result, test)
+ }
+ }
+}
+
+func TestFindIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindIndex(&test, MustCompile(test.pat).FindIndex([]byte(test.text)), t)
+ }
+}
+
+func TestFindStringIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindIndex(&test, MustCompile(test.pat).FindStringIndex(test.text), t)
+ }
+}
+
+// Now come the simple All cases.
+
+func TestFindAll(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAll([]byte(test.text), -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ if len(test.matches) != len(result) {
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ continue
+ }
+ for k, e := range test.matches {
+ expect := test.text[e[0]:e[1]]
+ if expect != string(result[k]) {
+ t.Errorf("match %d: expected %q got %q: %s", k, expect, result[k], test)
+ }
+ }
+ }
+ }
+}
+
+func TestFindAllString(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAllString(test.text, -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ if len(test.matches) != len(result) {
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ continue
+ }
+ for k, e := range test.matches {
+ expect := test.text[e[0]:e[1]]
+ if expect != result[k] {
+ t.Errorf("expected %q got %q: %s", expect, result, test)
+ }
+ }
+ }
+ }
+}
+
+func testFindAllIndex(test *FindTest, result [][]int, t *testing.T) {
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ if len(test.matches) != len(result) {
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ return
+ }
+ for k, e := range test.matches {
+ if e[0] != result[k][0] || e[1] != result[k][1] {
+ t.Errorf("match %d: expected %v got %v: %s", k, e, result[k], test)
+ }
+ }
+ }
+}
+
+func TestFindAllIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllIndex(&test, MustCompile(test.pat).FindAllIndex([]byte(test.text), -1), t)
+ }
+}
+
+func TestFindAllStringIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllIndex(&test, MustCompile(test.pat).FindAllStringIndex(test.text, -1), t)
+ }
+}
+
+// Now come the Submatch cases.
+
+func testSubmatchBytes(test *FindTest, n int, submatches []int, result [][]byte, t *testing.T) {
+ if len(submatches) != len(result)*2 {
+ t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
+ return
+ }
+ for k := 0; k < len(submatches); k += 2 {
+ if submatches[k] == -1 {
+ if result[k/2] != nil {
+ t.Errorf("match %d: expected nil got %q: %s", n, result, test)
+ }
+ continue
+ }
+ expect := test.text[submatches[k]:submatches[k+1]]
+ if expect != string(result[k/2]) {
+ t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
+ return
+ }
+ }
+}
+
+func TestFindSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindSubmatch([]byte(test.text))
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ testSubmatchBytes(&test, 0, test.matches[0], result, t)
+ }
+ }
+}
+
+func testSubmatchString(test *FindTest, n int, submatches []int, result []string, t *testing.T) {
+ if len(submatches) != len(result)*2 {
+ t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
+ return
+ }
+ for k := 0; k < len(submatches); k += 2 {
+ if submatches[k] == -1 {
+ if result[k/2] != "" {
+ t.Errorf("match %d: expected nil got %q: %s", n, result, test)
+ }
+ continue
+ }
+ expect := test.text[submatches[k]:submatches[k+1]]
+ if expect != result[k/2] {
+ t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
+ return
+ }
+ }
+}
+
+func TestFindStringSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindStringSubmatch(test.text)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ testSubmatchString(&test, 0, test.matches[0], result, t)
+ }
+ }
+}
+
+func testSubmatchIndices(test *FindTest, n int, expect, result []int, t *testing.T) {
+ if len(expect) != len(result) {
+ t.Errorf("match %d: expected %d matches; got %d: %s", n, len(expect)/2, len(result)/2, test)
+ return
+ }
+ for k, e := range expect {
+ if e != result[k] {
+ t.Errorf("match %d: submatch error: expected %v got %v: %s", n, expect, result, test)
+ }
+ }
+}
+
+func testFindSubmatchIndex(test *FindTest, result []int, t *testing.T) {
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ testSubmatchIndices(test, 0, test.matches[0], result, t)
+ }
+}
+
+func TestFindSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindSubmatchIndex(&test, MustCompile(test.pat).FindSubmatchIndex([]byte(test.text)), t)
+ }
+}
+
+func TestFindStringSubmatchndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindSubmatchIndex(&test, MustCompile(test.pat).FindStringSubmatchIndex(test.text), t)
+ }
+}
+
+// Now come the monster AllSubmatch cases.
+
+func TestFindAllSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAllSubmatch([]byte(test.text), -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchBytes(&test, k, match, result[k], t)
+ }
+ }
+ }
+}
+
+func TestFindAllStringSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAllStringSubmatch(test.text, -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchString(&test, k, match, result[k], t)
+ }
+ }
+ }
+}
+
+func testFindAllSubmatchIndex(test *FindTest, result [][]int, t *testing.T) {
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchIndices(test, k, match, result[k], t)
+ }
+ }
+}
+
+func TestFindAllSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllSubmatchIndex([]byte(test.text), -1), t)
+ }
+}
+
+func TestFindAllStringSubmatchndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllStringSubmatchIndex(test.text, -1), t)
+ }
+}
diff --git a/libgo/go/regexp/regexp.go b/libgo/go/regexp/regexp.go
new file mode 100644
index 000000000..d274ccdf5
--- /dev/null
+++ b/libgo/go/regexp/regexp.go
@@ -0,0 +1,1337 @@
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package regexp implements a simple regular expression library.
+//
+// The syntax of the regular expressions accepted is:
+//
+// regexp:
+// concatenation { '|' concatenation }
+// concatenation:
+// { closure }
+// closure:
+// term [ '*' | '+' | '?' ]
+// term:
+// '^'
+// '$'
+// '.'
+// character
+// '[' [ '^' ] { character-range } ']'
+// '(' regexp ')'
+// character-range:
+// character [ '-' character ]
+//
+// All characters are UTF-8-encoded code points. Backslashes escape special
+// characters, including inside character classes. The standard Go character
+// escapes are also recognized: \a \b \f \n \r \t \v.
+//
+// There are 16 methods of Regexp that match a regular expression and identify
+// the matched text. Their names are matched by this regular expression:
+//
+// Find(All)?(String)?(Submatch)?(Index)?
+//
+// If 'All' is present, the routine matches successive non-overlapping
+// matches of the entire expression. Empty matches abutting a preceding
+// match are ignored. The return value is a slice containing the successive
+// return values of the corresponding non-'All' routine. These routines take
+// an extra integer argument, n; if n >= 0, the function returns at most n
+// matches/submatches.
+//
+// If 'String' is present, the argument is a string; otherwise it is a slice
+// of bytes; return values are adjusted as appropriate.
+//
+// If 'Submatch' is present, the return value is a slice identifying the
+// successive submatches of the expression. Submatches are matches of
+// parenthesized subexpressions within the regular expression, numbered from
+// left to right in order of opening parenthesis. Submatch 0 is the match of
+// the entire expression, submatch 1 the match of the first parenthesized
+// subexpression, and so on.
+//
+// If 'Index' is present, matches and submatches are identified by byte index
+// pairs within the input string: result[2*n:2*n+1] identifies the indexes of
+// the nth submatch. The pair for n==0 identifies the match of the entire
+// expression. If 'Index' is not present, the match is identified by the
+// text of the match/submatch. If an index is negative, it means that
+// subexpression did not match any string in the input.
+//
+// (There are a few other methods that do not match this pattern.)
+//
+package regexp
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strings"
+ "utf8"
+)
+
+var debug = false
+
+// Error is the local type for a parsing error.
+type Error string
+
+func (e Error) String() string {
+ return string(e)
+}
+
+// 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")
+)
+
+const (
+ iStart = iota // beginning of program
+ iEnd // end of program: success
+ iBOT // '^' beginning of text
+ iEOT // '$' end of text
+ iChar // 'a' regular character
+ iCharClass // [a-z] character class
+ iAny // '.' any character including newline
+ iNotNL // [^\n] special case: any character but newline
+ iBra // '(' parenthesized expression: 2*braNum for left, 2*braNum+1 for right
+ iAlt // '|' alternation
+ iNop // do nothing; makes it easy to link without patching
+)
+
+// An instruction executed by the NFA
+type instr struct {
+ kind int // the type of this instruction: iChar, iAny, etc.
+ index int // used only in debugging; could be eliminated
+ next *instr // the instruction to execute after this one
+ // Special fields valid only for some items.
+ char int // iChar
+ braNum int // iBra, iEbra
+ cclass *charClass // iCharClass
+ left *instr // iAlt, other branch
+}
+
+func (i *instr) print() {
+ switch i.kind {
+ case iStart:
+ print("start")
+ case iEnd:
+ print("end")
+ case iBOT:
+ print("bot")
+ case iEOT:
+ print("eot")
+ case iChar:
+ print("char ", string(i.char))
+ case iCharClass:
+ i.cclass.print()
+ case iAny:
+ print("any")
+ case iNotNL:
+ print("notnl")
+ case iBra:
+ if i.braNum&1 == 0 {
+ print("bra", i.braNum/2)
+ } else {
+ print("ebra", i.braNum/2)
+ }
+ case iAlt:
+ print("alt(", i.left.index, ")")
+ case iNop:
+ print("nop")
+ }
+}
+
+// Regexp is the representation of a compiled regular expression.
+// The public interface is entirely through methods.
+type Regexp struct {
+ expr string // the original expression
+ prefix string // initial plain text string
+ prefixBytes []byte // initial plain text bytes
+ inst []*instr
+ start *instr // first instruction of machine
+ prefixStart *instr // where to start if there is a prefix
+ nbra int // number of brackets in expression, for subexpressions
+}
+
+type charClass struct {
+ negate bool // is character class negated? ([^a-z])
+ // slice of int, stored pairwise: [a-z] is (a,z); x is (x,x):
+ ranges []int
+ cmin, cmax int
+}
+
+func (cclass *charClass) print() {
+ print("charclass")
+ if cclass.negate {
+ print(" (negated)")
+ }
+ for i := 0; i < len(cclass.ranges); i += 2 {
+ l := cclass.ranges[i]
+ r := cclass.ranges[i+1]
+ if l == r {
+ print(" [", string(l), "]")
+ } else {
+ print(" [", string(l), "-", string(r), "]")
+ }
+ }
+}
+
+func (cclass *charClass) addRange(a, b int) {
+ // range is a through b inclusive
+ cclass.ranges = append(cclass.ranges, a, b)
+ if a < cclass.cmin {
+ cclass.cmin = a
+ }
+ if b > cclass.cmax {
+ cclass.cmax = b
+ }
+}
+
+func (cclass *charClass) matches(c int) bool {
+ if c < cclass.cmin || c > cclass.cmax {
+ return cclass.negate
+ }
+ ranges := cclass.ranges
+ for i := 0; i < len(ranges); i = i + 2 {
+ if ranges[i] <= c && c <= ranges[i+1] {
+ return !cclass.negate
+ }
+ }
+ return cclass.negate
+}
+
+func newCharClass() *instr {
+ i := &instr{kind: iCharClass}
+ i.cclass = new(charClass)
+ i.cclass.ranges = make([]int, 0, 4)
+ i.cclass.cmin = 0x10FFFF + 1 // MaxRune + 1
+ i.cclass.cmax = -1
+ return i
+}
+
+func (re *Regexp) add(i *instr) *instr {
+ i.index = len(re.inst)
+ re.inst = append(re.inst, i)
+ return i
+}
+
+type parser struct {
+ re *Regexp
+ nlpar int // number of unclosed lpars
+ pos int
+ ch int
+}
+
+func (p *parser) error(err Error) {
+ panic(err)
+}
+
+const endOfFile = -1
+
+func (p *parser) c() int { return p.ch }
+
+func (p *parser) nextc() int {
+ if p.pos >= len(p.re.expr) {
+ p.ch = endOfFile
+ } else {
+ c, w := utf8.DecodeRuneInString(p.re.expr[p.pos:])
+ p.ch = c
+ p.pos += w
+ }
+ return p.ch
+}
+
+func newParser(re *Regexp) *parser {
+ p := new(parser)
+ p.re = re
+ p.nextc() // load p.ch
+ return p
+}
+
+func special(c int) bool {
+ for _, r := range `\.+*?()|[]^$` {
+ if c == r {
+ return true
+ }
+ }
+ return false
+}
+
+func ispunct(c int) bool {
+ for _, r := range "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" {
+ if c == r {
+ return true
+ }
+ }
+ return false
+}
+
+var escapes = []byte("abfnrtv")
+var escaped = []byte("\a\b\f\n\r\t\v")
+
+func escape(c int) int {
+ for i, b := range escapes {
+ if int(b) == c {
+ return i
+ }
+ }
+ return -1
+}
+
+func (p *parser) checkBackslash() int {
+ c := p.c()
+ if c == '\\' {
+ c = p.nextc()
+ switch {
+ case c == endOfFile:
+ p.error(ErrExtraneousBackslash)
+ case ispunct(c):
+ // c is as delivered
+ case escape(c) >= 0:
+ c = int(escaped[escape(c)])
+ default:
+ p.error(ErrBadBackslash)
+ }
+ }
+ return c
+}
+
+func (p *parser) charClass() *instr {
+ i := newCharClass()
+ cc := i.cclass
+ if p.c() == '^' {
+ cc.negate = true
+ p.nextc()
+ }
+ left := -1
+ for {
+ switch c := p.c(); c {
+ case ']', endOfFile:
+ if left >= 0 {
+ p.error(ErrBadRange)
+ }
+ // Is it [^\n]?
+ if cc.negate && len(cc.ranges) == 2 &&
+ cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
+ nl := &instr{kind: iNotNL}
+ p.re.add(nl)
+ return nl
+ }
+ // Special common case: "[a]" -> "a"
+ if !cc.negate && len(cc.ranges) == 2 && cc.ranges[0] == cc.ranges[1] {
+ c := &instr{kind: iChar, char: cc.ranges[0]}
+ p.re.add(c)
+ return c
+ }
+ p.re.add(i)
+ return i
+ case '-': // do this before backslash processing
+ p.error(ErrBadRange)
+ default:
+ c = p.checkBackslash()
+ p.nextc()
+ switch {
+ case left < 0: // first of pair
+ if p.c() == '-' { // range
+ p.nextc()
+ left = c
+ } else { // single char
+ cc.addRange(c, c)
+ }
+ case left <= c: // second of pair
+ cc.addRange(left, c)
+ left = -1
+ default:
+ p.error(ErrBadRange)
+ }
+ }
+ }
+ panic("unreachable")
+}
+
+func (p *parser) term() (start, end *instr) {
+ switch c := p.c(); c {
+ case '|', endOfFile:
+ return nil, nil
+ case '*', '+', '?':
+ p.error(ErrBareClosure)
+ case ')':
+ if p.nlpar == 0 {
+ p.error(ErrUnmatchedRpar)
+ }
+ return nil, nil
+ case ']':
+ p.error(ErrUnmatchedRbkt)
+ case '^':
+ p.nextc()
+ start = p.re.add(&instr{kind: iBOT})
+ return start, start
+ case '$':
+ p.nextc()
+ start = p.re.add(&instr{kind: iEOT})
+ return start, start
+ case '.':
+ p.nextc()
+ start = p.re.add(&instr{kind: iAny})
+ return start, start
+ case '[':
+ p.nextc()
+ start = p.charClass()
+ if p.c() != ']' {
+ p.error(ErrUnmatchedLbkt)
+ }
+ p.nextc()
+ return start, start
+ case '(':
+ p.nextc()
+ p.nlpar++
+ p.re.nbra++ // increment first so first subexpr is \1
+ nbra := p.re.nbra
+ start, end = p.regexp()
+ if p.c() != ')' {
+ p.error(ErrUnmatchedLpar)
+ }
+ p.nlpar--
+ p.nextc()
+ bra := &instr{kind: iBra, braNum: 2 * nbra}
+ p.re.add(bra)
+ ebra := &instr{kind: iBra, braNum: 2*nbra + 1}
+ p.re.add(ebra)
+ if start == nil {
+ if end == nil {
+ p.error(ErrInternal)
+ return
+ }
+ start = ebra
+ } else {
+ end.next = ebra
+ }
+ bra.next = start
+ return bra, ebra
+ default:
+ c = p.checkBackslash()
+ p.nextc()
+ start = &instr{kind: iChar, char: c}
+ p.re.add(start)
+ return start, start
+ }
+ panic("unreachable")
+}
+
+func (p *parser) closure() (start, end *instr) {
+ start, end = p.term()
+ if start == nil {
+ return
+ }
+ switch p.c() {
+ case '*':
+ // (start,end)*:
+ alt := &instr{kind: iAlt}
+ p.re.add(alt)
+ end.next = alt // after end, do alt
+ alt.left = start // alternate brach: return to start
+ start = alt // alt becomes new (start, end)
+ end = alt
+ case '+':
+ // (start,end)+:
+ alt := &instr{kind: iAlt}
+ p.re.add(alt)
+ end.next = alt // after end, do alt
+ alt.left = start // alternate brach: return to start
+ end = alt // start is unchanged; end is alt
+ case '?':
+ // (start,end)?:
+ alt := &instr{kind: iAlt}
+ p.re.add(alt)
+ nop := &instr{kind: iNop}
+ p.re.add(nop)
+ alt.left = start // alternate branch is start
+ alt.next = nop // follow on to nop
+ end.next = nop // after end, go to nop
+ start = alt // start is now alt
+ end = nop // end is nop pointed to by both branches
+ default:
+ return
+ }
+ switch p.nextc() {
+ case '*', '+', '?':
+ p.error(ErrBadClosure)
+ }
+ return
+}
+
+func (p *parser) concatenation() (start, end *instr) {
+ for {
+ nstart, nend := p.closure()
+ switch {
+ case nstart == nil: // end of this concatenation
+ if start == nil { // this is the empty string
+ nop := p.re.add(&instr{kind: iNop})
+ return nop, nop
+ }
+ return
+ case start == nil: // this is first element of concatenation
+ start, end = nstart, nend
+ default:
+ end.next = nstart
+ end = nend
+ }
+ }
+ panic("unreachable")
+}
+
+func (p *parser) regexp() (start, end *instr) {
+ start, end = p.concatenation()
+ for {
+ switch p.c() {
+ default:
+ return
+ case '|':
+ p.nextc()
+ nstart, nend := p.concatenation()
+ alt := &instr{kind: iAlt}
+ p.re.add(alt)
+ alt.left = start
+ alt.next = nstart
+ nop := &instr{kind: iNop}
+ p.re.add(nop)
+ end.next = nop
+ nend.next = nop
+ start, end = alt, nop
+ }
+ }
+ panic("unreachable")
+}
+
+func unNop(i *instr) *instr {
+ for i.kind == iNop {
+ i = i.next
+ }
+ return i
+}
+
+func (re *Regexp) eliminateNops() {
+ for _, inst := range re.inst {
+ if inst.kind == iEnd {
+ continue
+ }
+ inst.next = unNop(inst.next)
+ if inst.kind == iAlt {
+ inst.left = unNop(inst.left)
+ }
+ }
+}
+
+func (re *Regexp) dump() {
+ print("prefix <", re.prefix, ">\n")
+ for _, inst := range re.inst {
+ print(inst.index, ": ")
+ inst.print()
+ if inst.kind != iEnd {
+ print(" -> ", inst.next.index)
+ }
+ print("\n")
+ }
+}
+
+func (re *Regexp) doParse() {
+ p := newParser(re)
+ start := &instr{kind: iStart}
+ re.add(start)
+ s, e := p.regexp()
+ start.next = s
+ re.start = start
+ e.next = re.add(&instr{kind: iEnd})
+
+ if debug {
+ re.dump()
+ println()
+ }
+
+ re.eliminateNops()
+ if debug {
+ re.dump()
+ println()
+ }
+ re.setPrefix()
+ if debug {
+ re.dump()
+ println()
+ }
+}
+
+// Extract regular text from the beginning of the pattern,
+// possibly after a leading iBOT.
+// That text can be used by doExecute to speed up matching.
+func (re *Regexp) setPrefix() {
+ var b []byte
+ var utf = make([]byte, utf8.UTFMax)
+ var inst *instr
+ // First instruction is start; skip that. Also skip any initial iBOT.
+ inst = re.inst[0].next
+ for inst.kind == iBOT {
+ inst = inst.next
+ }
+Loop:
+ for ; inst.kind != iEnd; inst = inst.next {
+ // stop if this is not a char
+ if inst.kind != iChar {
+ break
+ }
+ // stop if this char can be followed by a match for an empty string,
+ // which includes closures, ^, and $.
+ switch inst.next.kind {
+ case iBOT, iEOT, iAlt:
+ break Loop
+ }
+ n := utf8.EncodeRune(utf, inst.char)
+ b = append(b, utf[0:n]...)
+ }
+ // point prefixStart instruction to first non-CHAR after prefix
+ re.prefixStart = inst
+ re.prefixBytes = b
+ re.prefix = string(b)
+}
+
+// String returns the source text used to compile the regular expression.
+func (re *Regexp) String() string {
+ return re.expr
+}
+
+// Compile parses a regular expression and returns, if successful, a Regexp
+// object that can be used to match against text.
+func Compile(str string) (regexp *Regexp, error os.Error) {
+ regexp = new(Regexp)
+ // doParse will panic if there is a parse error.
+ defer func() {
+ if e := recover(); e != nil {
+ regexp = nil
+ error = e.(Error) // Will re-panic if error was not an Error, e.g. nil-pointer exception
+ }
+ }()
+ regexp.expr = str
+ regexp.inst = make([]*instr, 0, 10)
+ regexp.doParse()
+ return
+}
+
+// MustCompile is like Compile but panics if the expression cannot be parsed.
+// It simplifies safe initialization of global variables holding compiled regular
+// expressions.
+func MustCompile(str string) *Regexp {
+ regexp, error := Compile(str)
+ if error != nil {
+ panic(`regexp: compiling "` + str + `": ` + error.String())
+ }
+ return regexp
+}
+
+// NumSubexp returns the number of parenthesized subexpressions in this Regexp.
+func (re *Regexp) NumSubexp() int { return re.nbra }
+
+// The match arena allows us to reduce the garbage generated by tossing
+// match vectors away as we execute. Matches are ref counted and returned
+// to a free list when no longer active. Increases a simple benchmark by 22X.
+type matchArena struct {
+ head *matchVec
+ len int // length of match vector
+}
+
+type matchVec struct {
+ m []int // pairs of bracketing submatches. 0th is start,end
+ ref int
+ next *matchVec
+}
+
+func (a *matchArena) new() *matchVec {
+ if a.head == nil {
+ const N = 10
+ block := make([]matchVec, N)
+ for i := 0; i < N; i++ {
+ b := &block[i]
+ b.next = a.head
+ a.head = b
+ }
+ }
+ m := a.head
+ a.head = m.next
+ m.ref = 0
+ if m.m == nil {
+ m.m = make([]int, a.len)
+ }
+ return m
+}
+
+func (a *matchArena) free(m *matchVec) {
+ m.ref--
+ if m.ref == 0 {
+ m.next = a.head
+ a.head = m
+ }
+}
+
+func (a *matchArena) copy(m *matchVec) *matchVec {
+ m1 := a.new()
+ copy(m1.m, m.m)
+ return m1
+}
+
+func (a *matchArena) noMatch() *matchVec {
+ m := a.new()
+ for i := range m.m {
+ m.m[i] = -1 // no match seen; catches cases like "a(b)?c" on "ac"
+ }
+ m.ref = 1
+ return m
+}
+
+type state struct {
+ inst *instr // next instruction to execute
+ prefixed bool // this match began with a fixed prefix
+ match *matchVec
+}
+
+// Append new state to to-do list. Leftmost-longest wins so avoid
+// adding a state that's already active. The matchVec will be inc-ref'ed
+// if it is assigned to a state.
+func (a *matchArena) addState(s []state, inst *instr, prefixed bool, match *matchVec, pos, end int) []state {
+ switch inst.kind {
+ case iBOT:
+ if pos == 0 {
+ s = a.addState(s, inst.next, prefixed, match, pos, end)
+ }
+ return s
+ case iEOT:
+ if pos == end {
+ s = a.addState(s, inst.next, prefixed, match, pos, end)
+ }
+ return s
+ case iBra:
+ match.m[inst.braNum] = pos
+ s = a.addState(s, inst.next, prefixed, match, pos, end)
+ return s
+ }
+ l := len(s)
+ // States are inserted in order so it's sufficient to see if we have the same
+ // instruction; no need to see if existing match is earlier (it is).
+ for i := 0; i < l; i++ {
+ if s[i].inst == inst {
+ return s
+ }
+ }
+ s = append(s, state{inst, prefixed, match})
+ match.ref++
+ if inst.kind == iAlt {
+ s = a.addState(s, inst.left, prefixed, a.copy(match), pos, end)
+ // give other branch a copy of this match vector
+ s = a.addState(s, inst.next, prefixed, a.copy(match), pos, end)
+ }
+ return s
+}
+
+// Accepts either string or bytes - the logic is identical either way.
+// If bytes == nil, scan str.
+func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
+ var s [2][]state
+ s[0] = make([]state, 0, 10)
+ s[1] = make([]state, 0, 10)
+ in, out := 0, 1
+ var final state
+ found := false
+ end := len(str)
+ if bytestr != nil {
+ end = len(bytestr)
+ }
+ anchored := re.inst[0].next.kind == iBOT
+ if anchored && pos > 0 {
+ return nil
+ }
+ // fast check for initial plain substring
+ if re.prefix != "" {
+ advance := 0
+ if anchored {
+ if bytestr == nil {
+ if !strings.HasPrefix(str, re.prefix) {
+ return nil
+ }
+ } else {
+ if !bytes.HasPrefix(bytestr, re.prefixBytes) {
+ return nil
+ }
+ }
+ } else {
+ if bytestr == nil {
+ advance = strings.Index(str[pos:], re.prefix)
+ } else {
+ advance = bytes.Index(bytestr[pos:], re.prefixBytes)
+ }
+ }
+ if advance == -1 {
+ return nil
+ }
+ pos += advance
+ }
+ arena := &matchArena{nil, 2 * (re.nbra + 1)}
+ for startPos := pos; pos <= end; {
+ if !found && (pos == startPos || !anchored) {
+ // prime the pump if we haven't seen a match yet
+ match := arena.noMatch()
+ match.m[0] = pos
+ s[out] = arena.addState(s[out], re.start.next, false, match, pos, end)
+ arena.free(match) // if addState saved it, ref was incremented
+ } else if len(s[out]) == 0 {
+ // machine has completed
+ break
+ }
+ in, out = out, in // old out state is new in state
+ // clear out old state
+ old := s[out]
+ for _, state := range old {
+ arena.free(state.match)
+ }
+ s[out] = old[0:0] // truncate state vector
+ charwidth := 1
+ c := endOfFile
+ if pos < end {
+ if bytestr == nil {
+ c, charwidth = utf8.DecodeRuneInString(str[pos:end])
+ } else {
+ c, charwidth = utf8.DecodeRune(bytestr[pos:end])
+ }
+ }
+ pos += charwidth
+ for _, st := range s[in] {
+ switch st.inst.kind {
+ case iBOT:
+ case iEOT:
+ case iChar:
+ if c == st.inst.char {
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
+ }
+ case iCharClass:
+ if st.inst.cclass.matches(c) {
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
+ }
+ case iAny:
+ if c != endOfFile {
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
+ }
+ case iNotNL:
+ if c != endOfFile && c != '\n' {
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
+ }
+ case iBra:
+ case iAlt:
+ case iEnd:
+ // choose leftmost longest
+ if !found || // first
+ st.match.m[0] < final.match.m[0] || // leftmost
+ (st.match.m[0] == final.match.m[0] && pos-charwidth > final.match.m[1]) { // longest
+ if final.match != nil {
+ arena.free(final.match)
+ }
+ final = st
+ final.match.ref++
+ final.match.m[1] = pos - charwidth
+ }
+ found = true
+ default:
+ st.inst.print()
+ panic("unknown instruction in execute")
+ }
+ }
+ }
+ if final.match == nil {
+ return nil
+ }
+ // if match found, back up start of match by width of prefix.
+ if final.prefixed && len(final.match.m) > 0 {
+ final.match.m[0] -= len(re.prefix)
+ }
+ return final.match.m
+}
+
+// LiteralPrefix returns a literal string that must begin any match
+// of the regular expression re. It returns the boolean true if the
+// literal string comprises the entire regular expression.
+func (re *Regexp) LiteralPrefix() (prefix string, complete bool) {
+ c := make([]int, len(re.inst)-2) // minus start and end.
+ // First instruction is start; skip that.
+ i := 0
+ for inst := re.inst[0].next; inst.kind != iEnd; inst = inst.next {
+ // stop if this is not a char
+ if inst.kind != iChar {
+ return string(c[:i]), false
+ }
+ c[i] = inst.char
+ i++
+ }
+ return string(c[:i]), true
+}
+
+// MatchString returns whether the Regexp matches the string s.
+// The return value is a boolean: true for match, false for no match.
+func (re *Regexp) MatchString(s string) bool { return len(re.doExecute(s, nil, 0)) > 0 }
+
+// Match returns whether the Regexp matches the byte slice b.
+// The return value is a boolean: true for match, false for no match.
+func (re *Regexp) Match(b []byte) bool { return len(re.doExecute("", b, 0)) > 0 }
+
+
+// MatchString checks whether a textual regular expression
+// matches a string. More complicated queries need
+// to use Compile and the full Regexp interface.
+func MatchString(pattern string, s string) (matched bool, error os.Error) {
+ re, err := Compile(pattern)
+ if err != nil {
+ return false, err
+ }
+ return re.MatchString(s), nil
+}
+
+// Match checks whether a textual regular expression
+// matches a byte slice. More complicated queries need
+// to use Compile and the full Regexp interface.
+func Match(pattern string, b []byte) (matched bool, error os.Error) {
+ re, err := Compile(pattern)
+ if err != nil {
+ return false, err
+ }
+ return re.Match(b), nil
+}
+
+// ReplaceAllString returns a copy of src in which all matches for the Regexp
+// have been replaced by repl. No support is provided for expressions
+// (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllString(src, repl string) string {
+ return re.ReplaceAllStringFunc(src, func(string) string { return repl })
+}
+
+// ReplaceAllStringFunc returns a copy of src in which all matches for the
+// Regexp have been replaced by the return value of of function repl (whose
+// first argument is the matched string). No support is provided for
+// expressions (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
+ lastMatchEnd := 0 // end position of the most recent match
+ searchPos := 0 // position where we next look for a match
+ buf := new(bytes.Buffer)
+ for searchPos <= len(src) {
+ a := re.doExecute(src, nil, searchPos)
+ if len(a) == 0 {
+ break // no more matches
+ }
+
+ // Copy the unmatched characters before this match.
+ io.WriteString(buf, src[lastMatchEnd:a[0]])
+
+ // Now insert a copy of the replacement string, but not for a
+ // match of the empty string immediately after another match.
+ // (Otherwise, we get double replacement for patterns that
+ // match both empty and nonempty strings.)
+ if a[1] > lastMatchEnd || a[0] == 0 {
+ io.WriteString(buf, repl(src[a[0]:a[1]]))
+ }
+ lastMatchEnd = a[1]
+
+ // Advance past this match; always advance at least one character.
+ _, width := utf8.DecodeRuneInString(src[searchPos:])
+ if searchPos+width > a[1] {
+ searchPos += width
+ } else if searchPos+1 > a[1] {
+ // This clause is only needed at the end of the input
+ // string. In that case, DecodeRuneInString returns width=0.
+ searchPos++
+ } else {
+ searchPos = a[1]
+ }
+ }
+
+ // Copy the unmatched characters after the last match.
+ io.WriteString(buf, src[lastMatchEnd:])
+
+ return buf.String()
+}
+
+// ReplaceAll returns a copy of src in which all matches for the Regexp
+// have been replaced by repl. No support is provided for expressions
+// (e.g. \1 or $1) in the replacement text.
+func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
+ return re.ReplaceAllFunc(src, func([]byte) []byte { return repl })
+}
+
+// ReplaceAllFunc returns a copy of src in which all matches for the
+// Regexp have been replaced by the return value of of function repl (whose
+// first argument is the matched []byte). No support is provided for
+// expressions (e.g. \1 or $1) in the replacement string.
+func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
+ lastMatchEnd := 0 // end position of the most recent match
+ searchPos := 0 // position where we next look for a match
+ buf := new(bytes.Buffer)
+ for searchPos <= len(src) {
+ a := re.doExecute("", src, searchPos)
+ if len(a) == 0 {
+ break // no more matches
+ }
+
+ // Copy the unmatched characters before this match.
+ buf.Write(src[lastMatchEnd:a[0]])
+
+ // Now insert a copy of the replacement string, but not for a
+ // match of the empty string immediately after another match.
+ // (Otherwise, we get double replacement for patterns that
+ // match both empty and nonempty strings.)
+ if a[1] > lastMatchEnd || a[0] == 0 {
+ buf.Write(repl(src[a[0]:a[1]]))
+ }
+ lastMatchEnd = a[1]
+
+ // Advance past this match; always advance at least one character.
+ _, width := utf8.DecodeRune(src[searchPos:])
+ if searchPos+width > a[1] {
+ searchPos += width
+ } else if searchPos+1 > a[1] {
+ // This clause is only needed at the end of the input
+ // string. In that case, DecodeRuneInString returns width=0.
+ searchPos++
+ } else {
+ searchPos = a[1]
+ }
+ }
+
+ // Copy the unmatched characters after the last match.
+ buf.Write(src[lastMatchEnd:])
+
+ return buf.Bytes()
+}
+
+// QuoteMeta returns a string that quotes all regular expression metacharacters
+// inside the argument text; the returned string is a regular expression matching
+// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
+func QuoteMeta(s string) string {
+ b := make([]byte, 2*len(s))
+
+ // A byte loop is correct because all metacharacters are ASCII.
+ j := 0
+ for i := 0; i < len(s); i++ {
+ if special(int(s[i])) {
+ b[j] = '\\'
+ j++
+ }
+ b[j] = s[i]
+ j++
+ }
+ return string(b[0:j])
+}
+
+// Find matches in slice b if b is non-nil, otherwise find matches in string s.
+func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
+ var end int
+ if b == nil {
+ end = len(s)
+ } else {
+ end = len(b)
+ }
+
+ for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; {
+ matches := re.doExecute(s, b, pos)
+ if len(matches) == 0 {
+ break
+ }
+
+ accept := true
+ if matches[1] == pos {
+ // We've found an empty match.
+ if matches[0] == prevMatchEnd {
+ // We don't allow an empty match right
+ // after a previous match, so ignore it.
+ accept = false
+ }
+ var width int
+ if b == nil {
+ _, width = utf8.DecodeRuneInString(s[pos:end])
+ } else {
+ _, width = utf8.DecodeRune(b[pos:end])
+ }
+ if width > 0 {
+ pos += width
+ } else {
+ pos = end + 1
+ }
+ } else {
+ pos = matches[1]
+ }
+ prevMatchEnd = matches[1]
+
+ if accept {
+ deliver(matches)
+ i++
+ }
+ }
+}
+
+// Find returns a slice holding the text of the leftmost match in b of the regular expression.
+// A return value of nil indicates no match.
+func (re *Regexp) Find(b []byte) []byte {
+ a := re.doExecute("", b, 0)
+ if a == nil {
+ return nil
+ }
+ return b[a[0]:a[1]]
+}
+
+// FindIndex returns a two-element slice of integers defining the location of
+// the leftmost match in b of the regular expression. The match itself is at
+// b[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindIndex(b []byte) (loc []int) {
+ a := re.doExecute("", b, 0)
+ if a == nil {
+ return nil
+ }
+ return a[0:2]
+}
+
+// FindString returns a string holding the text of the leftmost match in s of the regular
+// expression. If there is no match, the return value is an empty string,
+// but it will also be empty if the regular expression successfully matches
+// an empty string. Use FindStringIndex or FindStringSubmatch if it is
+// necessary to distinguish these cases.
+func (re *Regexp) FindString(s string) string {
+ a := re.doExecute(s, nil, 0)
+ if a == nil {
+ return ""
+ }
+ return s[a[0]:a[1]]
+}
+
+// FindStringIndex returns a two-element slice of integers defining the
+// location of the leftmost match in s of the regular expression. The match
+// itself is at s[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringIndex(s string) []int {
+ a := re.doExecute(s, nil, 0)
+ if a == nil {
+ return nil
+ }
+ return a[0:2]
+}
+
+// FindSubmatch returns a slice of slices holding the text of the leftmost
+// match of the regular expression in b and the matches, if any, of its
+// subexpressions, as defined by the 'Submatch' descriptions in the package
+// comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatch(b []byte) [][]byte {
+ a := re.doExecute("", b, 0)
+ if a == nil {
+ return nil
+ }
+ ret := make([][]byte, len(a)/2)
+ for i := range ret {
+ if a[2*i] >= 0 {
+ ret[i] = b[a[2*i]:a[2*i+1]]
+ }
+ }
+ return ret
+}
+
+// FindSubmatchIndex returns a slice holding the index pairs identifying the
+// leftmost match of the regular expression in b and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' and 'Index' descriptions
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatchIndex(b []byte) []int {
+ return re.doExecute("", b, 0)
+}
+
+// FindStringSubmatch returns a slice of strings holding the text of the
+// leftmost match of the regular expression in s and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatch(s string) []string {
+ a := re.doExecute(s, nil, 0)
+ if a == nil {
+ return nil
+ }
+ ret := make([]string, len(a)/2)
+ for i := range ret {
+ if a[2*i] >= 0 {
+ ret[i] = s[a[2*i]:a[2*i+1]]
+ }
+ }
+ return ret
+}
+
+// FindStringSubmatchIndex returns a slice holding the index pairs
+// identifying the leftmost match of the regular expression in s and the
+// matches, if any, of its subexpressions, as defined by the 'Submatch' and
+// 'Index' descriptions in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatchIndex(s string) []int {
+ return re.doExecute(s, nil, 0)
+}
+
+const startSize = 10 // The size at which to start a slice in the 'All' routines.
+
+// FindAll is the 'All' version of Find; it returns a slice of all successive
+// matches of the expression, as defined by the 'All' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAll(b []byte, n int) [][]byte {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][]byte, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ result = append(result, b[match[0]:match[1]])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllIndex is the 'All' version of FindIndex; it returns a slice of all
+// successive matches of the expression, as defined by the 'All' description
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllIndex(b []byte, n int) [][]int {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ result = append(result, match[0:2])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllString is the 'All' version of FindString; it returns a slice of all
+// successive matches of the expression, as defined by the 'All' description
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllString(s string, n int) []string {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([]string, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ result = append(result, s[match[0]:match[1]])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllStringIndex is the 'All' version of FindStringIndex; it returns a
+// slice of all successive matches of the expression, as defined by the 'All'
+// description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringIndex(s string, n int) [][]int {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ result = append(result, match[0:2])
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllSubmatch is the 'All' version of FindSubmatch; it returns a slice
+// of all successive matches of the expression, as defined by the 'All'
+// description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][][]byte, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ slice := make([][]byte, len(match)/2)
+ for j := range slice {
+ if match[2*j] >= 0 {
+ slice[j] = b[match[2*j]:match[2*j+1]]
+ }
+ }
+ result = append(result, slice)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllSubmatchIndex is the 'All' version of FindSubmatchIndex; it returns
+// a slice of all successive matches of the expression, as defined by the
+// 'All' description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int {
+ if n < 0 {
+ n = len(b) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ result = append(result, match)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllStringSubmatch is the 'All' version of FindStringSubmatch; it
+// returns a slice of all successive matches of the expression, as defined by
+// the 'All' description in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([][]string, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ slice := make([]string, len(match)/2)
+ for j := range slice {
+ if match[2*j] >= 0 {
+ slice[j] = s[match[2*j]:match[2*j+1]]
+ }
+ }
+ result = append(result, slice)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// FindAllStringSubmatchIndex is the 'All' version of
+// FindStringSubmatchIndex; it returns a slice of all successive matches of
+// the expression, as defined by the 'All' description in the package
+// comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int {
+ if n < 0 {
+ n = len(s) + 1
+ }
+ result := make([][]int, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ result = append(result, match)
+ })
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
diff --git a/libgo/go/rpc/client.go b/libgo/go/rpc/client.go
new file mode 100644
index 000000000..601c49715
--- /dev/null
+++ b/libgo/go/rpc/client.go
@@ -0,0 +1,250 @@
+// 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 rpc
+
+import (
+ "bufio"
+ "gob"
+ "http"
+ "io"
+ "log"
+ "net"
+ "os"
+ "sync"
+)
+
+// Call represents an active RPC.
+type Call struct {
+ ServiceMethod string // The name of the service and method to call.
+ Args interface{} // The argument to the function (*struct).
+ Reply interface{} // The reply from the function (*struct).
+ Error os.Error // After completion, the error status.
+ Done chan *Call // Strobes when call is complete; value is the error status.
+ seq uint64
+}
+
+// Client represents an RPC Client.
+// There may be multiple outstanding Calls associated
+// with a single Client.
+type Client struct {
+ mutex sync.Mutex // protects pending, seq
+ shutdown os.Error // non-nil if the client is shut down
+ sending sync.Mutex
+ seq uint64
+ codec ClientCodec
+ pending map[uint64]*Call
+ closing bool
+}
+
+// A ClientCodec implements writing of RPC requests and
+// reading of RPC responses for the client side of an RPC session.
+// The client calls WriteRequest to write a request to the connection
+// and calls ReadResponseHeader and ReadResponseBody in pairs
+// to read responses. The client calls Close when finished with the
+// connection.
+type ClientCodec interface {
+ WriteRequest(*Request, interface{}) os.Error
+ ReadResponseHeader(*Response) os.Error
+ ReadResponseBody(interface{}) os.Error
+
+ Close() os.Error
+}
+
+func (client *Client) send(c *Call) {
+ // Register this call.
+ client.mutex.Lock()
+ if client.shutdown != nil {
+ c.Error = client.shutdown
+ client.mutex.Unlock()
+ _ = c.Done <- c // do not block
+ return
+ }
+ c.seq = client.seq
+ client.seq++
+ client.pending[c.seq] = c
+ client.mutex.Unlock()
+
+ // Encode and send the request.
+ request := new(Request)
+ client.sending.Lock()
+ defer client.sending.Unlock()
+ request.Seq = c.seq
+ request.ServiceMethod = c.ServiceMethod
+ if err := client.codec.WriteRequest(request, c.Args); err != nil {
+ panic("rpc: client encode error: " + err.String())
+ }
+}
+
+func (client *Client) input() {
+ var err os.Error
+ for err == nil {
+ response := new(Response)
+ err = client.codec.ReadResponseHeader(response)
+ if err != nil {
+ if err == os.EOF && !client.closing {
+ err = io.ErrUnexpectedEOF
+ }
+ break
+ }
+ seq := response.Seq
+ client.mutex.Lock()
+ c := client.pending[seq]
+ client.pending[seq] = c, false
+ client.mutex.Unlock()
+ err = client.codec.ReadResponseBody(c.Reply)
+ if response.Error != "" {
+ c.Error = os.ErrorString(response.Error)
+ } else if err != nil {
+ c.Error = err
+ } else {
+ // Empty strings should turn into nil os.Errors
+ c.Error = nil
+ }
+ // We don't want to block here. It is the caller's responsibility to make
+ // sure the channel has enough buffer space. See comment in Go().
+ _ = c.Done <- c // do not block
+ }
+ // Terminate pending calls.
+ client.mutex.Lock()
+ client.shutdown = err
+ for _, call := range client.pending {
+ call.Error = err
+ _ = call.Done <- call // do not block
+ }
+ client.mutex.Unlock()
+ if err != os.EOF || !client.closing {
+ log.Println("rpc: client protocol error:", err)
+ }
+}
+
+// NewClient returns a new Client to handle requests to the
+// set of services at the other end of the connection.
+func NewClient(conn io.ReadWriteCloser) *Client {
+ return NewClientWithCodec(&gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(conn)})
+}
+
+// NewClientWithCodec is like NewClient but uses the specified
+// codec to encode requests and decode responses.
+func NewClientWithCodec(codec ClientCodec) *Client {
+ client := &Client{
+ codec: codec,
+ pending: make(map[uint64]*Call),
+ }
+ go client.input()
+ return client
+}
+
+type gobClientCodec struct {
+ rwc io.ReadWriteCloser
+ dec *gob.Decoder
+ enc *gob.Encoder
+}
+
+func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) os.Error {
+ if err := c.enc.Encode(r); err != nil {
+ return err
+ }
+ return c.enc.Encode(body)
+}
+
+func (c *gobClientCodec) ReadResponseHeader(r *Response) os.Error {
+ return c.dec.Decode(r)
+}
+
+func (c *gobClientCodec) ReadResponseBody(body interface{}) os.Error {
+ return c.dec.Decode(body)
+}
+
+func (c *gobClientCodec) Close() os.Error {
+ return c.rwc.Close()
+}
+
+
+// DialHTTP connects to an HTTP RPC server at the specified network address
+// listening on the default HTTP RPC path.
+func DialHTTP(network, address string) (*Client, os.Error) {
+ return DialHTTPPath(network, address, DefaultRPCPath)
+}
+
+// DialHTTPPath connects to an HTTP RPC server
+// at the specified network address and path.
+func DialHTTPPath(network, address, path string) (*Client, os.Error) {
+ var err os.Error
+ conn, err := net.Dial(network, "", address)
+ if err != nil {
+ return nil, err
+ }
+ io.WriteString(conn, "CONNECT "+path+" HTTP/1.0\n\n")
+
+ // Require successful HTTP response
+ // before switching to RPC protocol.
+ resp, err := http.ReadResponse(bufio.NewReader(conn), "CONNECT")
+ if err == nil && resp.Status == connected {
+ return NewClient(conn), nil
+ }
+ if err == nil {
+ err = os.ErrorString("unexpected HTTP response: " + resp.Status)
+ }
+ conn.Close()
+ return nil, &net.OpError{"dial-http", network + " " + address, nil, err}
+}
+
+// Dial connects to an RPC server at the specified network address.
+func Dial(network, address string) (*Client, os.Error) {
+ conn, err := net.Dial(network, "", address)
+ if err != nil {
+ return nil, err
+ }
+ return NewClient(conn), nil
+}
+
+func (client *Client) Close() os.Error {
+ if client.shutdown != nil || client.closing {
+ return os.ErrorString("rpc: already closed")
+ }
+ client.mutex.Lock()
+ client.closing = true
+ client.mutex.Unlock()
+ return client.codec.Close()
+}
+
+// Go invokes the function asynchronously. It returns the Call structure representing
+// the invocation. The done channel will signal when the call is complete by returning
+// the same Call object. If done is nil, Go will allocate a new channel.
+// If non-nil, done must be buffered or Go will deliberately crash.
+func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
+ c := new(Call)
+ c.ServiceMethod = serviceMethod
+ c.Args = args
+ c.Reply = reply
+ if done == nil {
+ done = make(chan *Call, 10) // buffered.
+ } else {
+ // If caller passes done != nil, it must arrange that
+ // done has enough buffer for the number of simultaneous
+ // RPCs that will be using that channel. If the channel
+ // is totally unbuffered, it's best not to run at all.
+ if cap(done) == 0 {
+ log.Panic("rpc: done channel is unbuffered")
+ }
+ }
+ c.Done = done
+ if client.shutdown != nil {
+ c.Error = client.shutdown
+ _ = c.Done <- c // do not block
+ return c
+ }
+ client.send(c)
+ return c
+}
+
+// Call invokes the named function, waits for it to complete, and returns its error status.
+func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) os.Error {
+ if client.shutdown != nil {
+ return client.shutdown
+ }
+ call := <-client.Go(serviceMethod, args, reply, nil).Done
+ return call.Error
+}
diff --git a/libgo/go/rpc/debug.go b/libgo/go/rpc/debug.go
new file mode 100644
index 000000000..44b32e04b
--- /dev/null
+++ b/libgo/go/rpc/debug.go
@@ -0,0 +1,90 @@
+// 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 rpc
+
+/*
+ Some HTML presented at http://machine:port/debug/rpc
+ Lists services, their methods, and some statistics, still rudimentary.
+*/
+
+import (
+ "fmt"
+ "http"
+ "sort"
+ "template"
+)
+
+const debugText = `<html>
+ <body>
+ <title>Services</title>
+ {.repeated section @}
+ <hr>
+ Service {Name}
+ <hr>
+ <table>
+ <th align=center>Method</th><th align=center>Calls</th>
+ {.repeated section Method}
+ <tr>
+ <td align=left font=fixed>{Name}({Type.ArgType}, {Type.ReplyType}) os.Error</td>
+ <td align=center>{Type.NumCalls}</td>
+ </tr>
+ {.end}
+ </table>
+ {.end}
+ </body>
+ </html>`
+
+var debug = template.MustParse(debugText, nil)
+
+type debugMethod struct {
+ Type *methodType
+ Name string
+}
+
+type methodArray []debugMethod
+
+type debugService struct {
+ Service *service
+ Name string
+ Method methodArray
+}
+
+type serviceArray []debugService
+
+func (s serviceArray) Len() int { return len(s) }
+func (s serviceArray) Less(i, j int) bool { return s[i].Name < s[j].Name }
+func (s serviceArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+func (m methodArray) Len() int { return len(m) }
+func (m methodArray) Less(i, j int) bool { return m[i].Name < m[j].Name }
+func (m methodArray) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
+
+type debugHTTP struct {
+ *Server
+}
+
+// Runs at /debug/rpc
+func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ // Build a sorted version of the data.
+ var services = make(serviceArray, len(server.serviceMap))
+ i := 0
+ server.Lock()
+ for sname, service := range server.serviceMap {
+ services[i] = debugService{service, sname, make(methodArray, len(service.method))}
+ j := 0
+ for mname, method := range service.method {
+ services[i].Method[j] = debugMethod{method, mname}
+ j++
+ }
+ sort.Sort(services[i].Method)
+ i++
+ }
+ server.Unlock()
+ sort.Sort(services)
+ err := debug.Execute(services, w)
+ if err != nil {
+ fmt.Fprintln(w, "rpc: error executing template:", err.String())
+ }
+}
diff --git a/libgo/go/rpc/jsonrpc/all_test.go b/libgo/go/rpc/jsonrpc/all_test.go
new file mode 100644
index 000000000..764ee7ff3
--- /dev/null
+++ b/libgo/go/rpc/jsonrpc/all_test.go
@@ -0,0 +1,156 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jsonrpc
+
+import (
+ "fmt"
+ "json"
+ "net"
+ "os"
+ "rpc"
+ "testing"
+)
+
+type Args struct {
+ A, B int
+}
+
+type Reply struct {
+ C int
+}
+
+type Arith int
+
+func (t *Arith) Add(args *Args, reply *Reply) os.Error {
+ reply.C = args.A + args.B
+ return nil
+}
+
+func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
+ reply.C = args.A * args.B
+ return nil
+}
+
+func (t *Arith) Div(args *Args, reply *Reply) os.Error {
+ if args.B == 0 {
+ return os.ErrorString("divide by zero")
+ }
+ reply.C = args.A / args.B
+ return nil
+}
+
+func (t *Arith) Error(args *Args, reply *Reply) os.Error {
+ panic("ERROR")
+}
+
+func init() {
+ rpc.Register(new(Arith))
+}
+
+func TestServer(t *testing.T) {
+ type addResp struct {
+ Id interface{} "id"
+ Result Reply "result"
+ Error interface{} "error"
+ }
+
+ cli, srv := net.Pipe()
+ defer cli.Close()
+ go ServeConn(srv)
+ dec := json.NewDecoder(cli)
+
+ // Send hand-coded requests to server, parse responses.
+ for i := 0; i < 10; i++ {
+ fmt.Fprintf(cli, `{"method": "Arith.Add", "id": "\u%04d", "params": [{"A": %d, "B": %d}]}`, i, i, i+1)
+ var resp addResp
+ err := dec.Decode(&resp)
+ if err != nil {
+ t.Fatalf("Decode: %s", err)
+ }
+ if resp.Error != nil {
+ t.Fatalf("resp.Error: %s", resp.Error)
+ }
+ if resp.Id.(string) != string(i) {
+ t.Fatalf("resp: bad id %q want %q", resp.Id.(string), string(i))
+ }
+ if resp.Result.C != 2*i+1 {
+ t.Fatalf("resp: bad result: %d+%d=%d", i, i+1, resp.Result.C)
+ }
+ }
+
+ fmt.Fprintf(cli, "{}\n")
+ var resp addResp
+ if err := dec.Decode(&resp); err != nil {
+ t.Fatalf("Decode after empty: %s", err)
+ }
+ if resp.Error == nil {
+ t.Fatalf("Expected error, got nil")
+ }
+}
+
+func TestClient(t *testing.T) {
+ // Assume server is okay (TestServer is above).
+ // Test client against server.
+ cli, srv := net.Pipe()
+ go ServeConn(srv)
+
+ client := NewClient(cli)
+ defer client.Close()
+
+ // Synchronous calls
+ args := &Args{7, 8}
+ reply := new(Reply)
+ err := client.Call("Arith.Add", args, reply)
+ if err != nil {
+ t.Errorf("Add: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+ }
+
+ args = &Args{7, 8}
+ reply = new(Reply)
+ err = client.Call("Arith.Mul", args, reply)
+ if err != nil {
+ t.Errorf("Mul: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A*args.B {
+ t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B)
+ }
+
+ // Out of order.
+ args = &Args{7, 8}
+ mulReply := new(Reply)
+ mulCall := client.Go("Arith.Mul", args, mulReply, nil)
+ addReply := new(Reply)
+ addCall := client.Go("Arith.Add", args, addReply, nil)
+
+ addCall = <-addCall.Done
+ if addCall.Error != nil {
+ t.Errorf("Add: expected no error but got string %q", addCall.Error.String())
+ }
+ if addReply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", addReply.C, args.A+args.B)
+ }
+
+ mulCall = <-mulCall.Done
+ if mulCall.Error != nil {
+ t.Errorf("Mul: expected no error but got string %q", mulCall.Error.String())
+ }
+ if mulReply.C != args.A*args.B {
+ t.Errorf("Mul: expected %d got %d", mulReply.C, args.A*args.B)
+ }
+
+ // Error test
+ args = &Args{7, 0}
+ reply = new(Reply)
+ err = client.Call("Arith.Div", args, reply)
+ // expect an error: zero divide
+ if err == nil {
+ t.Error("Div: expected error")
+ } else if err.String() != "divide by zero" {
+ t.Error("Div: expected divide by zero error; got", err)
+ }
+}
diff --git a/libgo/go/rpc/jsonrpc/client.go b/libgo/go/rpc/jsonrpc/client.go
new file mode 100644
index 000000000..dcaa69f9d
--- /dev/null
+++ b/libgo/go/rpc/jsonrpc/client.go
@@ -0,0 +1,121 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package jsonrpc implements a JSON-RPC ClientCodec and ServerCodec
+// for the rpc package.
+package jsonrpc
+
+import (
+ "fmt"
+ "io"
+ "json"
+ "net"
+ "os"
+ "rpc"
+ "sync"
+)
+
+type clientCodec struct {
+ dec *json.Decoder // for reading JSON values
+ enc *json.Encoder // for writing JSON values
+ c io.Closer
+
+ // temporary work space
+ req clientRequest
+ resp clientResponse
+
+ // JSON-RPC responses include the request id but not the request method.
+ // Package rpc expects both.
+ // We save the request method in pending when sending a request
+ // and then look it up by request ID when filling out the rpc Response.
+ mutex sync.Mutex // protects pending
+ pending map[uint64]string // map request id to method name
+}
+
+// NewClientCodec returns a new rpc.ClientCodec using JSON-RPC on conn.
+func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec {
+ return &clientCodec{
+ dec: json.NewDecoder(conn),
+ enc: json.NewEncoder(conn),
+ c: conn,
+ pending: make(map[uint64]string),
+ }
+}
+
+type clientRequest struct {
+ Method string "method"
+ Params [1]interface{} "params"
+ Id uint64 "id"
+}
+
+func (c *clientCodec) WriteRequest(r *rpc.Request, param interface{}) os.Error {
+ c.mutex.Lock()
+ c.pending[r.Seq] = r.ServiceMethod
+ c.mutex.Unlock()
+ c.req.Method = r.ServiceMethod
+ c.req.Params[0] = param
+ c.req.Id = r.Seq
+ return c.enc.Encode(&c.req)
+}
+
+type clientResponse struct {
+ Id uint64 "id"
+ Result *json.RawMessage "result"
+ Error interface{} "error"
+}
+
+func (r *clientResponse) reset() {
+ r.Id = 0
+ r.Result = nil
+ r.Error = nil
+}
+
+func (c *clientCodec) ReadResponseHeader(r *rpc.Response) os.Error {
+ c.resp.reset()
+ if err := c.dec.Decode(&c.resp); err != nil {
+ return err
+ }
+
+ c.mutex.Lock()
+ r.ServiceMethod = c.pending[c.resp.Id]
+ c.pending[c.resp.Id] = "", false
+ c.mutex.Unlock()
+
+ r.Error = ""
+ r.Seq = c.resp.Id
+ if c.resp.Error != nil {
+ x, ok := c.resp.Error.(string)
+ if !ok {
+ return fmt.Errorf("invalid error %v", c.resp.Error)
+ }
+ if x == "" {
+ x = "unspecified error"
+ }
+ r.Error = x
+ }
+ return nil
+}
+
+func (c *clientCodec) ReadResponseBody(x interface{}) os.Error {
+ return json.Unmarshal(*c.resp.Result, x)
+}
+
+func (c *clientCodec) Close() os.Error {
+ return c.c.Close()
+}
+
+// NewClient returns a new rpc.Client to handle requests to the
+// set of services at the other end of the connection.
+func NewClient(conn io.ReadWriteCloser) *rpc.Client {
+ return rpc.NewClientWithCodec(NewClientCodec(conn))
+}
+
+// Dial connects to a JSON-RPC server at the specified network address.
+func Dial(network, address string) (*rpc.Client, os.Error) {
+ conn, err := net.Dial(network, "", address)
+ if err != nil {
+ return nil, err
+ }
+ return NewClient(conn), err
+}
diff --git a/libgo/go/rpc/jsonrpc/server.go b/libgo/go/rpc/jsonrpc/server.go
new file mode 100644
index 000000000..bf53bda8d
--- /dev/null
+++ b/libgo/go/rpc/jsonrpc/server.go
@@ -0,0 +1,133 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jsonrpc
+
+import (
+ "io"
+ "json"
+ "os"
+ "rpc"
+ "sync"
+)
+
+type serverCodec struct {
+ dec *json.Decoder // for reading JSON values
+ enc *json.Encoder // for writing JSON values
+ c io.Closer
+
+ // temporary work space
+ req serverRequest
+ resp serverResponse
+
+ // JSON-RPC clients can use arbitrary json values as request IDs.
+ // Package rpc expects uint64 request IDs.
+ // We assign uint64 sequence numbers to incoming requests
+ // but save the original request ID in the pending map.
+ // When rpc responds, we use the sequence number in
+ // the response to find the original request ID.
+ mutex sync.Mutex // protects seq, pending
+ seq uint64
+ pending map[uint64]*json.RawMessage
+}
+
+// NewServerCodec returns a new rpc.ServerCodec using JSON-RPC on conn.
+func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
+ return &serverCodec{
+ dec: json.NewDecoder(conn),
+ enc: json.NewEncoder(conn),
+ c: conn,
+ pending: make(map[uint64]*json.RawMessage),
+ }
+}
+
+type serverRequest struct {
+ Method string "method"
+ Params *json.RawMessage "params"
+ Id *json.RawMessage "id"
+}
+
+func (r *serverRequest) reset() {
+ r.Method = ""
+ if r.Params != nil {
+ *r.Params = (*r.Params)[0:0]
+ }
+ if r.Id != nil {
+ *r.Id = (*r.Id)[0:0]
+ }
+}
+
+type serverResponse struct {
+ Id *json.RawMessage "id"
+ Result interface{} "result"
+ Error interface{} "error"
+}
+
+func (c *serverCodec) ReadRequestHeader(r *rpc.Request) os.Error {
+ c.req.reset()
+ if err := c.dec.Decode(&c.req); err != nil {
+ return err
+ }
+ r.ServiceMethod = c.req.Method
+
+ // JSON request id can be any JSON value;
+ // RPC package expects uint64. Translate to
+ // internal uint64 and save JSON on the side.
+ c.mutex.Lock()
+ c.seq++
+ c.pending[c.seq] = c.req.Id
+ c.req.Id = nil
+ r.Seq = c.seq
+ c.mutex.Unlock()
+
+ return nil
+}
+
+func (c *serverCodec) ReadRequestBody(x interface{}) os.Error {
+ // JSON params is array value.
+ // RPC params is struct.
+ // Unmarshal into array containing struct for now.
+ // Should think about making RPC more general.
+ var params [1]interface{}
+ params[0] = x
+ return json.Unmarshal(*c.req.Params, &params)
+}
+
+var null = json.RawMessage([]byte("null"))
+
+func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) os.Error {
+ var resp serverResponse
+ c.mutex.Lock()
+ b, ok := c.pending[r.Seq]
+ if !ok {
+ c.mutex.Unlock()
+ return os.NewError("invalid sequence number in response")
+ }
+ c.pending[r.Seq] = nil, false
+ c.mutex.Unlock()
+
+ if b == nil {
+ // Invalid request so no id. Use JSON null.
+ b = &null
+ }
+ resp.Id = b
+ resp.Result = x
+ if r.Error == "" {
+ resp.Error = nil
+ } else {
+ resp.Error = r.Error
+ }
+ return c.enc.Encode(resp)
+}
+
+func (c *serverCodec) Close() os.Error {
+ return c.c.Close()
+}
+
+// ServeConn runs the JSON-RPC server on a single connection.
+// ServeConn blocks, serving the connection until the client hangs up.
+// The caller typically invokes ServeConn in a go statement.
+func ServeConn(conn io.ReadWriteCloser) {
+ rpc.ServeCodec(NewServerCodec(conn))
+}
diff --git a/libgo/go/rpc/server.go b/libgo/go/rpc/server.go
new file mode 100644
index 000000000..5c50bcc3a
--- /dev/null
+++ b/libgo/go/rpc/server.go
@@ -0,0 +1,530 @@
+// 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.
+
+/*
+ The rpc package provides access to the exported methods of an object across a
+ network or other I/O connection. A server registers an object, making it visible
+ as a service with the name of the type of the object. After registration, exported
+ methods of the object will be accessible remotely. A server may register multiple
+ objects (services) of different types but it is an error to register multiple
+ objects of the same type.
+
+ Only methods that satisfy these criteria will be made available for remote access;
+ other methods will be ignored:
+
+ - the method receiver and name are exported, that is, begin with an upper case letter.
+ - the method has two arguments, both pointers to exported types.
+ - the method has return type os.Error.
+
+ The method's first argument represents the arguments provided by the caller; the
+ second argument represents the result parameters to be returned to the caller.
+ The method's return value, if non-nil, is passed back as a string that the client
+ sees as an os.ErrorString.
+
+ The server may handle requests on a single connection by calling ServeConn. More
+ typically it will create a network listener and call Accept or, for an HTTP
+ listener, HandleHTTP and http.Serve.
+
+ A client wishing to use the service establishes a connection and then invokes
+ NewClient on the connection. The convenience function Dial (DialHTTP) performs
+ both steps for a raw network connection (an HTTP connection). The resulting
+ Client object has two methods, Call and Go, that specify the service and method to
+ call, a pointer containing the arguments, and a pointer to receive the result
+ parameters.
+
+ Call waits for the remote call to complete; Go launches the call asynchronously
+ and returns a channel that will signal completion.
+
+ Package "gob" is used to transport the data.
+
+ Here is a simple example. A server wishes to export an object of type Arith:
+
+ package server
+
+ type Args struct {
+ A, B int
+ }
+
+ type Quotient struct {
+ Quo, Rem int
+ }
+
+ type Arith int
+
+ func (t *Arith) Multiply(args *Args, reply *int) os.Error {
+ *reply = args.A * args.B
+ return nil
+ }
+
+ func (t *Arith) Divide(args *Args, quo *Quotient) os.Error {
+ if args.B == 0 {
+ return os.ErrorString("divide by zero")
+ }
+ quo.Quo = args.A / args.B
+ quo.Rem = args.A % args.B
+ return nil
+ }
+
+ The server calls (for HTTP service):
+
+ arith := new(Arith)
+ rpc.Register(arith)
+ rpc.HandleHTTP()
+ l, e := net.Listen("tcp", ":1234")
+ if e != nil {
+ log.Exit("listen error:", e)
+ }
+ go http.Serve(l, nil)
+
+ At this point, clients can see a service "Arith" with methods "Arith.Multiply" and
+ "Arith.Divide". To invoke one, a client first dials the server:
+
+ client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
+ if err != nil {
+ log.Exit("dialing:", err)
+ }
+
+ Then it can make a remote call:
+
+ // Synchronous call
+ args := &server.Args{7,8}
+ var reply int
+ err = client.Call("Arith.Multiply", args, &reply)
+ if err != nil {
+ log.Exit("arith error:", err)
+ }
+ fmt.Printf("Arith: %d*%d=%d", args.A, args.B, *reply)
+
+ or
+
+ // Asynchronous call
+ quotient := new(Quotient)
+ divCall := client.Go("Arith.Divide", args, &quotient, nil)
+ replyCall := <-divCall.Done // will be equal to divCall
+ // check errors, print, etc.
+
+ A server implementation will often provide a simple, type-safe wrapper for the
+ client.
+*/
+package rpc
+
+import (
+ "gob"
+ "http"
+ "log"
+ "io"
+ "net"
+ "os"
+ "reflect"
+ "strings"
+ "sync"
+ "unicode"
+ "utf8"
+)
+
+const (
+ // Defaults used by HandleHTTP
+ DefaultRPCPath = "/_goRPC_"
+ DefaultDebugPath = "/debug/rpc"
+)
+
+// Precompute the reflect type for os.Error. Can't use os.Error directly
+// because Typeof takes an empty interface value. This is annoying.
+var unusedError *os.Error
+var typeOfOsError = reflect.Typeof(unusedError).(*reflect.PtrType).Elem()
+
+type methodType struct {
+ sync.Mutex // protects counters
+ method reflect.Method
+ ArgType *reflect.PtrType
+ ReplyType *reflect.PtrType
+ numCalls uint
+}
+
+type service struct {
+ name string // name of service
+ rcvr reflect.Value // receiver of methods for the service
+ typ reflect.Type // type of the receiver
+ method map[string]*methodType // registered methods
+}
+
+// Request is a header written before every RPC call. It is used internally
+// but documented here as an aid to debugging, such as when analyzing
+// network traffic.
+type Request struct {
+ ServiceMethod string // format: "Service.Method"
+ Seq uint64 // sequence number chosen by client
+}
+
+// Response is a header written before every RPC return. It is used internally
+// but documented here as an aid to debugging, such as when analyzing
+// network traffic.
+type Response struct {
+ ServiceMethod string // echoes that of the Request
+ Seq uint64 // echoes that of the request
+ Error string // error, if any.
+}
+
+// ClientInfo records information about an RPC client connection.
+type ClientInfo struct {
+ LocalAddr string
+ RemoteAddr string
+}
+
+// Server represents an RPC Server.
+type Server struct {
+ sync.Mutex // protects the serviceMap
+ serviceMap map[string]*service
+}
+
+// NewServer returns a new Server.
+func NewServer() *Server {
+ return &Server{serviceMap: make(map[string]*service)}
+}
+
+// DefaultServer is the default instance of *Server.
+var DefaultServer = NewServer()
+
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
+// Register publishes in the server the set of methods of the
+// receiver value that satisfy the following conditions:
+// - exported method
+// - two arguments, both pointers to exported structs
+// - one return value, of type os.Error
+// It returns an error if the receiver is not an exported type or has no
+// suitable methods.
+// The client accesses each method using a string of the form "Type.Method",
+// where Type is the receiver's concrete type.
+func (server *Server) Register(rcvr interface{}) os.Error {
+ return server.register(rcvr, "", false)
+}
+
+// RegisterName is like Register but uses the provided name for the type
+// instead of the receiver's concrete type.
+func (server *Server) RegisterName(name string, rcvr interface{}) os.Error {
+ return server.register(rcvr, name, true)
+}
+
+func (server *Server) register(rcvr interface{}, name string, useName bool) os.Error {
+ server.Lock()
+ defer server.Unlock()
+ if server.serviceMap == nil {
+ server.serviceMap = make(map[string]*service)
+ }
+ s := new(service)
+ s.typ = reflect.Typeof(rcvr)
+ s.rcvr = reflect.NewValue(rcvr)
+ sname := reflect.Indirect(s.rcvr).Type().Name()
+ if useName {
+ sname = name
+ }
+ if sname == "" {
+ log.Exit("rpc: no service name for type", s.typ.String())
+ }
+ if s.typ.PkgPath() != "" && !isExported(sname) && !useName {
+ s := "rpc Register: type " + sname + " is not exported"
+ log.Print(s)
+ return os.ErrorString(s)
+ }
+ if _, present := server.serviceMap[sname]; present {
+ return os.ErrorString("rpc: service already defined: " + sname)
+ }
+ s.name = sname
+ s.method = make(map[string]*methodType)
+
+ // Install the methods
+ for m := 0; m < s.typ.NumMethod(); m++ {
+ method := s.typ.Method(m)
+ mtype := method.Type
+ mname := method.Name
+ if mtype.PkgPath() != "" || !isExported(mname) {
+ continue
+ }
+ // Method needs three ins: receiver, *args, *reply.
+ if mtype.NumIn() != 3 {
+ log.Println("method", mname, "has wrong number of ins:", mtype.NumIn())
+ continue
+ }
+ argType, ok := mtype.In(1).(*reflect.PtrType)
+ if !ok {
+ log.Println(mname, "arg type not a pointer:", mtype.In(1))
+ continue
+ }
+ replyType, ok := mtype.In(2).(*reflect.PtrType)
+ if !ok {
+ log.Println(mname, "reply type not a pointer:", mtype.In(2))
+ continue
+ }
+ if argType.Elem().PkgPath() != "" && !isExported(argType.Elem().Name()) {
+ log.Println(mname, "argument type not exported:", argType)
+ continue
+ }
+ if replyType.Elem().PkgPath() != "" && !isExported(replyType.Elem().Name()) {
+ log.Println(mname, "reply type not exported:", replyType)
+ continue
+ }
+ if mtype.NumIn() == 4 {
+ t := mtype.In(3)
+ if t != reflect.Typeof((*ClientInfo)(nil)) {
+ log.Println(mname, "last argument not *ClientInfo")
+ continue
+ }
+ }
+ // Method needs one out: os.Error.
+ if mtype.NumOut() != 1 {
+ log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
+ continue
+ }
+ if returnType := mtype.Out(0); returnType != typeOfOsError {
+ log.Println("method", mname, "returns", returnType.String(), "not os.Error")
+ continue
+ }
+ s.method[mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType}
+ }
+
+ if len(s.method) == 0 {
+ s := "rpc Register: type " + sname + " has no exported methods of suitable type"
+ log.Print(s)
+ return os.ErrorString(s)
+ }
+ server.serviceMap[s.name] = s
+ return nil
+}
+
+// A value sent as a placeholder for the response when the server receives an invalid request.
+type InvalidRequest struct {
+ marker int
+}
+
+var invalidRequest = InvalidRequest{1}
+
+func _new(t *reflect.PtrType) *reflect.PtrValue {
+ v := reflect.MakeZero(t).(*reflect.PtrValue)
+ v.PointTo(reflect.MakeZero(t.Elem()))
+ return v
+}
+
+func sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec ServerCodec, errmsg string) {
+ resp := new(Response)
+ // Encode the response header
+ resp.ServiceMethod = req.ServiceMethod
+ if errmsg != "" {
+ resp.Error = errmsg
+ }
+ resp.Seq = req.Seq
+ sending.Lock()
+ err := codec.WriteResponse(resp, reply)
+ if err != nil {
+ log.Println("rpc: writing response:", err)
+ }
+ sending.Unlock()
+}
+
+func (m *methodType) NumCalls() (n uint) {
+ m.Lock()
+ n = m.numCalls
+ m.Unlock()
+ return n
+}
+
+func (s *service) call(sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec) {
+ mtype.Lock()
+ mtype.numCalls++
+ mtype.Unlock()
+ function := mtype.method.Func
+ // Invoke the method, providing a new value for the reply.
+ returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})
+ // The return value for the method is an os.Error.
+ errInter := returnValues[0].Interface()
+ errmsg := ""
+ if errInter != nil {
+ errmsg = errInter.(os.Error).String()
+ }
+ sendResponse(sending, req, replyv.Interface(), codec, errmsg)
+}
+
+type gobServerCodec struct {
+ rwc io.ReadWriteCloser
+ dec *gob.Decoder
+ enc *gob.Encoder
+}
+
+func (c *gobServerCodec) ReadRequestHeader(r *Request) os.Error {
+ return c.dec.Decode(r)
+}
+
+func (c *gobServerCodec) ReadRequestBody(body interface{}) os.Error {
+ return c.dec.Decode(body)
+}
+
+func (c *gobServerCodec) WriteResponse(r *Response, body interface{}) os.Error {
+ if err := c.enc.Encode(r); err != nil {
+ return err
+ }
+ return c.enc.Encode(body)
+}
+
+func (c *gobServerCodec) Close() os.Error {
+ return c.rwc.Close()
+}
+
+
+// ServeConn runs the server on a single connection.
+// ServeConn blocks, serving the connection until the client hangs up.
+// The caller typically invokes ServeConn in a go statement.
+// ServeConn uses the gob wire format (see package gob) on the
+// connection. To use an alternate codec, use ServeCodec.
+func (server *Server) ServeConn(conn io.ReadWriteCloser) {
+ server.ServeCodec(&gobServerCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(conn)})
+}
+
+// ServeCodec is like ServeConn but uses the specified codec to
+// decode requests and encode responses.
+func (server *Server) ServeCodec(codec ServerCodec) {
+ sending := new(sync.Mutex)
+ for {
+ // Grab the request header.
+ req := new(Request)
+ err := codec.ReadRequestHeader(req)
+ if err != nil {
+ if err == os.EOF || err == io.ErrUnexpectedEOF {
+ if err == io.ErrUnexpectedEOF {
+ log.Println("rpc:", err)
+ }
+ break
+ }
+ s := "rpc: server cannot decode request: " + err.String()
+ sendResponse(sending, req, invalidRequest, codec, s)
+ break
+ }
+ serviceMethod := strings.Split(req.ServiceMethod, ".", -1)
+ if len(serviceMethod) != 2 {
+ s := "rpc: service/method request ill-formed: " + req.ServiceMethod
+ sendResponse(sending, req, invalidRequest, codec, s)
+ continue
+ }
+ // Look up the request.
+ server.Lock()
+ service, ok := server.serviceMap[serviceMethod[0]]
+ server.Unlock()
+ if !ok {
+ s := "rpc: can't find service " + req.ServiceMethod
+ sendResponse(sending, req, invalidRequest, codec, s)
+ continue
+ }
+ mtype, ok := service.method[serviceMethod[1]]
+ if !ok {
+ s := "rpc: can't find method " + req.ServiceMethod
+ sendResponse(sending, req, invalidRequest, codec, s)
+ continue
+ }
+ // Decode the argument value.
+ argv := _new(mtype.ArgType)
+ replyv := _new(mtype.ReplyType)
+ err = codec.ReadRequestBody(argv.Interface())
+ if err != nil {
+ log.Println("rpc: tearing down", serviceMethod[0], "connection:", err)
+ sendResponse(sending, req, replyv.Interface(), codec, err.String())
+ break
+ }
+ go service.call(sending, mtype, req, argv, replyv, codec)
+ }
+ codec.Close()
+}
+
+// Accept accepts connections on the listener and serves requests
+// for each incoming connection. Accept blocks; the caller typically
+// invokes it in a go statement.
+func (server *Server) Accept(lis net.Listener) {
+ for {
+ conn, err := lis.Accept()
+ if err != nil {
+ log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit?
+ }
+ go server.ServeConn(conn)
+ }
+}
+
+// Register publishes the receiver's methods in the DefaultServer.
+func Register(rcvr interface{}) os.Error { return DefaultServer.Register(rcvr) }
+
+// RegisterName is like Register but uses the provided name for the type
+// instead of the receiver's concrete type.
+func RegisterName(name string, rcvr interface{}) os.Error {
+ return DefaultServer.RegisterName(name, rcvr)
+}
+
+// A ServerCodec implements reading of RPC requests and writing of
+// RPC responses for the server side of an RPC session.
+// The server calls ReadRequestHeader and ReadRequestBody in pairs
+// to read requests from the connection, and it calls WriteResponse to
+// write a response back. The server calls Close when finished with the
+// connection.
+type ServerCodec interface {
+ ReadRequestHeader(*Request) os.Error
+ ReadRequestBody(interface{}) os.Error
+ WriteResponse(*Response, interface{}) os.Error
+
+ Close() os.Error
+}
+
+// ServeConn runs the DefaultServer on a single connection.
+// ServeConn blocks, serving the connection until the client hangs up.
+// The caller typically invokes ServeConn in a go statement.
+// ServeConn uses the gob wire format (see package gob) on the
+// connection. To use an alternate codec, use ServeCodec.
+func ServeConn(conn io.ReadWriteCloser) {
+ DefaultServer.ServeConn(conn)
+}
+
+// ServeCodec is like ServeConn but uses the specified codec to
+// decode requests and encode responses.
+func ServeCodec(codec ServerCodec) {
+ DefaultServer.ServeCodec(codec)
+}
+
+// Accept accepts connections on the listener and serves requests
+// to DefaultServer for each incoming connection.
+// Accept blocks; the caller typically invokes it in a go statement.
+func Accept(lis net.Listener) { DefaultServer.Accept(lis) }
+
+// Can connect to RPC service using HTTP CONNECT to rpcPath.
+var connected = "200 Connected to Go RPC"
+
+// ServeHTTP implements an http.Handler that answers RPC requests.
+func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ if req.Method != "CONNECT" {
+ w.SetHeader("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ io.WriteString(w, "405 must CONNECT\n")
+ return
+ }
+ conn, _, err := w.Hijack()
+ if err != nil {
+ log.Print("rpc hijacking ", w.RemoteAddr(), ": ", err.String())
+ return
+ }
+ io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
+ server.ServeConn(conn)
+}
+
+// HandleHTTP registers an HTTP handler for RPC messages on rpcPath,
+// and a debugging handler on debugPath.
+// It is still necessary to invoke http.Serve(), typically in a go statement.
+func (server *Server) HandleHTTP(rpcPath, debugPath string) {
+ http.Handle(rpcPath, server)
+ http.Handle(debugPath, debugHTTP{server})
+}
+
+// HandleHTTP registers an HTTP handler for RPC messages to DefaultServer
+// on DefaultRPCPath and a debugging handler on DefaultDebugPath.
+// It is still necessary to invoke http.Serve(), typically in a go statement.
+func HandleHTTP() {
+ DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath)
+}
diff --git a/libgo/go/rpc/server_test.go b/libgo/go/rpc/server_test.go
new file mode 100644
index 000000000..355d51ce4
--- /dev/null
+++ b/libgo/go/rpc/server_test.go
@@ -0,0 +1,384 @@
+// 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 rpc
+
+import (
+ "fmt"
+ "http"
+ "log"
+ "net"
+ "os"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+)
+
+var (
+ serverAddr, newServerAddr string
+ httpServerAddr string
+ once, newOnce, httpOnce sync.Once
+)
+
+const (
+ second = 1e9
+ newHttpPath = "/foo"
+)
+
+type Args struct {
+ A, B int
+}
+
+type Reply struct {
+ C int
+}
+
+type Arith int
+
+func (t *Arith) Add(args *Args, reply *Reply) os.Error {
+ reply.C = args.A + args.B
+ return nil
+}
+
+func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
+ reply.C = args.A * args.B
+ return nil
+}
+
+func (t *Arith) Div(args *Args, reply *Reply) os.Error {
+ if args.B == 0 {
+ return os.ErrorString("divide by zero")
+ }
+ reply.C = args.A / args.B
+ return nil
+}
+
+func (t *Arith) String(args *Args, reply *string) os.Error {
+ *reply = fmt.Sprintf("%d+%d=%d", args.A, args.B, args.A+args.B)
+ return nil
+}
+
+func (t *Arith) Scan(args *string, reply *Reply) (err os.Error) {
+ _, err = fmt.Sscan(*args, &reply.C)
+ return
+}
+
+func (t *Arith) Error(args *Args, reply *Reply) os.Error {
+ panic("ERROR")
+}
+
+func listenTCP() (net.Listener, string) {
+ l, e := net.Listen("tcp", "127.0.0.1:0") // any available address
+ if e != nil {
+ log.Exitf("net.Listen tcp :0: %v", e)
+ }
+ return l, l.Addr().String()
+}
+
+func startServer() {
+ Register(new(Arith))
+
+ var l net.Listener
+ l, serverAddr = listenTCP()
+ log.Println("Test RPC server listening on", serverAddr)
+ go Accept(l)
+
+ HandleHTTP()
+ httpOnce.Do(startHttpServer)
+}
+
+func startNewServer() {
+ s := NewServer()
+ s.Register(new(Arith))
+
+ var l net.Listener
+ l, newServerAddr = listenTCP()
+ log.Println("NewServer test RPC server listening on", newServerAddr)
+ go Accept(l)
+
+ s.HandleHTTP(newHttpPath, "/bar")
+ httpOnce.Do(startHttpServer)
+}
+
+func startHttpServer() {
+ var l net.Listener
+ l, httpServerAddr = listenTCP()
+ httpServerAddr = l.Addr().String()
+ log.Println("Test HTTP RPC server listening on", httpServerAddr)
+ go http.Serve(l, nil)
+}
+
+func TestRPC(t *testing.T) {
+ once.Do(startServer)
+ testRPC(t, serverAddr)
+ newOnce.Do(startNewServer)
+ testRPC(t, newServerAddr)
+}
+
+func testRPC(t *testing.T, addr string) {
+ client, err := Dial("tcp", addr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+
+ // Synchronous calls
+ args := &Args{7, 8}
+ reply := new(Reply)
+ err = client.Call("Arith.Add", args, reply)
+ if err != nil {
+ t.Errorf("Add: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+ }
+
+ args = &Args{7, 8}
+ reply = new(Reply)
+ err = client.Call("Arith.Mul", args, reply)
+ if err != nil {
+ t.Errorf("Mul: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A*args.B {
+ t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B)
+ }
+
+ // Out of order.
+ args = &Args{7, 8}
+ mulReply := new(Reply)
+ mulCall := client.Go("Arith.Mul", args, mulReply, nil)
+ addReply := new(Reply)
+ addCall := client.Go("Arith.Add", args, addReply, nil)
+
+ addCall = <-addCall.Done
+ if addCall.Error != nil {
+ t.Errorf("Add: expected no error but got string %q", addCall.Error.String())
+ }
+ if addReply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", addReply.C, args.A+args.B)
+ }
+
+ mulCall = <-mulCall.Done
+ if mulCall.Error != nil {
+ t.Errorf("Mul: expected no error but got string %q", mulCall.Error.String())
+ }
+ if mulReply.C != args.A*args.B {
+ t.Errorf("Mul: expected %d got %d", mulReply.C, args.A*args.B)
+ }
+
+ // Error test
+ args = &Args{7, 0}
+ reply = new(Reply)
+ err = client.Call("Arith.Div", args, reply)
+ // expect an error: zero divide
+ if err == nil {
+ t.Error("Div: expected error")
+ } else if err.String() != "divide by zero" {
+ t.Error("Div: expected divide by zero error; got", err)
+ }
+
+ // Non-struct argument
+ const Val = 12345
+ str := fmt.Sprint(Val)
+ reply = new(Reply)
+ err = client.Call("Arith.Scan", &str, reply)
+ if err != nil {
+ t.Errorf("Scan: expected no error but got string %q", err.String())
+ } else if reply.C != Val {
+ t.Errorf("Scan: expected %d got %d", Val, reply.C)
+ }
+
+ // Non-struct reply
+ args = &Args{27, 35}
+ str = ""
+ err = client.Call("Arith.String", args, &str)
+ if err != nil {
+ t.Errorf("String: expected no error but got string %q", err.String())
+ }
+ expect := fmt.Sprintf("%d+%d=%d", args.A, args.B, args.A+args.B)
+ if str != expect {
+ t.Errorf("String: expected %s got %s", expect, str)
+ }
+}
+
+func TestHTTPRPC(t *testing.T) {
+ once.Do(startServer)
+ testHTTPRPC(t, "")
+ newOnce.Do(startNewServer)
+ testHTTPRPC(t, newHttpPath)
+}
+
+func testHTTPRPC(t *testing.T, path string) {
+ var client *Client
+ var err os.Error
+ if path == "" {
+ client, err = DialHTTP("tcp", httpServerAddr)
+ } else {
+ client, err = DialHTTPPath("tcp", httpServerAddr, path)
+ }
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+
+ // Synchronous calls
+ args := &Args{7, 8}
+ reply := new(Reply)
+ err = client.Call("Arith.Add", args, reply)
+ if err != nil {
+ t.Errorf("Add: expected no error but got string %q", err.String())
+ }
+ if reply.C != args.A+args.B {
+ t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
+ }
+}
+
+func TestCheckUnknownService(t *testing.T) {
+ once.Do(startServer)
+
+ conn, err := net.Dial("tcp", "", serverAddr)
+ if err != nil {
+ t.Fatal("dialing:", err)
+ }
+
+ client := NewClient(conn)
+
+ args := &Args{7, 8}
+ reply := new(Reply)
+ err = client.Call("Unknown.Add", args, reply)
+ if err == nil {
+ t.Error("expected error calling unknown service")
+ } else if strings.Index(err.String(), "service") < 0 {
+ t.Error("expected error about service; got", err)
+ }
+}
+
+func TestCheckUnknownMethod(t *testing.T) {
+ once.Do(startServer)
+
+ conn, err := net.Dial("tcp", "", serverAddr)
+ if err != nil {
+ t.Fatal("dialing:", err)
+ }
+
+ client := NewClient(conn)
+
+ args := &Args{7, 8}
+ reply := new(Reply)
+ err = client.Call("Arith.Unknown", args, reply)
+ if err == nil {
+ t.Error("expected error calling unknown service")
+ } else if strings.Index(err.String(), "method") < 0 {
+ t.Error("expected error about method; got", err)
+ }
+}
+
+func TestCheckBadType(t *testing.T) {
+ once.Do(startServer)
+
+ conn, err := net.Dial("tcp", "", serverAddr)
+ if err != nil {
+ t.Fatal("dialing:", err)
+ }
+
+ client := NewClient(conn)
+
+ reply := new(Reply)
+ err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use
+ if err == nil {
+ t.Error("expected error calling Arith.Add with wrong arg type")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("expected error about type; got", err)
+ }
+}
+
+type ArgNotPointer int
+type ReplyNotPointer int
+type ArgNotPublic int
+type ReplyNotPublic int
+type local struct{}
+
+func (t *ArgNotPointer) ArgNotPointer(args Args, reply *Reply) os.Error {
+ return nil
+}
+
+func (t *ReplyNotPointer) ReplyNotPointer(args *Args, reply Reply) os.Error {
+ return nil
+}
+
+func (t *ArgNotPublic) ArgNotPublic(args *local, reply *Reply) os.Error {
+ return nil
+}
+
+func (t *ReplyNotPublic) ReplyNotPublic(args *Args, reply *local) os.Error {
+ return nil
+}
+
+// Check that registration handles lots of bad methods and a type with no suitable methods.
+func TestRegistrationError(t *testing.T) {
+ err := Register(new(ArgNotPointer))
+ if err == nil {
+ t.Errorf("expected error registering ArgNotPointer")
+ }
+ err = Register(new(ReplyNotPointer))
+ if err == nil {
+ t.Errorf("expected error registering ReplyNotPointer")
+ }
+ err = Register(new(ArgNotPublic))
+ if err == nil {
+ t.Errorf("expected error registering ArgNotPublic")
+ }
+ err = Register(new(ReplyNotPublic))
+ if err == nil {
+ t.Errorf("expected error registering ReplyNotPublic")
+ }
+}
+
+type WriteFailCodec int
+
+func (WriteFailCodec) WriteRequest(*Request, interface{}) os.Error {
+ // the panic caused by this error used to not unlock a lock.
+ return os.NewError("fail")
+}
+
+func (WriteFailCodec) ReadResponseHeader(*Response) os.Error {
+ time.Sleep(60e9)
+ panic("unreachable")
+}
+
+func (WriteFailCodec) ReadResponseBody(interface{}) os.Error {
+ time.Sleep(60e9)
+ panic("unreachable")
+}
+
+func (WriteFailCodec) Close() os.Error {
+ return nil
+}
+
+func TestSendDeadlock(t *testing.T) {
+ client := NewClientWithCodec(WriteFailCodec(0))
+
+ done := make(chan bool)
+ go func() {
+ testSendDeadlock(client)
+ testSendDeadlock(client)
+ done <- true
+ }()
+ for i := 0; i < 50; i++ {
+ time.Sleep(100 * 1e6)
+ _, ok := <-done
+ if ok {
+ return
+ }
+ }
+ t.Fatal("deadlock")
+}
+
+func testSendDeadlock(client *Client) {
+ defer func() {
+ recover()
+ }()
+ args := &Args{7, 8}
+ reply := new(Reply)
+ client.Call("Arith.Add", args, reply)
+}
diff --git a/libgo/go/runtime/chan_defs.go b/libgo/go/runtime/chan_defs.go
new file mode 100644
index 000000000..5cfea6e15
--- /dev/null
+++ b/libgo/go/runtime/chan_defs.go
@@ -0,0 +1,56 @@
+// 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.
+
+// Go definitions of internal structures. Master is chan.c
+
+package runtime
+
+type sudoG struct {
+ g *g_
+ selgen uint32
+ offset int16
+ isfree int8
+ link *sudoG
+ elem [8]byte
+}
+
+type waitQ struct {
+ first *sudoG
+ last *sudoG
+}
+
+type hChan struct {
+ qcount uint32
+ dataqsiz uint32
+ elemsize uint16
+ closed uint16
+ elemalign uint8
+ elemalg *alg
+ senddataq *link
+ recvdataq *link
+ recvq waitQ
+ sendq waitQ
+ free sudoG
+ lock
+}
+
+type link struct {
+ link *link
+ elem [8]byte
+}
+
+type scase struct {
+ chan_ *hChan
+ pc *byte
+ send uint16
+ so uint16
+ elemp *byte // union elem [8]byte
+}
+
+type select_ struct {
+ tcase uint16
+ ncase uint16
+ link *select_
+ scase [1]*scase
+}
diff --git a/libgo/go/runtime/debug.go b/libgo/go/runtime/debug.go
new file mode 100644
index 000000000..803ea4921
--- /dev/null
+++ b/libgo/go/runtime/debug.go
@@ -0,0 +1,159 @@
+// 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 runtime
+
+import "unsafe"
+
+// Breakpoint() executes a breakpoint trap.
+func Breakpoint()
+
+// LockOSThread wires the calling goroutine to its current operating system thread.
+// Until the calling goroutine exits or calls UnlockOSThread, it will always
+// execute in that thread, and no other goroutine can.
+// LockOSThread cannot be used during init functions.
+func LockOSThread()
+
+// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
+// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.
+func UnlockOSThread()
+
+// GOMAXPROCS sets the maximum number of CPUs that can be executing
+// simultaneously and returns the previous setting. If n < 1, it does not
+// change the current setting.
+// This call will go away when the scheduler improves.
+func GOMAXPROCS(n int) int
+
+// Cgocalls returns the number of cgo calls made by the current process.
+func Cgocalls() int64
+
+// Goroutines returns the number of goroutines that currently exist.
+func Goroutines() int32
+
+type MemStatsType struct {
+ // General statistics.
+ // Not locked during update; approximate.
+ Alloc uint64 // bytes allocated and still in use
+ TotalAlloc uint64 // bytes allocated (even if freed)
+ Sys uint64 // bytes obtained from system (should be sum of XxxSys below)
+ Lookups uint64 // number of pointer lookups
+ Mallocs uint64 // number of mallocs
+ Frees uint64 // number of frees
+
+ // Main allocation heap statistics.
+ HeapAlloc uint64 // bytes allocated and still in use
+ HeapSys uint64 // bytes obtained from system
+ HeapIdle uint64 // bytes in idle spans
+ HeapInuse uint64 // bytes in non-idle span
+ HeapObjects uint64 // total number of allocated objects
+
+ // Low-level fixed-size structure allocator statistics.
+ // Inuse is bytes used now.
+ // Sys is bytes obtained from system.
+ StackInuse uint64 // bootstrap stacks
+ StackSys uint64
+ MSpanInuse uint64 // mspan structures
+ MSpanSys uint64
+ MCacheInuse uint64 // mcache structures
+ MCacheSys uint64
+ MHeapMapSys uint64 // heap map
+ BuckHashSys uint64 // profiling bucket hash table
+
+ // Garbage collector statistics.
+ NextGC uint64
+ PauseTotalNs uint64
+ PauseNs [256]uint64 // most recent GC pause times
+ NumGC uint32
+ EnableGC bool
+ DebugGC bool
+
+ // Per-size allocation statistics.
+ // Not locked during update; approximate.
+ BySize [67]struct {
+ Size uint32
+ Mallocs uint64
+ Frees uint64
+ }
+}
+
+var Sizeof_C_MStats int // filled in by malloc.goc
+
+func init() {
+ if Sizeof_C_MStats != unsafe.Sizeof(MemStats) {
+ println(Sizeof_C_MStats, unsafe.Sizeof(MemStats))
+ panic("MStats vs MemStatsType size mismatch")
+ }
+}
+
+// MemStats holds statistics about the memory system.
+// The statistics are only approximate, as they are not interlocked on update.
+var MemStats MemStatsType
+
+// Alloc allocates a block of the given size.
+// FOR TESTING AND DEBUGGING ONLY.
+func Alloc(uintptr) *byte
+
+// Free frees the block starting at the given pointer.
+// FOR TESTING AND DEBUGGING ONLY.
+func Free(*byte)
+
+// Lookup returns the base and size of the block containing the given pointer.
+// FOR TESTING AND DEBUGGING ONLY.
+func Lookup(*byte) (*byte, uintptr)
+
+// GC runs a garbage collection.
+func GC()
+
+// MemProfileRate controls the fraction of memory allocations
+// that are recorded and reported in the memory profile.
+// The profiler aims to sample an average of
+// one allocation per MemProfileRate bytes allocated.
+//
+// To include every allocated block in the profile, set MemProfileRate to 1.
+// To turn off profiling entirely, set MemProfileRate to 0.
+//
+// The tools that process the memory profiles assume that the
+// profile rate is constant across the lifetime of the program
+// and equal to the current value. Programs that change the
+// memory profiling rate should do so just once, as early as
+// possible in the execution of the program (for example,
+// at the beginning of main).
+var MemProfileRate int = 512 * 1024
+
+// A MemProfileRecord describes the live objects allocated
+// by a particular call sequence (stack trace).
+type MemProfileRecord struct {
+ AllocBytes, FreeBytes int64 // number of bytes allocated, freed
+ AllocObjects, FreeObjects int64 // number of objects allocated, freed
+ Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
+}
+
+// InUseBytes returns the number of bytes in use (AllocBytes - FreeBytes).
+func (r *MemProfileRecord) InUseBytes() int64 { return r.AllocBytes - r.FreeBytes }
+
+// InUseObjects returns the number of objects in use (AllocObjects - FreeObjects).
+func (r *MemProfileRecord) InUseObjects() int64 {
+ return r.AllocObjects - r.FreeObjects
+}
+
+// Stack returns the stack trace associated with the record,
+// a prefix of r.Stack0.
+func (r *MemProfileRecord) Stack() []uintptr {
+ for i, v := range r.Stack0 {
+ if v == 0 {
+ return r.Stack0[0:i]
+ }
+ }
+ return r.Stack0[0:]
+}
+
+// MemProfile returns n, the number of records in the current memory profile.
+// If len(p) >= n, MemProfile copies the profile into p and returns n, true.
+// If len(p) < n, MemProfile does not change p and returns n, false.
+//
+// If inuseZero is true, the profile includes allocation records
+// where r.AllocBytes > 0 but r.AllocBytes == r.FreeBytes.
+// These are sites where memory was allocated, but it has all
+// been released back to the runtime.
+func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool)
diff --git a/libgo/go/runtime/debug/stack.go b/libgo/go/runtime/debug/stack.go
new file mode 100644
index 000000000..e7d56ac23
--- /dev/null
+++ b/libgo/go/runtime/debug/stack.go
@@ -0,0 +1,90 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The debug package contains facilities for programs to debug themselves
+// while they are running.
+package debug
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "runtime"
+)
+
+var (
+ dunno = []byte("???")
+ centerDot = []byte("·")
+ dot = []byte(".")
+)
+
+// PrintStack prints to standard error the stack trace returned by Stack.
+func PrintStack() {
+ os.Stderr.Write(stack())
+}
+
+// Stack returns a formatted stack trace of the goroutine that calls it.
+// For each routine, it includes the source line information and PC value,
+// then attempts to discover, for Go functions, the calling function or
+// method and the text of the line containing the invocation.
+func Stack() []byte {
+ return stack()
+}
+
+// stack implements Stack, skipping 2 frames
+func stack() []byte {
+ buf := new(bytes.Buffer) // the returned data
+ // As we loop, we open files and read them. These variables record the currently
+ // loaded file.
+ var lines [][]byte
+ var lastFile string
+ for i := 2; ; i++ { // Caller we care about is the user, 2 frames up
+ pc, file, line, ok := runtime.Caller(i)
+ if !ok {
+ break
+ }
+ // Print this much at least. If we can't find the source, it won't show.
+ fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
+ if file != lastFile {
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ continue
+ }
+ lines = bytes.Split(data, []byte{'\n'}, -1)
+ lastFile = file
+ }
+ line-- // in stack trace, lines are 1-indexed but our array is 0-indexed
+ fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
+ }
+ return buf.Bytes()
+}
+
+// source returns a space-trimmed slice of the n'th line.
+func source(lines [][]byte, n int) []byte {
+ if n < 0 || n >= len(lines) {
+ return dunno
+ }
+ return bytes.Trim(lines[n], " \t")
+}
+
+// function returns, if possible, the name of the function containing the PC.
+func function(pc uintptr) []byte {
+ fn := runtime.FuncForPC(pc)
+ if fn == nil {
+ return dunno
+ }
+ name := []byte(fn.Name())
+ // The name includes the path name to the package, which is unnecessary
+ // since the file name is already included. Plus, it has center dots.
+ // That is, we see
+ // runtime/debug.*T·ptrmethod
+ // and want
+ // *T.ptrmethod
+ if period := bytes.Index(name, dot); period >= 0 {
+ name = name[period+1:]
+ }
+ name = bytes.Replace(name, centerDot, dot, -1)
+ return name
+}
diff --git a/libgo/go/runtime/debug/stack_test.go b/libgo/go/runtime/debug/stack_test.go
new file mode 100644
index 000000000..f4bdc4624
--- /dev/null
+++ b/libgo/go/runtime/debug/stack_test.go
@@ -0,0 +1,55 @@
+// 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 debug
+
+import (
+ "strings"
+ "testing"
+)
+
+type T int
+
+func (t *T) ptrmethod() []byte {
+ return Stack()
+}
+func (t T) method() []byte {
+ return t.ptrmethod()
+}
+
+/*
+ The traceback should look something like this, modulo line numbers and hex constants.
+ Don't worry much about the base levels, but check the ones in our own package.
+
+ /Users/r/go/src/pkg/runtime/debug/stack_test.go:15 (0x13878)
+ *T.ptrmethod: return Stack()
+ /Users/r/go/src/pkg/runtime/debug/stack_test.go:18 (0x138dd)
+ T.method: return t.ptrmethod()
+ /Users/r/go/src/pkg/runtime/debug/stack_test.go:23 (0x13920)
+ TestStack: b := T(0).method()
+ /Users/r/go/src/pkg/testing/testing.go:132 (0x14a7a)
+ tRunner: test.F(t)
+ /Users/r/go/src/pkg/runtime/proc.c:145 (0xc970)
+ ???: runtime·unlock(&runtime·sched);
+*/
+func TestStack(t *testing.T) {
+ b := T(0).method()
+ lines := strings.Split(string(b), "\n", -1)
+ if len(lines) <= 6 {
+ t.Fatal("too few lines")
+ }
+ check(t, lines[0], "src/pkg/runtime/debug/stack_test.go")
+ check(t, lines[1], "\t*T.ptrmethod: return Stack()")
+ check(t, lines[2], "src/pkg/runtime/debug/stack_test.go")
+ check(t, lines[3], "\tT.method: return t.ptrmethod()")
+ check(t, lines[4], "src/pkg/runtime/debug/stack_test.go")
+ check(t, lines[5], "\tTestStack: b := T(0).method()")
+ check(t, lines[6], "src/pkg/testing/testing.go")
+}
+
+func check(t *testing.T, line, has string) {
+ if strings.Index(line, has) < 0 {
+ t.Errorf("expected %q in %q", has, line)
+ }
+}
diff --git a/libgo/go/runtime/error.go b/libgo/go/runtime/error.go
new file mode 100644
index 000000000..2515722aa
--- /dev/null
+++ b/libgo/go/runtime/error.go
@@ -0,0 +1,133 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// The Error interface identifies a run time error.
+type Error interface {
+ String() string
+
+ // RuntimeError is a no-op function but
+ // serves to distinguish types that are runtime
+ // errors from ordinary os.Errors: a type is a
+ // runtime error if it has a RuntimeError method.
+ RuntimeError()
+}
+
+// A TypeAssertionError explains a failed type assertion.
+type TypeAssertionError struct {
+ interfaceType *Type // interface had this type
+ concreteType *Type // concrete value had this type
+ assertedType *Type // asserted type
+ interfaceString string
+ concreteString string
+ assertedString string
+ missingMethod string // one method needed by Interface, missing from Concrete
+}
+
+func (*TypeAssertionError) RuntimeError() {}
+
+func (e *TypeAssertionError) String() string {
+ inter := e.interfaceString
+ if inter == "" {
+ inter = "interface"
+ }
+ if e.concreteType == nil {
+ return "interface conversion: " + inter + " is nil, not " + e.assertedString
+ }
+ if e.missingMethod == "" {
+ return "interface conversion: " + inter + " is " + e.concreteString +
+ ", not " + e.assertedString
+ }
+ return "interface conversion: " + e.concreteString + " is not " + e.assertedString +
+ ": missing method " + e.missingMethod
+}
+
+// Concrete returns the type of the concrete value in the failed type assertion.
+// If the interface value was nil, Concrete returns nil.
+func (e *TypeAssertionError) Concrete() *Type {
+ return e.concreteType
+}
+
+// Asserted returns the type incorrectly asserted by the type assertion.
+func (e *TypeAssertionError) Asserted() *Type {
+ return e.assertedType
+}
+
+// If the type assertion is to an interface type, MissingMethod returns the
+// name of a method needed to satisfy that interface type but not implemented
+// by Concrete. If there are multiple such methods,
+// MissingMethod returns one; which one is unspecified.
+// If the type assertion is not to an interface type, MissingMethod returns an empty string.
+func (e *TypeAssertionError) MissingMethod() string {
+ return e.missingMethod
+}
+
+// For calling from C.
+func NewTypeAssertionError(pt1, pt2, pt3 *Type, ps1, ps2, ps3 *string, pmeth *string, ret *interface{}) {
+ var t1, t2, t3 *Type
+ var s1, s2, s3, meth string
+
+ if pt1 != nil {
+ t1 = pt1
+ }
+ if pt2 != nil {
+ t2 = pt2
+ }
+ if pt3 != nil {
+ t3 = pt3
+ }
+ if ps1 != nil {
+ s1 = *ps1
+ }
+ if ps2 != nil {
+ s2 = *ps2
+ }
+ if ps3 != nil {
+ s3 = *ps3
+ }
+ if pmeth != nil {
+ meth = *pmeth
+ }
+ *ret = &TypeAssertionError{t1, t2, t3, s1, s2, s3, meth}
+}
+
+// An errorString represents a runtime error described by a single string.
+type errorString string
+
+func (e errorString) RuntimeError() {}
+
+func (e errorString) String() string {
+ return "runtime error: " + string(e)
+}
+
+// For calling from C.
+func NewErrorString(s string, ret *interface{}) {
+ *ret = errorString(s)
+}
+
+type stringer interface {
+ String() string
+}
+
+func typestring(interface{}) string
+
+// For calling from C.
+// Prints an argument passed to panic.
+// There's room for arbitrary complexity here, but we keep it
+// simple and handle just a few important cases: int, string, and Stringer.
+func Printany(i interface{}) {
+ switch v := i.(type) {
+ case nil:
+ print("nil")
+ case stringer:
+ print(v.String())
+ case int:
+ print(v)
+ case string:
+ print(v)
+ default:
+ print("(", typestring(i), ") ", i)
+ }
+}
diff --git a/libgo/go/runtime/export_test.go b/libgo/go/runtime/export_test.go
new file mode 100644
index 000000000..58631c7b4
--- /dev/null
+++ b/libgo/go/runtime/export_test.go
@@ -0,0 +1,17 @@
+// 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.
+
+// Export guts for testing.
+
+package runtime
+
+var Fadd64 = fadd64
+var Fsub64 = fsub64
+var Fmul64 = fmul64
+var Fdiv64 = fdiv64
+var F64to32 = f64to32
+var F32to64 = f32to64
+var Fcmp64 = fcmp64
+var Fintto64 = fintto64
+var F64toint = f64toint
diff --git a/libgo/go/runtime/extern.go b/libgo/go/runtime/extern.go
new file mode 100644
index 000000000..77c3e8e3a
--- /dev/null
+++ b/libgo/go/runtime/extern.go
@@ -0,0 +1,163 @@
+// 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.
+
+/*
+ The runtime package contains operations that interact with Go's runtime system,
+ such as functions to control goroutines. It also includes the low-level type information
+ used by the reflect package; see reflect's documentation for the programmable
+ interface to the run-time type system.
+*/
+package runtime
+
+// Gosched yields the processor, allowing other goroutines to run. It does not
+// suspend the current goroutine, so execution resumes automatically.
+func Gosched()
+
+// Goexit terminates the goroutine that calls it. No other goroutine is affected.
+// Goexit runs all deferred calls before terminating the goroutine.
+func Goexit()
+
+// Caller reports file and line number information about function invocations on
+// the calling goroutine's stack. The argument skip is the number of stack frames to
+// ascend, with 0 identifying the the caller of Caller. The return values report the
+// program counter, file name, and line number within the file of the corresponding
+// call. The boolean ok is false if it was not possible to recover the information.
+func Caller(skip int) (pc uintptr, file string, line int, ok bool)
+
+// Callers fills the slice pc with the program counters of function invocations
+// on the calling goroutine's stack. The argument skip is the number of stack frames
+// to skip before recording in pc, with 0 starting at the caller of Caller.
+// It returns the number of entries written to pc.
+func Callers(skip int, pc []uintptr) int
+
+// FuncForPC returns a *Func describing the function that contains the
+// given program counter address, or else nil.
+func FuncForPC(pc uintptr) *Func
+
+// Name returns the name of the function.
+func (f *Func) Name() string { return f.name }
+
+// Entry returns the entry address of the function.
+func (f *Func) Entry() uintptr { return f.entry }
+
+// FileLine returns the file name and line number of the
+// source code corresponding to the program counter pc.
+// The result will not be accurate if pc is not a program
+// counter within f.
+func (f *Func) FileLine(pc uintptr) (file string, line int) {
+ // NOTE(rsc): If you edit this function, also edit
+ // symtab.c:/^funcline.
+ var pcQuant uintptr = 1
+ if GOARCH == "arm" {
+ pcQuant = 4
+ }
+
+ targetpc := pc
+ p := f.pcln
+ pc = f.pc0
+ line = int(f.ln0)
+ file = f.src
+ for i := 0; i < len(p) && pc <= targetpc; i++ {
+ switch {
+ case p[i] == 0:
+ line += int(p[i+1]<<24) | int(p[i+2]<<16) | int(p[i+3]<<8) | int(p[i+4])
+ i += 4
+ case p[i] <= 64:
+ line += int(p[i])
+ case p[i] <= 128:
+ line -= int(p[i] - 64)
+ default:
+ pc += pcQuant * uintptr(p[i]-129)
+ }
+ pc += pcQuant
+ }
+ return
+}
+
+// mid returns the current os thread (m) id.
+func mid() uint32
+
+// Semacquire waits until *s > 0 and then atomically decrements it.
+// It is intended as a simple sleep primitive for use by the synchronization
+// library and should not be used directly.
+func Semacquire(s *uint32)
+
+// Semrelease atomically increments *s and notifies a waiting goroutine
+// if one is blocked in Semacquire.
+// It is intended as a simple wakeup primitive for use by the synchronization
+// library and should not be used directly.
+func Semrelease(s *uint32)
+
+// SetFinalizer sets the finalizer associated with x to f.
+// When the garbage collector finds an unreachable block
+// with an associated finalizer, it clears the association and runs
+// f(x) in a separate goroutine. This makes x reachable again, but
+// now without an associated finalizer. Assuming that SetFinalizer
+// is not called again, the next time the garbage collector sees
+// that x is unreachable, it will free x.
+//
+// SetFinalizer(x, nil) clears any finalizer associated with x.
+//
+// The argument x must be a pointer to an object allocated by
+// calling new or by taking the address of a composite literal.
+// The argument f must be a function that takes a single argument
+// of x's type and returns no arguments. If either of these is not
+// true, SetFinalizer aborts the program.
+//
+// Finalizers are run in dependency order: if A points at B, both have
+// finalizers, and they are otherwise unreachable, only the finalizer
+// for A runs; once A is freed, the finalizer for B can run.
+// If a cyclic structure includes a block with a finalizer, that
+// cycle is not guaranteed to be garbage collected and the finalizer
+// is not guaranteed to run, because there is no ordering that
+// respects the dependencies.
+//
+// The finalizer for x is scheduled to run at some arbitrary time after
+// x becomes unreachable.
+// There is no guarantee that finalizers will run before a program exits,
+// so typically they are useful only for releasing non-memory resources
+// associated with an object during a long-running program.
+// For example, an os.File object could use a finalizer to close the
+// associated operating system file descriptor when a program discards
+// an os.File without calling Close, but it would be a mistake
+// to depend on a finalizer to flush an in-memory I/O buffer such as a
+// bufio.Writer, because the buffer would not be flushed at program exit.
+//
+// A single goroutine runs all finalizers for a program, sequentially.
+// If a finalizer must run for a long time, it should do so by starting
+// a new goroutine.
+//
+// TODO(rsc): allow f to have (ignored) return values
+//
+func SetFinalizer(x, f interface{})
+
+func getgoroot() string
+
+// GOROOT returns the root of the Go tree.
+// It uses the GOROOT environment variable, if set,
+// or else the root used during the Go build.
+func GOROOT() string {
+ s := getgoroot()
+ if s != "" {
+ return s
+ }
+ return defaultGoroot
+}
+
+// Version returns the Go tree's version string.
+// It is either a sequence number or, when possible,
+// a release tag like "release.2010-03-04".
+// A trailing + indicates that the tree had local modifications
+// at the time of the build.
+func Version() string {
+ return theVersion
+}
+
+// GOOS is the Go tree's operating system target:
+// one of darwin, freebsd, linux, and so on.
+const GOOS string = theGoos
+
+// GOARCH is the Go tree's architecture target:
+// 386, amd64, or arm.
+const GOARCH string = theGoarch
diff --git a/libgo/go/runtime/hashmap_defs.go b/libgo/go/runtime/hashmap_defs.go
new file mode 100644
index 000000000..57780df87
--- /dev/null
+++ b/libgo/go/runtime/hashmap_defs.go
@@ -0,0 +1,51 @@
+// 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.
+
+// Go definitions of internal structures. Master is hashmap.[c,h]
+
+package runtime
+
+type hash_hash uintptr
+
+type hash_entry struct {
+ hash hash_hash
+ key byte // dwarf.c substitutes the real type
+ val byte // for key and val
+}
+
+type hash_subtable struct {
+ power uint8
+ used uint8
+ datasize uint8
+ max_probes uint8
+ limit_bytes int16
+ end *hash_entry
+ entry hash_entry // TODO: [0]hash_entry
+}
+
+type hash struct {
+ count uint32
+ datasize uint8
+ max_power uint8
+ max_probes uint8
+ indirectval uint8
+ changes int32
+ data_hash func(uint32, uintptr) hash_hash
+ data_eq func(uint32, uintptr, uintptr) uint32
+ data_del func(uint32, uintptr, uintptr)
+ st *hash_subtable
+ keysize uint32
+ valsize uint32
+ datavo uint32
+ ko0 uint32
+ vo0 uint32
+ ko1 uint32
+ vo1 uint32
+ po1 uint32
+ ko2 uint32
+ vo2 uint32
+ po2 uint32
+ keyalg *alg
+ valalg *alg
+}
diff --git a/libgo/go/runtime/iface_defs.go b/libgo/go/runtime/iface_defs.go
new file mode 100644
index 000000000..69d52ef9a
--- /dev/null
+++ b/libgo/go/runtime/iface_defs.go
@@ -0,0 +1,18 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+/*
+ * Must match iface.c:/Itable and compilers.
+ * NOTE: type.go has an Itable, that is the version of Itab used by the reflection code.
+ */
+type itab struct {
+ Itype *Type
+ Type *Type
+ link *itab
+ bad int32
+ unused int32
+ Fn func() // TODO: [0]func()
+}
diff --git a/libgo/go/runtime/malloc_defs.go b/libgo/go/runtime/malloc_defs.go
new file mode 100644
index 000000000..11d6627e1
--- /dev/null
+++ b/libgo/go/runtime/malloc_defs.go
@@ -0,0 +1,130 @@
+// 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.
+
+// Go definitions of internal structures. Master is malloc.h
+
+package runtime
+
+import "unsafe"
+
+const (
+ pageShift = 12
+ pageSize = 1 << pageShift
+ pageMask = pageSize - 1
+)
+
+type pageID uintptr
+
+const (
+ numSizeClasses = 67
+ maxSmallSize = 32 << 10
+ fixAllocChunk = 128 << 10
+ maxMCacheListLen = 256
+ maxMCacheSize = 2 << 20
+ maxMHeapList = 1 << 8 // 1 << (20 - pageShift)
+ heapAllocChunk = 1 << 20
+)
+
+type mLink struct {
+ next *mLink
+}
+
+type fixAlloc struct {
+ size uintptr
+ alloc func(uintptr)
+ first func(unsafe.Pointer, *byte)
+ arg unsafe.Pointer
+ list *mLink
+ chunk *byte
+ nchunk uint32
+ inuse uintptr
+ sys uintptr
+}
+
+
+// MStats? used to be in extern.go
+
+type mCacheList struct {
+ list *mLink
+ nlist uint32
+ nlistmin uint32
+}
+
+type mCache struct {
+ list [numSizeClasses]mCacheList
+ size uint64
+ local_alloc int64
+ local_objects int64
+ next_sample int32
+}
+
+type mSpan struct {
+ next *mSpan
+ prev *mSpan
+ allnext *mSpan
+ start pageID
+ npages uintptr
+ freelist *mLink
+ ref uint32
+ sizeclass uint32
+ state uint32
+ // union {
+ gcref *uint32 // sizeclass > 0
+ // gcref0 uint32; // sizeclass == 0
+ // }
+}
+
+type mCentral struct {
+ // lock
+ sizeclass int32
+ nonempty mSpan
+ empty mSpan
+ nfree int32
+}
+
+type mHeap struct {
+ // lock
+ free [maxMHeapList]mSpan
+ large mSpan
+ allspans *mSpan
+ // map_ mHeapMap
+ min *byte
+ max *byte
+ closure_min *byte
+ closure_max *byte
+
+ central [numSizeClasses]struct {
+ pad [64]byte
+ // union: mCentral
+ }
+
+ spanalloc fixAlloc
+ cachealloc fixAlloc
+}
+
+const (
+ refFree = iota
+ refStack
+ refNone
+ refSome
+ refcountOverhead = 4
+ refNoPointers = 0x80000000
+ refHasFinalizer = 0x40000000
+ refProfiled = 0x20000000
+ refNoProfiling = 0x10000000
+ refFlags = 0xFFFF0000
+)
+
+const (
+ mProf_None = iota
+ mProf_Sample
+ mProf_All
+)
+
+type finalizer struct {
+ next *finalizer
+ fn func(unsafe.Pointer)
+ arg unsafe.Pointer
+ nret int32
+}
diff --git a/libgo/go/runtime/mheapmap32_defs.go b/libgo/go/runtime/mheapmap32_defs.go
new file mode 100644
index 000000000..755725b46
--- /dev/null
+++ b/libgo/go/runtime/mheapmap32_defs.go
@@ -0,0 +1,23 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+const (
+ mHeapMap_Level1Bits = 10
+ mHeapMap_Level2Bits = 10
+ mHeapMap_TotalBits = mHeapMap_Level1Bits + mHeapMap_Level2Bits
+
+ mHeapMap_Level1Mask = (1 << mHeapMap_Level1Bits) - 1
+ mHeapMap_Level2Mask = (1 << mHeapMap_Level2Bits) - 1
+)
+
+type mHeapMap struct {
+ allocator func(uintptr)
+ p [1 << mHeapMap_Level1Bits]*mHeapMapNode2
+}
+
+type mHeapMapNode2 struct {
+ s [1 << mHeapMap_Level2Bits]*mSpan
+}
diff --git a/libgo/go/runtime/mheapmap64_defs.go b/libgo/go/runtime/mheapmap64_defs.go
new file mode 100644
index 000000000..d7ba2b420
--- /dev/null
+++ b/libgo/go/runtime/mheapmap64_defs.go
@@ -0,0 +1,31 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+const (
+ mHeapMap_Level1Bits = 18
+ mHeapMap_Level2Bits = 18
+ mHeapMap_Level3Bits = 16
+ mHeapMap_TotalBits = mHeapMap_Level1Bits + mHeapMap_Level2Bits + mHeapMap_Level3Bits
+
+ mHeapMap_Level1Mask = (1 << mHeapMap_Level1Bits) - 1
+ mHeapMap_Level2Mask = (1 << mHeapMap_Level2Bits) - 1
+ mHeapMap_Level3Mask = (1 << mHeapMap_Level3Bits) - 1
+)
+
+type mHeapMap struct {
+ allocator func(uintptr)
+ p [1 << mHeapMap_Level1Bits]*mHeapMapNode2
+}
+
+
+type mHeapMapNode2 struct {
+ p [1 << mHeapMap_Level2Bits]*mHeapMapNode3
+}
+
+
+type mHeapMapNode3 struct {
+ s [1 << mHeapMap_Level3Bits]*mSpan
+}
diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go
new file mode 100644
index 000000000..d0cc73089
--- /dev/null
+++ b/libgo/go/runtime/pprof/pprof.go
@@ -0,0 +1,108 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pprof writes runtime profiling data in the format expected
+// by the pprof visualization tool.
+// For more information about pprof, see
+// http://code.google.com/p/google-perftools/.
+package pprof
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "runtime"
+)
+
+// WriteHeapProfile writes a pprof-formatted heap profile to w.
+// If a write to w returns an error, WriteHeapProfile returns that error.
+// Otherwise, WriteHeapProfile returns nil.
+func WriteHeapProfile(w io.Writer) os.Error {
+ // Find out how many records there are (MemProfile(nil, false)),
+ // allocate that many records, and get the data.
+ // There's a race—more records might be added between
+ // the two calls—so allocate a few extra records for safety
+ // and also try again if we're very unlucky.
+ // The loop should only execute one iteration in the common case.
+ var p []runtime.MemProfileRecord
+ n, ok := runtime.MemProfile(nil, false)
+ for {
+ // Allocate room for a slightly bigger profile,
+ // in case a few more entries have been added
+ // since the call to MemProfile.
+ p = make([]runtime.MemProfileRecord, n+50)
+ n, ok = runtime.MemProfile(p, false)
+ if ok {
+ p = p[0:n]
+ break
+ }
+ // Profile grew; try again.
+ }
+
+ var total runtime.MemProfileRecord
+ for i := range p {
+ r := &p[i]
+ total.AllocBytes += r.AllocBytes
+ total.AllocObjects += r.AllocObjects
+ total.FreeBytes += r.FreeBytes
+ total.FreeObjects += r.FreeObjects
+ }
+
+ // Technically the rate is MemProfileRate not 2*MemProfileRate,
+ // but early versions of the C++ heap profiler reported 2*MemProfileRate,
+ // so that's what pprof has come to expect.
+ b := bufio.NewWriter(w)
+ fmt.Fprintf(b, "heap profile: %d: %d [%d: %d] @ heap/%d\n",
+ total.InUseObjects(), total.InUseBytes(),
+ total.AllocObjects, total.AllocBytes,
+ 2*runtime.MemProfileRate)
+
+ for i := range p {
+ r := &p[i]
+ fmt.Fprintf(b, "%d: %d [%d: %d] @",
+ r.InUseObjects(), r.InUseBytes(),
+ r.AllocObjects, r.AllocBytes)
+ for _, pc := range r.Stack() {
+ fmt.Fprintf(b, " %#x", pc)
+ }
+ fmt.Fprintf(b, "\n")
+ }
+
+ // Print memstats information too.
+ // Pprof will ignore, but useful for people.
+ s := &runtime.MemStats
+ fmt.Fprintf(b, "\n# runtime.MemStats\n")
+ fmt.Fprintf(b, "# Alloc = %d\n", s.Alloc)
+ fmt.Fprintf(b, "# TotalAlloc = %d\n", s.TotalAlloc)
+ fmt.Fprintf(b, "# Sys = %d\n", s.Sys)
+ fmt.Fprintf(b, "# Lookups = %d\n", s.Lookups)
+ fmt.Fprintf(b, "# Mallocs = %d\n", s.Mallocs)
+
+ fmt.Fprintf(b, "# HeapAlloc = %d\n", s.HeapAlloc)
+ fmt.Fprintf(b, "# HeapSys = %d\n", s.HeapSys)
+ fmt.Fprintf(b, "# HeapIdle = %d\n", s.HeapIdle)
+ fmt.Fprintf(b, "# HeapInuse = %d\n", s.HeapInuse)
+
+ fmt.Fprintf(b, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
+ fmt.Fprintf(b, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
+ fmt.Fprintf(b, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
+ fmt.Fprintf(b, "# MHeapMapSys = %d\n", s.MHeapMapSys)
+ fmt.Fprintf(b, "# BuckHashSys = %d\n", s.BuckHashSys)
+
+ fmt.Fprintf(b, "# NextGC = %d\n", s.NextGC)
+ fmt.Fprintf(b, "# PauseNs = %d\n", s.PauseNs)
+ fmt.Fprintf(b, "# NumGC = %d\n", s.NumGC)
+ fmt.Fprintf(b, "# EnableGC = %v\n", s.EnableGC)
+ fmt.Fprintf(b, "# DebugGC = %v\n", s.DebugGC)
+
+ fmt.Fprintf(b, "# BySize = Size * (Active = Mallocs - Frees)\n")
+ fmt.Fprintf(b, "# (Excluding large blocks.)\n")
+ for _, t := range s.BySize {
+ if t.Mallocs > 0 {
+ fmt.Fprintf(b, "# %d * (%d = %d - %d)\n", t.Size, t.Mallocs-t.Frees, t.Mallocs, t.Frees)
+ }
+ }
+ return b.Flush()
+}
diff --git a/libgo/go/runtime/runtime_defs.go b/libgo/go/runtime/runtime_defs.go
new file mode 100644
index 000000000..deea320b5
--- /dev/null
+++ b/libgo/go/runtime/runtime_defs.go
@@ -0,0 +1,200 @@
+// 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.
+
+// Go definitions of internal structures. Master is runtime.h
+
+// TODO(lvd): automate conversion to all the _defs.go files
+
+package runtime
+
+import "unsafe"
+
+const (
+ gidle = iota
+ grunnable
+ grunning
+ gsyscall
+ gwaiting
+ gmoribund
+ gdead
+ grecovery
+)
+
+// const ( Structrnd = sizeof(uintptr) )
+
+type string_ struct {
+ str *byte
+ len int32
+}
+
+type iface struct {
+ // tab *itab
+ data unsafe.Pointer
+}
+
+type eface struct {
+ type_ *Type
+ data unsafe.Pointer
+}
+
+type complex64 struct {
+ real float32
+ imag float32
+}
+
+type complex128 struct {
+ real float64
+ imag float64
+}
+
+type slice struct {
+ array *byte
+ len uint32
+ cap uint32
+}
+
+type gobuf struct {
+ sp unsafe.Pointer
+ pc unsafe.Pointer
+ g *g_
+}
+
+type g_ struct {
+ stackguard unsafe.Pointer
+ stackbase unsafe.Pointer
+ defer_ *defer_
+ panic_ *panic_
+ sched gobuf
+ stack0 unsafe.Pointer
+ entry unsafe.Pointer
+ alllink *g_
+ param unsafe.Pointer
+ status int16
+ goid int32
+ selgen uint32
+ schedlink *g_
+ readyonstop bool
+ ispanic bool
+ m *m_
+ lockedm *m_
+ sig int32
+ sigcode0 uintptr
+ sigcode1 uintptr
+}
+
+type m_ struct {
+ g0 *g_
+ morepc unsafe.Pointer
+ moreargp unsafe.Pointer
+ morebuf gobuf
+ moreframesize uint32
+ moreargsize uint32
+ cret uintptr
+ procid uint64
+ gsignal *g_
+ tls [8]uint32
+ sched gobuf
+ curg *g_
+ id int32
+ mallocing int32
+ gcing int32
+ locks int32
+ nomemprof int32
+ waitnextg int32
+ // havenextg note
+ nextg *g_
+ alllink *m_
+ schedlink *m_
+ machport uint32
+ mcache *mCache
+ lockedg *g_
+ freg [8]uint64
+ // gostack unsafe.Pointer // __WINDOWS__
+}
+
+type stktop struct {
+ stackguard *uint8
+ stackbase *uint8
+ gobuf gobuf
+ args uint32
+ fp *uint8
+ free bool
+ panic_ bool
+}
+
+type alg struct {
+ hash func(uint32, unsafe.Pointer) uintptr
+ equal func(uint32, unsafe.Pointer, unsafe.Pointer) uint32
+ print func(uint32, unsafe.Pointer)
+ copy func(uint32, unsafe.Pointer, unsafe.Pointer)
+}
+
+type sigtab struct {
+ flags int32
+ name *int8
+}
+
+const (
+ sigCatch = (1 << iota)
+ sigIgnore
+ sigRestart
+ sigQueue
+ sigPanic
+)
+
+type Func struct {
+ name string
+ typ string
+ src string
+ pcln []byte
+ entry uintptr
+ pc0 uintptr
+ ln0 int32
+ frame int32
+ args int32
+ locals int32
+}
+
+const (
+ aMEM = iota
+ aNOEQ
+ aSTRING
+ aINTER
+ aNILINTER
+ aMEMWORD
+ amax
+)
+
+type defer_ struct {
+ siz int32
+ sp unsafe.Pointer
+ pc unsafe.Pointer
+ fn unsafe.Pointer
+ link *defer_
+ args [8]byte // padded to actual size
+}
+
+type panic_ struct {
+ arg eface
+ stackbase unsafe.Pointer
+ link *panic_
+ recovered bool
+}
+
+/*
+ * External data.
+ */
+
+var (
+ algarray [amax]alg
+ emptystring string
+ allg *g_
+ allm *m_
+ goidgen int32
+ gomaxprocs int32
+ panicking int32
+ fd int32
+ gcwaiting int32
+ goos *int8
+)
diff --git a/libgo/go/runtime/sig.go b/libgo/go/runtime/sig.go
new file mode 100644
index 000000000..6d560b900
--- /dev/null
+++ b/libgo/go/runtime/sig.go
@@ -0,0 +1,16 @@
+// 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 runtime
+
+// Sigrecv returns a bitmask of signals that have arrived since the last call to Sigrecv.
+// It blocks until at least one signal arrives.
+func Sigrecv() uint32
+
+// Signame returns a string describing the signal, or "" if the signal is unknown.
+func Signame(sig int32) string
+
+// Siginit enables receipt of signals via Sigrecv. It should typically
+// be called during initialization.
+func Siginit()
diff --git a/libgo/go/runtime/softfloat64.go b/libgo/go/runtime/softfloat64.go
new file mode 100644
index 000000000..d9bbe5def
--- /dev/null
+++ b/libgo/go/runtime/softfloat64.go
@@ -0,0 +1,498 @@
+// 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.
+
+// Software IEEE754 64-bit floating point.
+// Only referred to (and thus linked in) by arm port
+// and by gotest in this directory.
+
+package runtime
+
+const (
+ mantbits64 uint = 52
+ expbits64 uint = 11
+ bias64 = -1<<(expbits64-1) + 1
+
+ nan64 uint64 = (1<<expbits64-1)<<mantbits64 + 1
+ inf64 uint64 = (1<<expbits64 - 1) << mantbits64
+ neg64 uint64 = 1 << (expbits64 + mantbits64)
+
+ mantbits32 uint = 23
+ expbits32 uint = 8
+ bias32 = -1<<(expbits32-1) + 1
+
+ nan32 uint32 = (1<<expbits32-1)<<mantbits32 + 1
+ inf32 uint32 = (1<<expbits32 - 1) << mantbits32
+ neg32 uint32 = 1 << (expbits32 + mantbits32)
+)
+
+func funpack64(f uint64) (sign, mant uint64, exp int, inf, nan bool) {
+ sign = f & (1 << (mantbits64 + expbits64))
+ mant = f & (1<<mantbits64 - 1)
+ exp = int(f>>mantbits64) & (1<<expbits64 - 1)
+
+ switch exp {
+ case 1<<expbits64 - 1:
+ if mant != 0 {
+ nan = true
+ return
+ }
+ inf = true
+ return
+
+ case 0:
+ // denormalized
+ if mant != 0 {
+ exp += bias64 + 1
+ for mant < 1<<mantbits64 {
+ mant <<= 1
+ exp--
+ }
+ }
+
+ default:
+ // add implicit top bit
+ mant |= 1 << mantbits64
+ exp += bias64
+ }
+ return
+}
+
+func funpack32(f uint32) (sign, mant uint32, exp int, inf, nan bool) {
+ sign = f & (1 << (mantbits32 + expbits32))
+ mant = f & (1<<mantbits32 - 1)
+ exp = int(f>>mantbits32) & (1<<expbits32 - 1)
+
+ switch exp {
+ case 1<<expbits32 - 1:
+ if mant != 0 {
+ nan = true
+ return
+ }
+ inf = true
+ return
+
+ case 0:
+ // denormalized
+ if mant != 0 {
+ exp += bias32 + 1
+ for mant < 1<<mantbits32 {
+ mant <<= 1
+ exp--
+ }
+ }
+
+ default:
+ // add implicit top bit
+ mant |= 1 << mantbits32
+ exp += bias32
+ }
+ return
+}
+
+func fpack64(sign, mant uint64, exp int, trunc uint64) uint64 {
+ mant0, exp0, trunc0 := mant, exp, trunc
+ if mant == 0 {
+ return sign
+ }
+ for mant < 1<<mantbits64 {
+ mant <<= 1
+ exp--
+ }
+ for mant >= 4<<mantbits64 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant >= 2<<mantbits64 {
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ if mant >= 4<<mantbits64 {
+ mant >>= 1
+ exp++
+ }
+ }
+ mant >>= 1
+ exp++
+ }
+ if exp >= 1<<expbits64-1+bias64 {
+ return sign ^ inf64
+ }
+ if exp < bias64+1 {
+ if exp < bias64-int(mantbits64) {
+ return sign | 0
+ }
+ // repeat expecting denormal
+ mant, exp, trunc = mant0, exp0, trunc0
+ for exp < bias64 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ }
+ mant >>= 1
+ exp++
+ if mant < 1<<mantbits64 {
+ return sign | mant
+ }
+ }
+ return sign | uint64(exp-bias64)<<mantbits64 | mant&(1<<mantbits64-1)
+}
+
+func fpack32(sign, mant uint32, exp int, trunc uint32) uint32 {
+ mant0, exp0, trunc0 := mant, exp, trunc
+ if mant == 0 {
+ return sign
+ }
+ for mant < 1<<mantbits32 {
+ mant <<= 1
+ exp--
+ }
+ for mant >= 4<<mantbits32 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant >= 2<<mantbits32 {
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ if mant >= 4<<mantbits32 {
+ mant >>= 1
+ exp++
+ }
+ }
+ mant >>= 1
+ exp++
+ }
+ if exp >= 1<<expbits32-1+bias32 {
+ return sign ^ inf32
+ }
+ if exp < bias32+1 {
+ if exp < bias32-int(mantbits32) {
+ return sign | 0
+ }
+ // repeat expecting denormal
+ mant, exp, trunc = mant0, exp0, trunc0
+ for exp < bias32 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ }
+ mant >>= 1
+ exp++
+ if mant < 1<<mantbits32 {
+ return sign | mant
+ }
+ }
+ return sign | uint32(exp-bias32)<<mantbits32 | mant&(1<<mantbits32-1)
+}
+
+func fadd64(f, g uint64) uint64 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ gs, gm, ge, gi, gn := funpack64(g)
+
+ // Special cases.
+ switch {
+ case fn || gn: // NaN + x or x + NaN = NaN
+ return nan64
+
+ case fi && gi && fs != gs: // +Inf + -Inf or -Inf + +Inf = NaN
+ return nan64
+
+ case fi: // ±Inf + g = ±Inf
+ return f
+
+ case gi: // f + ±Inf = ±Inf
+ return g
+
+ case fm == 0 && gm == 0 && fs != 0 && gs != 0: // -0 + -0 = -0
+ return f
+
+ case fm == 0: // 0 + g = g but 0 + -0 = +0
+ if gm == 0 {
+ g ^= gs
+ }
+ return g
+
+ case gm == 0: // f + 0 = f
+ return f
+
+ }
+
+ if fe < ge || fe == ge && fm < gm {
+ f, g, fs, fm, fe, gs, gm, ge = g, f, gs, gm, ge, fs, fm, fe
+ }
+
+ shift := uint(fe - ge)
+ fm <<= 2
+ gm <<= 2
+ trunc := gm & (1<<shift - 1)
+ gm >>= shift
+ if fs == gs {
+ fm += gm
+ } else {
+ fm -= gm
+ if trunc != 0 {
+ fm--
+ }
+ }
+ if fm == 0 {
+ fs = 0
+ }
+ return fpack64(fs, fm, fe-2, trunc)
+}
+
+func fsub64(f, g uint64) uint64 {
+ return fadd64(f, fneg64(g))
+}
+
+func fneg64(f uint64) uint64 {
+ return f ^ (1 << (mantbits64 + expbits64))
+}
+
+func fmul64(f, g uint64) uint64 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ gs, gm, ge, gi, gn := funpack64(g)
+
+ // Special cases.
+ switch {
+ case fn || gn: // NaN * g or f * NaN = NaN
+ return nan64
+
+ case fi && gi: // Inf * Inf = Inf (with sign adjusted)
+ return f ^ gs
+
+ case fi && gm == 0, fm == 0 && gi: // 0 * Inf = Inf * 0 = NaN
+ return nan64
+
+ case fm == 0: // 0 * x = 0 (with sign adjusted)
+ return f ^ gs
+
+ case gm == 0: // x * 0 = 0 (with sign adjusted)
+ return g ^ fs
+ }
+
+ // 53-bit * 53-bit = 107- or 108-bit
+ lo, hi := mullu(fm, gm)
+ shift := mantbits64 - 1
+ trunc := lo & (1<<shift - 1)
+ mant := hi<<(64-shift) | lo>>shift
+ return fpack64(fs^gs, mant, fe+ge-1, trunc)
+}
+
+func fdiv64(f, g uint64) uint64 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ gs, gm, ge, gi, gn := funpack64(g)
+
+ // Special cases.
+ switch {
+ case fn || gn: // NaN / g = f / NaN = NaN
+ return nan64
+
+ case fi && gi: // ±Inf / ±Inf = NaN
+ return nan64
+
+ case !fi && !gi && fm == 0 && gm == 0: // 0 / 0 = NaN
+ return nan64
+
+ case fi, !gi && gm == 0: // Inf / g = f / 0 = Inf
+ return fs ^ gs ^ inf64
+
+ case gi, fm == 0: // f / Inf = 0 / g = Inf
+ return fs ^ gs ^ 0
+ }
+ _, _, _, _ = fi, fn, gi, gn
+
+ // 53-bit<<54 / 53-bit = 53- or 54-bit.
+ shift := mantbits64 + 2
+ q, r := divlu(fm>>(64-shift), fm<<shift, gm)
+ return fpack64(fs^gs, q, fe-ge-2, r)
+}
+
+func f64to32(f uint64) uint32 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ if fn {
+ return nan32
+ }
+ fs32 := uint32(fs >> 32)
+ if fi {
+ return fs32 ^ inf32
+ }
+ const d = mantbits64 - mantbits32 - 1
+ return fpack32(fs32, uint32(fm>>d), fe-1, uint32(fm&(1<<d-1)))
+}
+
+func f32to64(f uint32) uint64 {
+ const d = mantbits64 - mantbits32
+ fs, fm, fe, fi, fn := funpack32(f)
+ if fn {
+ return nan64
+ }
+ fs64 := uint64(fs) << 32
+ if fi {
+ return fs64 ^ inf64
+ }
+ return fpack64(fs64, uint64(fm)<<d, fe, 0)
+}
+
+func fcmp64(f, g uint64) (cmp int, isnan bool) {
+ fs, fm, _, fi, fn := funpack64(f)
+ gs, gm, _, gi, gn := funpack64(g)
+
+ switch {
+ case fn, gn: // flag NaN
+ return 0, true
+
+ case !fi && !gi && fm == 0 && gm == 0: // ±0 == ±0
+ return 0, false
+
+ case fs > gs: // f < 0, g > 0
+ return -1, false
+
+ case fs < gs: // f > 0, g < 0
+ return +1, false
+
+ // Same sign, not NaN.
+ // Can compare encodings directly now.
+ // Reverse for sign.
+ case fs == 0 && f < g, fs != 0 && f > g:
+ return -1, false
+
+ case fs == 0 && f > g, fs != 0 && f < g:
+ return +1, false
+ }
+
+ // f == g
+ return 0, false
+}
+
+func f64toint(f uint64) (val int64, ok bool) {
+ fs, fm, fe, fi, fn := funpack64(f)
+
+ switch {
+ case fi, fn: // NaN
+ return 0, false
+
+ case fe < -1: // f < 0.5
+ return 0, false
+
+ case fe > 63: // f >= 2^63
+ if fs != 0 && fm == 0 { // f == -2^63
+ return -1 << 63, true
+ }
+ if fs != 0 {
+ return 0, false
+ }
+ return 0, false
+ }
+
+ for fe > int(mantbits64) {
+ fe--
+ fm <<= 1
+ }
+ for fe < int(mantbits64) {
+ fe++
+ fm >>= 1
+ }
+ val = int64(fm)
+ if fs != 0 {
+ val = -val
+ }
+ return val, true
+}
+
+func fintto64(val int64) (f uint64) {
+ fs := uint64(val) & (1 << 63)
+ mant := uint64(val)
+ if fs != 0 {
+ mant = -mant
+ }
+ return fpack64(fs, mant, int(mantbits64), 0)
+}
+
+// 64x64 -> 128 multiply.
+// adapted from hacker's delight.
+func mullu(u, v uint64) (lo, hi uint64) {
+ const (
+ s = 32
+ mask = 1<<s - 1
+ )
+ u0 := u & mask
+ u1 := u >> s
+ v0 := v & mask
+ v1 := v >> s
+ w0 := u0 * v0
+ t := u1*v0 + w0>>s
+ w1 := t & mask
+ w2 := t >> s
+ w1 += u0 * v1
+ return u * v, u1*v1 + w2 + w1>>s
+}
+
+// 128/64 -> 64 quotient, 64 remainder.
+// adapted from hacker's delight
+func divlu(u1, u0, v uint64) (q, r uint64) {
+ const b = 1 << 32
+
+ if u1 >= v {
+ return 1<<64 - 1, 1<<64 - 1
+ }
+
+ // s = nlz(v); v <<= s
+ s := uint(0)
+ for v&(1<<63) == 0 {
+ s++
+ v <<= 1
+ }
+
+ vn1 := v >> 32
+ vn0 := v & (1<<32 - 1)
+ un32 := u1<<s | u0>>(64-s)
+ un10 := u0 << s
+ un1 := un10 >> 32
+ un0 := un10 & (1<<32 - 1)
+ q1 := un32 / vn1
+ rhat := un32 - q1*vn1
+
+again1:
+ if q1 >= b || q1*vn0 > b*rhat+un1 {
+ q1--
+ rhat += vn1
+ if rhat < b {
+ goto again1
+ }
+ }
+
+ un21 := un32*b + un1 - q1*v
+ q0 := un21 / vn1
+ rhat = un21 - q0*vn1
+
+again2:
+ if q0 >= b || q0*vn0 > b*rhat+un0 {
+ q0--
+ rhat += vn1
+ if rhat < b {
+ goto again2
+ }
+ }
+
+ return q1*b + q0, (un21*b + un0 - q0*v) >> s
+}
+
+// callable from C
+
+func fadd64c(f, g uint64, ret *uint64) { *ret = fadd64(f, g) }
+func fsub64c(f, g uint64, ret *uint64) { *ret = fsub64(f, g) }
+func fmul64c(f, g uint64, ret *uint64) { *ret = fmul64(f, g) }
+func fdiv64c(f, g uint64, ret *uint64) { *ret = fdiv64(f, g) }
+func fneg64c(f uint64, ret *uint64) { *ret = fneg64(f) }
+func f32to64c(f uint32, ret *uint64) { *ret = f32to64(f) }
+func f64to32c(f uint64, ret *uint32) { *ret = f64to32(f) }
+func fcmp64c(f, g uint64, ret *int, retnan *bool) { *ret, *retnan = fcmp64(f, g) }
+func fintto64c(val int64, ret *uint64) { *ret = fintto64(val) }
+func f64tointc(f uint64, ret *int64, retok *bool) { *ret, *retok = f64toint(f) }
diff --git a/libgo/go/runtime/softfloat64_test.go b/libgo/go/runtime/softfloat64_test.go
new file mode 100644
index 000000000..fb7f3d3c0
--- /dev/null
+++ b/libgo/go/runtime/softfloat64_test.go
@@ -0,0 +1,198 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "math"
+ "rand"
+ . "runtime"
+ "testing"
+)
+
+// turn uint64 op into float64 op
+func fop(f func(x, y uint64) uint64) func(x, y float64) float64 {
+ return func(x, y float64) float64 {
+ bx := math.Float64bits(x)
+ by := math.Float64bits(y)
+ return math.Float64frombits(f(bx, by))
+ }
+}
+
+func add(x, y float64) float64 { return x + y }
+func sub(x, y float64) float64 { return x - y }
+func mul(x, y float64) float64 { return x * y }
+func div(x, y float64) float64 { return x / y }
+
+func TestFloat64(t *testing.T) {
+ base := []float64{
+ 0,
+ math.Copysign(0, -1),
+ -1,
+ 1,
+ math.NaN(),
+ math.Inf(+1),
+ math.Inf(-1),
+ 0.1,
+ 1.5,
+ 1.9999999999999998, // all 1s mantissa
+ 1.3333333333333333, // 1.010101010101...
+ 1.1428571428571428, // 1.001001001001...
+ 1.112536929253601e-308, // first normal
+ 2,
+ 4,
+ 8,
+ 16,
+ 32,
+ 64,
+ 128,
+ 256,
+ 3,
+ 12,
+ 1234,
+ 123456,
+ -0.1,
+ -1.5,
+ -1.9999999999999998,
+ -1.3333333333333333,
+ -1.1428571428571428,
+ -2,
+ -3,
+ 1e-200,
+ 1e-300,
+ 1e-310,
+ 5e-324,
+ 1e-105,
+ 1e-305,
+ 1e+200,
+ 1e+306,
+ 1e+307,
+ 1e+308,
+ }
+ all := make([]float64, 200)
+ copy(all, base)
+ for i := len(base); i < len(all); i++ {
+ all[i] = rand.NormFloat64()
+ }
+
+ test(t, "+", add, fop(Fadd64), all)
+ test(t, "-", sub, fop(Fsub64), all)
+ if GOARCH != "386" { // 386 is not precise!
+ test(t, "*", mul, fop(Fmul64), all)
+ test(t, "/", div, fop(Fdiv64), all)
+ }
+}
+
+// 64 -hw-> 32 -hw-> 64
+func trunc32(f float64) float64 {
+ return float64(float32(f))
+}
+
+// 64 -sw->32 -hw-> 64
+func to32sw(f float64) float64 {
+ return float64(math.Float32frombits(F64to32(math.Float64bits(f))))
+}
+
+// 64 -hw->32 -sw-> 64
+func to64sw(f float64) float64 {
+ return math.Float64frombits(F32to64(math.Float32bits(float32(f))))
+}
+
+// float64 -hw-> int64 -hw-> float64
+func hwint64(f float64) float64 {
+ return float64(int64(f))
+}
+
+// float64 -hw-> int32 -hw-> float64
+func hwint32(f float64) float64 {
+ return float64(int32(f))
+}
+
+// float64 -sw-> int64 -hw-> float64
+func toint64sw(f float64) float64 {
+ i, ok := F64toint(math.Float64bits(f))
+ if !ok {
+ // There's no right answer for out of range.
+ // Match the hardware to pass the test.
+ i = int64(f)
+ }
+ return float64(i)
+}
+
+// float64 -hw-> int64 -sw-> float64
+func fromint64sw(f float64) float64 {
+ return math.Float64frombits(Fintto64(int64(f)))
+}
+
+var nerr int
+
+func err(t *testing.T, format string, args ...interface{}) {
+ t.Errorf(format, args...)
+
+ // cut errors off after a while.
+ // otherwise we spend all our time
+ // allocating memory to hold the
+ // formatted output.
+ if nerr++; nerr >= 10 {
+ t.Fatal("too many errors")
+ }
+}
+
+func test(t *testing.T, op string, hw, sw func(float64, float64) float64, all []float64) {
+ for _, f := range all {
+ for _, g := range all {
+ h := hw(f, g)
+ s := sw(f, g)
+ if !same(h, s) {
+ err(t, "%g %s %g = sw %g, hw %g\n", f, op, g, s, h)
+ }
+ testu(t, "to32", trunc32, to32sw, h)
+ testu(t, "to64", trunc32, to64sw, h)
+ testu(t, "toint64", hwint64, toint64sw, h)
+ testu(t, "fromint64", hwint64, fromint64sw, h)
+ testcmp(t, f, h)
+ testcmp(t, h, f)
+ testcmp(t, g, h)
+ testcmp(t, h, g)
+ }
+ }
+}
+
+func testu(t *testing.T, op string, hw, sw func(float64) float64, v float64) {
+ h := hw(v)
+ s := sw(v)
+ if !same(h, s) {
+ err(t, "%s %g = sw %g, hw %g\n", op, v, s, h)
+ }
+}
+
+func hwcmp(f, g float64) (cmp int, isnan bool) {
+ switch {
+ case f < g:
+ return -1, false
+ case f > g:
+ return +1, false
+ case f == g:
+ return 0, false
+ }
+ return 0, true // must be NaN
+}
+
+func testcmp(t *testing.T, f, g float64) {
+ hcmp, hisnan := hwcmp(f, g)
+ scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g))
+ if hcmp != scmp || hisnan != sisnan {
+ err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan)
+ }
+}
+
+func same(f, g float64) bool {
+ if math.IsNaN(f) && math.IsNaN(g) {
+ return true
+ }
+ if math.Copysign(1, f) != math.Copysign(1, g) {
+ return false
+ }
+ return f == g
+}
diff --git a/libgo/go/runtime/type.go b/libgo/go/runtime/type.go
new file mode 100644
index 000000000..645e3647e
--- /dev/null
+++ b/libgo/go/runtime/type.go
@@ -0,0 +1,206 @@
+// 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.
+
+/*
+ * Runtime type representation.
+ *
+ * The following files know the exact layout of these
+ * data structures and must be kept in sync with this file:
+ *
+ * ../../cmd/gc/reflect.c
+ * ../../cmd/ld/dwarf.c
+ * ../reflect/type.go
+ * type.h
+ */
+
+package runtime
+
+import "unsafe"
+
+// All types begin with a few common fields needed for
+// the interface runtime.
+type commonType struct {
+ Kind uint8 // type kind
+ align uint8 // alignment of variable with this type
+ fieldAlign uint8 // alignment of struct field with this type
+ size uintptr // size in bytes
+ hash uint32 // hash of type; avoids computation in hash tables
+
+ hashfn func(unsafe.Pointer, uintptr) uintptr // hash function
+ equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool // equality function
+
+ string *string // string form; unnecessary but undeniably useful
+ *uncommonType // (relatively) uncommon fields
+}
+
+// Values for commonType.kind.
+const (
+ kindBool = 1 + iota
+ kindInt
+ kindInt8
+ kindInt16
+ kindInt32
+ kindInt64
+ kindUint
+ kindUint8
+ kindUint16
+ kindUint32
+ kindUint64
+ kindUintptr
+ kindFloat32
+ kindFloat64
+ kindComplex64
+ kindComplex128
+ kindArray
+ kindChan
+ kindFunc
+ kindInterface
+ kindMap
+ kindPtr
+ kindSlice
+ kindString
+ kindStruct
+ kindUnsafePointer
+
+ // Not currently generated by gccgo.
+ // kindNoPointers = 1 << 7 // OR'ed into kind
+)
+
+// Externally visible name.
+type Type commonType
+
+// Method on non-interface type
+type method struct {
+ name *string // name of method
+ pkgPath *string // nil for exported Names; otherwise import path
+ mtyp *Type // method type (without receiver)
+ typ *Type // .(*FuncType) underneath (with receiver)
+ tfn unsafe.Pointer // fn used for normal method call
+}
+
+// uncommonType is present only for types with names or methods
+// (if T is a named type, the uncommonTypes for T and *T have methods).
+// Using a pointer to this struct reduces the overall size required
+// to describe an unnamed type with no methods.
+type uncommonType struct {
+ name *string // name of type
+ pkgPath *string // import path; nil for built-in types like int, string
+ methods []method // methods associated with type
+}
+
+// BoolType represents a boolean type.
+type BoolType commonType
+
+// FloatType represents a float type.
+type FloatType commonType
+
+// ComplexType represents a complex type.
+type ComplexType commonType
+
+// IntType represents an int type.
+type IntType commonType
+
+// UintType represents a uint type.
+type UintType commonType
+
+// StringType represents a string type.
+type StringType commonType
+
+// UintptrType represents a uintptr type.
+type UintptrType commonType
+
+// UnsafePointerType represents an unsafe.Pointer type.
+type UnsafePointerType commonType
+
+// ArrayType represents a fixed array type.
+type ArrayType struct {
+ commonType
+ elem *Type // array element type
+ len uintptr
+}
+
+// SliceType represents a slice type.
+type SliceType struct {
+ commonType
+ elem *Type // slice element type
+}
+
+// ChanDir represents a channel type's direction.
+type ChanDir int
+
+const (
+ RecvDir ChanDir = 1 << iota // <-chan
+ SendDir // chan<-
+ BothDir = RecvDir | SendDir // chan
+)
+
+// ChanType represents a channel type.
+type ChanType struct {
+ commonType
+ elem *Type // channel element type
+ dir uintptr // channel direction (ChanDir)
+}
+
+// FuncType represents a function type.
+type FuncType struct {
+ commonType
+ dotdotdot bool // last input parameter is ...
+ in []*Type // input parameter types
+ out []*Type // output parameter types
+}
+
+// Method on interface type
+type imethod struct {
+ name *string // name of method
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *Type // .(*FuncType) underneath
+}
+
+// InterfaceType represents an interface type.
+type InterfaceType struct {
+ commonType
+ methods []imethod // sorted by hash
+}
+
+// MapType represents a map type.
+type MapType struct {
+ commonType
+ key *Type // map key type
+ elem *Type // map element (value) type
+}
+
+// PtrType represents a pointer type.
+type PtrType struct {
+ commonType
+ elem *Type // pointer element (pointed at) type
+}
+
+// Struct field
+type structField struct {
+ name *string // nil for embedded fields
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *Type // type of field
+ tag *string // nil if no tag
+ offset uintptr // byte offset of field within struct
+}
+
+// StructType represents a struct type.
+type StructType struct {
+ commonType
+ fields []structField // sorted by offset
+}
+
+/*
+ * Must match iface.c:/Itab and compilers.
+ * NOTE: this is the version used by the reflection code, there is another
+ * one in iface_defs.go that is closer to the original C version.
+ */
+type Itable struct {
+ Itype *Type // (*tab.inter).(*InterfaceType) is the interface type
+ Type *Type
+ link *Itable
+ bad int32
+ unused int32
+ Fn [100000]uintptr // bigger than we'll ever see
+}
diff --git a/libgo/go/scanner/scanner.go b/libgo/go/scanner/scanner.go
new file mode 100644
index 000000000..11aa9f43f
--- /dev/null
+++ b/libgo/go/scanner/scanner.go
@@ -0,0 +1,644 @@
+// 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 scanner and tokenizer for UTF-8-encoded text. Takes an io.Reader
+// providing the source, which then can be tokenized through repeated calls
+// to the Scan function. For compatibility with existing tools, the NUL
+// character is not allowed (implementation restriction).
+//
+// By default, a Scanner skips white space and Go comments and recognizes all
+// literals as defined by the Go language specification. It may be
+// customized to recognize only a subset of those literals and to recognize
+// different white space characters.
+//
+// Basic usage pattern:
+//
+// var s scanner.Scanner
+// s.Init(src)
+// tok := s.Scan()
+// for tok != scanner.EOF {
+// // do something with tok
+// tok = s.Scan()
+// }
+//
+package scanner
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "unicode"
+ "utf8"
+)
+
+
+// A source position is represented by a Position value.
+// A position is valid if Line > 0.
+type Position struct {
+ Filename string // filename, if any
+ Offset int // byte offset, starting at 0
+ Line int // line number, starting at 1
+ Column int // column number, starting at 0 (character count per line)
+}
+
+
+// IsValid returns true if the position is valid.
+func (pos *Position) IsValid() bool { return pos.Line > 0 }
+
+
+func (pos Position) String() string {
+ s := pos.Filename
+ if pos.IsValid() {
+ if s != "" {
+ s += ":"
+ }
+ s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
+ }
+ if s == "" {
+ s = "???"
+ }
+ return s
+}
+
+
+// Predefined mode bits to control recognition of tokens. For instance,
+// to configure a Scanner such that it only recognizes (Go) identifiers,
+// integers, and skips comments, set the Scanner's Mode field to:
+//
+// ScanIdents | ScanInts | SkipComments
+//
+const (
+ ScanIdents = 1 << -Ident
+ ScanInts = 1 << -Int
+ ScanFloats = 1 << -Float // includes Ints
+ ScanChars = 1 << -Char
+ ScanStrings = 1 << -String
+ ScanRawStrings = 1 << -RawString
+ ScanComments = 1 << -Comment
+ SkipComments = 1 << -skipComment // if set with ScanComments, comments become white space
+ GoTokens = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments
+)
+
+
+// The result of Scan is one of the following tokens or a Unicode character.
+const (
+ EOF = -(iota + 1)
+ Ident
+ Int
+ Float
+ Char
+ String
+ RawString
+ Comment
+ skipComment
+)
+
+
+var tokenString = map[int]string{
+ EOF: "EOF",
+ Ident: "Ident",
+ Int: "Int",
+ Float: "Float",
+ Char: "Char",
+ String: "String",
+ RawString: "RawString",
+ Comment: "Comment",
+}
+
+
+// TokenString returns a (visible) string for a token or Unicode character.
+func TokenString(tok int) string {
+ if s, found := tokenString[tok]; found {
+ return s
+ }
+ return fmt.Sprintf("U+%04X", tok)
+}
+
+
+// GoWhitespace is the default value for the Scanner's Whitespace field.
+// Its value selects Go's white space characters.
+const GoWhitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' '
+
+
+const bufLen = 1024 // at least utf8.UTFMax
+
+// A Scanner implements reading of Unicode characters and tokens from an io.Reader.
+type Scanner struct {
+ // Input
+ src io.Reader
+
+ // Source buffer
+ srcBuf [bufLen + 1]byte // +1 for sentinel for common case of s.next()
+ srcPos int // reading position (srcBuf index)
+ srcEnd int // source end (srcBuf index)
+
+ // Source position
+ srcBufOffset int // byte offset of srcBuf[0] in source
+ line int // newline count + 1
+ column int // character count on line
+
+ // Token text buffer
+ // Typically, token text is stored completely in srcBuf, but in general
+ // the token text's head may be buffered in tokBuf while the token text's
+ // tail is stored in srcBuf.
+ tokBuf bytes.Buffer // token text head that is not in srcBuf anymore
+ tokPos int // token text tail position (srcBuf index)
+ tokEnd int // token text tail end (srcBuf index)
+
+ // One character look-ahead
+ ch int // character before current srcPos
+
+ // Error is called for each error encountered. If no Error
+ // function is set, the error is reported to os.Stderr.
+ Error func(s *Scanner, msg string)
+
+ // ErrorCount is incremented by one for each error encountered.
+ ErrorCount int
+
+ // The Mode field controls which tokens are recognized. For instance,
+ // to recognize Ints, set the ScanInts bit in Mode. The field may be
+ // changed at any time.
+ Mode uint
+
+ // The Whitespace field controls which characters are recognized
+ // as white space. To recognize a character ch <= ' ' as white space,
+ // set the ch'th bit in Whitespace (the Scanner's behavior is undefined
+ // for values ch > ' '). The field may be changed at any time.
+ Whitespace uint64
+
+ // Current token position. The Offset, Line, and Column fields
+ // are set by Scan(); the Filename field is left untouched by the
+ // Scanner.
+ Position
+}
+
+
+// Init initializes a Scanner with a new source and returns itself.
+// Error is set to nil, ErrorCount is set to 0, Mode is set to GoTokens,
+// and Whitespace is set to GoWhitespace.
+func (s *Scanner) Init(src io.Reader) *Scanner {
+ s.src = src
+
+ // initialize source buffer
+ s.srcBuf[0] = utf8.RuneSelf // sentinel
+ s.srcPos = 0
+ s.srcEnd = 0
+
+ // initialize source position
+ s.srcBufOffset = 0
+ s.line = 1
+ s.column = 0
+
+ // initialize token text buffer
+ s.tokPos = -1
+
+ // initialize one character look-ahead
+ s.ch = s.next()
+
+ // initialize public fields
+ s.Error = nil
+ s.ErrorCount = 0
+ s.Mode = GoTokens
+ s.Whitespace = GoWhitespace
+
+ return s
+}
+
+
+// next reads and returns the next Unicode character. It is designed such
+// that only a minimal amount of work needs to be done in the common ASCII
+// case (one test to check for both ASCII and end-of-buffer, and one test
+// to check for newlines).
+func (s *Scanner) next() int {
+ ch := int(s.srcBuf[s.srcPos])
+
+ if ch >= utf8.RuneSelf {
+ // uncommon case: not ASCII or not enough bytes
+ for s.srcPos+utf8.UTFMax > s.srcEnd && !utf8.FullRune(s.srcBuf[s.srcPos:s.srcEnd]) {
+ // not enough bytes: read some more, but first
+ // save away token text if any
+ if s.tokPos >= 0 {
+ s.tokBuf.Write(s.srcBuf[s.tokPos:s.srcPos])
+ s.tokPos = 0
+ }
+ // move unread bytes to beginning of buffer
+ copy(s.srcBuf[0:], s.srcBuf[s.srcPos:s.srcEnd])
+ s.srcBufOffset += s.srcPos
+ // read more bytes
+ i := s.srcEnd - s.srcPos
+ n, err := s.src.Read(s.srcBuf[i:bufLen])
+ s.srcEnd = i + n
+ s.srcPos = 0
+ s.srcBuf[s.srcEnd] = utf8.RuneSelf // sentinel
+ if err != nil {
+ if s.srcEnd == 0 {
+ return EOF
+ }
+ if err != os.EOF {
+ s.error(err.String())
+ break
+ }
+ }
+ }
+ // at least one byte
+ ch = int(s.srcBuf[s.srcPos])
+ if ch >= utf8.RuneSelf {
+ // uncommon case: not ASCII
+ var width int
+ ch, width = utf8.DecodeRune(s.srcBuf[s.srcPos:s.srcEnd])
+ if ch == utf8.RuneError && width == 1 {
+ s.error("illegal UTF-8 encoding")
+ }
+ s.srcPos += width - 1
+ }
+ }
+
+ s.srcPos++
+ s.column++
+ switch ch {
+ case 0:
+ // implementation restriction for compatibility with other tools
+ s.error("illegal character NUL")
+ case '\n':
+ s.line++
+ s.column = 0
+ }
+
+ return ch
+}
+
+
+// Next reads and returns the next Unicode character.
+// It returns EOF at the end of the source. It reports
+// a read error by calling s.Error, if set, or else
+// prints an error message to os.Stderr. Next does not
+// update the Scanner's Position field; use Pos() to
+// get the current position.
+func (s *Scanner) Next() int {
+ s.tokPos = -1 // don't collect token text
+ ch := s.ch
+ s.ch = s.next()
+ return ch
+}
+
+
+// Peek returns the next Unicode character in the source without advancing
+// the scanner. It returns EOF if the scanner's position is at the last
+// character of the source.
+func (s *Scanner) Peek() int {
+ return s.ch
+}
+
+
+func (s *Scanner) error(msg string) {
+ s.ErrorCount++
+ if s.Error != nil {
+ s.Error(s, msg)
+ return
+ }
+ fmt.Fprintf(os.Stderr, "%s: %s", s.Position, msg)
+}
+
+
+func (s *Scanner) scanIdentifier() int {
+ ch := s.next() // read character after first '_' or letter
+ for ch == '_' || unicode.IsLetter(ch) || unicode.IsDigit(ch) {
+ ch = s.next()
+ }
+ return ch
+}
+
+
+func digitVal(ch int) int {
+ switch {
+ case '0' <= ch && ch <= '9':
+ return ch - '0'
+ case 'a' <= ch && ch <= 'f':
+ return ch - 'a' + 10
+ case 'A' <= ch && ch <= 'F':
+ return ch - 'A' + 10
+ }
+ return 16 // larger than any legal digit val
+}
+
+
+func isDecimal(ch int) bool { return '0' <= ch && ch <= '9' }
+
+
+func (s *Scanner) scanMantissa(ch int) int {
+ for isDecimal(ch) {
+ ch = s.next()
+ }
+ return ch
+}
+
+
+func (s *Scanner) scanFraction(ch int) int {
+ if ch == '.' {
+ ch = s.scanMantissa(s.next())
+ }
+ return ch
+}
+
+
+func (s *Scanner) scanExponent(ch int) int {
+ if ch == 'e' || ch == 'E' {
+ ch = s.next()
+ if ch == '-' || ch == '+' {
+ ch = s.next()
+ }
+ ch = s.scanMantissa(ch)
+ }
+ return ch
+}
+
+
+func (s *Scanner) scanNumber(ch int) (int, int) {
+ // isDecimal(ch)
+ if ch == '0' {
+ // int or float
+ ch = s.next()
+ if ch == 'x' || ch == 'X' {
+ // hexadecimal int
+ ch = s.next()
+ for digitVal(ch) < 16 {
+ ch = s.next()
+ }
+ } else {
+ // octal int or float
+ seenDecimalDigit := false
+ for isDecimal(ch) {
+ if ch > '7' {
+ seenDecimalDigit = true
+ }
+ ch = s.next()
+ }
+ if s.Mode&ScanFloats != 0 && (ch == '.' || ch == 'e' || ch == 'E') {
+ // float
+ ch = s.scanFraction(ch)
+ ch = s.scanExponent(ch)
+ return Float, ch
+ }
+ // octal int
+ if seenDecimalDigit {
+ s.error("illegal octal number")
+ }
+ }
+ return Int, ch
+ }
+ // decimal int or float
+ ch = s.scanMantissa(ch)
+ if s.Mode&ScanFloats != 0 && (ch == '.' || ch == 'e' || ch == 'E') {
+ // float
+ ch = s.scanFraction(ch)
+ ch = s.scanExponent(ch)
+ return Float, ch
+ }
+ return Int, ch
+}
+
+
+func (s *Scanner) scanDigits(ch, base, n int) int {
+ for n > 0 && digitVal(ch) < base {
+ ch = s.next()
+ n--
+ }
+ if n > 0 {
+ s.error("illegal char escape")
+ }
+ return ch
+}
+
+
+func (s *Scanner) scanEscape(quote int) int {
+ ch := s.next() // read character after '/'
+ switch ch {
+ case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
+ // nothing to do
+ ch = s.next()
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ ch = s.scanDigits(ch, 8, 3)
+ case 'x':
+ ch = s.scanDigits(s.next(), 16, 2)
+ case 'u':
+ ch = s.scanDigits(s.next(), 16, 4)
+ case 'U':
+ ch = s.scanDigits(s.next(), 16, 8)
+ default:
+ s.error("illegal char escape")
+ }
+ return ch
+}
+
+
+func (s *Scanner) scanString(quote int) (n int) {
+ ch := s.next() // read character after quote
+ for ch != quote {
+ if ch == '\n' || ch < 0 {
+ s.error("literal not terminated")
+ return
+ }
+ if ch == '\\' {
+ ch = s.scanEscape(quote)
+ } else {
+ ch = s.next()
+ }
+ n++
+ }
+ return
+}
+
+
+func (s *Scanner) scanRawString() {
+ ch := s.next() // read character after '`'
+ for ch != '`' {
+ if ch < 0 {
+ s.error("literal not terminated")
+ return
+ }
+ ch = s.next()
+ }
+}
+
+
+func (s *Scanner) scanChar() {
+ if s.scanString('\'') != 1 {
+ s.error("illegal char literal")
+ }
+}
+
+
+func (s *Scanner) scanLineComment() {
+ ch := s.next() // read character after "//"
+ for ch != '\n' {
+ if ch < 0 {
+ s.error("comment not terminated")
+ return
+ }
+ ch = s.next()
+ }
+}
+
+
+func (s *Scanner) scanGeneralComment() {
+ ch := s.next() // read character after "/*"
+ for {
+ if ch < 0 {
+ s.error("comment not terminated")
+ return
+ }
+ ch0 := ch
+ ch = s.next()
+ if ch0 == '*' && ch == '/' {
+ break
+ }
+ }
+}
+
+
+func (s *Scanner) scanComment(ch int) {
+ // ch == '/' || ch == '*'
+ if ch == '/' {
+ s.scanLineComment()
+ return
+ }
+ s.scanGeneralComment()
+}
+
+
+// Scan reads the next token or Unicode character from source and returns it.
+// It only recognizes tokens t for which the respective Mode bit (1<<-t) is set.
+// It returns EOF at the end of the source. It reports scanner errors (read and
+// token errors) by calling s.Error, if set; otherwise it prints an error message
+// to os.Stderr.
+func (s *Scanner) Scan() int {
+ ch := s.ch
+
+ // reset token text position
+ s.tokPos = -1
+
+redo:
+ // skip white space
+ for s.Whitespace&(1<<uint(ch)) != 0 {
+ ch = s.next()
+ }
+
+ // start collecting token text
+ s.tokBuf.Reset()
+ s.tokPos = s.srcPos - 1
+
+ // set token position
+ s.Offset = s.srcBufOffset + s.tokPos
+ s.Line = s.line
+ s.Column = s.column
+
+ // determine token value
+ tok := ch
+ switch {
+ case unicode.IsLetter(ch) || ch == '_':
+ if s.Mode&ScanIdents != 0 {
+ tok = Ident
+ ch = s.scanIdentifier()
+ } else {
+ ch = s.next()
+ }
+ case isDecimal(ch):
+ if s.Mode&(ScanInts|ScanFloats) != 0 {
+ tok, ch = s.scanNumber(ch)
+ } else {
+ ch = s.next()
+ }
+ default:
+ switch ch {
+ case '"':
+ if s.Mode&ScanStrings != 0 {
+ s.scanString('"')
+ tok = String
+ }
+ ch = s.next()
+ case '\'':
+ if s.Mode&ScanChars != 0 {
+ s.scanChar()
+ tok = Char
+ }
+ ch = s.next()
+ case '.':
+ ch = s.next()
+ if isDecimal(ch) && s.Mode&ScanFloats != 0 {
+ tok = Float
+ ch = s.scanMantissa(ch)
+ ch = s.scanExponent(ch)
+ }
+ case '/':
+ ch = s.next()
+ if (ch == '/' || ch == '*') && s.Mode&ScanComments != 0 {
+ if s.Mode&SkipComments != 0 {
+ s.tokPos = -1 // don't collect token text
+ s.scanComment(ch)
+ ch = s.next()
+ goto redo
+ }
+ s.scanComment(ch)
+ tok = Comment
+ ch = s.next()
+ }
+ case '`':
+ if s.Mode&ScanRawStrings != 0 {
+ s.scanRawString()
+ tok = String
+ }
+ ch = s.next()
+ default:
+ ch = s.next()
+ }
+ }
+
+ // end of token text
+ s.tokEnd = s.srcPos - 1
+
+ s.ch = ch
+ return tok
+}
+
+
+// Position returns the current source position. If called before Next()
+// or Scan(), it returns the position of the next Unicode character or token
+// returned by these functions. If called afterwards, it returns the position
+// immediately after the last character of the most recent token or character
+// scanned.
+func (s *Scanner) Pos() Position {
+ return Position{
+ s.Filename,
+ s.srcBufOffset + s.srcPos - 1,
+ s.line,
+ s.column,
+ }
+}
+
+
+// TokenText returns the string corresponding to the most recently scanned token.
+// Valid after calling Scan().
+func (s *Scanner) TokenText() string {
+ if s.tokPos < 0 {
+ // no token text
+ return ""
+ }
+
+ if s.tokEnd < 0 {
+ // if EOF was reached, s.tokEnd is set to -1 (s.srcPos == 0)
+ s.tokEnd = s.tokPos
+ }
+
+ if s.tokBuf.Len() == 0 {
+ // common case: the entire token text is still in srcBuf
+ return string(s.srcBuf[s.tokPos:s.tokEnd])
+ }
+
+ // part of the token text was saved in tokBuf: save the rest in
+ // tokBuf as well and return its content
+ s.tokBuf.Write(s.srcBuf[s.tokPos:s.tokEnd])
+ s.tokPos = s.tokEnd // ensure idempotency of TokenText() call
+ return s.tokBuf.String()
+}
diff --git a/libgo/go/scanner/scanner_test.go b/libgo/go/scanner/scanner_test.go
new file mode 100644
index 000000000..506f434fe
--- /dev/null
+++ b/libgo/go/scanner/scanner_test.go
@@ -0,0 +1,482 @@
+// 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 scanner
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+)
+
+
+// A StringReader delivers its data one string segment at a time via Read.
+type StringReader struct {
+ data []string
+ step int
+}
+
+
+func (r *StringReader) Read(p []byte) (n int, err os.Error) {
+ if r.step < len(r.data) {
+ s := r.data[r.step]
+ n = copy(p, s)
+ r.step++
+ } else {
+ err = os.EOF
+ }
+ return
+}
+
+
+func readRuneSegments(t *testing.T, segments []string) {
+ got := ""
+ want := strings.Join(segments, "")
+ s := new(Scanner).Init(&StringReader{data: segments})
+ for {
+ ch := s.Next()
+ if ch == EOF {
+ break
+ }
+ got += string(ch)
+ }
+ if got != want {
+ t.Errorf("segments=%v got=%s want=%s", segments, got, want)
+ }
+}
+
+
+var segmentList = [][]string{
+ {},
+ {""},
+ {"日", "本語"},
+ {"\u65e5", "\u672c", "\u8a9e"},
+ {"\U000065e5", " ", "\U0000672c", "\U00008a9e"},
+ {"\xe6", "\x97\xa5\xe6", "\x9c\xac\xe8\xaa\x9e"},
+ {"Hello", ", ", "World", "!"},
+ {"Hello", ", ", "", "World", "!"},
+}
+
+
+func TestNext(t *testing.T) {
+ for _, s := range segmentList {
+ readRuneSegments(t, s)
+ }
+}
+
+
+type token struct {
+ tok int
+ text string
+}
+
+var f100 = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+
+var tokenList = []token{
+ {Comment, "// line comments\n"},
+ {Comment, "//\n"},
+ {Comment, "////\n"},
+ {Comment, "// comment\n"},
+ {Comment, "// /* comment */\n"},
+ {Comment, "// // comment //\n"},
+ {Comment, "//" + f100 + "\n"},
+
+ {Comment, "// general comments\n"},
+ {Comment, "/**/"},
+ {Comment, "/***/"},
+ {Comment, "/* comment */"},
+ {Comment, "/* // comment */"},
+ {Comment, "/* /* comment */"},
+ {Comment, "/*\n comment\n*/"},
+ {Comment, "/*" + f100 + "*/"},
+
+ {Comment, "// identifiers\n"},
+ {Ident, "a"},
+ {Ident, "a0"},
+ {Ident, "foobar"},
+ {Ident, "abc123"},
+ {Ident, "LGTM"},
+ {Ident, "_"},
+ {Ident, "_abc123"},
+ {Ident, "abc123_"},
+ {Ident, "_abc_123_"},
+ {Ident, "_äöü"},
+ {Ident, "_本"},
+ // TODO for unknown reasons these fail when checking the literals
+ /*
+ token{Ident, "äöü"},
+ token{Ident, "本"},
+ */
+ {Ident, "a۰۱۸"},
+ {Ident, "foo६४"},
+ {Ident, "bar9876"},
+ {Ident, f100},
+
+ {Comment, "// decimal ints\n"},
+ {Int, "0"},
+ {Int, "1"},
+ {Int, "9"},
+ {Int, "42"},
+ {Int, "1234567890"},
+
+ {Comment, "// octal ints\n"},
+ {Int, "00"},
+ {Int, "01"},
+ {Int, "07"},
+ {Int, "042"},
+ {Int, "01234567"},
+
+ {Comment, "// hexadecimal ints\n"},
+ {Int, "0x0"},
+ {Int, "0x1"},
+ {Int, "0xf"},
+ {Int, "0x42"},
+ {Int, "0x123456789abcDEF"},
+ {Int, "0x" + f100},
+ {Int, "0X0"},
+ {Int, "0X1"},
+ {Int, "0XF"},
+ {Int, "0X42"},
+ {Int, "0X123456789abcDEF"},
+ {Int, "0X" + f100},
+
+ {Comment, "// floats\n"},
+ {Float, "0."},
+ {Float, "1."},
+ {Float, "42."},
+ {Float, "01234567890."},
+ {Float, ".0"},
+ {Float, ".1"},
+ {Float, ".42"},
+ {Float, ".0123456789"},
+ {Float, "0.0"},
+ {Float, "1.0"},
+ {Float, "42.0"},
+ {Float, "01234567890.0"},
+ {Float, "0e0"},
+ {Float, "1e0"},
+ {Float, "42e0"},
+ {Float, "01234567890e0"},
+ {Float, "0E0"},
+ {Float, "1E0"},
+ {Float, "42E0"},
+ {Float, "01234567890E0"},
+ {Float, "0e+10"},
+ {Float, "1e-10"},
+ {Float, "42e+10"},
+ {Float, "01234567890e-10"},
+ {Float, "0E+10"},
+ {Float, "1E-10"},
+ {Float, "42E+10"},
+ {Float, "01234567890E-10"},
+
+ {Comment, "// chars\n"},
+ {Char, `' '`},
+ {Char, `'a'`},
+ {Char, `'本'`},
+ {Char, `'\a'`},
+ {Char, `'\b'`},
+ {Char, `'\f'`},
+ {Char, `'\n'`},
+ {Char, `'\r'`},
+ {Char, `'\t'`},
+ {Char, `'\v'`},
+ {Char, `'\''`},
+ {Char, `'\000'`},
+ {Char, `'\777'`},
+ {Char, `'\x00'`},
+ {Char, `'\xff'`},
+ {Char, `'\u0000'`},
+ {Char, `'\ufA16'`},
+ {Char, `'\U00000000'`},
+ {Char, `'\U0000ffAB'`},
+
+ {Comment, "// strings\n"},
+ {String, `" "`},
+ {String, `"a"`},
+ {String, `"本"`},
+ {String, `"\a"`},
+ {String, `"\b"`},
+ {String, `"\f"`},
+ {String, `"\n"`},
+ {String, `"\r"`},
+ {String, `"\t"`},
+ {String, `"\v"`},
+ {String, `"\""`},
+ {String, `"\000"`},
+ {String, `"\777"`},
+ {String, `"\x00"`},
+ {String, `"\xff"`},
+ {String, `"\u0000"`},
+ {String, `"\ufA16"`},
+ {String, `"\U00000000"`},
+ {String, `"\U0000ffAB"`},
+ {String, `"` + f100 + `"`},
+
+ {Comment, "// raw strings\n"},
+ {String, "``"},
+ {String, "`\\`"},
+ {String, "`" + "\n\n/* foobar */\n\n" + "`"},
+ {String, "`" + f100 + "`"},
+
+ {Comment, "// individual characters\n"},
+ // NUL character is not allowed
+ {'\x01', "\x01"},
+ {' ' - 1, string(' ' - 1)},
+ {'+', "+"},
+ {'/', "/"},
+ {'.', "."},
+ {'~', "~"},
+ {'(', "("},
+}
+
+
+func makeSource(pattern string) *bytes.Buffer {
+ var buf bytes.Buffer
+ for _, k := range tokenList {
+ fmt.Fprintf(&buf, pattern, k.text)
+ }
+ return &buf
+}
+
+
+func checkTok(t *testing.T, s *Scanner, line, got, want int, text string) {
+ if got != want {
+ t.Fatalf("tok = %s, want %s for %q", TokenString(got), TokenString(want), text)
+ }
+ if s.Line != line {
+ t.Errorf("line = %d, want %d for %q", s.Line, line, text)
+ }
+ stext := s.TokenText()
+ if stext != text {
+ t.Errorf("text = %q, want %q", stext, text)
+ } else {
+ // check idempotency of TokenText() call
+ stext = s.TokenText()
+ if stext != text {
+ t.Errorf("text = %q, want %q (idempotency check)", stext, text)
+ }
+ }
+}
+
+
+func countNewlines(s string) int {
+ n := 0
+ for _, ch := range s {
+ if ch == '\n' {
+ n++
+ }
+ }
+ return n
+}
+
+
+func testScan(t *testing.T, mode uint) {
+ s := new(Scanner).Init(makeSource(" \t%s\t\n\r"))
+ s.Mode = mode
+ tok := s.Scan()
+ line := 1
+ for _, k := range tokenList {
+ if mode&SkipComments == 0 || k.tok != Comment {
+ checkTok(t, s, line, tok, k.tok, k.text)
+ tok = s.Scan()
+ }
+ line += countNewlines(k.text) + 1 // each token is on a new line
+ }
+ checkTok(t, s, line, tok, -1, "")
+}
+
+
+func TestScan(t *testing.T) {
+ testScan(t, GoTokens)
+ testScan(t, GoTokens&^SkipComments)
+}
+
+
+func TestPosition(t *testing.T) {
+ src := makeSource("\t\t\t\t%s\n")
+ s := new(Scanner).Init(src)
+ s.Mode = GoTokens &^ SkipComments
+ s.Scan()
+ pos := Position{"", 4, 1, 5}
+ for _, k := range tokenList {
+ if s.Offset != pos.Offset {
+ t.Errorf("offset = %d, want %d for %q", s.Offset, pos.Offset, k.text)
+ }
+ if s.Line != pos.Line {
+ t.Errorf("line = %d, want %d for %q", s.Line, pos.Line, k.text)
+ }
+ if s.Column != pos.Column {
+ t.Errorf("column = %d, want %d for %q", s.Column, pos.Column, k.text)
+ }
+ pos.Offset += 4 + len(k.text) + 1 // 4 tabs + token bytes + newline
+ pos.Line += countNewlines(k.text) + 1 // each token is on a new line
+ s.Scan()
+ }
+}
+
+
+func TestScanZeroMode(t *testing.T) {
+ src := makeSource("%s\n")
+ str := src.String()
+ s := new(Scanner).Init(src)
+ s.Mode = 0 // don't recognize any token classes
+ s.Whitespace = 0 // don't skip any whitespace
+ tok := s.Scan()
+ for i, ch := range str {
+ if tok != ch {
+ t.Fatalf("%d. tok = %s, want %s", i, TokenString(tok), TokenString(ch))
+ }
+ tok = s.Scan()
+ }
+ if tok != EOF {
+ t.Fatalf("tok = %s, want EOF", TokenString(tok))
+ }
+}
+
+
+func testScanSelectedMode(t *testing.T, mode uint, class int) {
+ src := makeSource("%s\n")
+ s := new(Scanner).Init(src)
+ s.Mode = mode
+ tok := s.Scan()
+ for tok != EOF {
+ if tok < 0 && tok != class {
+ t.Fatalf("tok = %s, want %s", TokenString(tok), TokenString(class))
+ }
+ tok = s.Scan()
+ }
+}
+
+
+func TestScanSelectedMask(t *testing.T) {
+ testScanSelectedMode(t, 0, 0)
+ testScanSelectedMode(t, ScanIdents, Ident)
+ // Don't test ScanInts and ScanNumbers since some parts of
+ // the floats in the source look like (illegal) octal ints
+ // and ScanNumbers may return either Int or Float.
+ testScanSelectedMode(t, ScanChars, Char)
+ testScanSelectedMode(t, ScanStrings, String)
+ testScanSelectedMode(t, SkipComments, 0)
+ testScanSelectedMode(t, ScanComments, Comment)
+}
+
+
+func TestScanNext(t *testing.T) {
+ s := new(Scanner).Init(bytes.NewBufferString("if a == bcd /* comment */ {\n\ta += c\n}"))
+ checkTok(t, s, 1, s.Scan(), Ident, "if")
+ checkTok(t, s, 1, s.Scan(), Ident, "a")
+ checkTok(t, s, 1, s.Scan(), '=', "=")
+ checkTok(t, s, 1, s.Next(), '=', "")
+ checkTok(t, s, 1, s.Next(), ' ', "")
+ checkTok(t, s, 1, s.Next(), 'b', "")
+ checkTok(t, s, 1, s.Scan(), Ident, "cd")
+ checkTok(t, s, 1, s.Scan(), '{', "{")
+ checkTok(t, s, 2, s.Scan(), Ident, "a")
+ checkTok(t, s, 2, s.Scan(), '+', "+")
+ checkTok(t, s, 2, s.Next(), '=', "")
+ checkTok(t, s, 2, s.Scan(), Ident, "c")
+ checkTok(t, s, 3, s.Scan(), '}', "}")
+ checkTok(t, s, 3, s.Scan(), -1, "")
+}
+
+
+func TestScanWhitespace(t *testing.T) {
+ var buf bytes.Buffer
+ var ws uint64
+ // start at 1, NUL character is not allowed
+ for ch := byte(1); ch < ' '; ch++ {
+ buf.WriteByte(ch)
+ ws |= 1 << ch
+ }
+ const orig = 'x'
+ buf.WriteByte(orig)
+
+ s := new(Scanner).Init(&buf)
+ s.Mode = 0
+ s.Whitespace = ws
+ tok := s.Scan()
+ if tok != orig {
+ t.Errorf("tok = %s, want %s", TokenString(tok), TokenString(orig))
+ }
+}
+
+
+func testError(t *testing.T, src, msg string, tok int) {
+ s := new(Scanner).Init(bytes.NewBufferString(src))
+ errorCalled := false
+ s.Error = func(s *Scanner, m string) {
+ if !errorCalled {
+ // only look at first error
+ if m != msg {
+ t.Errorf("msg = %q, want %q for %q", m, msg, src)
+ }
+ errorCalled = true
+ }
+ }
+ tk := s.Scan()
+ if tk != tok {
+ t.Errorf("tok = %s, want %s for %q", TokenString(tk), TokenString(tok), src)
+ }
+ if !errorCalled {
+ t.Errorf("error handler not called for %q", src)
+ }
+ if s.ErrorCount == 0 {
+ t.Errorf("count = %d, want > 0 for %q", s.ErrorCount, src)
+ }
+}
+
+
+func TestError(t *testing.T) {
+ testError(t, `01238`, "illegal octal number", Int)
+ testError(t, `'\"'`, "illegal char escape", Char)
+ testError(t, `'aa'`, "illegal char literal", Char)
+ testError(t, `'`, "literal not terminated", Char)
+ testError(t, `"\'"`, "illegal char escape", String)
+ testError(t, `"abc`, "literal not terminated", String)
+ testError(t, "`abc", "literal not terminated", String)
+ testError(t, `//`, "comment not terminated", EOF)
+ testError(t, `/*/`, "comment not terminated", EOF)
+ testError(t, `"abc`+"\x00"+`def"`, "illegal character NUL", String)
+ testError(t, `"abc`+"\xff"+`def"`, "illegal UTF-8 encoding", String)
+}
+
+
+func checkPos(t *testing.T, s *Scanner, offset, line, column, char int) {
+ pos := s.Pos()
+ if pos.Offset != offset {
+ t.Errorf("offset = %d, want %d", pos.Offset, offset)
+ }
+ if pos.Line != line {
+ t.Errorf("line = %d, want %d", pos.Line, line)
+ }
+ if pos.Column != column {
+ t.Errorf("column = %d, want %d", pos.Column, column)
+ }
+ ch := s.Scan()
+ if ch != char {
+ t.Errorf("ch = %s, want %s", TokenString(ch), TokenString(char))
+ }
+}
+
+
+func TestPos(t *testing.T) {
+ s := new(Scanner).Init(bytes.NewBufferString("abc\n012\n\nx"))
+ s.Mode = 0
+ s.Whitespace = 0
+ checkPos(t, s, 0, 1, 1, 'a')
+ checkPos(t, s, 1, 1, 2, 'b')
+ checkPos(t, s, 2, 1, 3, 'c')
+ checkPos(t, s, 3, 2, 0, '\n')
+ checkPos(t, s, 4, 2, 1, '0')
+ checkPos(t, s, 5, 2, 2, '1')
+ checkPos(t, s, 6, 2, 3, '2')
+ checkPos(t, s, 7, 3, 0, '\n')
+ checkPos(t, s, 8, 4, 0, '\n')
+ checkPos(t, s, 9, 4, 1, 'x')
+ checkPos(t, s, 9, 4, 1, EOF)
+ checkPos(t, s, 9, 4, 1, EOF) // after EOF, position doesn't change
+}
diff --git a/libgo/go/smtp/auth.go b/libgo/go/smtp/auth.go
new file mode 100644
index 000000000..dd27f8e93
--- /dev/null
+++ b/libgo/go/smtp/auth.go
@@ -0,0 +1,69 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package smtp
+
+import (
+ "os"
+)
+
+// Auth is implemented by an SMTP authentication mechanism.
+type Auth interface {
+ // Start begins an authentication with a server.
+ // It returns the name of the authentication protocol
+ // and optionally data to include in the initial AUTH message
+ // sent to the server. It can return proto == "" to indicate
+ // that the authentication should be skipped.
+ // If it returns a non-nil os.Error, the SMTP client aborts
+ // the authentication attempt and closes the connection.
+ Start(server *ServerInfo) (proto string, toServer []byte, err os.Error)
+
+ // Next continues the authentication. The server has just sent
+ // the fromServer data. If more is true, the server expects a
+ // response, which Next should return as toServer; otherwise
+ // Next should return toServer == nil.
+ // If Next returns a non-nil os.Error, the SMTP client aborts
+ // the authentication attempt and closes the connection.
+ Next(fromServer []byte, more bool) (toServer []byte, err os.Error)
+}
+
+// ServerInfo records information about an SMTP server.
+type ServerInfo struct {
+ Name string // SMTP server name
+ TLS bool // using TLS, with valid certificate for Name
+ Auth []string // advertised authentication mechanisms
+}
+
+type plainAuth struct {
+ identity, username, password string
+ host string
+}
+
+// PlainAuth returns an Auth that implements the PLAIN authentication
+// mechanism as defined in RFC 4616.
+// The returned Auth uses the given username and password to authenticate
+// on TLS connections to host and act as identity. Usually identity will be
+// left blank to act as username.
+func PlainAuth(identity, username, password, host string) Auth {
+ return &plainAuth{identity, username, password, host}
+}
+
+func (a *plainAuth) Start(server *ServerInfo) (string, []byte, os.Error) {
+ if !server.TLS {
+ return "", nil, os.NewError("unencrypted connection")
+ }
+ if server.Name != a.host {
+ return "", nil, os.NewError("wrong host name")
+ }
+ resp := []byte(a.identity + "\x00" + a.username + "\x00" + a.password)
+ return "PLAIN", resp, nil
+}
+
+func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, os.Error) {
+ if more {
+ // We've already sent everything.
+ return nil, os.NewError("unexpected server challenge")
+ }
+ return nil, nil
+}
diff --git a/libgo/go/smtp/smtp.go b/libgo/go/smtp/smtp.go
new file mode 100644
index 000000000..2f6d2f31a
--- /dev/null
+++ b/libgo/go/smtp/smtp.go
@@ -0,0 +1,295 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package smtp implements the Simple Mail Transfer Protocol as defined in RFC 5321.
+// It also implements the following extensions:
+// 8BITMIME RFC 1652
+// AUTH RFC 2554
+// STARTTLS RFC 3207
+// Additional extensions may be handled by clients.
+package smtp
+
+import (
+ "crypto/tls"
+ "encoding/base64"
+ "io"
+ "os"
+ "net"
+ "net/textproto"
+ "strings"
+)
+
+// A Client represents a client connection to an SMTP server.
+type Client struct {
+ // Text is the textproto.Conn used by the Client. It is exported to allow for
+ // clients to add extensions.
+ Text *textproto.Conn
+ // keep a reference to the connection so it can be used to create a TLS
+ // connection later
+ conn net.Conn
+ // whether the Client is using TLS
+ tls bool
+ serverName string
+ // map of supported extensions
+ ext map[string]string
+ // supported auth mechanisms
+ auth []string
+}
+
+// Dial returns a new Client connected to an SMTP server at addr.
+func Dial(addr string) (*Client, os.Error) {
+ conn, err := net.Dial("tcp", "", addr)
+ if err != nil {
+ return nil, err
+ }
+ host := addr[:strings.Index(addr, ":")]
+ return NewClient(conn, host)
+}
+
+// NewClient returns a new Client using an existing connection and host as a
+// server name to be used when authenticating.
+func NewClient(conn net.Conn, host string) (*Client, os.Error) {
+ text := textproto.NewConn(conn)
+ _, msg, err := text.ReadResponse(220)
+ if err != nil {
+ text.Close()
+ return nil, err
+ }
+ c := &Client{Text: text, conn: conn, serverName: host}
+ if strings.Contains(msg, "ESMTP") {
+ err = c.ehlo()
+ } else {
+ err = c.helo()
+ }
+ return c, err
+}
+
+// cmd is a convenience function that sends a command and returns the response
+func (c *Client) cmd(expectCode int, format string, args ...interface{}) (int, string, os.Error) {
+ id, err := c.Text.Cmd(format, args...)
+ if err != nil {
+ return 0, "", err
+ }
+ c.Text.StartResponse(id)
+ defer c.Text.EndResponse(id)
+ code, msg, err := c.Text.ReadResponse(expectCode)
+ return code, msg, err
+}
+
+// helo sends the HELO greeting to the server. It should be used only when the
+// server does not support ehlo.
+func (c *Client) helo() os.Error {
+ c.ext = nil
+ _, _, err := c.cmd(250, "HELO localhost")
+ return err
+}
+
+// ehlo sends the EHLO (extended hello) greeting to the server. It
+// should be the preferred greeting for servers that support it.
+func (c *Client) ehlo() os.Error {
+ _, msg, err := c.cmd(250, "EHLO localhost")
+ if err != nil {
+ return err
+ }
+ ext := make(map[string]string)
+ extList := strings.Split(msg, "\n", -1)
+ if len(extList) > 1 {
+ extList = extList[1:]
+ for _, line := range extList {
+ args := strings.Split(line, " ", 2)
+ if len(args) > 1 {
+ ext[args[0]] = args[1]
+ } else {
+ ext[args[0]] = ""
+ }
+ }
+ }
+ if mechs, ok := ext["AUTH"]; ok {
+ c.auth = strings.Split(mechs, " ", -1)
+ }
+ c.ext = ext
+ return err
+}
+
+// StartTLS sends the STARTTLS command and encrypts all further communication.
+// Only servers that advertise the STARTTLS extension support this function.
+func (c *Client) StartTLS(config *tls.Config) os.Error {
+ _, _, err := c.cmd(220, "STARTTLS")
+ if err != nil {
+ return err
+ }
+ c.conn = tls.Client(c.conn, config)
+ c.Text = textproto.NewConn(c.conn)
+ c.tls = true
+ return c.ehlo()
+}
+
+// Verify checks the validity of an email address on the server.
+// If Verify returns nil, the address is valid. A non-nil return
+// does not necessarily indicate an invalid address. Many servers
+// will not verify addresses for security reasons.
+func (c *Client) Verify(addr string) os.Error {
+ _, _, err := c.cmd(250, "VRFY %s", addr)
+ return err
+}
+
+// Auth authenticates a client using the provided authentication mechanism.
+// A failed authentication closes the connection.
+// Only servers that advertise the AUTH extension support this function.
+func (c *Client) Auth(a Auth) os.Error {
+ encoding := base64.StdEncoding
+ mech, resp, err := a.Start(&ServerInfo{c.serverName, c.tls, c.auth})
+ if err != nil {
+ c.Quit()
+ return err
+ }
+ resp64 := make([]byte, encoding.EncodedLen(len(resp)))
+ encoding.Encode(resp64, resp)
+ code, msg64, err := c.cmd(0, "AUTH %s %s", mech, resp64)
+ for err == nil {
+ var msg []byte
+ switch code {
+ case 334:
+ msg = make([]byte, encoding.DecodedLen(len(msg64)))
+ _, err = encoding.Decode(msg, []byte(msg64))
+ case 235:
+ // the last message isn't base64 because it isn't a challenge
+ msg = []byte(msg64)
+ default:
+ err = &textproto.Error{code, msg64}
+ }
+ resp, err = a.Next(msg, code == 334)
+ if err != nil {
+ // abort the AUTH
+ c.cmd(501, "*")
+ c.Quit()
+ break
+ }
+ if resp == nil {
+ break
+ }
+ resp64 = make([]byte, encoding.EncodedLen(len(resp)))
+ encoding.Encode(resp64, resp)
+ code, msg64, err = c.cmd(0, string(resp64))
+ }
+ return err
+}
+
+// Mail issues a MAIL command to the server using the provided email address.
+// If the server supports the 8BITMIME extension, Mail adds the BODY=8BITMIME
+// parameter.
+// This initiates a mail transaction and is followed by one or more Rcpt calls.
+func (c *Client) Mail(from string) os.Error {
+ cmdStr := "MAIL FROM:<%s>"
+ if c.ext != nil {
+ if _, ok := c.ext["8BITMIME"]; ok {
+ cmdStr += " BODY=8BITMIME"
+ }
+ }
+ _, _, err := c.cmd(250, cmdStr, from)
+ return err
+}
+
+// Rcpt issues a RCPT command to the server using the provided email address.
+// A call to Rcpt must be preceded by a call to Mail and may be followed by
+// a Data call or another Rcpt call.
+func (c *Client) Rcpt(to string) os.Error {
+ _, _, err := c.cmd(25, "RCPT TO:<%s>", to)
+ return err
+}
+
+type dataCloser struct {
+ c *Client
+ io.WriteCloser
+}
+
+func (d *dataCloser) Close() os.Error {
+ d.WriteCloser.Close()
+ _, _, err := d.c.Text.ReadResponse(250)
+ return err
+}
+
+// Data issues a DATA command to the server and returns a writer that
+// can be used to write the data. The caller should close the writer
+// before calling any more methods on c.
+// A call to Data must be preceded by one or more calls to Rcpt.
+func (c *Client) Data() (io.WriteCloser, os.Error) {
+ _, _, err := c.cmd(354, "DATA")
+ if err != nil {
+ return nil, err
+ }
+ return &dataCloser{c, c.Text.DotWriter()}, nil
+}
+
+// SendMail connects to the server at addr, switches to TLS if possible,
+// authenticates with mechanism a if possible, and then sends an email from
+// address from, to addresses to, with message msg.
+func SendMail(addr string, a Auth, from string, to []string, msg []byte) os.Error {
+ c, err := Dial(addr)
+ if err != nil {
+ return err
+ }
+ if ok, _ := c.Extension("STARTTLS"); ok {
+ if err = c.StartTLS(nil); err != nil {
+ return err
+ }
+ }
+ if a != nil && c.ext != nil {
+ if _, ok := c.ext["AUTH"]; ok {
+ if err = c.Auth(a); err != nil {
+ return err
+ }
+ }
+ }
+ if err = c.Mail(from); err != nil {
+ return err
+ }
+ for _, addr := range to {
+ if err = c.Rcpt(addr); err != nil {
+ return err
+ }
+ }
+ w, err := c.Data()
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(msg)
+ if err != nil {
+ return err
+ }
+ err = w.Close()
+ if err != nil {
+ return err
+ }
+ return c.Quit()
+}
+
+// Extension reports whether an extension is support by the server.
+// The extension name is case-insensitive. If the extension is supported,
+// Extension also returns a string that contains any parameters the
+// server specifies for the extension.
+func (c *Client) Extension(ext string) (bool, string) {
+ if c.ext == nil {
+ return false, ""
+ }
+ ext = strings.ToUpper(ext)
+ param, ok := c.ext[ext]
+ return ok, param
+}
+
+// Reset sends the RSET command to the server, aborting the current mail
+// transaction.
+func (c *Client) Reset() os.Error {
+ _, _, err := c.cmd(250, "RSET")
+ return err
+}
+
+// Quit sends the QUIT command and closes the connection to the server.
+func (c *Client) Quit() os.Error {
+ _, _, err := c.cmd(221, "QUIT")
+ if err != nil {
+ return err
+ }
+ return c.Text.Close()
+}
diff --git a/libgo/go/smtp/smtp_test.go b/libgo/go/smtp/smtp_test.go
new file mode 100644
index 000000000..49363adf0
--- /dev/null
+++ b/libgo/go/smtp/smtp_test.go
@@ -0,0 +1,182 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package smtp
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "net/textproto"
+ "os"
+ "strings"
+ "testing"
+)
+
+type authTest struct {
+ auth Auth
+ challenges []string
+ name string
+ responses []string
+}
+
+var authTests = []authTest{
+ {PlainAuth("", "user", "pass", "testserver"), []string{}, "PLAIN", []string{"\x00user\x00pass"}},
+ {PlainAuth("foo", "bar", "baz", "testserver"), []string{}, "PLAIN", []string{"foo\x00bar\x00baz"}},
+}
+
+func TestAuth(t *testing.T) {
+testLoop:
+ for i, test := range authTests {
+ name, resp, err := test.auth.Start(&ServerInfo{"testserver", true, nil})
+ if name != test.name {
+ t.Errorf("#%d got name %s, expected %s", i, name, test.name)
+ }
+ if !bytes.Equal(resp, []byte(test.responses[0])) {
+ t.Errorf("#%d got response %s, expected %s", i, resp, test.responses[0])
+ }
+ if err != nil {
+ t.Errorf("#%d error: %s", i, err.String())
+ }
+ for j := range test.challenges {
+ challenge := []byte(test.challenges[j])
+ expected := []byte(test.responses[j+1])
+ resp, err := test.auth.Next(challenge, true)
+ if err != nil {
+ t.Errorf("#%d error: %s", i, err.String())
+ continue testLoop
+ }
+ if !bytes.Equal(resp, expected) {
+ t.Errorf("#%d got %s, expected %s", i, resp, expected)
+ continue testLoop
+ }
+ }
+ }
+}
+
+type faker struct {
+ io.ReadWriter
+}
+
+func (f faker) Close() os.Error {
+ return nil
+}
+
+func TestBasic(t *testing.T) {
+ basicServer = strings.Join(strings.Split(basicServer, "\n", -1), "\r\n")
+ basicClient = strings.Join(strings.Split(basicClient, "\n", -1), "\r\n")
+
+ var cmdbuf bytes.Buffer
+ bcmdbuf := bufio.NewWriter(&cmdbuf)
+ var fake faker
+ fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(basicServer)), bcmdbuf)
+ c := &Client{Text: textproto.NewConn(fake)}
+
+ if err := c.helo(); err != nil {
+ t.Fatalf("HELO failed: %s", err.String())
+ }
+ if err := c.ehlo(); err == nil {
+ t.Fatalf("Expected first EHLO to fail")
+ }
+ if err := c.ehlo(); err != nil {
+ t.Fatalf("Second EHLO failed: %s", err.String())
+ }
+
+ if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" {
+ t.Fatalf("Expected AUTH supported")
+ }
+ if ok, _ := c.Extension("DSN"); ok {
+ t.Fatalf("Shouldn't support DSN")
+ }
+
+ if err := c.Mail("user@gmail.com"); err == nil {
+ t.Fatalf("MAIL should require authentication")
+ }
+
+ if err := c.Verify("user1@gmail.com"); err == nil {
+ t.Fatalf("First VRFY: expected no verification")
+ }
+ if err := c.Verify("user2@gmail.com"); err != nil {
+ t.Fatalf("Second VRFY: expected verification, got %s", err)
+ }
+
+ // fake TLS so authentication won't complain
+ c.tls = true
+ c.serverName = "smtp.google.com"
+ if err := c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")); err != nil {
+ t.Fatalf("AUTH failed: %s", err.String())
+ }
+
+ if err := c.Mail("user@gmail.com"); err != nil {
+ t.Fatalf("MAIL failed: %s", err.String())
+ }
+ if err := c.Rcpt("golang-nuts@googlegroups.com"); err != nil {
+ t.Fatalf("RCPT failed: %s", err.String())
+ }
+ msg := `From: user@gmail.com
+To: golang-nuts@googlegroups.com
+Subject: Hooray for Go
+
+Line 1
+.Leading dot line .
+Goodbye.`
+ w, err := c.Data()
+ if err != nil {
+ t.Fatalf("DATA failed: %s", err.String())
+ }
+ if _, err := w.Write([]byte(msg)); err != nil {
+ t.Fatalf("Data write failed: %s", err.String())
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Bad data response: %s", err.String())
+ }
+
+ if err := c.Quit(); err != nil {
+ t.Fatalf("QUIT failed: %s", err.String())
+ }
+
+ bcmdbuf.Flush()
+ actualcmds := cmdbuf.String()
+ if basicClient != actualcmds {
+ t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, basicClient)
+ }
+}
+
+var basicServer = `250 mx.google.com at your service
+502 Unrecognized command.
+250-mx.google.com at your service
+250-SIZE 35651584
+250-AUTH LOGIN PLAIN
+250 8BITMIME
+530 Authentication required
+252 Send some mail, I'll try my best
+250 User is valid
+235 Accepted
+250 Sender OK
+250 Receiver OK
+354 Go ahead
+250 Data OK
+221 OK
+`
+
+var basicClient = `HELO localhost
+EHLO localhost
+EHLO localhost
+MAIL FROM:<user@gmail.com> BODY=8BITMIME
+VRFY user1@gmail.com
+VRFY user2@gmail.com
+AUTH PLAIN AHVzZXIAcGFzcw==
+MAIL FROM:<user@gmail.com> BODY=8BITMIME
+RCPT TO:<golang-nuts@googlegroups.com>
+DATA
+From: user@gmail.com
+To: golang-nuts@googlegroups.com
+Subject: Hooray for Go
+
+Line 1
+..Leading dot line .
+Goodbye.
+.
+QUIT
+`
diff --git a/libgo/go/sort/search.go b/libgo/go/sort/search.go
new file mode 100644
index 000000000..6828e19b6
--- /dev/null
+++ b/libgo/go/sort/search.go
@@ -0,0 +1,110 @@
+// 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.
+
+// This file implements binary search.
+
+package sort
+
+// Search uses binary search to find and return the smallest index i
+// in [0, n) at which f(i) is true, assuming that on the range [0, n),
+// f(i) == true implies f(i+1) == true. That is, Search requires that
+// f is false for some (possibly empty) prefix of the input range [0, n)
+// and then true for the (possibly empty) remainder; Search returns
+// the first true index. If there is no such index, Search returns n.
+// 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.
+// 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.
+//
+// For instance, given a slice data sorted in ascending order,
+// the call Search(len(data), func(i int) bool { return data[i] >= 23 })
+// returns the smallest index i such that data[i] >= 23. If the caller
+// wants to find whether 23 is in the slice, it must test data[i] == 23
+// separately.
+//
+// Searching data sorted in descending order would use the <=
+// operator instead of the >= operator.
+//
+// To complete the example above, the following code tries to find the value
+// x in an integer slice data sorted in ascending order:
+//
+// x := 23
+// i := sort.Search(len(data), func(i int) bool { return data[i] >= x })
+// if i < len(data) && data[i] == x {
+// // x is present at data[i]
+// } else {
+// // x is not present in data,
+// // but i is the index where it would be inserted.
+// }
+//
+// As a more whimsical example, this program guesses your number:
+//
+// func GuessingGame() {
+// var s string
+// fmt.Printf("Pick an integer from 0 to 100.\n")
+// answer := sort.Search(100, func(i int) bool {
+// fmt.Printf("Is your number <= %d? ", i)
+// fmt.Scanf("%s", &s)
+// return s != "" && s[0] == 'y'
+// })
+// fmt.Printf("Your number is %d.\n", answer)
+// }
+//
+func Search(n int, f func(int) bool) int {
+ // Define f(-1) == false and f(n) == true.
+ // Invariant: f(i-1) == false, f(j) == true.
+ i, j := 0, n
+ for i < j {
+ h := i + (j-i)/2 // avoid overflow when computing h
+ // i ≤ h < j
+ if !f(h) {
+ i = h + 1 // preserves f(i-1) == false
+ } else {
+ j = h // preserves f(j) == true
+ }
+ }
+ // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i.
+ return i
+}
+
+
+// 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.
+//
+func SearchInts(a []int, x int) int {
+ return Search(len(a), func(i int) bool { return a[i] >= x })
+}
+
+
+// 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.
+//
+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.
+//
+func SearchStrings(a []string, x string) int {
+ return Search(len(a), func(i int) bool { return a[i] >= x })
+}
+
+
+// Search returns the result of applying SearchInts to the receiver and x.
+func (p IntArray) 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) }
+
+
+// Search returns the result of applying SearchStrings to the receiver and x.
+func (p StringArray) Search(x string) int { return SearchStrings(p, x) }
diff --git a/libgo/go/sort/search_test.go b/libgo/go/sort/search_test.go
new file mode 100644
index 000000000..939f66af3
--- /dev/null
+++ b/libgo/go/sort/search_test.go
@@ -0,0 +1,137 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sort
+
+import "testing"
+
+
+func f(a []int, x int) func(int) bool {
+ return func(i int) bool {
+ return a[i] >= x
+ }
+}
+
+
+var data = []int{0: -10, 1: -5, 2: 0, 3: 1, 4: 2, 5: 3, 6: 5, 7: 7, 8: 11, 9: 100, 10: 100, 11: 100, 12: 1000, 13: 10000}
+
+var tests = []struct {
+ name string
+ n int
+ f func(int) bool
+ i int
+}{
+ {"empty", 0, nil, 0},
+ {"1 1", 1, func(i int) bool { return i >= 1 }, 1},
+ {"1 true", 1, func(i int) bool { return true }, 0},
+ {"1 false", 1, func(i int) bool { return false }, 1},
+ {"1e9 991", 1e9, func(i int) bool { return i >= 991 }, 991},
+ {"1e9 true", 1e9, func(i int) bool { return true }, 0},
+ {"1e9 false", 1e9, func(i int) bool { return false }, 1e9},
+ {"data -20", len(data), f(data, -20), 0},
+ {"data -10", len(data), f(data, -10), 0},
+ {"data -9", len(data), f(data, -9), 1},
+ {"data -6", len(data), f(data, -6), 1},
+ {"data -5", len(data), f(data, -5), 1},
+ {"data 3", len(data), f(data, 3), 5},
+ {"data 11", len(data), f(data, 11), 8},
+ {"data 99", len(data), f(data, 99), 9},
+ {"data 100", len(data), f(data, 100), 9},
+ {"data 101", len(data), f(data, 101), 12},
+ {"data 10000", len(data), f(data, 10000), 13},
+ {"data 10001", len(data), f(data, 10001), 14},
+ {"descending a", 7, func(i int) bool { return []int{99, 99, 59, 42, 7, 0, -1, -1}[i] <= 7 }, 4},
+ {"descending 7", 1e9, func(i int) bool { return 1e9-i <= 7 }, 1e9 - 7},
+ {"overflow", 2e9, func(i int) bool { return false }, 2e9},
+}
+
+
+func TestSearch(t *testing.T) {
+ for _, e := range tests {
+ i := Search(e.n, e.f)
+ if i != e.i {
+ t.Errorf("%s: expected index %d; got %d", e.name, e.i, i)
+ }
+ }
+}
+
+
+// log2 computes the binary logarithm of x, rounded up to the next integer.
+// (log2(0) == 0, log2(1) == 0, log2(2) == 1, log2(3) == 2, etc.)
+//
+func log2(x int) int {
+ n := 0
+ for p := 1; p < x; p += p {
+ // p == 2**n
+ n++
+ }
+ // p/2 < x <= p == 2**n
+ return n
+}
+
+
+func TestSearchEfficiency(t *testing.T) {
+ n := 100
+ step := 1
+ for exp := 2; exp < 10; exp++ {
+ // n == 10**exp
+ // step == 10**(exp-2)
+ max := log2(n)
+ for x := 0; x < n; x += step {
+ count := 0
+ i := Search(n, func(i int) bool { count++; return i >= x })
+ if i != x {
+ t.Errorf("n = %d: expected index %d; got %d", n, x, i)
+ }
+ if count > max {
+ t.Errorf("n = %d, x = %d: expected <= %d calls; got %d", n, x, max, count)
+ }
+ }
+ n *= 10
+ step *= 10
+ }
+}
+
+
+// Smoke tests for convenience wrappers - not comprehensive.
+
+var fdata = []float64{0: -3.14, 1: 0, 2: 1, 3: 2, 4: 1000.7}
+var sdata = []string{0: "f", 1: "foo", 2: "foobar", 3: "x"}
+
+var wrappertests = []struct {
+ name string
+ result int
+ i int
+}{
+ {"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},
+}
+
+
+func TestSearchWrappers(t *testing.T) {
+ for _, e := range wrappertests {
+ if e.result != e.i {
+ t.Errorf("%s: expected index %d; got %d", e.name, e.i, e.result)
+ }
+ }
+}
+
+
+// Abstract exhaustive test: all sizes up to 100,
+// all possible return values. If there are any small
+// corner cases, this test exercises them.
+func TestSearchExhaustive(t *testing.T) {
+ for size := 0; size <= 100; size++ {
+ for targ := 0; targ <= size; targ++ {
+ i := Search(size, func(i int) bool { return i >= targ })
+ if i != targ {
+ t.Errorf("Search(%d, %d) = %d", size, targ, i)
+ }
+ }
+ }
+}
diff --git a/libgo/go/sort/sort.go b/libgo/go/sort/sort.go
new file mode 100644
index 000000000..c7945d21b
--- /dev/null
+++ b/libgo/go/sort/sort.go
@@ -0,0 +1,206 @@
+// 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.
+
+// The sort package provides primitives for sorting arrays
+// and user-defined collections.
+package sort
+
+// A type, typically a collection, that satisfies sort.Interface can be
+// sorted by the routines in this package. The methods require that the
+// elements of the collection be enumerated by an integer index.
+type Interface interface {
+ // Len is the number of elements in the collection.
+ Len() int
+ // Less returns whether the element with index i should sort
+ // before the element with index j.
+ Less(i, j int) bool
+ // Swap swaps the elements with indexes i and j.
+ Swap(i, j int)
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+// Insertion sort
+func insertionSort(data Interface, a, b int) {
+ for i := a + 1; i < b; i++ {
+ for j := i; j > a && data.Less(j, j-1); j-- {
+ data.Swap(j, j-1)
+ }
+ }
+}
+
+// Quicksort, following Bentley and McIlroy,
+// ``Engineering a Sort Function,'' SP&E November 1993.
+
+// Move the median of the three values data[a], data[b], data[c] into data[a].
+func medianOfThree(data Interface, a, b, c int) {
+ m0 := b
+ m1 := a
+ m2 := c
+ // bubble sort on 3 elements
+ if data.Less(m1, m0) {
+ data.Swap(m1, m0)
+ }
+ if data.Less(m2, m1) {
+ data.Swap(m2, m1)
+ }
+ if data.Less(m1, m0) {
+ data.Swap(m1, m0)
+ }
+ // now data[m0] <= data[m1] <= data[m2]
+}
+
+func swapRange(data Interface, a, b, n int) {
+ for i := 0; i < n; i++ {
+ data.Swap(a+i, b+i)
+ }
+}
+
+func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
+ m := lo + (hi-lo)/2 // Written like this to avoid integer overflow.
+ if hi-lo > 40 {
+ // Tukey's ``Ninther,'' median of three medians of three.
+ s := (hi - lo) / 8
+ medianOfThree(data, lo, lo+s, lo+2*s)
+ medianOfThree(data, m, m-s, m+s)
+ medianOfThree(data, hi-1, hi-1-s, hi-1-2*s)
+ }
+ medianOfThree(data, lo, m, hi-1)
+
+ // Invariants are:
+ // data[lo] = pivot (set up by ChoosePivot)
+ // data[lo <= i < a] = pivot
+ // data[a <= i < b] < pivot
+ // data[b <= i < c] is unexamined
+ // data[c <= i < d] > pivot
+ // data[d <= i < hi] = pivot
+ //
+ // Once b meets c, can swap the "= pivot" sections
+ // into the middle of the array.
+ pivot := lo
+ a, b, c, d := lo+1, lo+1, hi, hi
+ for b < c {
+ if data.Less(b, pivot) { // data[b] < pivot
+ b++
+ continue
+ }
+ if !data.Less(pivot, b) { // data[b] = pivot
+ data.Swap(a, b)
+ a++
+ b++
+ continue
+ }
+ if data.Less(pivot, c-1) { // data[c-1] > pivot
+ c--
+ continue
+ }
+ if !data.Less(c-1, pivot) { // data[c-1] = pivot
+ data.Swap(c-1, d-1)
+ c--
+ d--
+ continue
+ }
+ // data[b] > pivot; data[c-1] < pivot
+ data.Swap(b, c-1)
+ b++
+ c--
+ }
+
+ n := min(b-a, a-lo)
+ swapRange(data, lo, b-n, n)
+
+ n = min(hi-d, d-c)
+ swapRange(data, c, hi-n, n)
+
+ return lo + b - a, hi - (d - c)
+}
+
+func quickSort(data Interface, a, b int) {
+ for b-a > 7 {
+ mlo, mhi := doPivot(data, a, b)
+ // Avoiding recursion on the larger subproblem guarantees
+ // a stack depth of at most lg(b-a).
+ if mlo-a < b-mhi {
+ quickSort(data, a, mlo)
+ a = mhi // i.e., quickSort(data, mhi, b)
+ } else {
+ quickSort(data, mhi, b)
+ b = mlo // i.e., quickSort(data, a, mlo)
+ }
+ }
+ if b-a > 1 {
+ insertionSort(data, a, b)
+ }
+}
+
+func Sort(data Interface) { quickSort(data, 0, data.Len()) }
+
+
+func IsSorted(data Interface) bool {
+ n := data.Len()
+ for i := n - 1; i > 0; i-- {
+ if data.Less(i, i-1) {
+ return false
+ }
+ }
+ return true
+}
+
+
+// Convenience types for common cases
+
+// IntArray attaches the methods of Interface to []int, sorting in increasing order.
+type IntArray []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] }
+
+// Sort is a convenience method.
+func (p IntArray) Sort() { Sort(p) }
+
+
+// Float64Array attaches the methods of Interface to []float64, sorting in increasing order.
+type Float64Array []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] }
+
+// Sort is a convenience method.
+func (p Float64Array) Sort() { Sort(p) }
+
+
+// StringArray attaches the methods of Interface to []string, sorting in increasing order.
+type StringArray []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] }
+
+// Sort is a convenience method.
+func (p StringArray) 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)) }
+
+
+// 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)) }
diff --git a/libgo/go/sort/sort_test.go b/libgo/go/sort/sort_test.go
new file mode 100644
index 000000000..1bea8f032
--- /dev/null
+++ b/libgo/go/sort/sort_test.go
@@ -0,0 +1,267 @@
+// 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 sort
+
+import (
+ "fmt"
+ "rand"
+ "strconv"
+ "testing"
+)
+
+
+var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
+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) {
+ data := ints
+ a := IntArray(data[0:])
+ Sort(a)
+ if !IsSorted(a) {
+ t.Errorf("sorted %v", ints)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestSortFloat64Array(t *testing.T) {
+ data := float64s
+ a := Float64Array(data[0:])
+ Sort(a)
+ if !IsSorted(a) {
+ t.Errorf("sorted %v", float64s)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestSortStringArray(t *testing.T) {
+ data := strings
+ a := StringArray(data[0:])
+ Sort(a)
+ if !IsSorted(a) {
+ t.Errorf("sorted %v", strings)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestSortInts(t *testing.T) {
+ data := ints
+ SortInts(data[0:])
+ if !IntsAreSorted(data[0:]) {
+ t.Errorf("sorted %v", ints)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestSortFloat64s(t *testing.T) {
+ data := float64s
+ SortFloat64s(data[0:])
+ if !Float64sAreSorted(data[0:]) {
+ t.Errorf("sorted %v", float64s)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestSortStrings(t *testing.T) {
+ data := strings
+ SortStrings(data[0:])
+ if !StringsAreSorted(data[0:]) {
+ t.Errorf("sorted %v", strings)
+ t.Errorf(" got %v", data)
+ }
+}
+
+func TestSortLarge_Random(t *testing.T) {
+ data := make([]int, 1000000)
+ for i := 0; i < len(data); i++ {
+ data[i] = rand.Intn(100)
+ }
+ if IntsAreSorted(data) {
+ t.Fatalf("terrible rand.rand")
+ }
+ SortInts(data)
+ if !IntsAreSorted(data) {
+ t.Errorf("sort didn't sort - 1M ints")
+ }
+}
+
+func BenchmarkSortString1K(b *testing.B) {
+ b.StopTimer()
+ for i := 0; i < b.N; i++ {
+ data := make([]string, 1<<10)
+ for i := 0; i < len(data); i++ {
+ data[i] = strconv.Itoa(i ^ 0x2cc)
+ }
+ b.StartTimer()
+ SortStrings(data)
+ b.StopTimer()
+ }
+}
+
+func BenchmarkSortInt1K(b *testing.B) {
+ b.StopTimer()
+ for i := 0; i < b.N; i++ {
+ data := make([]int, 1<<10)
+ for i := 0; i < len(data); i++ {
+ data[i] = i ^ 0x2cc
+ }
+ b.StartTimer()
+ SortInts(data)
+ b.StopTimer()
+ }
+}
+
+func BenchmarkSortInt64K(b *testing.B) {
+ b.StopTimer()
+ for i := 0; i < b.N; i++ {
+ data := make([]int, 1<<16)
+ for i := 0; i < len(data); i++ {
+ data[i] = i ^ 0xcccc
+ }
+ b.StartTimer()
+ SortInts(data)
+ b.StopTimer()
+ }
+}
+
+const (
+ _Sawtooth = iota
+ _Rand
+ _Stagger
+ _Plateau
+ _Shuffle
+ _NDist
+)
+
+const (
+ _Copy = iota
+ _Reverse
+ _ReverseFirstHalf
+ _ReverseSecondHalf
+ _Sorted
+ _Dither
+ _NMode
+)
+
+type testingData struct {
+ desc string
+ t *testing.T
+ data []int
+ maxswap int // number of swaps allowed
+ nswap int
+}
+
+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.FailNow()
+ }
+ d.nswap++
+ d.data[i], d.data[j] = d.data[j], d.data[i]
+}
+
+func lg(n int) int {
+ i := 0
+ for 1<<uint(i) < n {
+ i++
+ }
+ return i
+}
+
+func TestBentleyMcIlroy(t *testing.T) {
+ sizes := []int{100, 1023, 1024, 1025}
+ dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"}
+ modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"}
+ var tmp1, tmp2 [1025]int
+ for ni := 0; ni < len(sizes); ni++ {
+ n := sizes[ni]
+ for m := 1; m < 2*n; m *= 2 {
+ for dist := 0; dist < _NDist; dist++ {
+ j := 0
+ k := 1
+ data := tmp1[0:n]
+ for i := 0; i < n; i++ {
+ switch dist {
+ case _Sawtooth:
+ data[i] = i % m
+ case _Rand:
+ data[i] = rand.Intn(m)
+ case _Stagger:
+ data[i] = (i*m + i) % n
+ case _Plateau:
+ data[i] = min(i, m)
+ case _Shuffle:
+ if rand.Intn(m) != 0 {
+ j += 2
+ data[i] = j
+ } else {
+ k += 2
+ data[i] = k
+ }
+ }
+ }
+
+ mdata := tmp2[0:n]
+ for mode := 0; mode < _NMode; mode++ {
+ switch mode {
+ case _Copy:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[i]
+ }
+ case _Reverse:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[n-i-1]
+ }
+ case _ReverseFirstHalf:
+ for i := 0; i < n/2; i++ {
+ mdata[i] = data[n/2-i-1]
+ }
+ for i := n / 2; i < n; i++ {
+ mdata[i] = data[i]
+ }
+ case _ReverseSecondHalf:
+ for i := 0; i < n/2; i++ {
+ mdata[i] = data[i]
+ }
+ for i := n / 2; i < n; i++ {
+ mdata[i] = data[n-(i-n/2)-1]
+ }
+ case _Sorted:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[i]
+ }
+ // SortInts is known to be correct
+ // because mode Sort runs after mode _Copy.
+ SortInts(mdata)
+ case _Dither:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[i] + i%5
+ }
+ }
+
+ desc := fmt.Sprintf("n=%d m=%d dist=%s mode=%s", n, m, dists[dist], modes[mode])
+ d := &testingData{desc, t, mdata[0:n], n * lg(n) * 12 / 10, 0}
+ 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
+ // 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.
+ if !IntsAreSorted(mdata) {
+ t.Errorf("%s: ints not sorted", desc)
+ t.Errorf("\t%v", mdata)
+ t.FailNow()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/libgo/go/strconv/atob.go b/libgo/go/strconv/atob.go
new file mode 100644
index 000000000..69fa2292a
--- /dev/null
+++ b/libgo/go/strconv/atob.go
@@ -0,0 +1,28 @@
+// 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 strconv
+
+import "os"
+
+// Atob returns the boolean value represented by the string.
+// It accepts 1, t, T, TRUE, true, 0, f, F, FALSE, false. Any other value returns
+// an error.
+func Atob(str string) (value bool, err os.Error) {
+ switch str {
+ case "1", "t", "T", "true", "TRUE", "True":
+ return true, nil
+ case "0", "f", "F", "false", "FALSE", "False":
+ return false, nil
+ }
+ return false, &NumError{str, os.EINVAL}
+}
+
+// Btoa returns "true" or "false" according to the value of the boolean argument
+func Btoa(b bool) string {
+ if b {
+ return "true"
+ }
+ return "false"
+}
diff --git a/libgo/go/strconv/atob_test.go b/libgo/go/strconv/atob_test.go
new file mode 100644
index 000000000..497df5b18
--- /dev/null
+++ b/libgo/go/strconv/atob_test.go
@@ -0,0 +1,56 @@
+// 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 strconv_test
+
+import (
+ "os"
+ . "strconv"
+ "testing"
+)
+
+type atobTest struct {
+ in string
+ out bool
+ err os.Error
+}
+
+var atobtests = []atobTest{
+ {"", false, os.EINVAL},
+ {"asdf", false, os.EINVAL},
+ {"0", false, nil},
+ {"f", false, nil},
+ {"F", false, nil},
+ {"FALSE", false, nil},
+ {"false", false, nil},
+ {"1", true, nil},
+ {"t", true, nil},
+ {"T", true, nil},
+ {"TRUE", true, nil},
+ {"true", true, nil},
+}
+
+func TestAtob(t *testing.T) {
+ for _, test := range atobtests {
+ b, e := Atob(test.in)
+ if test.err != nil {
+ // expect an error
+ if e == nil {
+ t.Errorf("%s: expected %s but got nil", test.in, test.err)
+ } else {
+ // NumError assertion must succeed; it's the only thing we return.
+ if test.err != e.(*NumError).Error {
+ t.Errorf("%s: expected %s but got %s", test.in, test.err, e)
+ }
+ }
+ } else {
+ if e != nil {
+ t.Errorf("%s: expected no error but got %s", test.in, e)
+ }
+ if b != test.out {
+ t.Errorf("%s: expected %t but got %t", test.in, test.out, b)
+ }
+ }
+ }
+}
diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go
new file mode 100644
index 000000000..72f162c51
--- /dev/null
+++ b/libgo/go/strconv/atof.go
@@ -0,0 +1,413 @@
+// 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.
+
+// decimal to binary floating point conversion.
+// Algorithm:
+// 1) Store input in multiprecision decimal.
+// 2) Multiply/divide decimal by powers of two until in range [0.5, 1)
+// 3) Multiply by 2^precision and round to get mantissa.
+
+// The strconv package implements conversions to and from
+// string representations of basic data types.
+package strconv
+
+import (
+ "math"
+ "os"
+)
+
+var optimize = true // can change for testing
+
+func equalIgnoreCase(s1, s2 string) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i := 0; i < len(s1); i++ {
+ c1 := s1[i]
+ if 'A' <= c1 && c1 <= 'Z' {
+ c1 += 'a' - 'A'
+ }
+ c2 := s2[i]
+ if 'A' <= c2 && c2 <= 'Z' {
+ c2 += 'a' - 'A'
+ }
+ if c1 != c2 {
+ return false
+ }
+ }
+ return true
+}
+
+func special(s string) (f float64, ok bool) {
+ switch {
+ case equalIgnoreCase(s, "nan"):
+ return math.NaN(), true
+ case equalIgnoreCase(s, "-inf"):
+ return math.Inf(-1), true
+ case equalIgnoreCase(s, "+inf"):
+ return math.Inf(1), true
+ case equalIgnoreCase(s, "inf"):
+ return math.Inf(1), true
+ }
+ return
+}
+
+// TODO(rsc): Better truncation handling.
+func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) {
+ i := 0
+
+ // optional sign
+ if i >= len(s) {
+ return
+ }
+ switch {
+ case s[i] == '+':
+ i++
+ case s[i] == '-':
+ neg = true
+ i++
+ }
+
+ // digits
+ b := new(decimal)
+ sawdot := false
+ sawdigits := false
+ for ; i < len(s); i++ {
+ switch {
+ case s[i] == '.':
+ if sawdot {
+ return
+ }
+ sawdot = true
+ b.dp = b.nd
+ continue
+
+ case '0' <= s[i] && s[i] <= '9':
+ sawdigits = true
+ if s[i] == '0' && b.nd == 0 { // ignore leading zeros
+ b.dp--
+ continue
+ }
+ b.d[b.nd] = s[i]
+ b.nd++
+ continue
+ }
+ break
+ }
+ if !sawdigits {
+ return
+ }
+ if !sawdot {
+ b.dp = b.nd
+ }
+
+ // optional exponent moves decimal point.
+ // if we read a very large, very long number,
+ // just be sure to move the decimal point by
+ // a lot (say, 100000). it doesn't matter if it's
+ // not the exact number.
+ if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
+ i++
+ if i >= len(s) {
+ return
+ }
+ esign := 1
+ if s[i] == '+' {
+ i++
+ } else if s[i] == '-' {
+ i++
+ esign = -1
+ }
+ if i >= len(s) || s[i] < '0' || s[i] > '9' {
+ return
+ }
+ e := 0
+ for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+ if e < 10000 {
+ e = e*10 + int(s[i]) - '0'
+ }
+ }
+ b.dp += e * esign
+ }
+
+ if i != len(s) {
+ return
+ }
+
+ d = b
+ ok = true
+ return
+}
+
+// decimal power of ten to binary power of two.
+var powtab = []int{1, 3, 6, 9, 13, 16, 19, 23, 26}
+
+func decimalToFloatBits(neg bool, d *decimal, trunc bool, flt *floatInfo) (b uint64, overflow bool) {
+ var exp int
+ var mant uint64
+
+ // Zero is always a special case.
+ if d.nd == 0 {
+ mant = 0
+ exp = flt.bias
+ goto out
+ }
+
+ // Obvious overflow/underflow.
+ // These bounds are for 64-bit floats.
+ // Will have to change if we want to support 80-bit floats in the future.
+ if d.dp > 310 {
+ goto overflow
+ }
+ if d.dp < -330 {
+ // zero
+ mant = 0
+ exp = flt.bias
+ goto out
+ }
+
+ // Scale by powers of two until in range [0.5, 1.0)
+ exp = 0
+ for d.dp > 0 {
+ var n int
+ if d.dp >= len(powtab) {
+ n = 27
+ } else {
+ n = powtab[d.dp]
+ }
+ d.Shift(-n)
+ exp += n
+ }
+ for d.dp < 0 || d.dp == 0 && d.d[0] < '5' {
+ var n int
+ if -d.dp >= len(powtab) {
+ n = 27
+ } else {
+ n = powtab[-d.dp]
+ }
+ d.Shift(n)
+ exp -= n
+ }
+
+ // Our range is [0.5,1) but floating point range is [1,2).
+ exp--
+
+ // Minimum representable exponent is flt.bias+1.
+ // If the exponent is smaller, move it up and
+ // adjust d accordingly.
+ if exp < flt.bias+1 {
+ n := flt.bias + 1 - exp
+ d.Shift(-n)
+ exp += n
+ }
+
+ if exp-flt.bias >= 1<<flt.expbits-1 {
+ goto overflow
+ }
+
+ // Extract 1+flt.mantbits bits.
+ mant = d.Shift(int(1 + flt.mantbits)).RoundedInteger()
+
+ // Rounding might have added a bit; shift down.
+ if mant == 2<<flt.mantbits {
+ mant >>= 1
+ exp++
+ if exp-flt.bias >= 1<<flt.expbits-1 {
+ goto overflow
+ }
+ }
+
+ // Denormalized?
+ if mant&(1<<flt.mantbits) == 0 {
+ exp = flt.bias
+ }
+ goto out
+
+overflow:
+ // ±Inf
+ mant = 0
+ exp = 1<<flt.expbits - 1 + flt.bias
+ overflow = true
+
+out:
+ // Assemble bits.
+ bits := mant & (uint64(1)<<flt.mantbits - 1)
+ bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits
+ if neg {
+ bits |= 1 << flt.mantbits << flt.expbits
+ }
+ return bits, overflow
+}
+
+// Compute exact floating-point integer from d's digits.
+// Caller is responsible for avoiding overflow.
+func decimalAtof64Int(neg bool, d *decimal) float64 {
+ f := 0.0
+ for i := 0; i < d.nd; i++ {
+ f = f*10 + float64(d.d[i]-'0')
+ }
+ if neg {
+ f *= -1 // BUG work around 6g f = -f.
+ }
+ return f
+}
+
+func decimalAtof32Int(neg bool, d *decimal) float32 {
+ f := float32(0)
+ for i := 0; i < d.nd; i++ {
+ f = f*10 + float32(d.d[i]-'0')
+ }
+ if neg {
+ f *= -1 // BUG work around 6g f = -f.
+ }
+ return f
+}
+
+// Exact powers of 10.
+var float64pow10 = []float64{
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22,
+}
+var float32pow10 = []float32{1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10}
+
+// If possible to convert decimal d to 64-bit float f exactly,
+// entirely in floating-point math, do so, avoiding the expense of decimalToFloatBits.
+// Three common cases:
+// value is exact integer
+// value is exact integer * exact power of ten
+// value is exact integer / exact power of ten
+// These all produce potentially inexact but correctly rounded answers.
+func decimalAtof64(neg bool, d *decimal, trunc bool) (f float64, ok bool) {
+ // Exact integers are <= 10^15.
+ // Exact powers of ten are <= 10^22.
+ if d.nd > 15 {
+ return
+ }
+ switch {
+ case d.dp == d.nd: // int
+ f := decimalAtof64Int(neg, d)
+ return f, true
+
+ case d.dp > d.nd && d.dp <= 15+22: // int * 10^k
+ f := decimalAtof64Int(neg, d)
+ k := d.dp - d.nd
+ // If exponent is big but number of digits is not,
+ // can move a few zeros into the integer part.
+ if k > 22 {
+ f *= float64pow10[k-22]
+ k = 22
+ }
+ return f * float64pow10[k], true
+
+ case d.dp < d.nd && d.nd-d.dp <= 22: // int / 10^k
+ f := decimalAtof64Int(neg, d)
+ return f / float64pow10[d.nd-d.dp], true
+ }
+ return
+}
+
+// If possible to convert decimal d to 32-bit float f exactly,
+// entirely in floating-point math, do so, avoiding the machinery above.
+func decimalAtof32(neg bool, d *decimal, trunc bool) (f float32, ok bool) {
+ // Exact integers are <= 10^7.
+ // Exact powers of ten are <= 10^10.
+ if d.nd > 7 {
+ return
+ }
+ switch {
+ case d.dp == d.nd: // int
+ f := decimalAtof32Int(neg, d)
+ return f, true
+
+ case d.dp > d.nd && d.dp <= 7+10: // int * 10^k
+ f := decimalAtof32Int(neg, d)
+ k := d.dp - d.nd
+ // If exponent is big but number of digits is not,
+ // can move a few zeros into the integer part.
+ if k > 10 {
+ f *= float32pow10[k-10]
+ k = 10
+ }
+ return f * float32pow10[k], true
+
+ case d.dp < d.nd && d.nd-d.dp <= 10: // int / 10^k
+ f := decimalAtof32Int(neg, d)
+ return f / float32pow10[d.nd-d.dp], true
+ }
+ return
+}
+
+// Atof32 converts the string s to a 32-bit floating-point number.
+//
+// If s is well-formed and near a valid floating point number,
+// Atof32 returns the nearest floating point number rounded
+// using IEEE754 unbiased rounding.
+//
+// The errors that Atof32 returns have concrete type *NumError
+// and include err.Num = s.
+//
+// If s is not syntactically well-formed, Atof32 returns err.Error = os.EINVAL.
+//
+// If s is syntactically well-formed but is more than 1/2 ULP
+// away from the largest floating point number of the given size,
+// Atof32 returns f = ±Inf, err.Error = os.ERANGE.
+func Atof32(s string) (f float32, err os.Error) {
+ if val, ok := special(s); ok {
+ return float32(val), nil
+ }
+
+ neg, d, trunc, ok := stringToDecimal(s)
+ if !ok {
+ return 0, &NumError{s, os.EINVAL}
+ }
+ if optimize {
+ if f, ok := decimalAtof32(neg, d, trunc); ok {
+ return f, nil
+ }
+ }
+ b, ovf := decimalToFloatBits(neg, d, trunc, &float32info)
+ f = math.Float32frombits(uint32(b))
+ if ovf {
+ err = &NumError{s, os.ERANGE}
+ }
+ return f, err
+}
+
+// Atof64 converts the string s to a 64-bit floating-point number.
+// Except for the type of its result, its definition is the same as that
+// of Atof32.
+func Atof64(s string) (f float64, err os.Error) {
+ if val, ok := special(s); ok {
+ return val, nil
+ }
+
+ neg, d, trunc, ok := stringToDecimal(s)
+ if !ok {
+ return 0, &NumError{s, os.EINVAL}
+ }
+ if optimize {
+ if f, ok := decimalAtof64(neg, d, trunc); ok {
+ return f, nil
+ }
+ }
+ b, ovf := decimalToFloatBits(neg, d, trunc, &float64info)
+ f = math.Float64frombits(b)
+ if ovf {
+ err = &NumError{s, os.ERANGE}
+ }
+ return f, err
+}
+
+// AtofN converts the string s to a 64-bit floating-point number,
+// but it rounds the result assuming that it will be stored in a value
+// of n bits (32 or 64).
+func AtofN(s string, n int) (f float64, err os.Error) {
+ if n == 32 {
+ f1, err1 := Atof32(s)
+ return float64(f1), err1
+ }
+ f1, err1 := Atof64(s)
+ return f1, err1
+}
diff --git a/libgo/go/strconv/atof_test.go b/libgo/go/strconv/atof_test.go
new file mode 100644
index 000000000..6cc60e549
--- /dev/null
+++ b/libgo/go/strconv/atof_test.go
@@ -0,0 +1,183 @@
+// 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 strconv_test
+
+import (
+ "os"
+ "reflect"
+ . "strconv"
+ "testing"
+)
+
+type atofTest struct {
+ in string
+ out string
+ err os.Error
+}
+
+var atoftests = []atofTest{
+ {"", "0", os.EINVAL},
+ {"1", "1", nil},
+ {"+1", "1", nil},
+ {"1x", "0", os.EINVAL},
+ {"1.1.", "0", os.EINVAL},
+ {"1e23", "1e+23", nil},
+ {"1E23", "1e+23", nil},
+ {"100000000000000000000000", "1e+23", nil},
+ {"1e-100", "1e-100", nil},
+ {"123456700", "1.234567e+08", nil},
+ {"99999999999999974834176", "9.999999999999997e+22", nil},
+ {"100000000000000000000001", "1.0000000000000001e+23", nil},
+ {"100000000000000008388608", "1.0000000000000001e+23", nil},
+ {"100000000000000016777215", "1.0000000000000001e+23", nil},
+ {"100000000000000016777216", "1.0000000000000003e+23", nil},
+ {"-1", "-1", nil},
+ {"-0", "-0", nil},
+ {"1e-20", "1e-20", nil},
+ {"625e-3", "0.625", nil},
+
+ // NaNs
+ {"nan", "NaN", nil},
+ {"NaN", "NaN", nil},
+ {"NAN", "NaN", nil},
+
+ // Infs
+ {"inf", "+Inf", nil},
+ {"-Inf", "-Inf", nil},
+ {"+INF", "+Inf", nil},
+
+ // largest float64
+ {"1.7976931348623157e308", "1.7976931348623157e+308", nil},
+ {"-1.7976931348623157e308", "-1.7976931348623157e+308", nil},
+ // next float64 - too large
+ {"1.7976931348623159e308", "+Inf", os.ERANGE},
+ {"-1.7976931348623159e308", "-Inf", os.ERANGE},
+ // the border is ...158079
+ // borderline - okay
+ {"1.7976931348623158e308", "1.7976931348623157e+308", nil},
+ {"-1.7976931348623158e308", "-1.7976931348623157e+308", nil},
+ // borderline - too large
+ {"1.797693134862315808e308", "+Inf", os.ERANGE},
+ {"-1.797693134862315808e308", "-Inf", os.ERANGE},
+
+ // a little too large
+ {"1e308", "1e+308", nil},
+ {"2e308", "+Inf", os.ERANGE},
+ {"1e309", "+Inf", os.ERANGE},
+
+ // way too large
+ {"1e310", "+Inf", os.ERANGE},
+ {"-1e310", "-Inf", os.ERANGE},
+ {"1e400", "+Inf", os.ERANGE},
+ {"-1e400", "-Inf", os.ERANGE},
+ {"1e400000", "+Inf", os.ERANGE},
+ {"-1e400000", "-Inf", os.ERANGE},
+
+ // denormalized
+ {"1e-305", "1e-305", nil},
+ {"1e-306", "1e-306", nil},
+ {"1e-307", "1e-307", nil},
+ {"1e-308", "1e-308", nil},
+ {"1e-309", "1e-309", nil},
+ {"1e-310", "1e-310", nil},
+ {"1e-322", "1e-322", nil},
+ // smallest denormal
+ {"5e-324", "5e-324", nil},
+ {"4e-324", "5e-324", nil},
+ {"3e-324", "5e-324", nil},
+ // too small
+ {"2e-324", "0", nil},
+ // way too small
+ {"1e-350", "0", nil},
+ {"1e-400000", "0", nil},
+
+ // try to overflow exponent
+ {"1e-4294967296", "0", nil},
+ {"1e+4294967296", "+Inf", os.ERANGE},
+ {"1e-18446744073709551616", "0", nil},
+ {"1e+18446744073709551616", "+Inf", os.ERANGE},
+
+ // Parse errors
+ {"1e", "0", os.EINVAL},
+ {"1e-", "0", os.EINVAL},
+ {".e-1", "0", os.EINVAL},
+}
+
+func init() {
+ // The atof routines return NumErrors wrapping
+ // the error and the string. Convert the table above.
+ for i := range atoftests {
+ test := &atoftests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+}
+
+func testAtof(t *testing.T, opt bool) {
+ oldopt := SetOptimize(opt)
+ for i := 0; i < len(atoftests); i++ {
+ test := &atoftests[i]
+ out, err := Atof64(test.in)
+ outs := Ftoa64(out, 'g', -1)
+ if outs != test.out || !reflect.DeepEqual(err, test.err) {
+ t.Errorf("Atof64(%v) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+
+ out, err = AtofN(test.in, 64)
+ outs = FtoaN(out, 'g', -1, 64)
+ if outs != test.out || !reflect.DeepEqual(err, test.err) {
+ t.Errorf("AtofN(%v, 64) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+
+ if float64(float32(out)) == out {
+ out32, err := Atof32(test.in)
+ outs := Ftoa32(out32, 'g', -1)
+ if outs != test.out || !reflect.DeepEqual(err, test.err) {
+ t.Errorf("Atof32(%v) = %v, %v want %v, %v # %v",
+ test.in, out32, err, test.out, test.err, out)
+ }
+
+ out, err := AtofN(test.in, 32)
+ out32 = float32(out)
+ outs = FtoaN(float64(out32), 'g', -1, 32)
+ if outs != test.out || !reflect.DeepEqual(err, test.err) {
+ t.Errorf("AtofN(%v, 32) = %v, %v want %v, %v # %v",
+ test.in, out32, err, test.out, test.err, out)
+ }
+ }
+ }
+ SetOptimize(oldopt)
+}
+
+func TestAtof(t *testing.T) { testAtof(t, true) }
+
+func TestAtofSlow(t *testing.T) { testAtof(t, false) }
+
+func BenchmarkAtof64Decimal(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atof64("33909")
+ }
+}
+
+func BenchmarkAtof64Float(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atof64("339.7784")
+ }
+}
+
+func BenchmarkAtof64FloatExp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atof64("-5.09e75")
+ }
+}
+
+func BenchmarkAtof64Big(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atof64("123456789123456789123456789")
+ }
+}
diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go
new file mode 100644
index 000000000..f7b845672
--- /dev/null
+++ b/libgo/go/strconv/atoi.go
@@ -0,0 +1,202 @@
+// 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 strconv
+
+import "os"
+
+type NumError struct {
+ Num string
+ Error os.Error
+}
+
+func (e *NumError) String() string { return `parsing "` + e.Num + `": ` + e.Error.String() }
+
+
+func computeIntsize() uint {
+ siz := uint(8)
+ for 1<<siz != 0 {
+ siz *= 2
+ }
+ return siz
+}
+
+var IntSize = computeIntsize()
+
+// Return the first number n such that n*base >= 1<<64.
+func cutoff64(base int) uint64 {
+ if base < 2 {
+ return 0
+ }
+ return (1<<64-1)/uint64(base) + 1
+}
+
+// Btoui64 interprets a string s in an arbitrary base b (2 to 36)
+// and returns the corresponding value n. If b == 0, the base
+// is taken from the string prefix: base 16 for "0x", base 8 for "0",
+// and base 10 otherwise.
+//
+// The errors that Btoui64 returns have concrete type *NumError
+// and include err.Num = s. If s is empty or contains invalid
+// 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) {
+ s0 := s
+ switch {
+ case len(s) < 1:
+ err = os.EINVAL
+ goto Error
+
+ case 2 <= b && b <= 36:
+ // valid base; nothing to do
+
+ case b == 0:
+ // Look for octal, hex prefix.
+ switch {
+ case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
+ b = 16
+ s = s[2:]
+ if len(s) < 1 {
+ err = os.EINVAL
+ goto Error
+ }
+ case s[0] == '0':
+ b = 8
+ default:
+ b = 10
+ }
+
+ default:
+ err = os.ErrorString("invalid base " + Itoa(b))
+ goto Error
+ }
+
+ n = 0
+ cutoff := cutoff64(b)
+
+ for i := 0; i < len(s); i++ {
+ var v byte
+ d := s[i]
+ switch {
+ case '0' <= d && d <= '9':
+ v = d - '0'
+ case 'a' <= d && d <= 'z':
+ v = d - 'a' + 10
+ case 'A' <= d && d <= 'Z':
+ v = d - 'A' + 10
+ default:
+ n = 0
+ err = os.EINVAL
+ goto Error
+ }
+ if int(v) >= b {
+ n = 0
+ err = os.EINVAL
+ goto Error
+ }
+
+ if n >= cutoff {
+ // n*b overflows
+ n = 1<<64 - 1
+ err = os.ERANGE
+ goto Error
+ }
+ n *= uint64(b)
+
+ n1 := n + uint64(v)
+ if n1 < n {
+ // n+v overflows
+ n = 1<<64 - 1
+ err = os.ERANGE
+ goto Error
+ }
+ n = n1
+ }
+
+ return n, nil
+
+Error:
+ return n, &NumError{s0, err}
+}
+
+// Atoui64 interprets a string s as a decimal number and
+// returns the corresponding value n.
+//
+// Atoui64 returns err == os.EINVAL if s is empty or contains invalid digits.
+// It returns err == os.ERANGE if s cannot be represented by a uint64.
+func Atoui64(s string) (n uint64, err os.Error) {
+ return Btoui64(s, 10)
+}
+
+// Btoi64 is like Btoui64 but allows signed numbers and
+// returns its result in an int64.
+func Btoi64(s string, base int) (i int64, err os.Error) {
+ // Empty string bad.
+ if len(s) == 0 {
+ return 0, &NumError{s, os.EINVAL}
+ }
+
+ // Pick off leading sign.
+ s0 := s
+ neg := false
+ if s[0] == '+' {
+ s = s[1:]
+ } else if s[0] == '-' {
+ neg = true
+ s = s[1:]
+ }
+
+ // Convert unsigned and check range.
+ var un uint64
+ un, err = Btoui64(s, base)
+ if err != nil && err.(*NumError).Error != os.ERANGE {
+ err.(*NumError).Num = s0
+ return 0, err
+ }
+ if !neg && un >= 1<<63 {
+ return 1<<63 - 1, &NumError{s0, os.ERANGE}
+ }
+ if neg && un > 1<<63 {
+ return -1 << 63, &NumError{s0, os.ERANGE}
+ }
+ n := int64(un)
+ if neg {
+ n = -n
+ }
+ return n, nil
+}
+
+// Atoi64 is like Atoui64 but allows signed numbers and
+// returns its result in an int64.
+func Atoi64(s string) (i int64, err os.Error) { return Btoi64(s, 10) }
+
+
+// Atoui is like Atoui64 but returns its result as a uint.
+func Atoui(s string) (i uint, err os.Error) {
+ i1, e1 := Atoui64(s)
+ if e1 != nil && e1.(*NumError).Error != os.ERANGE {
+ return 0, e1
+ }
+ i = uint(i1)
+ if uint64(i) != i1 {
+ return ^uint(0), &NumError{s, os.ERANGE}
+ }
+ return i, nil
+}
+
+// Atoi is like Atoi64 but returns its result as an int.
+func Atoi(s string) (i int, err os.Error) {
+ i1, e1 := Atoi64(s)
+ if e1 != nil && e1.(*NumError).Error != os.ERANGE {
+ return 0, e1
+ }
+ i = int(i1)
+ if int64(i) != i1 {
+ if i1 < 0 {
+ return -1 << (IntSize - 1), &NumError{s, os.ERANGE}
+ }
+ return 1<<(IntSize-1) - 1, &NumError{s, os.ERANGE}
+ }
+ return i, nil
+}
diff --git a/libgo/go/strconv/atoi_test.go b/libgo/go/strconv/atoi_test.go
new file mode 100644
index 000000000..0b9f29553
--- /dev/null
+++ b/libgo/go/strconv/atoi_test.go
@@ -0,0 +1,303 @@
+// 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 strconv_test
+
+import (
+ "os"
+ "reflect"
+ . "strconv"
+ "testing"
+)
+
+type atoui64Test struct {
+ in string
+ out uint64
+ err os.Error
+}
+
+var atoui64tests = []atoui64Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"1", 1, nil},
+ {"12345", 12345, nil},
+ {"012345", 12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"98765432100", 98765432100, nil},
+ {"18446744073709551615", 1<<64 - 1, nil},
+ {"18446744073709551616", 1<<64 - 1, os.ERANGE},
+ {"18446744073709551620", 1<<64 - 1, os.ERANGE},
+}
+
+var btoui64tests = []atoui64Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"1", 1, nil},
+ {"12345", 12345, nil},
+ {"012345", 012345, nil},
+ {"0x12345", 0x12345, nil},
+ {"0X12345", 0x12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"98765432100", 98765432100, nil},
+ {"18446744073709551615", 1<<64 - 1, nil},
+ {"18446744073709551616", 1<<64 - 1, os.ERANGE},
+ {"18446744073709551620", 1<<64 - 1, os.ERANGE},
+ {"0xFFFFFFFFFFFFFFFF", 1<<64 - 1, nil},
+ {"0x10000000000000000", 1<<64 - 1, os.ERANGE},
+ {"01777777777777777777777", 1<<64 - 1, nil},
+ {"01777777777777777777778", 0, os.EINVAL},
+ {"02000000000000000000000", 1<<64 - 1, os.ERANGE},
+ {"0200000000000000000000", 1 << 61, nil},
+}
+
+type atoi64Test struct {
+ in string
+ out int64
+ err os.Error
+}
+
+var atoi64tests = []atoi64Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"-0", 0, nil},
+ {"1", 1, nil},
+ {"-1", -1, nil},
+ {"12345", 12345, nil},
+ {"-12345", -12345, nil},
+ {"012345", 12345, nil},
+ {"-012345", -12345, nil},
+ {"98765432100", 98765432100, nil},
+ {"-98765432100", -98765432100, nil},
+ {"9223372036854775807", 1<<63 - 1, nil},
+ {"-9223372036854775807", -(1<<63 - 1), nil},
+ {"9223372036854775808", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775808", -1 << 63, nil},
+ {"9223372036854775809", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775809", -1 << 63, os.ERANGE},
+}
+
+var btoi64tests = []atoi64Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"-0", 0, nil},
+ {"1", 1, nil},
+ {"-1", -1, nil},
+ {"12345", 12345, nil},
+ {"-12345", -12345, nil},
+ {"012345", 012345, nil},
+ {"-012345", -012345, nil},
+ {"0x12345", 0x12345, nil},
+ {"-0X12345", -0x12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"-12345x", 0, os.EINVAL},
+ {"98765432100", 98765432100, nil},
+ {"-98765432100", -98765432100, nil},
+ {"9223372036854775807", 1<<63 - 1, nil},
+ {"-9223372036854775807", -(1<<63 - 1), nil},
+ {"9223372036854775808", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775808", -1 << 63, nil},
+ {"9223372036854775809", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775809", -1 << 63, os.ERANGE},
+}
+
+type atoui32Test struct {
+ in string
+ out uint32
+ err os.Error
+}
+
+var atoui32tests = []atoui32Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"1", 1, nil},
+ {"12345", 12345, nil},
+ {"012345", 12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"987654321", 987654321, nil},
+ {"4294967295", 1<<32 - 1, nil},
+ {"4294967296", 1<<32 - 1, os.ERANGE},
+}
+
+type atoi32Test struct {
+ in string
+ out int32
+ err os.Error
+}
+
+var atoi32tests = []atoi32Test{
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"-0", 0, nil},
+ {"1", 1, nil},
+ {"-1", -1, nil},
+ {"12345", 12345, nil},
+ {"-12345", -12345, nil},
+ {"012345", 12345, nil},
+ {"-012345", -12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"-12345x", 0, os.EINVAL},
+ {"987654321", 987654321, nil},
+ {"-987654321", -987654321, nil},
+ {"2147483647", 1<<31 - 1, nil},
+ {"-2147483647", -(1<<31 - 1), nil},
+ {"2147483648", 1<<31 - 1, os.ERANGE},
+ {"-2147483648", -1 << 31, nil},
+ {"2147483649", 1<<31 - 1, os.ERANGE},
+ {"-2147483649", -1 << 31, os.ERANGE},
+}
+
+func init() {
+ // The atoi routines return NumErrors wrapping
+ // the error and the string. Convert the tables above.
+ for i := range atoui64tests {
+ test := &atoui64tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+ for i := range btoui64tests {
+ test := &btoui64tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+ for i := range atoi64tests {
+ test := &atoi64tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+ for i := range btoi64tests {
+ test := &btoi64tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+ for i := range atoui32tests {
+ test := &atoui32tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+ for i := range atoi32tests {
+ test := &atoi32tests[i]
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+}
+
+func TestAtoui64(t *testing.T) {
+ for i := range atoui64tests {
+ test := &atoui64tests[i]
+ out, err := Atoui64(test.in)
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoui64(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+}
+
+func TestBtoui64(t *testing.T) {
+ for i := range btoui64tests {
+ test := &btoui64tests[i]
+ out, err := Btoui64(test.in, 0)
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Btoui64(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+}
+
+func TestAtoi64(t *testing.T) {
+ for i := range atoi64tests {
+ test := &atoi64tests[i]
+ out, err := Atoi64(test.in)
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoi64(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+}
+
+func TestBtoi64(t *testing.T) {
+ for i := range btoi64tests {
+ test := &btoi64tests[i]
+ out, err := Btoi64(test.in, 0)
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Btoi64(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+}
+
+func TestAtoui(t *testing.T) {
+ switch IntSize {
+ case 32:
+ for i := range atoui32tests {
+ test := &atoui32tests[i]
+ out, err := Atoui(test.in)
+ if test.out != uint32(out) || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoui(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+ case 64:
+ for i := range atoui64tests {
+ test := &atoui64tests[i]
+ out, err := Atoui(test.in)
+ if test.out != uint64(out) || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoui(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+ }
+}
+
+func TestAtoi(t *testing.T) {
+ switch IntSize {
+ case 32:
+ for i := range atoi32tests {
+ test := &atoi32tests[i]
+ out, err := Atoi(test.in)
+ if test.out != int32(out) || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoi(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+ case 64:
+ for i := range atoi64tests {
+ test := &atoi64tests[i]
+ out, err := Atoi(test.in)
+ if test.out != int64(out) || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Atoi(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, test.err)
+ }
+ }
+ }
+}
+
+func BenchmarkAtoi(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atoi("12345678")
+ }
+}
+
+func BenchmarkAtoiNeg(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atoi("-12345678")
+ }
+}
+
+func BenchmarkAtoi64(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atoi64("12345678901234")
+ }
+}
+
+func BenchmarkAtoi64Neg(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Atoi64("-12345678901234")
+ }
+}
diff --git a/libgo/go/strconv/decimal.go b/libgo/go/strconv/decimal.go
new file mode 100644
index 000000000..3a5cf1ba6
--- /dev/null
+++ b/libgo/go/strconv/decimal.go
@@ -0,0 +1,371 @@
+// 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.
+
+// Multiprecision decimal numbers.
+// For floating-point formatting only; not general purpose.
+// Only operations are assign and (binary) left/right shift.
+// Can do binary floating point in multiprecision decimal precisely
+// because 2 divides 10; cannot do decimal floating point
+// in multiprecision binary precisely.
+
+package strconv
+
+type decimal struct {
+ // TODO(rsc): Can make d[] a bit smaller and add
+ // truncated bool;
+ d [2000]byte // digits
+ nd int // number of digits used
+ dp int // decimal point
+}
+
+func (a *decimal) String() string {
+ n := 10 + a.nd
+ if a.dp > 0 {
+ n += a.dp
+ }
+ if a.dp < 0 {
+ n += -a.dp
+ }
+
+ buf := make([]byte, n)
+ w := 0
+ switch {
+ case a.nd == 0:
+ return "0"
+
+ case a.dp <= 0:
+ // zeros fill space between decimal point and digits
+ buf[w] = '0'
+ w++
+ buf[w] = '.'
+ w++
+ w += digitZero(buf[w : w+-a.dp])
+ w += copy(buf[w:], a.d[0:a.nd])
+
+ case a.dp < a.nd:
+ // decimal point in middle of digits
+ w += copy(buf[w:], a.d[0:a.dp])
+ buf[w] = '.'
+ w++
+ w += copy(buf[w:], a.d[a.dp:a.nd])
+
+ default:
+ // zeros fill space between digits and decimal point
+ w += copy(buf[w:], a.d[0:a.nd])
+ w += digitZero(buf[w : w+a.dp-a.nd])
+ }
+ return string(buf[0:w])
+}
+
+func digitZero(dst []byte) int {
+ for i := range dst {
+ dst[i] = '0'
+ }
+ return len(dst)
+}
+
+// trim trailing zeros from number.
+// (They are meaningless; the decimal point is tracked
+// independent of the number of digits.)
+func trim(a *decimal) {
+ for a.nd > 0 && a.d[a.nd-1] == '0' {
+ a.nd--
+ }
+ if a.nd == 0 {
+ a.dp = 0
+ }
+}
+
+// Assign v to a.
+func (a *decimal) Assign(v uint64) {
+ var buf [50]byte
+
+ // Write reversed decimal in buf.
+ n := 0
+ for v > 0 {
+ v1 := v / 10
+ v -= 10 * v1
+ buf[n] = byte(v + '0')
+ n++
+ v = v1
+ }
+
+ // Reverse again to produce forward decimal in a.d.
+ a.nd = 0
+ for n--; n >= 0; n-- {
+ a.d[a.nd] = buf[n]
+ a.nd++
+ }
+ a.dp = a.nd
+ trim(a)
+}
+
+func newDecimal(i uint64) *decimal {
+ a := new(decimal)
+ a.Assign(i)
+ return a
+}
+
+// Maximum shift that we can do in one pass without overflow.
+// Signed int has 31 bits, and we have to be able to accomodate 9<<k.
+const maxShift = 27
+
+// Binary shift right (* 2) by k bits. k <= maxShift to avoid overflow.
+func rightShift(a *decimal, k uint) {
+ r := 0 // read pointer
+ w := 0 // write pointer
+
+ // Pick up enough leading digits to cover first shift.
+ n := 0
+ for ; n>>k == 0; r++ {
+ if r >= a.nd {
+ if n == 0 {
+ // a == 0; shouldn't get here, but handle anyway.
+ a.nd = 0
+ return
+ }
+ for n>>k == 0 {
+ n = n * 10
+ r++
+ }
+ break
+ }
+ c := int(a.d[r])
+ n = n*10 + c - '0'
+ }
+ a.dp -= r - 1
+
+ // Pick up a digit, put down a digit.
+ for ; r < a.nd; r++ {
+ c := int(a.d[r])
+ dig := n >> k
+ n -= dig << k
+ a.d[w] = byte(dig + '0')
+ w++
+ n = n*10 + c - '0'
+ }
+
+ // Put down extra digits.
+ for n > 0 {
+ dig := n >> k
+ n -= dig << k
+ a.d[w] = byte(dig + '0')
+ w++
+ n = n * 10
+ }
+
+ a.nd = w
+ trim(a)
+}
+
+// Cheat sheet for left shift: table indexed by shift count giving
+// number of new digits that will be introduced by that shift.
+//
+// For example, leftcheats[4] = {2, "625"}. That means that
+// if we are shifting by 4 (multiplying by 16), it will add 2 digits
+// when the string prefix is "625" through "999", and one fewer digit
+// if the string prefix is "000" through "624".
+//
+// Credit for this trick goes to Ken.
+
+type leftCheat struct {
+ delta int // number of new digits
+ cutoff string // minus one digit if original < a.
+}
+
+var leftcheats = []leftCheat{
+ // Leading digits of 1/2^i = 5^i.
+ // 5^23 is not an exact 64-bit floating point number,
+ // so have to use bc for the math.
+ /*
+ seq 27 | sed 's/^/5^/' | bc |
+ awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," }
+ {
+ log2 = log(2)/log(10)
+ printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n",
+ int(log2*NR+1), $0, 2**NR)
+ }'
+ */
+ {0, ""},
+ {1, "5"}, // * 2
+ {1, "25"}, // * 4
+ {1, "125"}, // * 8
+ {2, "625"}, // * 16
+ {2, "3125"}, // * 32
+ {2, "15625"}, // * 64
+ {3, "78125"}, // * 128
+ {3, "390625"}, // * 256
+ {3, "1953125"}, // * 512
+ {4, "9765625"}, // * 1024
+ {4, "48828125"}, // * 2048
+ {4, "244140625"}, // * 4096
+ {4, "1220703125"}, // * 8192
+ {5, "6103515625"}, // * 16384
+ {5, "30517578125"}, // * 32768
+ {5, "152587890625"}, // * 65536
+ {6, "762939453125"}, // * 131072
+ {6, "3814697265625"}, // * 262144
+ {6, "19073486328125"}, // * 524288
+ {7, "95367431640625"}, // * 1048576
+ {7, "476837158203125"}, // * 2097152
+ {7, "2384185791015625"}, // * 4194304
+ {7, "11920928955078125"}, // * 8388608
+ {8, "59604644775390625"}, // * 16777216
+ {8, "298023223876953125"}, // * 33554432
+ {8, "1490116119384765625"}, // * 67108864
+ {9, "7450580596923828125"}, // * 134217728
+}
+
+// Is the leading prefix of b lexicographically less than s?
+func prefixIsLessThan(b []byte, s string) bool {
+ for i := 0; i < len(s); i++ {
+ if i >= len(b) {
+ return true
+ }
+ if b[i] != s[i] {
+ return b[i] < s[i]
+ }
+ }
+ return false
+}
+
+// Binary shift left (/ 2) by k bits. k <= maxShift to avoid overflow.
+func leftShift(a *decimal, k uint) {
+ delta := leftcheats[k].delta
+ if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
+ delta--
+ }
+
+ r := a.nd // read index
+ w := a.nd + delta // write index
+ n := 0
+
+ // Pick up a digit, put down a digit.
+ for r--; r >= 0; r-- {
+ n += (int(a.d[r]) - '0') << k
+ quo := n / 10
+ rem := n - 10*quo
+ w--
+ a.d[w] = byte(rem + '0')
+ n = quo
+ }
+
+ // Put down extra digits.
+ for n > 0 {
+ quo := n / 10
+ rem := n - 10*quo
+ w--
+ a.d[w] = byte(rem + '0')
+ n = quo
+ }
+
+ a.nd += delta
+ a.dp += delta
+ trim(a)
+}
+
+// Binary shift left (k > 0) or right (k < 0).
+// Returns receiver for convenience.
+func (a *decimal) Shift(k int) *decimal {
+ switch {
+ case a.nd == 0:
+ // nothing to do: a == 0
+ case k > 0:
+ for k > maxShift {
+ leftShift(a, maxShift)
+ k -= maxShift
+ }
+ leftShift(a, uint(k))
+ case k < 0:
+ for k < -maxShift {
+ rightShift(a, maxShift)
+ k += maxShift
+ }
+ rightShift(a, uint(-k))
+ }
+ return a
+}
+
+// If we chop a at nd digits, should we round up?
+func shouldRoundUp(a *decimal, nd int) bool {
+ if nd < 0 || nd >= a.nd {
+ return false
+ }
+ if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even
+ return nd > 0 && (a.d[nd-1]-'0')%2 != 0
+ }
+ // not halfway - digit tells all
+ return a.d[nd] >= '5'
+}
+
+// Round a to nd digits (or fewer).
+// Returns receiver for convenience.
+// If nd is zero, it means we're rounding
+// just to the left of the digits, as in
+// 0.09 -> 0.1.
+func (a *decimal) Round(nd int) *decimal {
+ if nd < 0 || nd >= a.nd {
+ return a
+ }
+ if shouldRoundUp(a, nd) {
+ return a.RoundUp(nd)
+ }
+ return a.RoundDown(nd)
+}
+
+// Round a down to nd digits (or fewer).
+// Returns receiver for convenience.
+func (a *decimal) RoundDown(nd int) *decimal {
+ if nd < 0 || nd >= a.nd {
+ return a
+ }
+ a.nd = nd
+ trim(a)
+ return a
+}
+
+// Round a up to nd digits (or fewer).
+// Returns receiver for convenience.
+func (a *decimal) RoundUp(nd int) *decimal {
+ if nd < 0 || nd >= a.nd {
+ return a
+ }
+
+ // round up
+ for i := nd - 1; i >= 0; i-- {
+ c := a.d[i]
+ if c < '9' { // can stop after this digit
+ a.d[i]++
+ a.nd = i + 1
+ return a
+ }
+ }
+
+ // Number is all 9s.
+ // Change to single 1 with adjusted decimal point.
+ a.d[0] = '1'
+ a.nd = 1
+ a.dp++
+ return a
+}
+
+// Extract integer part, rounded appropriately.
+// No guarantees about overflow.
+func (a *decimal) RoundedInteger() uint64 {
+ if a.dp > 20 {
+ return 0xFFFFFFFFFFFFFFFF
+ }
+ var i int
+ n := uint64(0)
+ for i = 0; i < a.dp && i < a.nd; i++ {
+ n = n*10 + uint64(a.d[i]-'0')
+ }
+ for ; i < a.dp; i++ {
+ n *= 10
+ }
+ if shouldRoundUp(a, a.dp) {
+ n++
+ }
+ return n
+}
diff --git a/libgo/go/strconv/decimal_test.go b/libgo/go/strconv/decimal_test.go
new file mode 100644
index 000000000..9b7903516
--- /dev/null
+++ b/libgo/go/strconv/decimal_test.go
@@ -0,0 +1,117 @@
+// 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 strconv_test
+
+import (
+ . "strconv"
+ "testing"
+)
+
+type shiftTest struct {
+ i uint64
+ shift int
+ out string
+}
+
+var shifttests = []shiftTest{
+ {0, -100, "0"},
+ {0, 100, "0"},
+ {1, 100, "1267650600228229401496703205376"},
+ {1, -100,
+ "0.00000000000000000000000000000078886090522101180541" +
+ "17285652827862296732064351090230047702789306640625",
+ },
+ {12345678, 8, "3160493568"},
+ {12345678, -8, "48225.3046875"},
+ {195312, 9, "99999744"},
+ {1953125, 9, "1000000000"},
+}
+
+func TestDecimalShift(t *testing.T) {
+ for i := 0; i < len(shifttests); i++ {
+ test := &shifttests[i]
+ s := NewDecimal(test.i).Shift(test.shift).String()
+ if s != test.out {
+ t.Errorf("Decimal %v << %v = %v, want %v",
+ test.i, test.shift, s, test.out)
+ }
+ }
+}
+
+type roundTest struct {
+ i uint64
+ nd int
+ down, round, up string
+ int uint64
+}
+
+var roundtests = []roundTest{
+ {0, 4, "0", "0", "0", 0},
+ {12344999, 4, "12340000", "12340000", "12350000", 12340000},
+ {12345000, 4, "12340000", "12340000", "12350000", 12340000},
+ {12345001, 4, "12340000", "12350000", "12350000", 12350000},
+ {23454999, 4, "23450000", "23450000", "23460000", 23450000},
+ {23455000, 4, "23450000", "23460000", "23460000", 23460000},
+ {23455001, 4, "23450000", "23460000", "23460000", 23460000},
+
+ {99994999, 4, "99990000", "99990000", "100000000", 99990000},
+ {99995000, 4, "99990000", "100000000", "100000000", 100000000},
+ {99999999, 4, "99990000", "100000000", "100000000", 100000000},
+
+ {12994999, 4, "12990000", "12990000", "13000000", 12990000},
+ {12995000, 4, "12990000", "13000000", "13000000", 13000000},
+ {12999999, 4, "12990000", "13000000", "13000000", 13000000},
+}
+
+func TestDecimalRound(t *testing.T) {
+ for i := 0; i < len(roundtests); i++ {
+ test := &roundtests[i]
+ s := NewDecimal(test.i).RoundDown(test.nd).String()
+ if s != test.down {
+ t.Errorf("Decimal %v RoundDown %d = %v, want %v",
+ test.i, test.nd, s, test.down)
+ }
+ s = NewDecimal(test.i).Round(test.nd).String()
+ if s != test.round {
+ t.Errorf("Decimal %v Round %d = %v, want %v",
+ test.i, test.nd, s, test.down)
+ }
+ s = NewDecimal(test.i).RoundUp(test.nd).String()
+ if s != test.up {
+ t.Errorf("Decimal %v RoundUp %d = %v, want %v",
+ test.i, test.nd, s, test.up)
+ }
+ }
+}
+
+type roundIntTest struct {
+ i uint64
+ shift int
+ int uint64
+}
+
+var roundinttests = []roundIntTest{
+ {0, 100, 0},
+ {512, -8, 2},
+ {513, -8, 2},
+ {640, -8, 2},
+ {641, -8, 3},
+ {384, -8, 2},
+ {385, -8, 2},
+ {383, -8, 1},
+ {1, 100, 1<<64 - 1},
+ {1000, 0, 1000},
+}
+
+func TestDecimalRoundedInteger(t *testing.T) {
+ for i := 0; i < len(roundinttests); i++ {
+ test := roundinttests[i]
+ int := NewDecimal(test.i).Shift(test.shift).RoundedInteger()
+ if int != test.int {
+ t.Errorf("Decimal %v >> %v RoundedInteger = %v, want %v",
+ test.i, test.shift, int, test.int)
+ }
+ }
+}
diff --git a/libgo/go/strconv/fp_test.go b/libgo/go/strconv/fp_test.go
new file mode 100644
index 000000000..305adcc0c
--- /dev/null
+++ b/libgo/go/strconv/fp_test.go
@@ -0,0 +1,149 @@
+// 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 strconv_test
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+func pow2(i int) float64 {
+ switch {
+ case i < 0:
+ return 1 / pow2(-i)
+ case i == 0:
+ return 1
+ case i == 1:
+ return 2
+ }
+ return pow2(i/2) * pow2(i-i/2)
+}
+
+// Wrapper around strconv.Atof64. Handles dddddp+ddd (binary exponent)
+// itself, passes the rest on to strconv.Atof64.
+func myatof64(s string) (f float64, ok bool) {
+ a := strings.Split(s, "p", 2)
+ if len(a) == 2 {
+ n, err := strconv.Atoi64(a[0])
+ if err != nil {
+ return 0, false
+ }
+ e, err1 := strconv.Atoi(a[1])
+ if err1 != nil {
+ println("bad e", a[1])
+ return 0, false
+ }
+ v := float64(n)
+ // We expect that v*pow2(e) fits in a float64,
+ // but pow2(e) by itself may not. Be careful.
+ if e <= -1000 {
+ v *= pow2(-1000)
+ e += 1000
+ for e < 0 {
+ v /= 2
+ e++
+ }
+ return v, true
+ }
+ if e >= 1000 {
+ v *= pow2(1000)
+ e -= 1000
+ for e > 0 {
+ v *= 2
+ e--
+ }
+ return v, true
+ }
+ return v * pow2(e), true
+ }
+ f1, err := strconv.Atof64(s)
+ if err != nil {
+ return 0, false
+ }
+ return f1, true
+}
+
+// Wrapper around strconv.Atof32. Handles dddddp+ddd (binary exponent)
+// itself, passes the rest on to strconv.Atof32.
+func myatof32(s string) (f float32, ok bool) {
+ a := strings.Split(s, "p", 2)
+ if len(a) == 2 {
+ n, err := strconv.Atoi(a[0])
+ if err != nil {
+ println("bad n", a[0])
+ return 0, false
+ }
+ e, err1 := strconv.Atoi(a[1])
+ if err1 != nil {
+ println("bad p", a[1])
+ return 0, false
+ }
+ return float32(float64(n) * pow2(e)), true
+ }
+ f1, err1 := strconv.Atof32(s)
+ if err1 != nil {
+ return 0, false
+ }
+ return f1, true
+}
+
+func TestFp(t *testing.T) {
+ f, err := os.Open("testfp.txt", os.O_RDONLY, 0)
+ if err != nil {
+ t.Fatal("testfp: open testfp.txt:", err.String())
+ }
+ defer f.Close()
+
+ b := bufio.NewReader(f)
+
+ lineno := 0
+ for {
+ line, err2 := b.ReadString('\n')
+ if err2 == os.EOF {
+ break
+ }
+ if err2 != nil {
+ t.Fatal("testfp: read testfp.txt: " + err2.String())
+ }
+ line = line[0 : len(line)-1]
+ lineno++
+ if len(line) == 0 || line[0] == '#' {
+ continue
+ }
+ a := strings.Split(line, " ", -1)
+ if len(a) != 4 {
+ t.Error("testfp.txt:", lineno, ": wrong field count")
+ continue
+ }
+ var s string
+ var v float64
+ switch a[0] {
+ case "float64":
+ var ok bool
+ v, ok = myatof64(a[2])
+ if !ok {
+ t.Error("testfp.txt:", lineno, ": cannot atof64 ", a[2])
+ continue
+ }
+ s = fmt.Sprintf(a[1], v)
+ case "float32":
+ v1, ok := myatof32(a[2])
+ if !ok {
+ t.Error("testfp.txt:", lineno, ": cannot atof32 ", a[2])
+ continue
+ }
+ s = fmt.Sprintf(a[1], v1)
+ v = float64(v1)
+ }
+ if s != a[3] {
+ t.Error("testfp.txt:", lineno, ": ", a[0], " ", a[1], " ", a[2], " (", v, ") ",
+ "want ", a[3], " got ", s)
+ }
+ }
+}
diff --git a/libgo/go/strconv/ftoa.go b/libgo/go/strconv/ftoa.go
new file mode 100644
index 000000000..4ec3cdbb9
--- /dev/null
+++ b/libgo/go/strconv/ftoa.go
@@ -0,0 +1,405 @@
+// 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.
+
+// Binary to decimal floating point conversion.
+// Algorithm:
+// 1) store mantissa in multiprecision decimal
+// 2) shift decimal by exponent
+// 3) read digits out & format
+
+package strconv
+
+import "math"
+
+// TODO: move elsewhere?
+type floatInfo struct {
+ mantbits uint
+ expbits uint
+ bias int
+}
+
+var float32info = floatInfo{23, 8, -127}
+var float64info = floatInfo{52, 11, -1023}
+
+// Ftoa32 converts the 32-bit floating-point number f to a string,
+// according to the format fmt and precision prec.
+//
+// The format fmt is one of
+// 'b' (-ddddp±ddd, a binary exponent),
+// 'e' (-d.dddde±dd, a decimal exponent),
+// 'E' (-d.ddddE±dd, a decimal exponent),
+// 'f' (-ddd.dddd, no exponent),
+// 'g' ('e' for large exponents, 'f' otherwise), or
+// 'G' ('E' for large exponents, 'f' otherwise).
+//
+// The precision prec controls the number of digits
+// (excluding the exponent) printed by the 'e', 'E', 'f', 'g', and 'G' formats.
+// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
+// For 'g' and 'G' it is the total number of digits.
+// The special precision -1 uses the smallest number of digits
+// necessary such that Atof32 will return f exactly.
+//
+// Ftoa32(f) is not the same as Ftoa64(float32(f)),
+// because correct rounding and the number of digits
+// needed to identify f depend on the precision of the representation.
+func Ftoa32(f float32, fmt byte, prec int) string {
+ return genericFtoa(uint64(math.Float32bits(f)), fmt, prec, &float32info)
+}
+
+// Ftoa64 is like Ftoa32 but converts a 64-bit floating-point number.
+func Ftoa64(f float64, fmt byte, prec int) string {
+ return genericFtoa(math.Float64bits(f), fmt, prec, &float64info)
+}
+
+// FtoaN converts the 64-bit floating-point number f to a string,
+// according to the format fmt and precision prec, but it rounds the
+// result assuming that it was obtained from a floating-point value
+// of n bits (32 or 64).
+func FtoaN(f float64, fmt byte, prec int, n int) string {
+ if n == 32 {
+ return Ftoa32(float32(f), fmt, prec)
+ }
+ return Ftoa64(f, fmt, prec)
+}
+
+func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
+ neg := bits>>flt.expbits>>flt.mantbits != 0
+ exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
+ mant := bits & (uint64(1)<<flt.mantbits - 1)
+
+ switch exp {
+ case 1<<flt.expbits - 1:
+ // Inf, NaN
+ if mant != 0 {
+ return "NaN"
+ }
+ if neg {
+ return "-Inf"
+ }
+ return "+Inf"
+
+ case 0:
+ // denormalized
+ exp++
+
+ default:
+ // add implicit top bit
+ mant |= uint64(1) << flt.mantbits
+ }
+ exp += flt.bias
+
+ // Pick off easy binary format.
+ if fmt == 'b' {
+ return fmtB(neg, mant, exp, flt)
+ }
+
+ // Create exact decimal representation.
+ // The shift is exp - flt.mantbits because mant is a 1-bit integer
+ // followed by a flt.mantbits fraction, and we are treating it as
+ // a 1+flt.mantbits-bit integer.
+ d := newDecimal(mant).Shift(exp - int(flt.mantbits))
+
+ // Round appropriately.
+ // Negative precision means "only as much as needed to be exact."
+ shortest := false
+ if prec < 0 {
+ shortest = true
+ roundShortest(d, mant, exp, flt)
+ switch fmt {
+ case 'e', 'E':
+ prec = d.nd - 1
+ case 'f':
+ prec = max(d.nd-d.dp, 0)
+ case 'g', 'G':
+ prec = d.nd
+ }
+ } else {
+ switch fmt {
+ case 'e', 'E':
+ d.Round(prec + 1)
+ case 'f':
+ d.Round(d.dp + prec)
+ case 'g', 'G':
+ if prec == 0 {
+ prec = 1
+ }
+ d.Round(prec)
+ }
+ }
+
+ switch fmt {
+ case 'e', 'E':
+ return fmtE(neg, d, prec, fmt)
+ case 'f':
+ return fmtF(neg, d, prec)
+ case 'g', 'G':
+ // trailing fractional zeros in 'e' form will be trimmed.
+ eprec := prec
+ if eprec > d.nd && d.nd >= d.dp {
+ eprec = d.nd
+ }
+ // %e is used if the exponent from the conversion
+ // is less than -4 or greater than or equal to the precision.
+ // if precision was the shortest possible, use precision 6 for this decision.
+ if shortest {
+ eprec = 6
+ }
+ exp := d.dp - 1
+ if exp < -4 || exp >= eprec {
+ if prec > d.nd {
+ prec = d.nd
+ }
+ return fmtE(neg, d, prec-1, fmt+'e'-'g')
+ }
+ if prec > d.dp {
+ prec = d.nd
+ }
+ return fmtF(neg, d, max(prec-d.dp, 0))
+ }
+
+ return "%" + string(fmt)
+}
+
+// Round d (= mant * 2^exp) to the shortest number of digits
+// that will let the original floating point value be precisely
+// reconstructed. Size is original floating point size (64 or 32).
+func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
+ // If mantissa is zero, the number is zero; stop now.
+ if mant == 0 {
+ d.nd = 0
+ return
+ }
+
+ // TODO(rsc): Unless exp == minexp, if the number of digits in d
+ // is less than 17, it seems likely that it would be
+ // the shortest possible number already. So maybe we can
+ // bail out without doing the extra multiprecision math here.
+
+ // Compute upper and lower such that any decimal number
+ // between upper and lower (possibly inclusive)
+ // will round to the original floating point number.
+
+ // d = mant << (exp - mantbits)
+ // Next highest floating point number is mant+1 << exp-mantbits.
+ // Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
+ upper := newDecimal(mant*2 + 1).Shift(exp - int(flt.mantbits) - 1)
+
+ // d = mant << (exp - mantbits)
+ // Next lowest floating point number is mant-1 << exp-mantbits,
+ // unless mant-1 drops the significant bit and exp is not the minimum exp,
+ // in which case the next lowest is mant*2-1 << exp-mantbits-1.
+ // Either way, call it mantlo << explo-mantbits.
+ // Our lower bound is halfway inbetween, mantlo*2+1 << explo-mantbits-1.
+ minexp := flt.bias + 1 // minimum possible exponent
+ var mantlo uint64
+ var explo int
+ if mant > 1<<flt.mantbits || exp == minexp {
+ mantlo = mant - 1
+ explo = exp
+ } else {
+ mantlo = mant*2 - 1
+ explo = exp - 1
+ }
+ lower := newDecimal(mantlo*2 + 1).Shift(explo - int(flt.mantbits) - 1)
+
+ // The upper and lower bounds are possible outputs only if
+ // the original mantissa is even, so that IEEE round-to-even
+ // would round to the original mantissa and not the neighbors.
+ inclusive := mant%2 == 0
+
+ // Now we can figure out the minimum number of digits required.
+ // Walk along until d has distinguished itself from upper and lower.
+ for i := 0; i < d.nd; i++ {
+ var l, m, u byte // lower, middle, upper digits
+ if i < lower.nd {
+ l = lower.d[i]
+ } else {
+ l = '0'
+ }
+ m = d.d[i]
+ if i < upper.nd {
+ u = upper.d[i]
+ } else {
+ u = '0'
+ }
+
+ // Okay to round down (truncate) if lower has a different digit
+ // or if lower is inclusive and is exactly the result of rounding down.
+ okdown := l != m || (inclusive && l == m && i+1 == lower.nd)
+
+ // Okay to round up if upper has a different digit and
+ // either upper is inclusive or upper is bigger than the result of rounding up.
+ okup := m != u && (inclusive || i+1 < upper.nd)
+
+ // If it's okay to do either, then round to the nearest one.
+ // If it's okay to do only one, do it.
+ switch {
+ case okdown && okup:
+ d.Round(i + 1)
+ return
+ case okdown:
+ d.RoundDown(i + 1)
+ return
+ case okup:
+ d.RoundUp(i + 1)
+ return
+ }
+ }
+}
+
+// %e: -d.ddddde±dd
+func fmtE(neg bool, d *decimal, prec int, fmt byte) string {
+ buf := make([]byte, 3+max(prec, 0)+30) // "-0." + prec digits + exp
+ w := 0 // write index
+
+ // sign
+ if neg {
+ buf[w] = '-'
+ w++
+ }
+
+ // first digit
+ if d.nd == 0 {
+ buf[w] = '0'
+ } else {
+ buf[w] = d.d[0]
+ }
+ w++
+
+ // .moredigits
+ if prec > 0 {
+ buf[w] = '.'
+ w++
+ for i := 0; i < prec; i++ {
+ if 1+i < d.nd {
+ buf[w] = d.d[1+i]
+ } else {
+ buf[w] = '0'
+ }
+ w++
+ }
+ }
+
+ // e±
+ buf[w] = fmt
+ w++
+ exp := d.dp - 1
+ if d.nd == 0 { // special case: 0 has exponent 0
+ exp = 0
+ }
+ if exp < 0 {
+ buf[w] = '-'
+ exp = -exp
+ } else {
+ buf[w] = '+'
+ }
+ w++
+
+ // dddd
+ // count digits
+ n := 0
+ for e := exp; e > 0; e /= 10 {
+ n++
+ }
+ // leading zeros
+ for i := n; i < 2; i++ {
+ buf[w] = '0'
+ w++
+ }
+ // digits
+ w += n
+ n = 0
+ for e := exp; e > 0; e /= 10 {
+ n++
+ buf[w-n] = byte(e%10 + '0')
+ }
+
+ return string(buf[0:w])
+}
+
+// %f: -ddddddd.ddddd
+func fmtF(neg bool, d *decimal, prec int) string {
+ buf := make([]byte, 1+max(d.dp, 1)+1+max(prec, 0))
+ w := 0
+
+ // sign
+ if neg {
+ buf[w] = '-'
+ w++
+ }
+
+ // integer, padded with zeros as needed.
+ if d.dp > 0 {
+ var i int
+ for i = 0; i < d.dp && i < d.nd; i++ {
+ buf[w] = d.d[i]
+ w++
+ }
+ for ; i < d.dp; i++ {
+ buf[w] = '0'
+ w++
+ }
+ } else {
+ buf[w] = '0'
+ w++
+ }
+
+ // fraction
+ if prec > 0 {
+ buf[w] = '.'
+ w++
+ for i := 0; i < prec; i++ {
+ if d.dp+i < 0 || d.dp+i >= d.nd {
+ buf[w] = '0'
+ } else {
+ buf[w] = d.d[d.dp+i]
+ }
+ w++
+ }
+ }
+
+ return string(buf[0:w])
+}
+
+// %b: -ddddddddp+ddd
+func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string {
+ var buf [50]byte
+ w := len(buf)
+ exp -= int(flt.mantbits)
+ esign := byte('+')
+ if exp < 0 {
+ esign = '-'
+ exp = -exp
+ }
+ n := 0
+ for exp > 0 || n < 1 {
+ n++
+ w--
+ buf[w] = byte(exp%10 + '0')
+ exp /= 10
+ }
+ w--
+ buf[w] = esign
+ w--
+ buf[w] = 'p'
+ n = 0
+ for mant > 0 || n < 1 {
+ n++
+ w--
+ buf[w] = byte(mant%10 + '0')
+ mant /= 10
+ }
+ if neg {
+ w--
+ buf[w] = '-'
+ }
+ return string(buf[w:])
+}
+
+func max(a, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+}
diff --git a/libgo/go/strconv/ftoa_test.go b/libgo/go/strconv/ftoa_test.go
new file mode 100644
index 000000000..3a862a2be
--- /dev/null
+++ b/libgo/go/strconv/ftoa_test.go
@@ -0,0 +1,145 @@
+// 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 strconv_test
+
+import (
+ "math"
+ . "strconv"
+ "testing"
+)
+
+type ftoaTest struct {
+ f float64
+ fmt byte
+ prec int
+ s string
+}
+
+func fdiv(a, b float64) float64 { return a / b } // keep compiler in the dark
+
+const (
+ below1e23 = 99999999999999974834176
+ above1e23 = 100000000000000008388608
+)
+
+var ftoatests = []ftoaTest{
+ {1, 'e', 5, "1.00000e+00"},
+ {1, 'f', 5, "1.00000"},
+ {1, 'g', 5, "1"},
+ {1, 'g', -1, "1"},
+ {20, 'g', -1, "20"},
+ {1234567.8, 'g', -1, "1.2345678e+06"},
+ {200000, 'g', -1, "200000"},
+ {2000000, 'g', -1, "2e+06"},
+
+ // g conversion and zero suppression
+ {400, 'g', 2, "4e+02"},
+ {40, 'g', 2, "40"},
+ {4, 'g', 2, "4"},
+ {.4, 'g', 2, "0.4"},
+ {.04, 'g', 2, "0.04"},
+ {.004, 'g', 2, "0.004"},
+ {.0004, 'g', 2, "0.0004"},
+ {.00004, 'g', 2, "4e-05"},
+ {.000004, 'g', 2, "4e-06"},
+
+ {0, 'e', 5, "0.00000e+00"},
+ {0, 'f', 5, "0.00000"},
+ {0, 'g', 5, "0"},
+ {0, 'g', -1, "0"},
+
+ {-1, 'e', 5, "-1.00000e+00"},
+ {-1, 'f', 5, "-1.00000"},
+ {-1, 'g', 5, "-1"},
+ {-1, 'g', -1, "-1"},
+
+ {12, 'e', 5, "1.20000e+01"},
+ {12, 'f', 5, "12.00000"},
+ {12, 'g', 5, "12"},
+ {12, 'g', -1, "12"},
+
+ {123456700, 'e', 5, "1.23457e+08"},
+ {123456700, 'f', 5, "123456700.00000"},
+ {123456700, 'g', 5, "1.2346e+08"},
+ {123456700, 'g', -1, "1.234567e+08"},
+
+ {1.2345e6, 'e', 5, "1.23450e+06"},
+ {1.2345e6, 'f', 5, "1234500.00000"},
+ {1.2345e6, 'g', 5, "1.2345e+06"},
+
+ {1e23, 'e', 17, "9.99999999999999916e+22"},
+ {1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
+ {1e23, 'g', 17, "9.9999999999999992e+22"},
+
+ {1e23, 'e', -1, "1e+23"},
+ {1e23, 'f', -1, "100000000000000000000000"},
+ {1e23, 'g', -1, "1e+23"},
+
+ {below1e23, 'e', 17, "9.99999999999999748e+22"},
+ {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
+ {below1e23, 'g', 17, "9.9999999999999975e+22"},
+
+ {below1e23, 'e', -1, "9.999999999999997e+22"},
+ {below1e23, 'f', -1, "99999999999999970000000"},
+ {below1e23, 'g', -1, "9.999999999999997e+22"},
+
+ {above1e23, 'e', 17, "1.00000000000000008e+23"},
+ {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
+ {above1e23, 'g', 17, "1.0000000000000001e+23"},
+
+ {above1e23, 'e', -1, "1.0000000000000001e+23"},
+ {above1e23, 'f', -1, "100000000000000010000000"},
+ {above1e23, 'g', -1, "1.0000000000000001e+23"},
+
+ {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
+ {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
+
+ {32, 'g', -1, "32"},
+ {32, 'g', 0, "3e+01"},
+
+ {100, 'x', -1, "%x"},
+
+ {math.NaN(), 'g', -1, "NaN"},
+ {-math.NaN(), 'g', -1, "NaN"},
+ {math.Inf(0), 'g', -1, "+Inf"},
+ {math.Inf(-1), 'g', -1, "-Inf"},
+ {-math.Inf(0), 'g', -1, "-Inf"},
+
+ {-1, 'b', -1, "-4503599627370496p-52"},
+
+ // fixed bugs
+ {0.9, 'f', 1, "0.9"},
+ {0.09, 'f', 1, "0.1"},
+ {0.0999, 'f', 1, "0.1"},
+ {0.05, 'f', 1, "0.1"},
+ {0.05, 'f', 0, "0"},
+ {0.5, 'f', 1, "0.5"},
+ {0.5, 'f', 0, "0"},
+ {1.5, 'f', 0, "2"},
+}
+
+func TestFtoa(t *testing.T) {
+ for i := 0; i < len(ftoatests); i++ {
+ test := &ftoatests[i]
+ s := Ftoa64(test.f, test.fmt, test.prec)
+ if s != test.s {
+ t.Error("test", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+ }
+ s = FtoaN(test.f, test.fmt, test.prec, 64)
+ if s != test.s {
+ t.Error("testN=64", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+ }
+ if float64(float32(test.f)) == test.f && test.fmt != 'b' {
+ s := Ftoa32(float32(test.f), test.fmt, test.prec)
+ if s != test.s {
+ t.Error("test32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+ }
+ s = FtoaN(test.f, test.fmt, test.prec, 32)
+ if s != test.s {
+ t.Error("testN=32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
+ }
+ }
+ }
+}
diff --git a/libgo/go/strconv/internal_test.go b/libgo/go/strconv/internal_test.go
new file mode 100644
index 000000000..9a7f4f086
--- /dev/null
+++ b/libgo/go/strconv/internal_test.go
@@ -0,0 +1,15 @@
+// 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.
+
+// export access to strconv internals for tests
+
+package strconv
+
+func NewDecimal(i uint64) *decimal { return newDecimal(i) }
+
+func SetOptimize(b bool) bool {
+ old := optimize
+ optimize = b
+ return old
+}
diff --git a/libgo/go/strconv/itoa.go b/libgo/go/strconv/itoa.go
new file mode 100644
index 000000000..a0a749664
--- /dev/null
+++ b/libgo/go/strconv/itoa.go
@@ -0,0 +1,57 @@
+// 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 strconv
+
+// Uitob64 returns the string representation of i in the given base.
+func Uitob64(u uint64, base uint) string {
+ if base < 2 || 36 < base {
+ panic("invalid base " + Uitoa(base))
+ }
+ if u == 0 {
+ return "0"
+ }
+
+ // Assemble decimal in reverse order.
+ var buf [64]byte
+ j := len(buf)
+ b := uint64(base)
+ for u > 0 {
+ j--
+ buf[j] = "0123456789abcdefghijklmnopqrstuvwxyz"[u%b]
+ u /= b
+ }
+
+ return string(buf[j:])
+}
+
+// Itob64 returns the string representation of i in the given base.
+func Itob64(i int64, base uint) string {
+ if i == 0 {
+ return "0"
+ }
+
+ if i < 0 {
+ return "-" + Uitob64(-uint64(i), base)
+ }
+ return Uitob64(uint64(i), base)
+}
+
+// Itoa64 returns the decimal string representation of i.
+func Itoa64(i int64) string { return Itob64(i, 10) }
+
+// Uitoa64 returns the decimal string representation of i.
+func Uitoa64(i uint64) string { return Uitob64(i, 10) }
+
+// Uitob returns the string representation of i in the given base.
+func Uitob(i uint, base uint) string { return Uitob64(uint64(i), base) }
+
+// Itob returns the string representation of i in the given base.
+func Itob(i int, base uint) string { return Itob64(int64(i), base) }
+
+// Itoa returns the decimal string representation of i.
+func Itoa(i int) string { return Itob64(int64(i), 10) }
+
+// Uitoa returns the decimal string representation of i.
+func Uitoa(i uint) string { return Uitob64(uint64(i), 10) }
diff --git a/libgo/go/strconv/itoa_test.go b/libgo/go/strconv/itoa_test.go
new file mode 100644
index 000000000..8514b21e4
--- /dev/null
+++ b/libgo/go/strconv/itoa_test.go
@@ -0,0 +1,174 @@
+// 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 strconv_test
+
+import (
+ . "strconv"
+ "testing"
+)
+
+type itob64Test struct {
+ in int64
+ base uint
+ out string
+}
+
+var itob64tests = []itob64Test{
+ {0, 10, "0"},
+ {1, 10, "1"},
+ {-1, 10, "-1"},
+ {12345678, 10, "12345678"},
+ {-987654321, 10, "-987654321"},
+ {1<<31 - 1, 10, "2147483647"},
+ {-1<<31 + 1, 10, "-2147483647"},
+ {1 << 31, 10, "2147483648"},
+ {-1 << 31, 10, "-2147483648"},
+ {1<<31 + 1, 10, "2147483649"},
+ {-1<<31 - 1, 10, "-2147483649"},
+ {1<<32 - 1, 10, "4294967295"},
+ {-1<<32 + 1, 10, "-4294967295"},
+ {1 << 32, 10, "4294967296"},
+ {-1 << 32, 10, "-4294967296"},
+ {1<<32 + 1, 10, "4294967297"},
+ {-1<<32 - 1, 10, "-4294967297"},
+ {1 << 50, 10, "1125899906842624"},
+ {1<<63 - 1, 10, "9223372036854775807"},
+ {-1<<63 + 1, 10, "-9223372036854775807"},
+ {-1 << 63, 10, "-9223372036854775808"},
+
+ {0, 2, "0"},
+ {10, 2, "1010"},
+ {-1, 2, "-1"},
+ {1 << 15, 2, "1000000000000000"},
+
+ {-8, 8, "-10"},
+ {057635436545, 8, "57635436545"},
+ {1 << 24, 8, "100000000"},
+
+ {16, 16, "10"},
+ {-0x123456789abcdef, 16, "-123456789abcdef"},
+ {1<<63 - 1, 16, "7fffffffffffffff"},
+ {1<<63 - 1, 2, "111111111111111111111111111111111111111111111111111111111111111"},
+
+ {16, 17, "g"},
+ {25, 25, "10"},
+ {(((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, 35, "holycow"},
+ {(((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, 36, "holycow"},
+}
+
+func TestItoa(t *testing.T) {
+ for _, test := range itob64tests {
+ s := Itob64(test.in, test.base)
+ if s != test.out {
+ t.Errorf("Itob64(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+
+ if test.in >= 0 {
+ s := Uitob64(uint64(test.in), test.base)
+ if s != test.out {
+ t.Errorf("Uitob64(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+ }
+
+ if int64(int(test.in)) == test.in {
+ s := Itob(int(test.in), test.base)
+ if s != test.out {
+ t.Errorf("Itob(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+
+ if test.in >= 0 {
+ s := Uitob(uint(test.in), test.base)
+ if s != test.out {
+ t.Errorf("Uitob(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+ }
+ }
+
+ if test.base == 10 {
+ s := Itoa64(test.in)
+ if s != test.out {
+ t.Errorf("Itoa64(%v) = %v want %v",
+ test.in, s, test.out)
+ }
+
+ if test.in >= 0 {
+ s := Uitob64(uint64(test.in), test.base)
+ if s != test.out {
+ t.Errorf("Uitob64(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+ }
+
+ if int64(int(test.in)) == test.in {
+ s := Itoa(int(test.in))
+ if s != test.out {
+ t.Errorf("Itoa(%v) = %v want %v",
+ test.in, s, test.out)
+ }
+
+ if test.in >= 0 {
+ s := Uitoa(uint(test.in))
+ if s != test.out {
+ t.Errorf("Uitoa(%v) = %v want %v",
+ test.in, s, test.out)
+ }
+ }
+ }
+ }
+ }
+}
+
+type uitob64Test struct {
+ in uint64
+ base uint
+ out string
+}
+
+var uitob64tests = []uitob64Test{
+ {1<<63 - 1, 10, "9223372036854775807"},
+ {1 << 63, 10, "9223372036854775808"},
+ {1<<63 + 1, 10, "9223372036854775809"},
+ {1<<64 - 2, 10, "18446744073709551614"},
+ {1<<64 - 1, 10, "18446744073709551615"},
+ {1<<64 - 1, 2, "1111111111111111111111111111111111111111111111111111111111111111"},
+}
+
+func TestUitoa(t *testing.T) {
+ for _, test := range uitob64tests {
+ s := Uitob64(test.in, test.base)
+ if s != test.out {
+ t.Errorf("Uitob64(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+
+ if uint64(uint(test.in)) == test.in {
+ s := Uitob(uint(test.in), test.base)
+ if s != test.out {
+ t.Errorf("Uitob(%v, %v) = %v want %v",
+ test.in, test.base, s, test.out)
+ }
+ }
+
+ if test.base == 10 {
+ s := Uitoa64(test.in)
+ if s != test.out {
+ t.Errorf("Uitoa64(%v) = %v want %v",
+ test.in, s, test.out)
+ }
+
+ if uint64(uint(test.in)) == test.in {
+ s := Uitoa(uint(test.in))
+ if s != test.out {
+ t.Errorf("Uitoa(%v) = %v want %v",
+ test.in, s, test.out)
+ }
+ }
+ }
+ }
+}
diff --git a/libgo/go/strconv/quote.go b/libgo/go/strconv/quote.go
new file mode 100644
index 000000000..ed5889723
--- /dev/null
+++ b/libgo/go/strconv/quote.go
@@ -0,0 +1,264 @@
+// 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 strconv
+
+import (
+ "bytes"
+ "os"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+const lowerhex = "0123456789abcdef"
+
+// Quote returns a double-quoted Go string literal
+// representing s. The returned string s uses Go escape
+// sequences (\t, \n, \xFF, \u0100) for control characters
+// and non-ASCII characters.
+func Quote(s string) string {
+ var buf bytes.Buffer
+ buf.WriteByte('"')
+ for ; len(s) > 0; s = s[1:] {
+ switch c := s[0]; {
+ case c == '"':
+ buf.WriteString(`\"`)
+ case c == '\\':
+ buf.WriteString(`\\`)
+ case ' ' <= c && c <= '~':
+ buf.WriteString(string(c))
+ case c == '\a':
+ buf.WriteString(`\a`)
+ case c == '\b':
+ buf.WriteString(`\b`)
+ case c == '\f':
+ buf.WriteString(`\f`)
+ case c == '\n':
+ buf.WriteString(`\n`)
+ case c == '\r':
+ buf.WriteString(`\r`)
+ case c == '\t':
+ buf.WriteString(`\t`)
+ case c == '\v':
+ buf.WriteString(`\v`)
+
+ case c >= utf8.RuneSelf && utf8.FullRuneInString(s):
+ r, size := utf8.DecodeRuneInString(s)
+ if r == utf8.RuneError && size == 1 {
+ goto EscX
+ }
+ s = s[size-1:] // next iteration will slice off 1 more
+ if r < 0x10000 {
+ buf.WriteString(`\u`)
+ for j := uint(0); j < 4; j++ {
+ buf.WriteByte(lowerhex[(r>>(12-4*j))&0xF])
+ }
+ } else {
+ buf.WriteString(`\U`)
+ for j := uint(0); j < 8; j++ {
+ buf.WriteByte(lowerhex[(r>>(28-4*j))&0xF])
+ }
+ }
+
+ default:
+ EscX:
+ buf.WriteString(`\x`)
+ buf.WriteByte(lowerhex[c>>4])
+ buf.WriteByte(lowerhex[c&0xF])
+ }
+ }
+ buf.WriteByte('"')
+ return buf.String()
+}
+
+// CanBackquote returns whether the string s would be
+// a valid Go string literal if enclosed in backquotes.
+func CanBackquote(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' {
+ return false
+ }
+ }
+ return true
+}
+
+func unhex(b byte) (v int, ok bool) {
+ c := int(b)
+ switch {
+ case '0' <= c && c <= '9':
+ return c - '0', true
+ case 'a' <= c && c <= 'f':
+ return c - 'a' + 10, true
+ case 'A' <= c && c <= 'F':
+ return c - 'A' + 10, true
+ }
+ return
+}
+
+// UnquoteChar decodes the first character or byte in the escaped string
+// or character literal represented by the string s.
+// It returns four values:
+//
+// 1) value, the decoded Unicode code point or byte value;
+// 2) multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation;
+// 3) tail, the remainder of the string after the character; and
+// 4) an error that will be nil if the character is syntactically valid.
+//
+// The second argument, quote, specifies the type of literal being parsed
+// and therefore which escaped quote character is permitted.
+// If set to a single quote, it permits the sequence \' and disallows unescaped '.
+// If set to a double quote, it permits \" and disallows unescaped ".
+// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped.
+func UnquoteChar(s string, quote byte) (value int, multibyte bool, tail string, err os.Error) {
+ // easy cases
+ switch c := s[0]; {
+ case c == quote && (quote == '\'' || quote == '"'):
+ err = os.EINVAL
+ return
+ case c >= utf8.RuneSelf:
+ r, size := utf8.DecodeRuneInString(s)
+ return r, true, s[size:], nil
+ case c != '\\':
+ return int(s[0]), false, s[1:], nil
+ }
+
+ // hard case: c is backslash
+ if len(s) <= 1 {
+ err = os.EINVAL
+ return
+ }
+ c := s[1]
+ s = s[2:]
+
+ switch c {
+ case 'a':
+ value = '\a'
+ case 'b':
+ value = '\b'
+ case 'f':
+ value = '\f'
+ case 'n':
+ value = '\n'
+ case 'r':
+ value = '\r'
+ case 't':
+ value = '\t'
+ case 'v':
+ value = '\v'
+ case 'x', 'u', 'U':
+ n := 0
+ switch c {
+ case 'x':
+ n = 2
+ case 'u':
+ n = 4
+ case 'U':
+ n = 8
+ }
+ v := 0
+ if len(s) < n {
+ err = os.EINVAL
+ return
+ }
+ for j := 0; j < n; j++ {
+ x, ok := unhex(s[j])
+ if !ok {
+ err = os.EINVAL
+ return
+ }
+ v = v<<4 | x
+ }
+ s = s[n:]
+ if c == 'x' {
+ // single-byte string, possibly not UTF-8
+ value = v
+ break
+ }
+ if v > unicode.MaxRune {
+ err = os.EINVAL
+ return
+ }
+ value = v
+ multibyte = true
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ v := int(c) - '0'
+ if len(s) < 2 {
+ err = os.EINVAL
+ return
+ }
+ for j := 0; j < 2; j++ { // one digit already; two more
+ x := int(s[j]) - '0'
+ if x < 0 || x > 7 {
+ return
+ }
+ v = (v << 3) | x
+ }
+ s = s[2:]
+ if v > 255 {
+ err = os.EINVAL
+ return
+ }
+ value = v
+ case '\\':
+ value = '\\'
+ case '\'', '"':
+ if c != quote {
+ err = os.EINVAL
+ return
+ }
+ value = int(c)
+ default:
+ err = os.EINVAL
+ return
+ }
+ tail = s
+ return
+}
+
+// Unquote interprets s as a single-quoted, double-quoted,
+// or backquoted Go string literal, returning the string value
+// that s quotes. (If s is single-quoted, it would be a Go
+// character literal; Unquote returns the corresponding
+// one-character string.)
+func Unquote(s string) (t string, err os.Error) {
+ n := len(s)
+ if n < 2 {
+ return "", os.EINVAL
+ }
+ quote := s[0]
+ if quote != s[n-1] {
+ return "", os.EINVAL
+ }
+ s = s[1 : n-1]
+
+ if quote == '`' {
+ if strings.Contains(s, "`") {
+ return "", os.EINVAL
+ }
+ return s, nil
+ }
+ if quote != '"' && quote != '\'' {
+ return "", os.EINVAL
+ }
+
+ var buf bytes.Buffer
+ for len(s) > 0 {
+ c, multibyte, ss, err := UnquoteChar(s, quote)
+ if err != nil {
+ return "", err
+ }
+ s = ss
+ if c < utf8.RuneSelf || !multibyte {
+ buf.WriteByte(byte(c))
+ } else {
+ buf.WriteString(string(c))
+ }
+ if quote == '\'' && len(s) != 0 {
+ // single-quoted must be single character
+ return "", os.EINVAL
+ }
+ }
+ return buf.String(), nil
+}
diff --git a/libgo/go/strconv/quote_test.go b/libgo/go/strconv/quote_test.go
new file mode 100644
index 000000000..1235fcb9a
--- /dev/null
+++ b/libgo/go/strconv/quote_test.go
@@ -0,0 +1,170 @@
+// 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 strconv_test
+
+import (
+ "os"
+ . "strconv"
+ "testing"
+)
+
+type quoteTest struct {
+ in string
+ out string
+}
+
+var quotetests = []quoteTest{
+ {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
+ {"\\", `"\\"`},
+ {"abc\xffdef", `"abc\xffdef"`},
+ {"\u263a", `"\u263a"`},
+ {"\U0010ffff", `"\U0010ffff"`},
+ {"\x04", `"\x04"`},
+}
+
+func TestQuote(t *testing.T) {
+ for i := 0; i < len(quotetests); i++ {
+ tt := quotetests[i]
+ if out := Quote(tt.in); out != tt.out {
+ t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out)
+ }
+ }
+}
+
+type canBackquoteTest struct {
+ in string
+ out bool
+}
+
+var canbackquotetests = []canBackquoteTest{
+ {"`", false},
+ {string(0), false},
+ {string(1), false},
+ {string(2), false},
+ {string(3), false},
+ {string(4), false},
+ {string(5), false},
+ {string(6), false},
+ {string(7), false},
+ {string(8), false},
+ {string(9), true}, // \t
+ {string(10), false},
+ {string(11), false},
+ {string(12), false},
+ {string(13), false},
+ {string(14), false},
+ {string(15), false},
+ {string(16), false},
+ {string(17), false},
+ {string(18), false},
+ {string(19), false},
+ {string(20), false},
+ {string(21), false},
+ {string(22), false},
+ {string(23), false},
+ {string(24), false},
+ {string(25), false},
+ {string(26), false},
+ {string(27), false},
+ {string(28), false},
+ {string(29), false},
+ {string(30), false},
+ {string(31), false},
+ {`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
+ {`0123456789`, true},
+ {`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
+ {`abcdefghijklmnopqrstuvwxyz`, true},
+ {`☺`, true},
+}
+
+func TestCanBackquote(t *testing.T) {
+ for i := 0; i < len(canbackquotetests); i++ {
+ tt := canbackquotetests[i]
+ if out := CanBackquote(tt.in); out != tt.out {
+ t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out)
+ }
+ }
+}
+
+var unquotetests = []quoteTest{
+ {`""`, ""},
+ {`"a"`, "a"},
+ {`"abc"`, "abc"},
+ {`"☺"`, "☺"},
+ {`"hello world"`, "hello world"},
+ {`"\xFF"`, "\xFF"},
+ {`"\377"`, "\377"},
+ {`"\u1234"`, "\u1234"},
+ {`"\U00010111"`, "\U00010111"},
+ {`"\U0001011111"`, "\U0001011111"},
+ {`"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\""},
+ {`"'"`, "'"},
+
+ {`'a'`, "a"},
+ {`'☹'`, "☹"},
+ {`'\a'`, "\a"},
+ {`'\x10'`, "\x10"},
+ {`'\377'`, "\377"},
+ {`'\u1234'`, "\u1234"},
+ {`'\U00010111'`, "\U00010111"},
+ {`'\t'`, "\t"},
+ {`' '`, " "},
+ {`'\''`, "'"},
+ {`'"'`, "\""},
+
+ {"``", ``},
+ {"`a`", `a`},
+ {"`abc`", `abc`},
+ {"`☺`", `☺`},
+ {"`hello world`", `hello world`},
+ {"`\\xFF`", `\xFF`},
+ {"`\\377`", `\377`},
+ {"`\\`", `\`},
+ {"` `", ` `},
+ {"` `", ` `},
+}
+
+var misquoted = []string{
+ ``,
+ `"`,
+ `"a`,
+ `"'`,
+ `b"`,
+ `"\"`,
+ `'\'`,
+ `'ab'`,
+ `"\x1!"`,
+ `"\U12345678"`,
+ `"\z"`,
+ "`",
+ "`xxx",
+ "`\"",
+ `"\'"`,
+ `'\"'`,
+}
+
+func TestUnquote(t *testing.T) {
+ for i := 0; i < len(unquotetests); i++ {
+ tt := unquotetests[i]
+ if out, err := Unquote(tt.in); err != nil && out != tt.out {
+ t.Errorf("Unquote(%#q) = %q, %v want %q, nil", tt.in, out, err, tt.out)
+ }
+ }
+
+ // run the quote tests too, backward
+ for i := 0; i < len(quotetests); i++ {
+ tt := quotetests[i]
+ if in, err := Unquote(tt.out); in != tt.in {
+ t.Errorf("Unquote(%#q) = %q, %v, want %q, nil", tt.out, in, err, tt.in)
+ }
+ }
+
+ for i := 0; i < len(misquoted); i++ {
+ s := misquoted[i]
+ if out, err := Unquote(s); out != "" || err != os.EINVAL {
+ t.Errorf("Unquote(%#q) = %q, %v want %q, %v", s, out, err, "", os.EINVAL)
+ }
+ }
+}
diff --git a/libgo/go/strconv/testfp.txt b/libgo/go/strconv/testfp.txt
new file mode 100644
index 000000000..08d3c4ef0
--- /dev/null
+++ b/libgo/go/strconv/testfp.txt
@@ -0,0 +1,181 @@
+# Floating-point conversion test cases.
+# Empty lines and lines beginning with # are ignored.
+# The rest have four fields per line: type, format, input, and output.
+# The input is given either in decimal or binary scientific notation.
+# The output is the string that should be produced by formatting the
+# input with the given format.
+#
+# The formats are as in C's printf, except that %b means print
+# binary scientific notation: NpE = N x 2^E.
+
+# TODO:
+# Powers of 10.
+# Powers of 2.
+# %.20g versions.
+# random sources
+# random targets
+# random targets ± half a ULP
+
+# Difficult boundary cases, derived from tables given in
+# Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion
+# ftp://ftp.ee.lbl.gov/testbase-report.ps.Z
+
+# Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
+float64 %b 5e+125 6653062250012735p+365
+float64 %b 69e+267 4705683757438170p+841
+float64 %b 999e-026 6798841691080350p-129
+float64 %b 7861e-034 8975675289889240p-153
+float64 %b 75569e-254 6091718967192243p-880
+float64 %b 928609e-261 7849264900213743p-900
+float64 %b 9210917e+080 8341110837370930p+236
+float64 %b 84863171e+114 4625202867375927p+353
+float64 %b 653777767e+273 5068902999763073p+884
+float64 %b 5232604057e-298 5741343011915040p-1010
+float64 %b 27235667517e-109 6707124626673586p-380
+float64 %b 653532977297e-123 7078246407265384p-422
+float64 %b 3142213164987e-294 8219991337640559p-988
+float64 %b 46202199371337e-072 5224462102115359p-246
+float64 %b 231010996856685e-073 5224462102115359p-247
+float64 %b 9324754620109615e+212 5539753864394442p+705
+float64 %b 78459735791271921e+049 8388176519442766p+166
+float64 %b 272104041512242479e+200 5554409530847367p+670
+float64 %b 6802601037806061975e+198 5554409530847367p+668
+float64 %b 20505426358836677347e-221 4524032052079546p-722
+float64 %b 836168422905420598437e-234 5070963299887562p-760
+float64 %b 4891559871276714924261e+222 6452687840519111p+757
+
+# Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
+float64 %b 9e-265 8168427841980010p-930
+float64 %b 85e-037 6360455125664090p-169
+float64 %b 623e+100 6263531988747231p+289
+float64 %b 3571e+263 6234526311072170p+833
+float64 %b 81661e+153 6696636728760206p+472
+float64 %b 920657e-023 5975405561110124p-109
+float64 %b 4603285e-024 5975405561110124p-110
+float64 %b 87575437e-309 8452160731874668p-1053
+float64 %b 245540327e+122 4985336549131723p+381
+float64 %b 6138508175e+120 4985336549131723p+379
+float64 %b 83356057653e+193 5986732817132056p+625
+float64 %b 619534293513e+124 4798406992060657p+399
+float64 %b 2335141086879e+218 5419088166961646p+713
+float64 %b 36167929443327e-159 8135819834632444p-536
+float64 %b 609610927149051e-255 4576664294594737p-850
+float64 %b 3743626360493413e-165 6898586531774201p-549
+float64 %b 94080055902682397e-242 6273271706052298p-800
+float64 %b 899810892172646163e+283 7563892574477827p+947
+float64 %b 7120190517612959703e+120 5385467232557565p+409
+float64 %b 25188282901709339043e-252 5635662608542340p-825
+float64 %b 308984926168550152811e-052 5644774693823803p-157
+float64 %b 6372891218502368041059e+064 4616868614322430p+233
+
+# Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP
+float64 %.0e 8511030020275656p-342 9e-88
+float64 %.1e 5201988407066741p-824 4.6e-233
+float64 %.2e 6406892948269899p+237 1.41e+87
+float64 %.3e 8431154198732492p+72 3.981e+37
+float64 %.4e 6475049196144587p+99 4.1040e+45
+float64 %.5e 8274307542972842p+726 2.92084e+234
+float64 %.6e 5381065484265332p-456 2.891946e-122
+float64 %.7e 6761728585499734p-1057 4.3787718e-303
+float64 %.8e 7976538478610756p+376 1.22770163e+129
+float64 %.9e 5982403858958067p+377 1.841552452e+129
+float64 %.10e 5536995190630837p+93 5.4835744350e+43
+float64 %.11e 7225450889282194p+710 3.89190181146e+229
+float64 %.12e 7225450889282194p+709 1.945950905732e+229
+float64 %.13e 8703372741147379p+117 1.4460958381605e+51
+float64 %.14e 8944262675275217p-1001 4.17367747458531e-286
+float64 %.15e 7459803696087692p-707 1.107950772878888e-197
+float64 %.16e 6080469016670379p-381 1.2345501366327440e-99
+float64 %.17e 8385515147034757p+721 9.25031711960365024e+232
+float64 %.18e 7514216811389786p-828 4.198047150284889840e-234
+float64 %.19e 8397297803260511p-345 1.1716315319786511046e-88
+float64 %.20e 6733459239310543p+202 4.32810072844612493629e+76
+float64 %.21e 8091450587292794p-473 3.317710118160031081518e-127
+
+# Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP
+float64 %.0e 6567258882077402p+952 3e+302
+float64 %.1e 6712731423444934p+535 7.6e+176
+float64 %.2e 6712731423444934p+534 3.78e+176
+float64 %.3e 5298405411573037p-957 4.350e-273
+float64 %.4e 5137311167659507p-144 2.3037e-28
+float64 %.5e 6722280709661868p+363 1.26301e+125
+float64 %.6e 5344436398034927p-169 7.142211e-36
+float64 %.7e 8369123604277281p-853 1.3934574e-241
+float64 %.8e 8995822108487663p-780 1.41463449e-219
+float64 %.9e 8942832835564782p-383 4.539277920e-100
+float64 %.10e 8942832835564782p-384 2.2696389598e-100
+float64 %.11e 8942832835564782p-385 1.13481947988e-100
+float64 %.12e 6965949469487146p-249 7.700366561890e-60
+float64 %.13e 6965949469487146p-250 3.8501832809448e-60
+float64 %.14e 6965949469487146p-251 1.92509164047238e-60
+float64 %.15e 7487252720986826p+548 6.898586531774201e+180
+float64 %.16e 5592117679628511p+164 1.3076622631878654e+65
+float64 %.17e 8887055249355788p+665 1.36052020756121240e+216
+float64 %.18e 6994187472632449p+690 3.592810217475959676e+223
+float64 %.19e 8797576579012143p+588 8.9125197712484551899e+192
+float64 %.20e 7363326733505337p+272 5.58769757362301140950e+97
+float64 %.21e 8549497411294502p-448 1.176257830728540379990e-119
+
+# Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
+# NOTE: The lines with exponent p-149 have been changed from the
+# paper. Those entries originally read p-150 and had a mantissa
+# twice as large (and even), but IEEE single-precision has no p-150:
+# that's the start of the denormals.
+float32 %b 5e-20 15474250p-88
+float32 %b 67e+14 12479722p+29
+float32 %b 985e+15 14333636p+36
+# float32 %b 7693e-42 10979816p-150
+float32 %b 7693e-42 5489908p-149
+float32 %b 55895e-16 12888509p-61
+# float32 %b 996622e-44 14224264p-150
+float32 %b 996622e-44 7112132p-149
+float32 %b 7038531e-32 11420669p-107
+# float32 %b 60419369e-46 8623340p-150
+float32 %b 60419369e-46 4311670p-149
+float32 %b 702990899e-20 16209866p-61
+# float32 %b 6930161142e-48 9891056p-150
+float32 %b 6930161142e-48 4945528p-149
+float32 %b 25933168707e+13 14395800p+54
+float32 %b 596428896559e+20 12333860p+82
+
+# Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
+float32 %b 3e-23 9507380p-98
+float32 %b 57e+18 12960300p+42
+float32 %b 789e-35 10739312p-130
+float32 %b 2539e-18 11990089p-72
+float32 %b 76173e+28 9845130p+86
+float32 %b 887745e-11 9760860p-40
+float32 %b 5382571e-37 11447463p-124
+float32 %b 82381273e-35 8554961p-113
+float32 %b 750486563e-38 9975678p-120
+float32 %b 3752432815e-39 9975678p-121
+float32 %b 75224575729e-45 13105970p-137
+float32 %b 459926601011e+15 12466336p+65
+
+# Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP
+float32 %.0e 12676506p-102 2e-24
+float32 %.1e 12676506p-103 1.2e-24
+float32 %.2e 15445013p+86 1.19e+33
+float32 %.3e 13734123p-138 3.941e-35
+float32 %.4e 12428269p-130 9.1308e-33
+float32 %.5e 15334037p-146 1.71900e-37
+float32 %.6e 11518287p-41 5.237910e-06
+float32 %.7e 12584953p-145 2.8216440e-37
+float32 %.8e 15961084p-125 3.75243281e-31
+float32 %.9e 14915817p-146 1.672120916e-37
+float32 %.10e 10845484p-102 2.1388945814e-24
+float32 %.11e 16431059p-61 7.12583594561e-12
+
+# Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP
+float32 %.0e 16093626p+69 1e+28
+float32 %.1e 9983778p+25 3.4e+14
+float32 %.2e 12745034p+104 2.59e+38
+float32 %.3e 12706553p+72 6.001e+28
+float32 %.4e 11005028p+45 3.8721e+20
+float32 %.5e 15059547p+71 3.55584e+28
+float32 %.6e 16015691p-99 2.526831e-23
+float32 %.7e 8667859p+56 6.2458507e+23
+float32 %.8e 14855922p-82 3.07213267e-18
+float32 %.9e 14855922p-83 1.536066333e-18
+float32 %.10e 10144164p-110 7.8147796834e-27
+float32 %.11e 13248074p+95 5.24810279937e+35
diff --git a/libgo/go/strings/reader.go b/libgo/go/strings/reader.go
new file mode 100644
index 000000000..914faa003
--- /dev/null
+++ b/libgo/go/strings/reader.go
@@ -0,0 +1,61 @@
+// 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 strings
+
+import (
+ "os"
+ "utf8"
+)
+
+// A Reader satisfies calls to Read, ReadByte, and ReadRune by
+// reading from a string.
+type Reader string
+
+func (r *Reader) Read(b []byte) (n int, err os.Error) {
+ s := *r
+ if len(s) == 0 {
+ return 0, os.EOF
+ }
+ for n < len(s) && n < len(b) {
+ b[n] = s[n]
+ n++
+ }
+ *r = s[n:]
+ return
+}
+
+func (r *Reader) ReadByte() (b byte, err os.Error) {
+ s := *r
+ if len(s) == 0 {
+ return 0, os.EOF
+ }
+ b = s[0]
+ *r = s[1:]
+ return
+}
+
+// ReadRune reads and returns the next UTF-8-encoded
+// Unicode code point from the buffer.
+// If no bytes are available, the error returned is os.EOF.
+// If the bytes are an erroneous UTF-8 encoding, it
+// consumes one byte and returns U+FFFD, 1.
+func (r *Reader) ReadRune() (rune int, size int, err os.Error) {
+ s := *r
+ if len(s) == 0 {
+ return 0, 0, os.EOF
+ }
+ c := s[0]
+ if c < utf8.RuneSelf {
+ *r = s[1:]
+ return int(c), 1, nil
+ }
+ rune, size = utf8.DecodeRuneInString(string(s))
+ *r = s[size:]
+ return
+}
+
+// NewReader returns a new Reader reading from s.
+// It is similar to bytes.NewBufferString but more efficient and read-only.
+func NewReader(s string) *Reader { return (*Reader)(&s) }
diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go
new file mode 100644
index 000000000..98a0d5731
--- /dev/null
+++ b/libgo/go/strings/strings.go
@@ -0,0 +1,559 @@
+// 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 package of simple functions to manipulate strings.
+package strings
+
+import (
+ "unicode"
+ "utf8"
+)
+
+// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n < 0 means no limit).
+// Invalid UTF-8 sequences become correct encodings of U+FFF8.
+func explode(s string, n int) []string {
+ if n == 0 {
+ return nil
+ }
+ l := utf8.RuneCountInString(s)
+ if n <= 0 || n > l {
+ n = l
+ }
+ a := make([]string, n)
+ var size, rune int
+ i, cur := 0, 0
+ for ; i+1 < n; i++ {
+ rune, size = utf8.DecodeRuneInString(s[cur:])
+ a[i] = string(rune)
+ cur += size
+ }
+ // add the rest, if there is any
+ if cur < len(s) {
+ a[i] = s[cur:]
+ }
+ return a
+}
+
+// Count counts the number of non-overlapping instances of sep in s.
+func Count(s, sep string) int {
+ if sep == "" {
+ return utf8.RuneCountInString(s) + 1
+ }
+ c := sep[0]
+ l := len(sep)
+ n := 0
+ if l == 1 {
+ // special case worth making fast
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ n++
+ }
+ }
+ return n
+ }
+ for i := 0; i+l <= len(s); i++ {
+ if s[i] == c && s[i:i+l] == sep {
+ n++
+ i += l - 1
+ }
+ }
+ return n
+}
+
+// Contains returns true if substr is within s.
+func Contains(s, substr string) bool {
+ return Index(s, substr) != -1
+}
+
+// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
+func Index(s, sep string) int {
+ n := len(sep)
+ if n == 0 {
+ return 0
+ }
+ c := sep[0]
+ if n == 1 {
+ // special case worth making fast
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ return i
+ }
+ }
+ return -1
+ }
+ // n > 1
+ for i := 0; i+n <= len(s); i++ {
+ if s[i] == c && s[i:i+n] == sep {
+ return i
+ }
+ }
+ return -1
+}
+
+// LastIndex returns the index of the last instance of sep in s, or -1 if sep is not present in s.
+func LastIndex(s, sep string) int {
+ n := len(sep)
+ if n == 0 {
+ return len(s)
+ }
+ c := sep[0]
+ if n == 1 {
+ // special case worth making fast
+ for i := len(s) - 1; i >= 0; i-- {
+ if s[i] == c {
+ return i
+ }
+ }
+ return -1
+ }
+ // n > 1
+ for i := len(s) - n; i >= 0; i-- {
+ if s[i] == c && s[i:i+n] == sep {
+ return i
+ }
+ }
+ return -1
+}
+
+// IndexRune returns the index of the first instance of the Unicode code point
+// rune, or -1 if rune is not present in s.
+func IndexRune(s string, rune int) int {
+ for i, c := range s {
+ if c == rune {
+ return i
+ }
+ }
+ return -1
+}
+
+// IndexAny returns the index of the first instance of any Unicode code point
+// from chars in s, or -1 if no Unicode code point from chars is present in s.
+func IndexAny(s, chars string) int {
+ if len(chars) > 0 {
+ for i, c := range s {
+ for _, m := range chars {
+ if c == m {
+ return i
+ }
+ }
+ }
+ }
+ return -1
+}
+
+// LastIndexAny returns the index of the last instance of any Unicode code
+// point from chars in s, or -1 if no Unicode code point from chars is
+// present in s.
+func LastIndexAny(s, chars string) int {
+ if len(chars) > 0 {
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRuneInString(s[0:i])
+ i -= size
+ for _, m := range chars {
+ if rune == m {
+ return i
+ }
+ }
+ }
+ }
+ return -1
+}
+
+// Generic split: splits after each instance of sep,
+// including sepSave bytes of sep in the subarrays.
+func genSplit(s, sep string, sepSave, n int) []string {
+ if n == 0 {
+ return nil
+ }
+ if sep == "" {
+ return explode(s, n)
+ }
+ if n < 0 {
+ n = Count(s, sep) + 1
+ }
+ c := sep[0]
+ start := 0
+ a := make([]string, n)
+ na := 0
+ for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
+ if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
+ a[na] = s[start : i+sepSave]
+ na++
+ start = i + len(sep)
+ i += len(sep) - 1
+ }
+ }
+ a[na] = s[start:]
+ return a[0 : na+1]
+}
+
+// Split slices s into substrings separated by sep and returns a slice of
+// the substrings between those separators.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of substrings to return:
+// n > 0: at most n substrings; the last substring will be the unsplit remainder.
+// n == 0: the result is nil (zero substrings)
+// n < 0: all substrings
+func Split(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
+
+// SplitAfter slices s into substrings after each instance of sep and
+// returns a slice of those substrings.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of substrings to return:
+// n > 0: at most n substrings; the last substring will be the unsplit remainder.
+// n == 0: the result is nil (zero substrings)
+// n < 0: all substrings
+func SplitAfter(s, sep string, n int) []string {
+ return genSplit(s, sep, len(sep), n)
+}
+
+// Fields splits the string s around each instance of one or more consecutive white space
+// characters, returning an array of substrings of s or an empty list if s contains only white space.
+func Fields(s string) []string {
+ return FieldsFunc(s, unicode.IsSpace)
+}
+
+// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c)
+// and returns an array of slices of s. If all code points in s satisfy f(c) or the
+// string is empty, an empty slice is returned.
+func FieldsFunc(s string, f func(int) bool) []string {
+ // First count the fields.
+ n := 0
+ inField := false
+ for _, rune := range s {
+ wasInField := inField
+ inField = !f(rune)
+ if inField && !wasInField {
+ n++
+ }
+ }
+
+ // Now create them.
+ a := make([]string, n)
+ na := 0
+ fieldStart := -1 // Set to -1 when looking for start of field.
+ for i, rune := range s {
+ if f(rune) {
+ if fieldStart >= 0 {
+ a[na] = s[fieldStart:i]
+ na++
+ fieldStart = -1
+ }
+ } else if fieldStart == -1 {
+ fieldStart = i
+ }
+ }
+ if fieldStart != -1 { // Last field might end at EOF.
+ a[na] = s[fieldStart:]
+ }
+ return a
+}
+
+// Join concatenates the elements of a to create a single string. The separator string
+// sep is placed between elements in the resulting string.
+func Join(a []string, sep string) string {
+ if len(a) == 0 {
+ return ""
+ }
+ if len(a) == 1 {
+ return a[0]
+ }
+ n := len(sep) * (len(a) - 1)
+ for i := 0; i < len(a); i++ {
+ n += len(a[i])
+ }
+
+ b := make([]byte, n)
+ bp := 0
+ for i := 0; i < len(a); i++ {
+ s := a[i]
+ for j := 0; j < len(s); j++ {
+ b[bp] = s[j]
+ bp++
+ }
+ if i+1 < len(a) {
+ s = sep
+ for j := 0; j < len(s); j++ {
+ b[bp] = s[j]
+ bp++
+ }
+ }
+ }
+ return string(b)
+}
+
+// HasPrefix tests whether the string s begins with prefix.
+func HasPrefix(s, prefix string) bool {
+ return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
+}
+
+// HasSuffix tests whether the string s ends with suffix.
+func HasSuffix(s, suffix string) bool {
+ return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
+}
+
+// Map returns a copy of the string s with all its characters modified
+// according to the mapping function. If mapping returns a negative value, the character is
+// dropped from the string with no replacement.
+func Map(mapping func(rune int) int, s string) string {
+ // In the worst case, the string can grow when mapped, making
+ // things unpleasant. But it's so rare we barge in assuming it's
+ // fine. It could also shrink but that falls out naturally.
+ maxbytes := len(s) // length of b
+ nbytes := 0 // number of bytes encoded in b
+ b := make([]byte, maxbytes)
+ for _, c := range s {
+ rune := mapping(c)
+ if rune >= 0 {
+ wid := 1
+ if rune >= utf8.RuneSelf {
+ wid = utf8.RuneLen(rune)
+ }
+ if nbytes+wid > maxbytes {
+ // Grow the buffer.
+ maxbytes = maxbytes*2 + utf8.UTFMax
+ nb := make([]byte, maxbytes)
+ copy(nb, b[0:nbytes])
+ b = nb
+ }
+ nbytes += utf8.EncodeRune(b[nbytes:maxbytes], rune)
+ }
+ }
+ return string(b[0:nbytes])
+}
+
+// Repeat returns a new string consisting of count copies of the string s.
+func Repeat(s string, count int) string {
+ b := make([]byte, len(s)*count)
+ bp := 0
+ for i := 0; i < count; i++ {
+ for j := 0; j < len(s); j++ {
+ b[bp] = s[j]
+ bp++
+ }
+ }
+ return string(b)
+}
+
+
+// ToUpper returns a copy of the string s with all Unicode letters mapped to their upper case.
+func ToUpper(s string) string { return Map(unicode.ToUpper, s) }
+
+// ToLower returns a copy of the string s with all Unicode letters mapped to their lower case.
+func ToLower(s string) string { return Map(unicode.ToLower, s) }
+
+// ToTitle returns a copy of the string s with all Unicode letters mapped to their title case.
+func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
+
+// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their
+// upper case, giving priority to the special casing rules.
+func ToUpperSpecial(_case unicode.SpecialCase, s string) string {
+ return Map(func(r int) int { return _case.ToUpper(r) }, s)
+}
+
+// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their
+// lower case, giving priority to the special casing rules.
+func ToLowerSpecial(_case unicode.SpecialCase, s string) string {
+ return Map(func(r int) int { return _case.ToLower(r) }, s)
+}
+
+// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their
+// title case, giving priority to the special casing rules.
+func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
+ return Map(func(r int) int { return _case.ToTitle(r) }, s)
+}
+
+// isSeparator reports whether the rune could mark a word boundary.
+// TODO: update when package unicode captures more of the properties.
+func isSeparator(rune int) bool {
+ // ASCII alphanumerics and underscore are not separators
+ if rune <= 0x7F {
+ switch {
+ case '0' <= rune && rune <= '9':
+ return false
+ case 'a' <= rune && rune <= 'z':
+ return false
+ case 'A' <= rune && rune <= 'Z':
+ return false
+ case rune == '_':
+ return false
+ }
+ return true
+ }
+ // Letters and digits are not separators
+ if unicode.IsLetter(rune) || unicode.IsDigit(rune) {
+ return false
+ }
+ // Otherwise, all we can do for now is treat spaces as separators.
+ return unicode.IsSpace(rune)
+}
+
+// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+
+// Title returns a copy of the string s with all Unicode letters that begin words
+// mapped to their title case.
+func Title(s string) string {
+ // Use a closure here to remember state.
+ // Hackish but effective. Depends on Map scanning in order and calling
+ // the closure once per rune.
+ prev := ' '
+ return Map(
+ func(r int) int {
+ if isSeparator(prev) {
+ prev = r
+ return unicode.ToTitle(r)
+ }
+ prev = r
+ return r
+ },
+ s)
+}
+
+// TrimLeftFunc returns a slice of the string s with all leading
+// Unicode code points c satisfying f(c) removed.
+func TrimLeftFunc(s string, f func(r int) bool) string {
+ i := indexFunc(s, f, false)
+ if i == -1 {
+ return ""
+ }
+ return s[i:]
+}
+
+// TrimRightFunc returns a slice of the string s with all trailing
+// Unicode code points c satisfying f(c) removed.
+func TrimRightFunc(s string, f func(r int) bool) string {
+ i := lastIndexFunc(s, f, false)
+ if i >= 0 && s[i] >= utf8.RuneSelf {
+ _, wid := utf8.DecodeRuneInString(s[i:])
+ i += wid
+ } else {
+ i++
+ }
+ return s[0:i]
+}
+
+// TrimFunc returns a slice of the string s with all leading
+// and trailing Unicode code points c satisfying f(c) removed.
+func TrimFunc(s string, f func(r int) bool) string {
+ return TrimRightFunc(TrimLeftFunc(s, f), f)
+}
+
+// IndexFunc returns the index into s of the first Unicode
+// code point satisfying f(c), or -1 if none do.
+func IndexFunc(s string, f func(r int) bool) int {
+ return indexFunc(s, f, true)
+}
+
+// LastIndexFunc returns the index into s of the last
+// Unicode code point satisfying f(c), or -1 if none do.
+func LastIndexFunc(s string, f func(r int) bool) int {
+ return lastIndexFunc(s, f, true)
+}
+
+// indexFunc is the same as IndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func indexFunc(s string, f func(r int) bool, truth bool) int {
+ start := 0
+ for start < len(s) {
+ wid := 1
+ rune := int(s[start])
+ if rune >= utf8.RuneSelf {
+ rune, wid = utf8.DecodeRuneInString(s[start:])
+ }
+ if f(rune) == truth {
+ return start
+ }
+ start += wid
+ }
+ return -1
+}
+
+// lastIndexFunc is the same as LastIndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func lastIndexFunc(s string, f func(r int) bool, truth bool) int {
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRuneInString(s[0:i])
+ i -= size
+ if f(rune) == truth {
+ return i
+ }
+ }
+ return -1
+}
+
+func makeCutsetFunc(cutset string) func(rune int) bool {
+ return func(rune int) bool { return IndexRune(cutset, rune) != -1 }
+}
+
+// Trim returns a slice of the string s with all leading and
+// trailing Unicode code points contained in cutset removed.
+func Trim(s string, cutset string) string {
+ if s == "" || cutset == "" {
+ return s
+ }
+ return TrimFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimLeft returns a slice of the string s with all leading
+// Unicode code points contained in cutset removed.
+func TrimLeft(s string, cutset string) string {
+ if s == "" || cutset == "" {
+ return s
+ }
+ return TrimLeftFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimRight returns a slice of the string s, with all trailing
+// Unicode code points contained in cutset removed.
+func TrimRight(s string, cutset string) string {
+ if s == "" || cutset == "" {
+ return s
+ }
+ return TrimRightFunc(s, makeCutsetFunc(cutset))
+}
+
+// TrimSpace returns a slice of the string s, with all leading
+// and trailing white space removed, as defined by Unicode.
+func TrimSpace(s string) string {
+ return TrimFunc(s, unicode.IsSpace)
+}
+
+// Replace returns a copy of the string s with the first n
+// non-overlapping instances of old replaced by new.
+// If n < 0, there is no limit on the number of replacements.
+func Replace(s, old, new string, n int) string {
+ if old == new || n == 0 {
+ return s // avoid allocation
+ }
+
+ // Compute number of replacements.
+ if m := Count(s, old); m == 0 {
+ return s // avoid allocation
+ } else if n < 0 || m < n {
+ n = m
+ }
+
+ // Apply replacements to buffer.
+ t := make([]byte, len(s)+n*(len(new)-len(old)))
+ w := 0
+ start := 0
+ for i := 0; i < n; i++ {
+ j := start
+ if len(old) == 0 {
+ if i > 0 {
+ _, wid := utf8.DecodeRuneInString(s[start:])
+ j += wid
+ }
+ } else {
+ j += Index(s[start:], old)
+ }
+ w += copy(t[w:], s[start:j])
+ w += copy(t[w:], new)
+ start = j + len(old)
+ }
+ w += copy(t[w:], s[start:])
+ return string(t[0:w])
+}
diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go
new file mode 100644
index 000000000..734fdd33d
--- /dev/null
+++ b/libgo/go/strings/strings_test.go
@@ -0,0 +1,776 @@
+// 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 strings_test
+
+import (
+ "os"
+ . "strings"
+ "testing"
+ "unicode"
+ "utf8"
+)
+
+func eq(a, b []string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := 0; i < len(a); i++ {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+var abcd = "abcd"
+var faces = "☺☻☹"
+var commas = "1,2,3,4"
+var dots = "1....2....3....4"
+
+type IndexTest struct {
+ s string
+ sep string
+ out int
+}
+
+var indexTests = []IndexTest{
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"oofofoofooo", "f", 2},
+ {"oofofoofooo", "foo", 4},
+ {"barfoobarfoo", "foo", 3},
+ {"foo", "", 0},
+ {"foo", "o", 1},
+ {"abcABCabc", "A", 3},
+ // cases with one byte strings - test special case in Index()
+ {"", "a", -1},
+ {"x", "a", -1},
+ {"x", "x", 0},
+ {"abc", "a", 0},
+ {"abc", "b", 1},
+ {"abc", "c", 2},
+ {"abc", "x", -1},
+}
+
+var lastIndexTests = []IndexTest{
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"foo", "f", 0},
+ {"oofofoofooo", "f", 7},
+ {"oofofoofooo", "foo", 7},
+ {"barfoobarfoo", "foo", 9},
+ {"foo", "", 3},
+ {"foo", "o", 2},
+ {"abcABCabc", "A", 3},
+ {"abcABCabc", "a", 6},
+}
+
+var indexAnyTests = []IndexTest{
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 0},
+ {"abc", "xyz", -1},
+ {"abc", "xcz", 2},
+ {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"aRegExp*", ".(|)*+?^$[]", 7},
+ {dots + dots + dots, " ", -1},
+}
+var lastIndexAnyTests = []IndexTest{
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 2},
+ {"abc", "xyz", -1},
+ {"abc", "ab", 1},
+ {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"a.RegExp*", ".(|)*+?^$[]", 8},
+ {dots + dots + dots, " ", -1},
+}
+
+// Execute f on each test case. funcName should be the name of f; it's used
+// in failure reports.
+func runIndexTests(t *testing.T, f func(s, sep string) int, funcName string, testCases []IndexTest) {
+ for _, test := range testCases {
+ actual := f(test.s, test.sep)
+ if actual != test.out {
+ t.Errorf("%s(%q,%q) = %v; want %v", funcName, test.s, test.sep, actual, test.out)
+ }
+ }
+}
+
+func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) }
+func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
+func TestIndexAny(t *testing.T) { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
+func TestLastIndexAny(t *testing.T) { runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) }
+
+type ExplodeTest struct {
+ s string
+ n int
+ a []string
+}
+
+var explodetests = []ExplodeTest{
+ {"", -1, []string{}},
+ {abcd, 4, []string{"a", "b", "c", "d"}},
+ {faces, 3, []string{"☺", "☻", "☹"}},
+ {abcd, 2, []string{"a", "bcd"}},
+}
+
+func TestExplode(t *testing.T) {
+ for _, tt := range explodetests {
+ a := Split(tt.s, "", tt.n)
+ if !eq(a, tt.a) {
+ t.Errorf("explode(%q, %d) = %v; want %v", tt.s, tt.n, a, tt.a)
+ continue
+ }
+ s := Join(a, "")
+ if s != tt.s {
+ t.Errorf(`Join(explode(%q, %d), "") = %q`, tt.s, tt.n, s)
+ }
+ }
+}
+
+type SplitTest struct {
+ s string
+ sep string
+ n int
+ a []string
+}
+
+var splittests = []SplitTest{
+ {abcd, "a", 0, nil},
+ {abcd, "a", -1, []string{"", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1", "2", "3", "4"}},
+ {dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
+ {faces, "☹", -1, []string{"☺☻", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
+ {"1 2", " ", 3, []string{"1", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplit(t *testing.T) {
+ for _, tt := range splittests {
+ a := Split(tt.s, tt.sep, tt.n)
+ if !eq(a, tt.a) {
+ t.Errorf("Split(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, a, tt.a)
+ continue
+ }
+ if tt.n == 0 {
+ continue
+ }
+ s := Join(a, tt.sep)
+ if s != tt.s {
+ t.Errorf("Join(Split(%q, %q, %d), %q) = %q", tt.s, tt.sep, tt.n, tt.sep, s)
+ }
+ }
+}
+
+var splitaftertests = []SplitTest{
+ {abcd, "a", -1, []string{"a", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1,", "2,", "3,", "4"}},
+ {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
+ {faces, "☹", -1, []string{"☺☻☹", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
+ {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
+ {"1 2", " ", 3, []string{"1 ", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
+}
+
+func TestSplitAfter(t *testing.T) {
+ for _, tt := range splitaftertests {
+ a := SplitAfter(tt.s, tt.sep, tt.n)
+ if !eq(a, tt.a) {
+ t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, a, tt.a)
+ continue
+ }
+ s := Join(a, "")
+ if s != tt.s {
+ t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
+ }
+ }
+}
+
+type FieldsTest struct {
+ s string
+ a []string
+}
+
+var fieldstests = []FieldsTest{
+ {"", []string{}},
+ {" ", []string{}},
+ {" \t ", []string{}},
+ {" abc ", []string{"abc"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
+ {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
+ {"\u2000\u2001\u2002", []string{}},
+ {"\n™\t™\n", []string{"™", "™"}},
+ {faces, []string{faces}},
+}
+
+func TestFields(t *testing.T) {
+ for _, tt := range fieldstests {
+ a := Fields(tt.s)
+ if !eq(a, tt.a) {
+ t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)
+ continue
+ }
+ }
+}
+
+func TestFieldsFunc(t *testing.T) {
+ pred := func(c int) bool { return c == 'X' }
+ var fieldsFuncTests = []FieldsTest{
+ {"", []string{}},
+ {"XX", []string{}},
+ {"XXhiXXX", []string{"hi"}},
+ {"aXXbXXXcX", []string{"a", "b", "c"}},
+ }
+ for _, tt := range fieldsFuncTests {
+ a := FieldsFunc(tt.s, pred)
+ if !eq(a, tt.a) {
+ t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)
+ }
+ }
+}
+
+
+// Test case for any function which accepts and returns a single string.
+type StringTest struct {
+ in, out string
+}
+
+// Execute f on each test case. funcName should be the name of f; it's used
+// in failure reports.
+func runStringTests(t *testing.T, f func(string) string, funcName string, testCases []StringTest) {
+ for _, tc := range testCases {
+ actual := f(tc.in)
+ if actual != tc.out {
+ t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out)
+ }
+ }
+}
+
+var upperTests = []StringTest{
+ {"", ""},
+ {"abc", "ABC"},
+ {"AbC123", "ABC123"},
+ {"azAZ09_", "AZAZ09_"},
+ {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
+}
+
+var lowerTests = []StringTest{
+ {"", ""},
+ {"abc", "abc"},
+ {"AbC123", "abc123"},
+ {"azAZ09_", "azaz09_"},
+ {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
+}
+
+const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
+
+var trimSpaceTests = []StringTest{
+ {"", ""},
+ {"abc", "abc"},
+ {space + "abc" + space, "abc"},
+ {" ", ""},
+ {" \t\r\n \t\t\r\r\n\n ", ""},
+ {" \t\r\n x\t\t\r\r\n\n ", "x"},
+ {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},
+ {"1 \t\r\n2", "1 \t\r\n2"},
+ {" x\x80", "x\x80"},
+ {" x\xc0", "x\xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x \xc0", "x \xc0"},
+ {"x \xc0 ", "x \xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"},
+ {"x ☺ ", "x ☺"},
+}
+
+func tenRunes(rune int) string {
+ r := make([]int, 10)
+ for i := range r {
+ r[i] = rune
+ }
+ return string(r)
+}
+
+// User-defined self-inverse mapping function
+func rot13(rune int) int {
+ step := 13
+ if rune >= 'a' && rune <= 'z' {
+ return ((rune - 'a' + step) % 26) + 'a'
+ }
+ if rune >= 'A' && rune <= 'Z' {
+ return ((rune - 'A' + step) % 26) + 'A'
+ }
+ return rune
+}
+
+func TestMap(t *testing.T) {
+ // Run a couple of awful growth/shrinkage tests
+ a := tenRunes('a')
+ // 1. Grow. This triggers two reallocations in Map.
+ maxRune := func(rune int) int { return unicode.MaxRune }
+ m := Map(maxRune, a)
+ expect := tenRunes(unicode.MaxRune)
+ if m != expect {
+ t.Errorf("growing: expected %q got %q", expect, m)
+ }
+
+ // 2. Shrink
+ minRune := func(rune int) int { return 'a' }
+ m = Map(minRune, tenRunes(unicode.MaxRune))
+ expect = a
+ if m != expect {
+ t.Errorf("shrinking: expected %q got %q", expect, m)
+ }
+
+ // 3. Rot13
+ m = Map(rot13, "a to zed")
+ expect = "n gb mrq"
+ if m != expect {
+ t.Errorf("rot13: expected %q got %q", expect, m)
+ }
+
+ // 4. Rot13^2
+ m = Map(rot13, Map(rot13, "a to zed"))
+ expect = "a to zed"
+ if m != expect {
+ t.Errorf("rot13: expected %q got %q", expect, m)
+ }
+
+ // 5. Drop
+ dropNotLatin := func(rune int) int {
+ if unicode.Is(unicode.Latin, rune) {
+ return rune
+ }
+ return -1
+ }
+ m = Map(dropNotLatin, "Hello, 세계")
+ expect = "Hello"
+ if m != expect {
+ t.Errorf("drop: expected %q got %q", expect, m)
+ }
+}
+
+func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
+
+func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }
+
+func TestSpecialCase(t *testing.T) {
+ lower := "abcçdefgğhıijklmnoöprsştuüvyz"
+ upper := "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ"
+ u := ToUpperSpecial(unicode.TurkishCase, upper)
+ if u != upper {
+ t.Errorf("Upper(upper) is %s not %s", u, upper)
+ }
+ u = ToUpperSpecial(unicode.TurkishCase, lower)
+ if u != upper {
+ t.Errorf("Upper(lower) is %s not %s", u, upper)
+ }
+ l := ToLowerSpecial(unicode.TurkishCase, lower)
+ if l != lower {
+ t.Errorf("Lower(lower) is %s not %s", l, lower)
+ }
+ l = ToLowerSpecial(unicode.TurkishCase, upper)
+ if l != lower {
+ t.Errorf("Lower(upper) is %s not %s", l, lower)
+ }
+}
+
+func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
+
+type TrimTest struct {
+ f func(string, string) string
+ in, cutset, out string
+}
+
+var trimTests = []TrimTest{
+ {Trim, "abba", "a", "bb"},
+ {Trim, "abba", "ab", ""},
+ {TrimLeft, "abba", "ab", ""},
+ {TrimRight, "abba", "ab", ""},
+ {TrimLeft, "abba", "a", "bba"},
+ {TrimRight, "abba", "a", "abb"},
+ {Trim, "<tag>", "<>", "tag"},
+ {Trim, "* listitem", " *", "listitem"},
+ {Trim, `"quote"`, `"`, "quote"},
+ {Trim, "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+ //empty string tests
+ {Trim, "abba", "", "abba"},
+ {Trim, "", "123", ""},
+ {Trim, "", "", ""},
+ {TrimLeft, "abba", "", "abba"},
+ {TrimLeft, "", "123", ""},
+ {TrimLeft, "", "", ""},
+ {TrimRight, "abba", "", "abba"},
+ {TrimRight, "", "123", ""},
+ {TrimRight, "", "", ""},
+ {TrimRight, "☺\xc0", "☺", "☺\xc0"},
+}
+
+func TestTrim(t *testing.T) {
+ for _, tc := range trimTests {
+ actual := tc.f(tc.in, tc.cutset)
+ var name string
+ switch tc.f {
+ case Trim:
+ name = "Trim"
+ case TrimLeft:
+ name = "TrimLeft"
+ case TrimRight:
+ name = "TrimRight"
+ default:
+ t.Error("Undefined trim function")
+ }
+ if actual != tc.out {
+ t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
+ }
+ }
+}
+
+type predicate struct {
+ f func(r int) bool
+ name string
+}
+
+var isSpace = predicate{unicode.IsSpace, "IsSpace"}
+var isDigit = predicate{unicode.IsDigit, "IsDigit"}
+var isUpper = predicate{unicode.IsUpper, "IsUpper"}
+var isValidRune = predicate{
+ func(r int) bool {
+ return r != utf8.RuneError
+ },
+ "IsValidRune",
+}
+
+type TrimFuncTest struct {
+ f predicate
+ in, out string
+}
+
+func not(p predicate) predicate {
+ return predicate{
+ func(r int) bool {
+ return !p.f(r)
+ },
+ "not " + p.name,
+ }
+}
+
+var trimFuncTests = []TrimFuncTest{
+ {isSpace, space + " hello " + space, "hello"},
+ {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
+ {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
+ {not(isSpace), "hello" + space + "hello", space},
+ {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"},
+ {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"},
+ {not(isValidRune), "\xc0a\xc0", "a"},
+}
+
+func TestTrimFunc(t *testing.T) {
+ for _, tc := range trimFuncTests {
+ actual := TrimFunc(tc.in, tc.f.f)
+ if actual != tc.out {
+ t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out)
+ }
+ }
+}
+
+type IndexFuncTest struct {
+ in string
+ f predicate
+ first, last int
+}
+
+var indexFuncTests = []IndexFuncTest{
+ {"", isValidRune, -1, -1},
+ {"abc", isDigit, -1, -1},
+ {"0123", isDigit, 0, 3},
+ {"a1b", isDigit, 1, 1},
+ {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes
+ {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},
+ {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},
+ {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},
+
+ // tests of invalid UTF-8
+ {"\x801", isDigit, 1, 1},
+ {"\x80abc", isDigit, -1, -1},
+ {"\xc0a\xc0", isValidRune, 1, 1},
+ {"\xc0a\xc0", not(isValidRune), 0, 2},
+ {"\xc0☺\xc0", not(isValidRune), 0, 4},
+ {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},
+ {"ab\xc0a\xc0cd", not(isValidRune), 2, 4},
+ {"a\xe0\x80cd", not(isValidRune), 1, 2},
+ {"\x80\x80\x80\x80", not(isValidRune), 0, 3},
+}
+
+func TestIndexFunc(t *testing.T) {
+ for _, tc := range indexFuncTests {
+ first := IndexFunc(tc.in, tc.f.f)
+ if first != tc.first {
+ t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first)
+ }
+ last := LastIndexFunc(tc.in, tc.f.f)
+ if last != tc.last {
+ t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last)
+ }
+ }
+}
+
+func equal(m string, s1, s2 string, t *testing.T) bool {
+ if s1 == s2 {
+ return true
+ }
+ e1 := Split(s1, "", -1)
+ e2 := Split(s2, "", -1)
+ for i, c1 := range e1 {
+ if i > len(e2) {
+ break
+ }
+ r1, _ := utf8.DecodeRuneInString(c1)
+ r2, _ := utf8.DecodeRuneInString(e2[i])
+ if r1 != r2 {
+ t.Errorf("%s diff at %d: U+%04X U+%04X", m, i, r1, r2)
+ }
+ }
+ return false
+}
+
+func TestCaseConsistency(t *testing.T) {
+ // Make a string of all the runes.
+ a := make([]int, unicode.MaxRune+1)
+ for i := range a {
+ a[i] = i
+ }
+ s := string(a)
+ // convert the cases.
+ upper := ToUpper(s)
+ lower := ToLower(s)
+
+ // Consistency checks
+ if n := utf8.RuneCountInString(upper); n != unicode.MaxRune+1 {
+ t.Error("rune count wrong in upper:", n)
+ }
+ if n := utf8.RuneCountInString(lower); n != unicode.MaxRune+1 {
+ t.Error("rune count wrong in lower:", n)
+ }
+ if !equal("ToUpper(upper)", ToUpper(upper), upper, t) {
+ t.Error("ToUpper(upper) consistency fail")
+ }
+ if !equal("ToLower(lower)", ToLower(lower), lower, t) {
+ t.Error("ToLower(lower) consistency fail")
+ }
+ /*
+ These fail because of non-one-to-oneness of the data, such as multiple
+ upper case 'I' mapping to 'i'. We comment them out but keep them for
+ interest.
+ For instance: CAPITAL LETTER I WITH DOT ABOVE:
+ unicode.ToUpper(unicode.ToLower('\u0130')) != '\u0130'
+
+ if !equal("ToUpper(lower)", ToUpper(lower), upper, t) {
+ t.Error("ToUpper(lower) consistency fail");
+ }
+ if !equal("ToLower(upper)", ToLower(upper), lower, t) {
+ t.Error("ToLower(upper) consistency fail");
+ }
+ */
+}
+
+type RepeatTest struct {
+ in, out string
+ count int
+}
+
+var RepeatTests = []RepeatTest{
+ {"", "", 0},
+ {"", "", 1},
+ {"", "", 2},
+ {"-", "", 0},
+ {"-", "-", 1},
+ {"-", "----------", 10},
+ {"abc ", "abc abc abc ", 3},
+}
+
+func TestRepeat(t *testing.T) {
+ for _, tt := range RepeatTests {
+ a := Repeat(tt.in, tt.count)
+ if !equal("Repeat(s)", a, tt.out, t) {
+ t.Errorf("Repeat(%v, %d) = %v; want %v", tt.in, tt.count, a, tt.out)
+ continue
+ }
+ }
+}
+
+func runesEqual(a, b []int) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i, r := range a {
+ if r != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+type RunesTest struct {
+ in string
+ out []int
+ lossy bool
+}
+
+var RunesTests = []RunesTest{
+ {"", []int{}, false},
+ {" ", []int{32}, false},
+ {"ABC", []int{65, 66, 67}, false},
+ {"abc", []int{97, 98, 99}, false},
+ {"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
+ {"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
+ {"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
+}
+
+func TestRunes(t *testing.T) {
+ for _, tt := range RunesTests {
+ a := []int(tt.in)
+ if !runesEqual(a, tt.out) {
+ t.Errorf("[]int(%q) = %v; want %v", tt.in, a, tt.out)
+ continue
+ }
+ if !tt.lossy {
+ // can only test reassembly if we didn't lose information
+ s := string(a)
+ if s != tt.in {
+ t.Errorf("string([]int(%q)) = %x; want %x", tt.in, s, tt.in)
+ }
+ }
+ }
+}
+
+func TestReadRune(t *testing.T) {
+ testStrings := []string{"", abcd, faces, commas}
+ for _, s := range testStrings {
+ reader := NewReader(s)
+ res := ""
+ for {
+ r, _, e := reader.ReadRune()
+ if e == os.EOF {
+ break
+ }
+ if e != nil {
+ t.Errorf("Reading %q: %s", s, e)
+ break
+ }
+ res += string(r)
+ }
+ if res != s {
+ t.Errorf("Reader(%q).ReadRune() produced %q", s, res)
+ }
+ }
+}
+
+type ReplaceTest struct {
+ in string
+ old, new string
+ n int
+ out string
+}
+
+var ReplaceTests = []ReplaceTest{
+ {"hello", "l", "L", 0, "hello"},
+ {"hello", "l", "L", -1, "heLLo"},
+ {"hello", "x", "X", -1, "hello"},
+ {"", "x", "X", -1, ""},
+ {"radar", "r", "<r>", -1, "<r>ada<r>"},
+ {"", "", "<>", -1, "<>"},
+ {"banana", "a", "<>", -1, "b<>n<>n<>"},
+ {"banana", "a", "<>", 1, "b<>nana"},
+ {"banana", "a", "<>", 1000, "b<>n<>n<>"},
+ {"banana", "an", "<>", -1, "b<><>a"},
+ {"banana", "ana", "<>", -1, "b<>na"},
+ {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
+ {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
+ {"banana", "", "<>", 1, "<>banana"},
+ {"banana", "a", "a", -1, "banana"},
+ {"banana", "a", "a", 1, "banana"},
+ {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
+}
+
+func TestReplace(t *testing.T) {
+ for _, tt := range ReplaceTests {
+ if s := Replace(tt.in, tt.old, tt.new, tt.n); s != tt.out {
+ t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out)
+ }
+ }
+}
+
+type TitleTest struct {
+ in, out string
+}
+
+var TitleTests = []TitleTest{
+ {"", ""},
+ {"a", "A"},
+ {" aaa aaa aaa ", " Aaa Aaa Aaa "},
+ {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "},
+ {"123a456", "123a456"},
+ {"double-blind", "Double-Blind"},
+ {"ÿøû", "Ÿøû"},
+}
+
+func TestTitle(t *testing.T) {
+ for _, tt := range TitleTests {
+ if s := Title(tt.in); s != tt.out {
+ t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out)
+ }
+ }
+}
+
+type ContainsTest struct {
+ str, substr string
+ expected bool
+}
+
+var ContainsTests = []ContainsTest{
+ {"abc", "bc", true},
+ {"abc", "bcd", false},
+ {"abc", "", true},
+ {"", "a", false},
+}
+
+func TestContains(t *testing.T) {
+ for _, ct := range ContainsTests {
+ if Contains(ct.str, ct.substr) != ct.expected {
+ t.Errorf("Contains(%s, %s) = %v, want %v",
+ ct.str, ct.substr, !ct.expected, ct.expected)
+ }
+ }
+}
diff --git a/libgo/go/sync/cas.c b/libgo/go/sync/cas.c
new file mode 100644
index 000000000..ffcd133cb
--- /dev/null
+++ b/libgo/go/sync/cas.c
@@ -0,0 +1,15 @@
+/* cas.c -- implement sync.cas for Go.
+
+ 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. */
+
+#include <stdint.h>
+
+_Bool cas (int32_t *, int32_t, int32_t) asm ("libgo_sync.sync.cas");
+
+_Bool
+cas (int32_t *ptr, int32_t old, int32_t new)
+{
+ return __sync_bool_compare_and_swap (ptr, old, new);
+}
diff --git a/libgo/go/sync/mutex.go b/libgo/go/sync/mutex.go
new file mode 100644
index 000000000..9a2bb2bb4
--- /dev/null
+++ b/libgo/go/sync/mutex.go
@@ -0,0 +1,61 @@
+// 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.
+
+// The sync package provides basic synchronization primitives
+// such as mutual exclusion locks. Other than the Once type,
+// most are intended for use by low-level library routines.
+// Higher-level synchronization is better done via channels
+// and communication.
+package sync
+
+import "runtime"
+
+func cas(val *uint32, old, new uint32) bool
+
+// A Mutex is a mutual exclusion lock.
+// Mutexes can be created as part of other structures;
+// the zero value for a Mutex is an unlocked mutex.
+type Mutex struct {
+ key uint32
+ sema uint32
+}
+
+// Add delta to *val, and return the new *val in a thread-safe way. If multiple
+// goroutines call xadd on the same val concurrently, the changes will be
+// serialized, and all the deltas will be added in an undefined order.
+func xadd(val *uint32, delta int32) (new uint32) {
+ for {
+ v := *val
+ nv := v + uint32(delta)
+ if cas(val, v, nv) {
+ return nv
+ }
+ }
+ panic("unreached")
+}
+
+// Lock locks m.
+// If the lock is already in use, the calling goroutine
+// blocks until the mutex is available.
+func (m *Mutex) Lock() {
+ if xadd(&m.key, 1) == 1 {
+ // changed from 0 to 1; we hold lock
+ return
+ }
+ runtime.Semacquire(&m.sema)
+}
+
+// Unlock unlocks m.
+// It is a run-time error if m is not locked on entry to Unlock.
+//
+// A locked Mutex is not associated with a particular goroutine.
+// It is allowed for one goroutine to lock a Mutex and then
+// arrange for another goroutine to unlock it.
+func (m *Mutex) Unlock() {
+ if xadd(&m.key, -1) == 0 {
+ // changed from 1 to 0; no contention
+ return
+ }
+ runtime.Semrelease(&m.sema)
+}
diff --git a/libgo/go/sync/mutex_test.go b/libgo/go/sync/mutex_test.go
new file mode 100644
index 000000000..d0e048ed7
--- /dev/null
+++ b/libgo/go/sync/mutex_test.go
@@ -0,0 +1,91 @@
+// 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.
+
+// GOMAXPROCS=10 gotest
+
+package sync_test
+
+import (
+ "runtime"
+ . "sync"
+ "testing"
+)
+
+func HammerSemaphore(s *uint32, loops int, cdone chan bool) {
+ for i := 0; i < loops; i++ {
+ runtime.Semacquire(s)
+ runtime.Semrelease(s)
+ }
+ cdone <- true
+}
+
+func TestSemaphore(t *testing.T) {
+ s := new(uint32)
+ *s = 1
+ c := make(chan bool)
+ for i := 0; i < 10; i++ {
+ go HammerSemaphore(s, 1000, c)
+ }
+ for i := 0; i < 10; i++ {
+ <-c
+ }
+}
+
+func BenchmarkUncontendedSemaphore(b *testing.B) {
+ s := new(uint32)
+ *s = 1
+ HammerSemaphore(s, b.N, make(chan bool, 2))
+}
+
+func BenchmarkContendedSemaphore(b *testing.B) {
+ b.StopTimer()
+ s := new(uint32)
+ *s = 1
+ c := make(chan bool)
+ runtime.GOMAXPROCS(2)
+ b.StartTimer()
+
+ go HammerSemaphore(s, b.N/2, c)
+ go HammerSemaphore(s, b.N/2, c)
+ <-c
+ <-c
+}
+
+
+func HammerMutex(m *Mutex, loops int, cdone chan bool) {
+ for i := 0; i < loops; i++ {
+ m.Lock()
+ m.Unlock()
+ }
+ cdone <- true
+}
+
+func TestMutex(t *testing.T) {
+ m := new(Mutex)
+ c := make(chan bool)
+ for i := 0; i < 10; i++ {
+ go HammerMutex(m, 1000, c)
+ }
+ for i := 0; i < 10; i++ {
+ <-c
+ }
+}
+
+func BenchmarkUncontendedMutex(b *testing.B) {
+ m := new(Mutex)
+ HammerMutex(m, b.N, make(chan bool, 2))
+}
+
+func BenchmarkContendedMutex(b *testing.B) {
+ b.StopTimer()
+ m := new(Mutex)
+ c := make(chan bool)
+ runtime.GOMAXPROCS(2)
+ b.StartTimer()
+
+ go HammerMutex(m, b.N/2, c)
+ go HammerMutex(m, b.N/2, c)
+ <-c
+ <-c
+}
diff --git a/libgo/go/sync/once.go b/libgo/go/sync/once.go
new file mode 100644
index 000000000..8c877cdec
--- /dev/null
+++ b/libgo/go/sync/once.go
@@ -0,0 +1,35 @@
+// 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 sync
+
+// Once is an object that will perform exactly one action.
+type Once struct {
+ m Mutex
+ done bool
+}
+
+// Do calls the function f if and only if the method is being called for the
+// first time with this receiver. In other words, given
+// var once Once
+// if Do(f) is called multiple times, only the first call will invoke f,
+// even if f has a different value in each invocation. A new instance of
+// Once is required for each function to execute.
+//
+// Do is intended for initialization that must be run exactly once. Since f
+// is niladic, it may be necessary to use a function literal to capture the
+// arguments to a function to be invoked by Do:
+// config.once.Do(func() { config.init(filename) })
+//
+// Because no call to Do returns until the one call to f returns, if f causes
+// Do to be called, it will deadlock.
+//
+func (o *Once) Do(f func()) {
+ o.m.Lock()
+ defer o.m.Unlock()
+ if !o.done {
+ o.done = true
+ f()
+ }
+}
diff --git a/libgo/go/sync/once_test.go b/libgo/go/sync/once_test.go
new file mode 100644
index 000000000..155954a49
--- /dev/null
+++ b/libgo/go/sync/once_test.go
@@ -0,0 +1,37 @@
+// 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 sync_test
+
+import (
+ . "sync"
+ "testing"
+)
+
+type one int
+
+func (o *one) Increment() {
+ *o++
+}
+
+func run(once *Once, o *one, c chan bool) {
+ once.Do(func() { o.Increment() })
+ c <- true
+}
+
+func TestOnce(t *testing.T) {
+ o := new(one)
+ once := new(Once)
+ c := make(chan bool)
+ const N = 10
+ for i := 0; i < N; i++ {
+ go run(once, o, c)
+ }
+ for i := 0; i < N; i++ {
+ <-c
+ }
+ if *o != 1 {
+ t.Errorf("once failed: %d is not 1", *o)
+ }
+}
diff --git a/libgo/go/sync/rwmutex.go b/libgo/go/sync/rwmutex.go
new file mode 100644
index 000000000..06fd0b0ff
--- /dev/null
+++ b/libgo/go/sync/rwmutex.go
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync
+
+// An RWMutex is a reader/writer mutual exclusion lock.
+// The lock can be held by an arbitrary number of readers
+// or a single writer.
+// RWMutexes can be created as part of other
+// structures; the zero value for a RWMutex is
+// an unlocked mutex.
+//
+// Writers take priority over Readers: no new RLocks
+// are granted while a blocked Lock call is waiting.
+type RWMutex struct {
+ w Mutex // held if there are pending readers or writers
+ r Mutex // held if the w is being rd
+ readerCount uint32 // number of pending readers
+}
+
+// RLock locks rw for reading.
+// If the lock is already locked for writing or there is a writer already waiting
+// to release the lock, RLock blocks until the writer has released the lock.
+func (rw *RWMutex) RLock() {
+ // Use rw.r.Lock() to block granting the RLock if a goroutine
+ // is waiting for its Lock. This is the prevent starvation of W in
+ // this situation:
+ // A: rw.RLock() // granted
+ // W: rw.Lock() // waiting for rw.w().Lock()
+ // B: rw.RLock() // granted
+ // C: rw.RLock() // granted
+ // B: rw.RUnlock()
+ // ... (new readers come and go indefinitely, W is starving)
+ rw.r.Lock()
+ if xadd(&rw.readerCount, 1) == 1 {
+ // The first reader locks rw.w, so writers will be blocked
+ // while the readers have the RLock.
+ rw.w.Lock()
+ }
+ rw.r.Unlock()
+}
+
+// RUnlock undoes a single RLock call;
+// it does not affect other simultaneous readers.
+// It is a run-time error if rw is not locked for reading
+// on entry to RUnlock.
+func (rw *RWMutex) RUnlock() {
+ if xadd(&rw.readerCount, -1) == 0 {
+ // last reader finished, enable writers
+ rw.w.Unlock()
+ }
+}
+
+// Lock locks rw for writing.
+// If the lock is already locked for reading or writing,
+// Lock blocks until the lock is available.
+// To ensure that the lock eventually becomes available,
+// a blocked Lock call excludes new readers from acquiring
+// the lock.
+func (rw *RWMutex) Lock() {
+ rw.r.Lock()
+ rw.w.Lock()
+ rw.r.Unlock()
+}
+
+// Unlock unlocks rw for writing.
+// It is a run-time error if rw is not locked for writing
+// on entry to Unlock.
+//
+// Like for Mutexes,
+// a locked RWMutex is not associated with a particular goroutine.
+// It is allowed for one goroutine to RLock (Lock) an RWMutex and then
+// arrange for another goroutine to RUnlock (Unlock) it.
+func (rw *RWMutex) Unlock() { rw.w.Unlock() }
diff --git a/libgo/go/sync/rwmutex_test.go b/libgo/go/sync/rwmutex_test.go
new file mode 100644
index 000000000..111bca1e3
--- /dev/null
+++ b/libgo/go/sync/rwmutex_test.go
@@ -0,0 +1,114 @@
+// 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.
+
+// GOMAXPROCS=10 gotest
+
+package sync_test
+
+import (
+ "fmt"
+ "runtime"
+ . "sync"
+ "testing"
+)
+
+func parallelReader(m *RWMutex, clocked, cunlock, cdone chan bool) {
+ m.RLock()
+ clocked <- true
+ <-cunlock
+ m.RUnlock()
+ cdone <- true
+}
+
+func doTestParallelReaders(numReaders, gomaxprocs int) {
+ runtime.GOMAXPROCS(gomaxprocs)
+ var m RWMutex
+ clocked := make(chan bool)
+ cunlock := make(chan bool)
+ cdone := make(chan bool)
+ for i := 0; i < numReaders; i++ {
+ go parallelReader(&m, clocked, cunlock, cdone)
+ }
+ // Wait for all parallel RLock()s to succeed.
+ for i := 0; i < numReaders; i++ {
+ <-clocked
+ }
+ for i := 0; i < numReaders; i++ {
+ cunlock <- true
+ }
+ // Wait for the goroutines to finish.
+ for i := 0; i < numReaders; i++ {
+ <-cdone
+ }
+}
+
+func TestParallelReaders(t *testing.T) {
+ doTestParallelReaders(1, 4)
+ doTestParallelReaders(3, 4)
+ doTestParallelReaders(4, 2)
+}
+
+func reader(rwm *RWMutex, num_iterations int, activity *uint32, cdone chan bool) {
+ for i := 0; i < num_iterations; i++ {
+ rwm.RLock()
+ n := Xadd(activity, 1)
+ if n < 1 || n >= 10000 {
+ panic(fmt.Sprintf("wlock(%d)\n", n))
+ }
+ for i := 0; i < 100; i++ {
+ }
+ Xadd(activity, -1)
+ rwm.RUnlock()
+ }
+ cdone <- true
+}
+
+func writer(rwm *RWMutex, num_iterations int, activity *uint32, cdone chan bool) {
+ for i := 0; i < num_iterations; i++ {
+ rwm.Lock()
+ n := Xadd(activity, 10000)
+ if n != 10000 {
+ panic(fmt.Sprintf("wlock(%d)\n", n))
+ }
+ for i := 0; i < 100; i++ {
+ }
+ Xadd(activity, -10000)
+ rwm.Unlock()
+ }
+ cdone <- true
+}
+
+func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) {
+ runtime.GOMAXPROCS(gomaxprocs)
+ // Number of active readers + 10000 * number of active writers.
+ var activity uint32
+ var rwm RWMutex
+ cdone := make(chan bool)
+ go writer(&rwm, num_iterations, &activity, cdone)
+ var i int
+ for i = 0; i < numReaders/2; i++ {
+ go reader(&rwm, num_iterations, &activity, cdone)
+ }
+ go writer(&rwm, num_iterations, &activity, cdone)
+ for ; i < numReaders; i++ {
+ go reader(&rwm, num_iterations, &activity, cdone)
+ }
+ // Wait for the 2 writers and all readers to finish.
+ for i := 0; i < 2+numReaders; i++ {
+ <-cdone
+ }
+}
+
+func TestRWMutex(t *testing.T) {
+ HammerRWMutex(1, 1, 1000)
+ HammerRWMutex(1, 3, 1000)
+ HammerRWMutex(1, 10, 1000)
+ HammerRWMutex(4, 1, 1000)
+ HammerRWMutex(4, 3, 1000)
+ HammerRWMutex(4, 10, 1000)
+ HammerRWMutex(10, 1, 1000)
+ HammerRWMutex(10, 3, 1000)
+ HammerRWMutex(10, 10, 1000)
+ HammerRWMutex(10, 5, 10000)
+}
diff --git a/libgo/go/sync/xadd_test.go b/libgo/go/sync/xadd_test.go
new file mode 100644
index 000000000..8b2ef76e6
--- /dev/null
+++ b/libgo/go/sync/xadd_test.go
@@ -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.
+
+package sync
+
+func Xadd(val *uint32, delta int32) (new uint32) {
+ return xadd(val, delta)
+}
diff --git a/libgo/go/syslog/syslog.go b/libgo/go/syslog/syslog.go
new file mode 100644
index 000000000..711d5ddc7
--- /dev/null
+++ b/libgo/go/syslog/syslog.go
@@ -0,0 +1,150 @@
+// 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.
+
+// The syslog package provides a simple interface to
+// the system log service. It can send messages to the
+// syslog daemon using UNIX domain sockets, UDP, or
+// TCP connections.
+package syslog
+
+import (
+ "fmt"
+ "log"
+ "net"
+ "os"
+)
+
+type Priority int
+
+const (
+ // From /usr/include/sys/syslog.h.
+ // These are the same on Linux, BSD, and OS X.
+ LOG_EMERG Priority = iota
+ LOG_ALERT
+ LOG_CRIT
+ LOG_ERR
+ LOG_WARNING
+ LOG_NOTICE
+ LOG_INFO
+ LOG_DEBUG
+)
+
+// A Writer is a connection to a syslog server.
+type Writer struct {
+ priority Priority
+ prefix string
+ conn serverConn
+}
+
+type serverConn interface {
+ writeBytes(p Priority, prefix string, b []byte) (int, os.Error)
+ writeString(p Priority, prefix string, s string) (int, os.Error)
+ close() os.Error
+}
+
+type netConn struct {
+ conn net.Conn
+}
+
+// New establishes a new connection to the system log daemon.
+// Each write to the returned writer sends a log message with
+// the given priority and prefix.
+func New(priority Priority, prefix string) (w *Writer, err os.Error) {
+ return Dial("", "", priority, prefix)
+}
+
+// Dial establishes a connection to a log daemon by connecting
+// to address raddr on the network net.
+// Each write to the returned writer sends a log message with
+// the given priority and prefix.
+func Dial(network, raddr string, priority Priority, prefix string) (w *Writer, err os.Error) {
+ if prefix == "" {
+ prefix = os.Args[0]
+ }
+ var conn serverConn
+ if network == "" {
+ conn, err = unixSyslog()
+ } else {
+ var c net.Conn
+ c, err = net.Dial(network, "", raddr)
+ conn = netConn{c}
+ }
+ return &Writer{priority, prefix, conn}, err
+}
+
+// Write sends a log message to the syslog daemon.
+func (w *Writer) Write(b []byte) (int, os.Error) {
+ if w.priority > LOG_DEBUG || w.priority < LOG_EMERG {
+ return 0, os.EINVAL
+ }
+ return w.conn.writeBytes(w.priority, w.prefix, b)
+}
+
+func (w *Writer) writeString(p Priority, s string) (int, os.Error) {
+ return w.conn.writeString(p, w.prefix, s)
+}
+
+func (w *Writer) Close() os.Error { return w.conn.close() }
+
+// Emerg logs a message using the LOG_EMERG priority.
+func (w *Writer) Emerg(m string) (err os.Error) {
+ _, err = w.writeString(LOG_EMERG, m)
+ return err
+}
+// Crit logs a message using the LOG_CRIT priority.
+func (w *Writer) Crit(m string) (err os.Error) {
+ _, err = w.writeString(LOG_CRIT, m)
+ return err
+}
+// ERR logs a message using the LOG_ERR priority.
+func (w *Writer) Err(m string) (err os.Error) {
+ _, err = w.writeString(LOG_ERR, m)
+ return err
+}
+
+// Warning logs a message using the LOG_WARNING priority.
+func (w *Writer) Warning(m string) (err os.Error) {
+ _, err = w.writeString(LOG_WARNING, m)
+ return err
+}
+
+// Notice logs a message using the LOG_NOTICE priority.
+func (w *Writer) Notice(m string) (err os.Error) {
+ _, err = w.writeString(LOG_NOTICE, m)
+ return err
+}
+// Info logs a message using the LOG_INFO priority.
+func (w *Writer) Info(m string) (err os.Error) {
+ _, err = w.writeString(LOG_INFO, m)
+ return err
+}
+// Debug logs a message using the LOG_DEBUG priority.
+func (w *Writer) Debug(m string) (err os.Error) {
+ _, err = w.writeString(LOG_DEBUG, m)
+ return err
+}
+
+func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, os.Error) {
+ return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, b)
+}
+
+func (n netConn) writeString(p Priority, prefix string, s string) (int, os.Error) {
+ return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, s)
+}
+
+func (n netConn) close() os.Error {
+ return n.conn.Close()
+}
+
+// NewLogger provides an object that implements the full log.Logger interface,
+// but sends messages to Syslog instead; flag is passed as is to Logger;
+// priority will be used for all messages sent using this interface.
+// All messages are logged with priority p.
+func NewLogger(p Priority, flag int) *log.Logger {
+ s, err := New(p, "")
+ if err != nil {
+ return nil
+ }
+ return log.New(s, "", flag)
+}
diff --git a/libgo/go/syslog/syslog_c.c b/libgo/go/syslog/syslog_c.c
new file mode 100644
index 000000000..f49b9ffcb
--- /dev/null
+++ b/libgo/go/syslog/syslog_c.c
@@ -0,0 +1,19 @@
+/* syslog_c.c -- call syslog for Go.
+
+ 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 <syslog.h>
+
+/* We need to use a C function to call the syslog function, because we
+ can't represent a C varargs function in Go. */
+
+void syslog_c(int, const char*)
+ asm ("libgo_syslog.syslog.syslog_c");
+
+void
+syslog_c (int priority, const char *msg)
+{
+ syslog (priority, "%s", msg);
+}
diff --git a/libgo/go/syslog/syslog_solaris.go b/libgo/go/syslog/syslog_solaris.go
new file mode 100644
index 000000000..044351dbf
--- /dev/null
+++ b/libgo/go/syslog/syslog_solaris.go
@@ -0,0 +1,37 @@
+// 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.
+
+// gccgo specific implementation of syslog for Solaris. Solaris uses
+// STREAMS to communicate with syslogd. That is enough of a pain that
+// we just call the libc function.
+
+package syslog
+
+import (
+ "fmt"
+ "os"
+ "syscall"
+)
+
+func unixSyslog() (conn serverConn, err os.Error) {
+ return libcConn(0), nil
+}
+
+type libcConn int
+
+func syslog_c(int, *byte)
+
+func (libcConn) writeBytes(p Priority, prefix string, b []byte) (int, os.Error) {
+ syslog_c(int(p), syscall.StringBytePtr(fmt.Sprintf("%s: %s", prefix, b)))
+ return len(b), nil
+}
+
+func (libcConn) writeString(p Priority, prefix string, s string) (int, os.Error) {
+ syslog_c(int(p), syscall.StringBytePtr(fmt.Sprintf("%s: %s", prefix, s)))
+ return len(s), nil
+}
+
+func (libcConn) close() os.Error {
+ return nil
+}
diff --git a/libgo/go/syslog/syslog_test.go b/libgo/go/syslog/syslog_test.go
new file mode 100644
index 000000000..063ab71b4
--- /dev/null
+++ b/libgo/go/syslog/syslog_test.go
@@ -0,0 +1,95 @@
+// 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 syslog
+
+import (
+ "io"
+ "log"
+ "net"
+ "testing"
+)
+
+var serverAddr string
+
+func runSyslog(c net.PacketConn, done chan<- string) {
+ var buf [4096]byte
+ var rcvd string = ""
+ for {
+ n, _, err := c.ReadFrom(buf[0:])
+ if err != nil || n == 0 {
+ break
+ }
+ rcvd += string(buf[0:n])
+ }
+ done <- rcvd
+}
+
+func startServer(done chan<- string) {
+ c, e := net.ListenPacket("udp", "127.0.0.1:0")
+ if e != nil {
+ log.Exitf("net.ListenPacket failed udp :0 %v", e)
+ }
+ serverAddr = c.LocalAddr().String()
+ c.SetReadTimeout(100e6) // 100ms
+ go runSyslog(c, done)
+}
+
+func TestNew(t *testing.T) {
+ s, err := New(LOG_INFO, "")
+ if err != nil {
+ t.Fatalf("New() failed: %s", err)
+ }
+ // Don't send any messages.
+ s.Close()
+}
+
+func TestNewLogger(t *testing.T) {
+ f := NewLogger(LOG_INFO, 0)
+ if f == nil {
+ t.Error("NewLogger() failed")
+ }
+}
+
+func TestDial(t *testing.T) {
+ l, err := Dial("", "", LOG_ERR, "syslog_test")
+ if err != nil {
+ t.Fatalf("Dial() failed: %s", err)
+ }
+ l.Close()
+}
+
+func TestUDPDial(t *testing.T) {
+ done := make(chan string)
+ startServer(done)
+ l, err := Dial("udp", serverAddr, LOG_INFO, "syslog_test")
+ if err != nil {
+ t.Fatalf("syslog.Dial() failed: %s", err)
+ }
+ msg := "udp test"
+ l.Info(msg)
+ expected := "<6>syslog_test: udp test\n"
+ rcvd := <-done
+ if rcvd != expected {
+ t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
+ }
+}
+
+func TestWrite(t *testing.T) {
+ done := make(chan string)
+ startServer(done)
+ l, err := Dial("udp", serverAddr, LOG_ERR, "syslog_test")
+ if err != nil {
+ t.Fatalf("syslog.Dial() failed: %s", err)
+ }
+ msg := "write test"
+ _, err = io.WriteString(l, msg)
+ if err != nil {
+ t.Fatalf("WriteString() failed: %s", err)
+ }
+ expected := "<3>syslog_test: write test\n"
+ rcvd := <-done
+ if rcvd != expected {
+ t.Fatalf("s.Info() = '%q', but wanted '%q'", rcvd, expected)
+ }
+}
diff --git a/libgo/go/syslog/syslog_unix.go b/libgo/go/syslog/syslog_unix.go
new file mode 100644
index 000000000..b4daf88ee
--- /dev/null
+++ b/libgo/go/syslog/syslog_unix.go
@@ -0,0 +1,31 @@
+// 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 syslog
+
+import (
+ "net"
+ "os"
+)
+
+// unixSyslog opens a connection to the syslog daemon running on the
+// local machine using a Unix domain socket.
+
+func unixSyslog() (conn serverConn, err os.Error) {
+ logTypes := []string{"unixgram", "unix"}
+ logPaths := []string{"/dev/log", "/var/run/syslog"}
+ var raddr string
+ for _, network := range logTypes {
+ for _, path := range logPaths {
+ raddr = path
+ conn, err := net.Dial(network, "", raddr)
+ if err != nil {
+ continue
+ } else {
+ return netConn{conn}, nil
+ }
+ }
+ }
+ return nil, os.ErrorString("Unix syslog delivery error")
+}
diff --git a/libgo/go/tabwriter/tabwriter.go b/libgo/go/tabwriter/tabwriter.go
new file mode 100644
index 000000000..848703e8c
--- /dev/null
+++ b/libgo/go/tabwriter/tabwriter.go
@@ -0,0 +1,586 @@
+// 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.
+
+// The tabwriter package implements a write filter (tabwriter.Writer)
+// that translates tabbed columns in input into properly aligned text.
+//
+// The package is using the Elastic Tabstops algorithm described at
+// http://nickgravgaard.com/elastictabstops/index.html.
+//
+package tabwriter
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "utf8"
+)
+
+
+// ----------------------------------------------------------------------------
+// Filter implementation
+
+// A cell represents a segment of text terminated by tabs or line breaks.
+// The text itself is stored in a separate buffer; cell only describes the
+// segment's size in bytes, its width in runes, and whether it's an htab
+// ('\t') terminated cell.
+//
+type cell struct {
+ size int // cell size in bytes
+ width int // cell width in runes
+ htab bool // true if the cell is terminated by an htab ('\t')
+}
+
+
+// A Writer is a filter that inserts padding around tab-delimited
+// columns in its input to align them in the output.
+//
+// The Writer treats incoming bytes as UTF-8 encoded text consisting
+// of cells terminated by (horizontal or vertical) tabs or line
+// breaks (newline or formfeed characters). Cells in adjacent lines
+// constitute a column. The Writer inserts padding as needed to
+// make all cells in a column have the same width, effectively
+// aligning the columns. It assumes that all characters have the
+// same width except for tabs for which a tabwidth must be specified.
+// Note that cells are tab-terminated, not tab-separated: trailing
+// non-tab text at the end of a line does not form a column cell.
+//
+// The Writer assumes that all Unicode code points have the same width;
+// this may not be true in some fonts.
+//
+// If DiscardEmptyColumns is set, empty columns that are terminated
+// entirely by vertical (or "soft") tabs are discarded. Columns
+// terminated by horizontal (or "hard") tabs are not affected by
+// this flag.
+//
+// If a Writer is configured to filter HTML, HTML tags and entities
+// are simply passed through. The widths of tags and entities are
+// assumed to be zero (tags) and one (entities) for formatting purposes.
+//
+// A segment of text may be escaped by bracketing it with Escape
+// characters. The tabwriter passes escaped text segments through
+// unchanged. In particular, it does not interpret any tabs or line
+// breaks within the segment. If the StripEscape flag is set, the
+// Escape characters are stripped from the output; otherwise they
+// are passed through as well. For the purpose of formatting, the
+// width of the escaped text is always computed excluding the Escape
+// characters.
+//
+// The formfeed character ('\f') acts like a newline but it also
+// terminates all columns in the current line (effectively calling
+// Flush). Cells in the next line start new columns. Unless found
+// inside an HTML tag or inside an escaped text segment, formfeed
+// characters appear as newlines in the output.
+//
+// The Writer must buffer input internally, because proper spacing
+// of one line may depend on the cells in future lines. Clients must
+// call Flush when done calling Write.
+//
+type Writer struct {
+ // configuration
+ output io.Writer
+ minwidth int
+ tabwidth int
+ padding int
+ padbytes [8]byte
+ flags uint
+
+ // current state
+ buf bytes.Buffer // collected text excluding tabs or line breaks
+ pos int // buffer position up to which cell.width of incomplete cell has been computed
+ cell cell // current incomplete cell; cell.width is up to buf[pos] excluding ignored sections
+ endChar byte // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
+ lines [][]cell // list of lines; each line is a list of cells
+ widths []int // list of column widths in runes - re-used during formatting
+}
+
+
+func (b *Writer) addLine() { b.lines = append(b.lines, []cell{}) }
+
+
+// Reset the current state.
+func (b *Writer) reset() {
+ b.buf.Reset()
+ b.pos = 0
+ b.cell = cell{}
+ b.endChar = 0
+ b.lines = b.lines[0:0]
+ b.widths = b.widths[0:0]
+ b.addLine()
+}
+
+
+// Internal representation (current state):
+//
+// - all text written is appended to buf; tabs and line breaks are stripped away
+// - at any given time there is a (possibly empty) incomplete cell at the end
+// (the cell starts after a tab or line break)
+// - cell.size is the number of bytes belonging to the cell so far
+// - cell.width is text width in runes of that cell from the start of the cell to
+// position pos; html tags and entities are excluded from this width if html
+// filtering is enabled
+// - the sizes and widths of processed text are kept in the lines list
+// which contains a list of cells for each line
+// - the widths list is a temporary list with current widths used during
+// formatting; it is kept in Writer because it's re-used
+//
+// |<---------- size ---------->|
+// | |
+// |<- width ->|<- ignored ->| |
+// | | | |
+// [---processed---tab------------<tag>...</tag>...]
+// ^ ^ ^
+// | | |
+// buf start of incomplete cell pos
+
+
+// Formatting can be controlled with these flags.
+const (
+ // Ignore html tags and treat entities (starting with '&'
+ // and ending in ';') as single characters (width = 1).
+ FilterHTML uint = 1 << iota
+
+ // Strip Escape characters bracketing escaped text segments
+ // instead of passing them through unchanged with the text.
+ StripEscape
+
+ // Force right-alignment of cell content.
+ // Default is left-alignment.
+ AlignRight
+
+ // Handle empty columns as if they were not present in
+ // the input in the first place.
+ DiscardEmptyColumns
+
+ // Always use tabs for indentation columns (i.e., padding of
+ // leading empty cells on the left) independent of padchar.
+ TabIndent
+
+ // Print a vertical bar ('|') between columns (after formatting).
+ // Discarded colums appear as zero-width columns ("||").
+ Debug
+)
+
+
+// A Writer must be initialized with a call to Init. The first parameter (output)
+// specifies the filter output. The remaining parameters control the formatting:
+//
+// minwidth minimal cell width including any padding
+// tabwidth width of tab characters (equivalent number of spaces)
+// padding padding added to a cell before computing its width
+// padchar ASCII char used for padding
+// if padchar == '\t', the Writer will assume that the
+// width of a '\t' in the formatted output is tabwidth,
+// and cells are left-aligned independent of align_left
+// (for correct-looking results, tabwidth must correspond
+// to the tab width in the viewer displaying the result)
+// flags formatting control
+//
+// To format in tab-separated columns with a tab stop of 8:
+// b.Init(w, 8, 1, 8, '\t', 0);
+//
+// To format in space-separated columns with at least 4 spaces between columns:
+// b.Init(w, 0, 4, 8, ' ', 0);
+//
+func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
+ if minwidth < 0 || tabwidth < 0 || padding < 0 {
+ panic("negative minwidth, tabwidth, or padding")
+ }
+ b.output = output
+ b.minwidth = minwidth
+ b.tabwidth = tabwidth
+ b.padding = padding
+ for i := range b.padbytes {
+ b.padbytes[i] = padchar
+ }
+ if padchar == '\t' {
+ // tab padding enforces left-alignment
+ flags &^= AlignRight
+ }
+ b.flags = flags
+
+ b.reset()
+
+ return b
+}
+
+
+// debugging support (keep code around)
+func (b *Writer) dump() {
+ pos := 0
+ for i, line := range b.lines {
+ print("(", i, ") ")
+ for _, c := range line {
+ print("[", string(b.buf.Bytes()[pos:pos+c.size]), "]")
+ pos += c.size
+ }
+ print("\n")
+ }
+ print("\n")
+}
+
+
+// local error wrapper so we can distinguish os.Errors we want to return
+// as errors from genuine panics (which we don't want to return as errors)
+type osError struct {
+ err os.Error
+}
+
+
+func (b *Writer) write0(buf []byte) {
+ n, err := b.output.Write(buf)
+ if n != len(buf) && err == nil {
+ err = os.EIO
+ }
+ if err != nil {
+ panic(osError{err})
+ }
+}
+
+
+func (b *Writer) writeN(src []byte, n int) {
+ for n > len(src) {
+ b.write0(src)
+ n -= len(src)
+ }
+ b.write0(src[0:n])
+}
+
+
+var (
+ newline = []byte{'\n'}
+ tabs = []byte("\t\t\t\t\t\t\t\t")
+)
+
+
+func (b *Writer) writePadding(textw, cellw int, useTabs bool) {
+ if b.padbytes[0] == '\t' || useTabs {
+ // padding is done with tabs
+ if b.tabwidth == 0 {
+ return // tabs have no width - can't do any padding
+ }
+ // make cellw the smallest multiple of b.tabwidth
+ cellw = (cellw + b.tabwidth - 1) / b.tabwidth * b.tabwidth
+ n := cellw - textw // amount of padding
+ if n < 0 {
+ panic("internal error")
+ }
+ b.writeN(tabs, (n+b.tabwidth-1)/b.tabwidth)
+ return
+ }
+
+ // padding is done with non-tab characters
+ b.writeN(b.padbytes[0:], cellw-textw)
+}
+
+
+var vbar = []byte{'|'}
+
+func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
+ pos = pos0
+ for i := line0; i < line1; i++ {
+ line := b.lines[i]
+
+ // if TabIndent is set, use tabs to pad leading empty cells
+ useTabs := b.flags&TabIndent != 0
+
+ for j, c := range line {
+ if j > 0 && b.flags&Debug != 0 {
+ // indicate column break
+ b.write0(vbar)
+ }
+
+ if c.size == 0 {
+ // empty cell
+ if j < len(b.widths) {
+ b.writePadding(c.width, b.widths[j], useTabs)
+ }
+ } else {
+ // non-empty cell
+ useTabs = false
+ if b.flags&AlignRight == 0 { // align left
+ b.write0(b.buf.Bytes()[pos : pos+c.size])
+ pos += c.size
+ if j < len(b.widths) {
+ b.writePadding(c.width, b.widths[j], false)
+ }
+ } else { // align right
+ if j < len(b.widths) {
+ b.writePadding(c.width, b.widths[j], false)
+ }
+ b.write0(b.buf.Bytes()[pos : pos+c.size])
+ pos += c.size
+ }
+ }
+ }
+
+ if i+1 == len(b.lines) {
+ // last buffered line - we don't have a newline, so just write
+ // any outstanding buffered data
+ b.write0(b.buf.Bytes()[pos : pos+b.cell.size])
+ pos += b.cell.size
+ } else {
+ // not the last line - write newline
+ b.write0(newline)
+ }
+ }
+ return
+}
+
+
+// Format the text between line0 and line1 (excluding line1); pos
+// is the buffer position corresponding to the beginning of line0.
+// Returns the buffer position corresponding to the beginning of
+// line1 and an error, if any.
+//
+func (b *Writer) format(pos0 int, line0, line1 int) (pos int) {
+ pos = pos0
+ column := len(b.widths)
+ for this := line0; this < line1; this++ {
+ line := b.lines[this]
+
+ if column < len(line)-1 {
+ // cell exists in this column => this line
+ // has more cells than the previous line
+ // (the last cell per line is ignored because cells are
+ // tab-terminated; the last cell per line describes the
+ // text before the newline/formfeed and does not belong
+ // to a column)
+
+ // print unprinted lines until beginning of block
+ pos = b.writeLines(pos, line0, this)
+ line0 = this
+
+ // column block begin
+ width := b.minwidth // minimal column width
+ discardable := true // true if all cells in this column are empty and "soft"
+ for ; this < line1; this++ {
+ line = b.lines[this]
+ if column < len(line)-1 {
+ // cell exists in this column
+ c := line[column]
+ // update width
+ if w := c.width + b.padding; w > width {
+ width = w
+ }
+ // update discardable
+ if c.width > 0 || c.htab {
+ discardable = false
+ }
+ } else {
+ break
+ }
+ }
+ // column block end
+
+ // discard empty columns if necessary
+ if discardable && b.flags&DiscardEmptyColumns != 0 {
+ width = 0
+ }
+
+ // format and print all columns to the right of this column
+ // (we know the widths of this column and all columns to the left)
+ b.widths = append(b.widths, width) // push width
+ pos = b.format(pos, line0, this)
+ b.widths = b.widths[0 : len(b.widths)-1] // pop width
+ line0 = this
+ }
+ }
+
+ // print unprinted lines until end
+ return b.writeLines(pos, line0, line1)
+}
+
+
+// Append text to current cell.
+func (b *Writer) append(text []byte) {
+ b.buf.Write(text)
+ b.cell.size += len(text)
+}
+
+
+// Update the cell width.
+func (b *Writer) updateWidth() {
+ b.cell.width += utf8.RuneCount(b.buf.Bytes()[b.pos:b.buf.Len()])
+ b.pos = b.buf.Len()
+}
+
+
+// To escape a text segment, bracket it with Escape characters.
+// For instance, the tab in this string "Ignore this tab: \xff\t\xff"
+// does not terminate a cell and constitutes a single character of
+// width one for formatting purposes.
+//
+// The value 0xff was chosen because it cannot appear in a valid UTF-8 sequence.
+//
+const Escape = '\xff'
+
+
+// Start escaped mode.
+func (b *Writer) startEscape(ch byte) {
+ switch ch {
+ case Escape:
+ b.endChar = Escape
+ case '<':
+ b.endChar = '>'
+ case '&':
+ b.endChar = ';'
+ }
+}
+
+
+// Terminate escaped mode. If the escaped text was an HTML tag, its width
+// is assumed to be zero for formatting purposes; if it was an HTML entity,
+// its width is assumed to be one. In all other cases, the width is the
+// unicode width of the text.
+//
+func (b *Writer) endEscape() {
+ switch b.endChar {
+ case Escape:
+ b.updateWidth()
+ if b.flags&StripEscape == 0 {
+ b.cell.width -= 2 // don't count the Escape chars
+ }
+ case '>': // tag of zero width
+ case ';':
+ b.cell.width++ // entity, count as one rune
+ }
+ b.pos = b.buf.Len()
+ b.endChar = 0
+}
+
+
+// Terminate the current cell by adding it to the list of cells of the
+// current line. Returns the number of cells in that line.
+//
+func (b *Writer) terminateCell(htab bool) int {
+ b.cell.htab = htab
+ line := &b.lines[len(b.lines)-1]
+ *line = append(*line, b.cell)
+ b.cell = cell{}
+ return len(*line)
+}
+
+
+func handlePanic(err *os.Error) {
+ if e := recover(); e != nil {
+ *err = e.(osError).err // re-panics if it's not a local osError
+ }
+}
+
+
+// Flush should be called after the last call to Write to ensure
+// that any data buffered in the Writer is written to output. Any
+// incomplete escape sequence at the end is simply considered
+// complete for formatting purposes.
+//
+func (b *Writer) Flush() (err os.Error) {
+ defer b.reset() // even in the presence of errors
+ defer handlePanic(&err)
+
+ // add current cell if not empty
+ if b.cell.size > 0 {
+ if b.endChar != 0 {
+ // inside escape - terminate it even if incomplete
+ b.endEscape()
+ }
+ b.terminateCell(false)
+ }
+
+ // format contents of buffer
+ b.format(0, 0, len(b.lines))
+
+ return
+}
+
+
+var hbar = []byte("---\n")
+
+// Write writes buf to the writer b.
+// The only errors returned are ones encountered
+// while writing to the underlying output stream.
+//
+func (b *Writer) Write(buf []byte) (n int, err os.Error) {
+ defer handlePanic(&err)
+
+ // split text into cells
+ n = 0
+ for i, ch := range buf {
+ if b.endChar == 0 {
+ // outside escape
+ switch ch {
+ case '\t', '\v', '\n', '\f':
+ // end of cell
+ b.append(buf[n:i])
+ b.updateWidth()
+ n = i + 1 // ch consumed
+ ncells := b.terminateCell(ch == '\t')
+ if ch == '\n' || ch == '\f' {
+ // terminate line
+ b.addLine()
+ if ch == '\f' || ncells == 1 {
+ // A '\f' always forces a flush. Otherwise, if the previous
+ // line has only one cell which does not have an impact on
+ // the formatting of the following lines (the last cell per
+ // line is ignored by format()), thus we can flush the
+ // Writer contents.
+ if err = b.Flush(); err != nil {
+ return
+ }
+ if ch == '\f' && b.flags&Debug != 0 {
+ // indicate section break
+ b.write0(hbar)
+ }
+ }
+ }
+
+ case Escape:
+ // start of escaped sequence
+ b.append(buf[n:i])
+ b.updateWidth()
+ n = i
+ if b.flags&StripEscape != 0 {
+ n++ // strip Escape
+ }
+ b.startEscape(Escape)
+
+ case '<', '&':
+ // possibly an html tag/entity
+ if b.flags&FilterHTML != 0 {
+ // begin of tag/entity
+ b.append(buf[n:i])
+ b.updateWidth()
+ n = i
+ b.startEscape(ch)
+ }
+ }
+
+ } else {
+ // inside escape
+ if ch == b.endChar {
+ // end of tag/entity
+ j := i + 1
+ if ch == Escape && b.flags&StripEscape != 0 {
+ j = i // strip Escape
+ }
+ b.append(buf[n:j])
+ n = i + 1 // ch consumed
+ b.endEscape()
+ }
+ }
+ }
+
+ // append leftover text
+ b.append(buf[n:])
+ n = len(buf)
+ return
+}
+
+
+// NewWriter allocates and initializes a new tabwriter.Writer.
+// The parameters are the same as for the the Init function.
+//
+func NewWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
+ return new(Writer).Init(output, minwidth, tabwidth, padding, padchar, flags)
+}
diff --git a/libgo/go/tabwriter/tabwriter_test.go b/libgo/go/tabwriter/tabwriter_test.go
new file mode 100644
index 000000000..043d9154e
--- /dev/null
+++ b/libgo/go/tabwriter/tabwriter_test.go
@@ -0,0 +1,625 @@
+// 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 tabwriter
+
+import (
+ "io"
+ "os"
+ "testing"
+)
+
+
+type buffer struct {
+ a []byte
+}
+
+
+func (b *buffer) init(n int) { b.a = make([]byte, n)[0:0] }
+
+
+func (b *buffer) clear() { b.a = b.a[0:0] }
+
+
+func (b *buffer) Write(buf []byte) (written int, err os.Error) {
+ n := len(b.a)
+ m := len(buf)
+ if n+m <= cap(b.a) {
+ b.a = b.a[0 : n+m]
+ for i := 0; i < m; i++ {
+ b.a[n+i] = buf[i]
+ }
+ } else {
+ panic("buffer.Write: buffer too small")
+ }
+ return len(buf), nil
+}
+
+
+func (b *buffer) String() string { return string(b.a) }
+
+
+func write(t *testing.T, testname string, w *Writer, src string) {
+ written, err := io.WriteString(w, src)
+ if err != nil {
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- write error: %v\n", testname, src, err)
+ }
+ if written != len(src) {
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- written = %d, len(src) = %d\n", testname, src, written, len(src))
+ }
+}
+
+
+func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected string) {
+ err := w.Flush()
+ if err != nil {
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- flush error: %v\n", testname, src, err)
+ }
+
+ res := b.String()
+ if res != expected {
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- found:\n%q\n--- expected:\n%q\n", testname, src, res, expected)
+ }
+}
+
+
+func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padchar byte, flags uint, src, expected string) {
+ var b buffer
+ b.init(1000)
+
+ var w Writer
+ w.Init(&b, minwidth, tabwidth, padding, padchar, flags)
+
+ // write all at once
+ title := testname + " (written all at once)"
+ b.clear()
+ write(t, title, &w, src)
+ verify(t, title, &w, &b, src, expected)
+
+ // write byte-by-byte
+ title = testname + " (written byte-by-byte)"
+ b.clear()
+ for i := 0; i < len(src); i++ {
+ write(t, title, &w, src[i:i+1])
+ }
+ verify(t, title, &w, &b, src, expected)
+
+ // write using Fibonacci slice sizes
+ title = testname + " (written in fibonacci slices)"
+ b.clear()
+ for i, d := 0, 0; i < len(src); {
+ write(t, title, &w, src[i:i+d])
+ i, d = i+d, d+1
+ if i+d > len(src) {
+ d = len(src) - i
+ }
+ }
+ verify(t, title, &w, &b, src, expected)
+}
+
+
+var tests = []struct {
+ testname string
+ minwidth, tabwidth, padding int
+ padchar byte
+ flags uint
+ src, expected string
+}{
+ {
+ "1a",
+ 8, 0, 1, '.', 0,
+ "",
+ "",
+ },
+
+ {
+ "1a debug",
+ 8, 0, 1, '.', Debug,
+ "",
+ "",
+ },
+
+ {
+ "1b esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "\xff\xff",
+ "",
+ },
+
+ {
+ "1b esc",
+ 8, 0, 1, '.', 0,
+ "\xff\xff",
+ "\xff\xff",
+ },
+
+ {
+ "1c esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "\xff\t\xff",
+ "\t",
+ },
+
+ {
+ "1c esc",
+ 8, 0, 1, '.', 0,
+ "\xff\t\xff",
+ "\xff\t\xff",
+ },
+
+ {
+ "1d esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "\xff\"foo\t\n\tbar\"\xff",
+ "\"foo\t\n\tbar\"",
+ },
+
+ {
+ "1d esc",
+ 8, 0, 1, '.', 0,
+ "\xff\"foo\t\n\tbar\"\xff",
+ "\xff\"foo\t\n\tbar\"\xff",
+ },
+
+ {
+ "1e esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "abc\xff\tdef", // unterminated escape
+ "abc\tdef",
+ },
+
+ {
+ "1e esc",
+ 8, 0, 1, '.', 0,
+ "abc\xff\tdef", // unterminated escape
+ "abc\xff\tdef",
+ },
+
+ {
+ "2",
+ 8, 0, 1, '.', 0,
+ "\n\n\n",
+ "\n\n\n",
+ },
+
+ {
+ "3",
+ 8, 0, 1, '.', 0,
+ "a\nb\nc",
+ "a\nb\nc",
+ },
+
+ {
+ "4a",
+ 8, 0, 1, '.', 0,
+ "\t", // '\t' terminates an empty cell on last line - nothing to print
+ "",
+ },
+
+ {
+ "4b",
+ 8, 0, 1, '.', AlignRight,
+ "\t", // '\t' terminates an empty cell on last line - nothing to print
+ "",
+ },
+
+ {
+ "5",
+ 8, 0, 1, '.', 0,
+ "*\t*",
+ "*.......*",
+ },
+
+ {
+ "5b",
+ 8, 0, 1, '.', 0,
+ "*\t*\n",
+ "*.......*\n",
+ },
+
+ {
+ "5c",
+ 8, 0, 1, '.', 0,
+ "*\t*\t",
+ "*.......*",
+ },
+
+ {
+ "5c debug",
+ 8, 0, 1, '.', Debug,
+ "*\t*\t",
+ "*.......|*",
+ },
+
+ {
+ "5d",
+ 8, 0, 1, '.', AlignRight,
+ "*\t*\t",
+ ".......**",
+ },
+
+ {
+ "6",
+ 8, 0, 1, '.', 0,
+ "\t\n",
+ "........\n",
+ },
+
+ {
+ "7a",
+ 8, 0, 1, '.', 0,
+ "a) foo",
+ "a) foo",
+ },
+
+ {
+ "7b",
+ 8, 0, 1, ' ', 0,
+ "b) foo\tbar",
+ "b) foo bar",
+ },
+
+ {
+ "7c",
+ 8, 0, 1, '.', 0,
+ "c) foo\tbar\t",
+ "c) foo..bar",
+ },
+
+ {
+ "7d",
+ 8, 0, 1, '.', 0,
+ "d) foo\tbar\n",
+ "d) foo..bar\n",
+ },
+
+ {
+ "7e",
+ 8, 0, 1, '.', 0,
+ "e) foo\tbar\t\n",
+ "e) foo..bar.....\n",
+ },
+
+ {
+ "7f",
+ 8, 0, 1, '.', FilterHTML,
+ "f) f&lt;o\t<b>bar</b>\t\n",
+ "f) f&lt;o..<b>bar</b>.....\n",
+ },
+
+ {
+ "7g",
+ 8, 0, 1, '.', FilterHTML,
+ "g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
+ "g) f&lt;o..<b>bar</b>..... non-terminated entity &amp",
+ },
+
+ {
+ "7g debug",
+ 8, 0, 1, '.', FilterHTML | Debug,
+ "g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
+ "g) f&lt;o..|<b>bar</b>.....| non-terminated entity &amp",
+ },
+
+ {
+ "8",
+ 8, 0, 1, '*', 0,
+ "Hello, world!\n",
+ "Hello, world!\n",
+ },
+
+ {
+ "9a",
+ 1, 0, 0, '.', 0,
+ "1\t2\t3\t4\n" +
+ "11\t222\t3333\t44444\n",
+
+ "1.2..3...4\n" +
+ "11222333344444\n",
+ },
+
+ {
+ "9b",
+ 1, 0, 0, '.', FilterHTML,
+ "1\t2<!---\f--->\t3\t4\n" + // \f inside HTML is ignored
+ "11\t222\t3333\t44444\n",
+
+ "1.2<!---\f--->..3...4\n" +
+ "11222333344444\n",
+ },
+
+ {
+ "9c",
+ 1, 0, 0, '.', 0,
+ "1\t2\t3\t4\f" + // \f causes a newline and flush
+ "11\t222\t3333\t44444\n",
+
+ "1234\n" +
+ "11222333344444\n",
+ },
+
+ {
+ "9c debug",
+ 1, 0, 0, '.', Debug,
+ "1\t2\t3\t4\f" + // \f causes a newline and flush
+ "11\t222\t3333\t44444\n",
+
+ "1|2|3|4\n" +
+ "---\n" +
+ "11|222|3333|44444\n",
+ },
+
+ {
+ "10a",
+ 5, 0, 0, '.', 0,
+ "1\t2\t3\t4\n",
+ "1....2....3....4\n",
+ },
+
+ {
+ "10b",
+ 5, 0, 0, '.', 0,
+ "1\t2\t3\t4\t\n",
+ "1....2....3....4....\n",
+ },
+
+ {
+ "11",
+ 8, 0, 1, '.', 0,
+ "本\tb\tc\n" +
+ "aa\t\u672c\u672c\u672c\tcccc\tddddd\n" +
+ "aaa\tbbbb\n",
+
+ "本.......b.......c\n" +
+ "aa......本本本.....cccc....ddddd\n" +
+ "aaa.....bbbb\n",
+ },
+
+ {
+ "12a",
+ 8, 0, 1, ' ', AlignRight,
+ "a\tè\tc\t\n" +
+ "aa\tèèè\tcccc\tddddd\t\n" +
+ "aaa\tèèèè\t\n",
+
+ " a è c\n" +
+ " aa èèè cccc ddddd\n" +
+ " aaa èèèè\n",
+ },
+
+ {
+ "12b",
+ 2, 0, 0, ' ', 0,
+ "a\tb\tc\n" +
+ "aa\tbbb\tcccc\n" +
+ "aaa\tbbbb\n",
+
+ "a b c\n" +
+ "aa bbbcccc\n" +
+ "aaabbbb\n",
+ },
+
+ {
+ "12c",
+ 8, 0, 1, '_', 0,
+ "a\tb\tc\n" +
+ "aa\tbbb\tcccc\n" +
+ "aaa\tbbbb\n",
+
+ "a_______b_______c\n" +
+ "aa______bbb_____cccc\n" +
+ "aaa_____bbbb\n",
+ },
+
+ {
+ "13a",
+ 4, 0, 1, '-', 0,
+ "4444\t日本語\t22\t1\t333\n" +
+ "999999999\t22\n" +
+ "7\t22\n" +
+ "\t\t\t88888888\n" +
+ "\n" +
+ "666666\t666666\t666666\t4444\n" +
+ "1\t1\t999999999\t0000000000\n",
+
+ "4444------日本語-22--1---333\n" +
+ "999999999-22\n" +
+ "7---------22\n" +
+ "------------------88888888\n" +
+ "\n" +
+ "666666-666666-666666----4444\n" +
+ "1------1------999999999-0000000000\n",
+ },
+
+ {
+ "13b",
+ 4, 0, 3, '.', 0,
+ "4444\t333\t22\t1\t333\n" +
+ "999999999\t22\n" +
+ "7\t22\n" +
+ "\t\t\t88888888\n" +
+ "\n" +
+ "666666\t666666\t666666\t4444\n" +
+ "1\t1\t999999999\t0000000000\n",
+
+ "4444........333...22...1...333\n" +
+ "999999999...22\n" +
+ "7...........22\n" +
+ "....................88888888\n" +
+ "\n" +
+ "666666...666666...666666......4444\n" +
+ "1........1........999999999...0000000000\n",
+ },
+
+ {
+ "13c",
+ 8, 8, 1, '\t', FilterHTML,
+ "4444\t333\t22\t1\t333\n" +
+ "999999999\t22\n" +
+ "7\t22\n" +
+ "\t\t\t88888888\n" +
+ "\n" +
+ "666666\t666666\t666666\t4444\n" +
+ "1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n",
+
+ "4444\t\t333\t22\t1\t333\n" +
+ "999999999\t22\n" +
+ "7\t\t22\n" +
+ "\t\t\t\t88888888\n" +
+ "\n" +
+ "666666\t666666\t666666\t\t4444\n" +
+ "1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n",
+ },
+
+ {
+ "14",
+ 1, 0, 2, ' ', AlignRight,
+ ".0\t.3\t2.4\t-5.1\t\n" +
+ "23.0\t12345678.9\t2.4\t-989.4\t\n" +
+ "5.1\t12.0\t2.4\t-7.0\t\n" +
+ ".0\t0.0\t332.0\t8908.0\t\n" +
+ ".0\t-.3\t456.4\t22.1\t\n" +
+ ".0\t1.2\t44.4\t-13.3\t\t",
+
+ " .0 .3 2.4 -5.1\n" +
+ " 23.0 12345678.9 2.4 -989.4\n" +
+ " 5.1 12.0 2.4 -7.0\n" +
+ " .0 0.0 332.0 8908.0\n" +
+ " .0 -.3 456.4 22.1\n" +
+ " .0 1.2 44.4 -13.3",
+ },
+
+ {
+ "14 debug",
+ 1, 0, 2, ' ', AlignRight | Debug,
+ ".0\t.3\t2.4\t-5.1\t\n" +
+ "23.0\t12345678.9\t2.4\t-989.4\t\n" +
+ "5.1\t12.0\t2.4\t-7.0\t\n" +
+ ".0\t0.0\t332.0\t8908.0\t\n" +
+ ".0\t-.3\t456.4\t22.1\t\n" +
+ ".0\t1.2\t44.4\t-13.3\t\t",
+
+ " .0| .3| 2.4| -5.1|\n" +
+ " 23.0| 12345678.9| 2.4| -989.4|\n" +
+ " 5.1| 12.0| 2.4| -7.0|\n" +
+ " .0| 0.0| 332.0| 8908.0|\n" +
+ " .0| -.3| 456.4| 22.1|\n" +
+ " .0| 1.2| 44.4| -13.3|",
+ },
+
+ {
+ "15a",
+ 4, 0, 0, '.', 0,
+ "a\t\tb",
+ "a.......b",
+ },
+
+ {
+ "15b",
+ 4, 0, 0, '.', DiscardEmptyColumns,
+ "a\t\tb", // htabs - do not discard column
+ "a.......b",
+ },
+
+ {
+ "15c",
+ 4, 0, 0, '.', DiscardEmptyColumns,
+ "a\v\vb",
+ "a...b",
+ },
+
+ {
+ "15d",
+ 4, 0, 0, '.', AlignRight | DiscardEmptyColumns,
+ "a\v\vb",
+ "...ab",
+ },
+
+ {
+ "16a",
+ 100, 100, 0, '\t', 0,
+ "a\tb\t\td\n" +
+ "a\tb\t\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+
+ "a\tb\t\td\n" +
+ "a\tb\t\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+ },
+
+ {
+ "16b",
+ 100, 100, 0, '\t', DiscardEmptyColumns,
+ "a\vb\v\vd\n" +
+ "a\vb\v\vd\ve\n" +
+ "a\n" +
+ "a\vb\vc\vd\n" +
+ "a\vb\vc\vd\ve\n",
+
+ "a\tb\td\n" +
+ "a\tb\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+ },
+
+ {
+ "16b debug",
+ 100, 100, 0, '\t', DiscardEmptyColumns | Debug,
+ "a\vb\v\vd\n" +
+ "a\vb\v\vd\ve\n" +
+ "a\n" +
+ "a\vb\vc\vd\n" +
+ "a\vb\vc\vd\ve\n",
+
+ "a\t|b\t||d\n" +
+ "a\t|b\t||d\t|e\n" +
+ "a\n" +
+ "a\t|b\t|c\t|d\n" +
+ "a\t|b\t|c\t|d\t|e\n",
+ },
+
+ {
+ "16c",
+ 100, 100, 0, '\t', DiscardEmptyColumns,
+ "a\tb\t\td\n" + // hard tabs - do not discard column
+ "a\tb\t\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+
+ "a\tb\t\td\n" +
+ "a\tb\t\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+ },
+
+ {
+ "16c debug",
+ 100, 100, 0, '\t', DiscardEmptyColumns | Debug,
+ "a\tb\t\td\n" + // hard tabs - do not discard column
+ "a\tb\t\td\te\n" +
+ "a\n" +
+ "a\tb\tc\td\n" +
+ "a\tb\tc\td\te\n",
+
+ "a\t|b\t|\t|d\n" +
+ "a\t|b\t|\t|d\t|e\n" +
+ "a\n" +
+ "a\t|b\t|c\t|d\n" +
+ "a\t|b\t|c\t|d\t|e\n",
+ },
+}
+
+
+func Test(t *testing.T) {
+ for _, e := range tests {
+ check(t, e.testname, e.minwidth, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected)
+ }
+}
diff --git a/libgo/go/template/format.go b/libgo/go/template/format.go
new file mode 100644
index 000000000..9156b0808
--- /dev/null
+++ b/libgo/go/template/format.go
@@ -0,0 +1,77 @@
+// 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.
+
+// Template library: default formatters
+
+package template
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+)
+
+// StringFormatter formats into the default string representation.
+// It is stored under the name "str" and is the default formatter.
+// You can override the default formatter by storing your default
+// under the name "" in your custom formatter map.
+func StringFormatter(w io.Writer, format string, value ...interface{}) {
+ if len(value) == 1 {
+ if b, ok := value[0].([]byte); ok {
+ w.Write(b)
+ return
+ }
+ }
+ fmt.Fprint(w, value...)
+}
+
+var (
+ esc_quot = []byte("&#34;") // shorter than "&quot;"
+ esc_apos = []byte("&#39;") // shorter than "&apos;"
+ esc_amp = []byte("&amp;")
+ esc_lt = []byte("&lt;")
+ esc_gt = []byte("&gt;")
+)
+
+// HTMLEscape writes to w the properly escaped HTML equivalent
+// of the plain text data s.
+func HTMLEscape(w io.Writer, s []byte) {
+ var esc []byte
+ last := 0
+ for i, c := range s {
+ switch c {
+ case '"':
+ esc = esc_quot
+ case '\'':
+ esc = esc_apos
+ case '&':
+ esc = esc_amp
+ case '<':
+ esc = esc_lt
+ case '>':
+ esc = esc_gt
+ default:
+ continue
+ }
+ w.Write(s[last:i])
+ w.Write(esc)
+ last = i + 1
+ }
+ w.Write(s[last:])
+}
+
+// HTMLFormatter formats arbitrary values for HTML
+func HTMLFormatter(w io.Writer, format string, value ...interface{}) {
+ ok := false
+ var b []byte
+ if len(value) == 1 {
+ b, ok = value[0].([]byte)
+ }
+ if !ok {
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, value...)
+ b = buf.Bytes()
+ }
+ HTMLEscape(w, b)
+}
diff --git a/libgo/go/template/template.go b/libgo/go/template/template.go
new file mode 100644
index 000000000..a67dbf8ad
--- /dev/null
+++ b/libgo/go/template/template.go
@@ -0,0 +1,992 @@
+// 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.
+
+/*
+ Data-driven templates for generating textual output such as
+ HTML.
+
+ Templates are executed by applying them to a data structure.
+ Annotations in the template refer to elements of the data
+ structure (typically a field of a struct or a key in a map)
+ to control execution and derive values to be displayed.
+ The template walks the structure as it executes and the
+ "cursor" @ represents the value at the current location
+ in the structure.
+
+ Data items may be values or pointers; the interface hides the
+ indirection.
+
+ In the following, 'field' is one of several things, according to the data.
+
+ - The name of a field of a struct (result = data.field),
+ - The value stored in a map under that key (result = data[field]), or
+ - The result of invoking a niladic single-valued method with that name
+ (result = data.field())
+
+ Major constructs ({} are metacharacters; [] marks optional elements):
+
+ {# comment }
+
+ A one-line comment.
+
+ {.section field} XXX [ {.or} YYY ] {.end}
+
+ Set @ to the value of the field. It may be an explicit @
+ to stay at the same point in the data. If the field is nil
+ or empty, execute YYY; otherwise execute XXX.
+
+ {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end}
+
+ Like .section, but field must be an array or slice. XXX
+ is executed for each element. If the array is nil or empty,
+ YYY is executed instead. If the {.alternates with} marker
+ is present, ZZZ is executed between iterations of XXX.
+
+ {field}
+ {field1 field2 ...}
+ {field|formatter}
+ {field1 field2...|formatter}
+
+ Insert the value of the fields into the output. Each field is
+ first looked for in the cursor, as in .section and .repeated.
+ If it is not found, the search continues in outer sections
+ until the top level is reached.
+
+ If a formatter is specified, it must be named in the formatter
+ map passed to the template set up routines or in the default
+ set ("html","str","") and is used to process the data for
+ output. The formatter function has signature
+ func(wr io.Writer, formatter string, data ...interface{})
+ where wr is the destination for output, data holds the field
+ values at the instantiation, and formatter is its name at
+ the invocation site. The default formatter just concatenates
+ the string representations of the fields.
+*/
+package template
+
+import (
+ "container/vector"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "reflect"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// Errors returned during parsing and execution. Users may extract the information and reformat
+// if they desire.
+type Error struct {
+ Line int
+ Msg string
+}
+
+func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
+
+// Most of the literals are aces.
+var lbrace = []byte{'{'}
+var rbrace = []byte{'}'}
+var space = []byte{' '}
+var tab = []byte{'\t'}
+
+// The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
+const (
+ tokAlternates = iota
+ tokComment
+ tokEnd
+ tokLiteral
+ tokOr
+ tokRepeated
+ tokSection
+ tokText
+ tokVariable
+)
+
+// FormatterMap is the type describing the mapping from formatter
+// names to the functions that implement them.
+type FormatterMap map[string]func(io.Writer, string, ...interface{})
+
+// Built-in formatters.
+var builtins = FormatterMap{
+ "html": HTMLFormatter,
+ "str": StringFormatter,
+ "": StringFormatter,
+}
+
+// The parsed state of a template is a vector of xxxElement structs.
+// Sections have line numbers so errors can be reported better during execution.
+
+// Plain text.
+type textElement struct {
+ text []byte
+}
+
+// A literal such as .meta-left or .meta-right
+type literalElement struct {
+ text []byte
+}
+
+// A variable invocation to be evaluated
+type variableElement struct {
+ linenum int
+ word []string // The fields in the invocation.
+ formatter string // TODO(r): implement pipelines
+}
+
+// A .section block, possibly with a .or
+type sectionElement struct {
+ linenum int // of .section itself
+ field string // cursor field for this block
+ start int // first element
+ or int // first element of .or block
+ end int // one beyond last element
+}
+
+// A .repeated block, possibly with a .or and a .alternates
+type repeatedElement struct {
+ sectionElement // It has the same structure...
+ altstart int // ... except for alternates
+ altend int
+}
+
+// Template is the type that represents a template definition.
+// It is unchanged after parsing.
+type Template struct {
+ fmap FormatterMap // formatters for variables
+ // Used during parsing:
+ ldelim, rdelim []byte // delimiters; default {}
+ buf []byte // input text to process
+ p int // position in buf
+ linenum int // position in input
+ // Parsed results:
+ elems *vector.Vector
+}
+
+// Internal state for executing a Template. As we evaluate the struct,
+// the data item descends into the fields associated with sections, etc.
+// Parent is used to walk upwards to find variables higher in the tree.
+type state struct {
+ parent *state // parent in hierarchy
+ data reflect.Value // the driver data for this section etc.
+ wr io.Writer // where to send output
+}
+
+func (parent *state) clone(data reflect.Value) *state {
+ return &state{parent, data, parent.wr}
+}
+
+// New creates a new template with the specified formatter map (which
+// may be nil) to define auxiliary functions for formatting variables.
+func New(fmap FormatterMap) *Template {
+ t := new(Template)
+ t.fmap = fmap
+ t.ldelim = lbrace
+ t.rdelim = rbrace
+ t.elems = new(vector.Vector)
+ return t
+}
+
+// Report error and stop executing. The line number must be provided explicitly.
+func (t *Template) execError(st *state, line int, err string, args ...interface{}) {
+ panic(&Error{line, fmt.Sprintf(err, args...)})
+}
+
+// Report error, panic to terminate parsing.
+// The line number comes from the template state.
+func (t *Template) parseError(err string, args ...interface{}) {
+ panic(&Error{t.linenum, fmt.Sprintf(err, args...)})
+}
+
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
+// -- Lexical analysis
+
+// Is c a white space character?
+func white(c uint8) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' }
+
+// Safely, does s[n:n+len(t)] == t?
+func equal(s []byte, n int, t []byte) bool {
+ b := s[n:]
+ if len(t) > len(b) { // not enough space left for a match.
+ return false
+ }
+ for i, c := range t {
+ if c != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// nextItem returns the next item from the input buffer. If the returned
+// item is empty, we are at EOF. The item will be either a
+// delimited string or a non-empty string between delimited
+// strings. Tokens stop at (but include, if plain text) a newline.
+// Action tokens on a line by themselves drop any space on
+// either side, up to and including the newline.
+func (t *Template) nextItem() []byte {
+ startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
+ start := t.p
+ var i int
+ newline := func() {
+ t.linenum++
+ i++
+ }
+ // Leading white space up to but not including newline
+ for i = start; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' || !white(t.buf[i]) {
+ break
+ }
+ }
+ leadingSpace := i > start
+ // What's left is nothing, newline, delimited string, or plain text
+Switch:
+ switch {
+ case i == len(t.buf):
+ // EOF; nothing to do
+ case t.buf[i] == '\n':
+ newline()
+ case equal(t.buf, i, t.ldelim):
+ left := i // Start of left delimiter.
+ right := -1 // Will be (immediately after) right delimiter.
+ haveText := false // Delimiters contain text.
+ i += len(t.ldelim)
+ // Find the end of the action.
+ for ; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' {
+ break
+ }
+ if equal(t.buf, i, t.rdelim) {
+ i += len(t.rdelim)
+ right = i
+ break
+ }
+ haveText = true
+ }
+ if right < 0 {
+ t.parseError("unmatched opening delimiter")
+ return nil
+ }
+ // Is this a special action (starts with '.' or '#') and the only thing on the line?
+ if startOfLine && haveText {
+ firstChar := t.buf[left+len(t.ldelim)]
+ if firstChar == '.' || firstChar == '#' {
+ // It's special and the first thing on the line. Is it the last?
+ for j := right; j < len(t.buf) && white(t.buf[j]); j++ {
+ if t.buf[j] == '\n' {
+ // Yes it is. Drop the surrounding space and return the {.foo}
+ t.linenum++
+ t.p = j + 1
+ return t.buf[left:right]
+ }
+ }
+ }
+ }
+ // No it's not. If there's leading space, return that.
+ if leadingSpace {
+ // not trimming space: return leading white space if there is some.
+ t.p = left
+ return t.buf[start:left]
+ }
+ // Return the word, leave the trailing space.
+ start = left
+ break
+ default:
+ for ; i < len(t.buf); i++ {
+ if t.buf[i] == '\n' {
+ newline()
+ break
+ }
+ if equal(t.buf, i, t.ldelim) {
+ break
+ }
+ }
+ }
+ item := t.buf[start:i]
+ t.p = i
+ return item
+}
+
+// Turn a byte array into a white-space-split array of strings.
+func words(buf []byte) []string {
+ s := make([]string, 0, 5)
+ p := 0 // position in buf
+ // one word per loop
+ for i := 0; ; i++ {
+ // skip white space
+ for ; p < len(buf) && white(buf[p]); p++ {
+ }
+ // grab word
+ start := p
+ for ; p < len(buf) && !white(buf[p]); p++ {
+ }
+ if start == p { // no text left
+ break
+ }
+ s = append(s, string(buf[start:p]))
+ }
+ return s
+}
+
+// Analyze an item and return its token type and, if it's an action item, an array of
+// its constituent words.
+func (t *Template) analyze(item []byte) (tok int, w []string) {
+ // item is known to be non-empty
+ if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
+ tok = tokText
+ return
+ }
+ if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
+ t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
+ return
+ }
+ if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
+ t.parseError("empty directive")
+ return
+ }
+ // Comment
+ if item[len(t.ldelim)] == '#' {
+ tok = tokComment
+ return
+ }
+ // Split into words
+ w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]) // drop final delimiter
+ if len(w) == 0 {
+ t.parseError("empty directive")
+ return
+ }
+ if len(w) > 0 && w[0][0] != '.' {
+ tok = tokVariable
+ return
+ }
+ switch w[0] {
+ case ".meta-left", ".meta-right", ".space", ".tab":
+ tok = tokLiteral
+ return
+ case ".or":
+ tok = tokOr
+ return
+ case ".end":
+ tok = tokEnd
+ return
+ case ".section":
+ if len(w) != 2 {
+ t.parseError("incorrect fields for .section: %s", item)
+ return
+ }
+ tok = tokSection
+ return
+ case ".repeated":
+ if len(w) != 3 || w[1] != "section" {
+ t.parseError("incorrect fields for .repeated: %s", item)
+ return
+ }
+ tok = tokRepeated
+ return
+ case ".alternates":
+ if len(w) != 2 || w[1] != "with" {
+ t.parseError("incorrect fields for .alternates: %s", item)
+ return
+ }
+ tok = tokAlternates
+ return
+ }
+ t.parseError("bad directive: %s", item)
+ return
+}
+
+// -- Parsing
+
+// Allocate a new variable-evaluation element.
+func (t *Template) newVariable(words []string) (v *variableElement) {
+ // The words are tokenized elements from the {item}. The last one may be of
+ // the form "|fmt". For example: {a b c|d}
+ formatter := ""
+ lastWord := words[len(words)-1]
+ bar := strings.Index(lastWord, "|")
+ if bar >= 0 {
+ words[len(words)-1] = lastWord[0:bar]
+ formatter = lastWord[bar+1:]
+ }
+ // Probably ok, so let's build it.
+ v = &variableElement{t.linenum, words, formatter}
+
+ // We could remember the function address here and avoid the lookup later,
+ // but it's more dynamic to let the user change the map contents underfoot.
+ // We do require the name to be present, though.
+
+ // Is it in user-supplied map?
+ if t.fmap != nil {
+ if _, ok := t.fmap[formatter]; ok {
+ return
+ }
+ }
+ // Is it in builtin map?
+ if _, ok := builtins[formatter]; ok {
+ return
+ }
+ t.parseError("unknown formatter: %s", formatter)
+ return
+}
+
+// Grab the next item. If it's simple, just append it to the template.
+// Otherwise return its details.
+func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
+ tok, w = t.analyze(item)
+ done = true // assume for simplicity
+ switch tok {
+ case tokComment:
+ return
+ case tokText:
+ t.elems.Push(&textElement{item})
+ return
+ case tokLiteral:
+ switch w[0] {
+ case ".meta-left":
+ t.elems.Push(&literalElement{t.ldelim})
+ case ".meta-right":
+ t.elems.Push(&literalElement{t.rdelim})
+ case ".space":
+ t.elems.Push(&literalElement{space})
+ case ".tab":
+ t.elems.Push(&literalElement{tab})
+ default:
+ t.parseError("internal error: unknown literal: %s", w[0])
+ }
+ return
+ case tokVariable:
+ t.elems.Push(t.newVariable(w))
+ return
+ }
+ return false, tok, w
+}
+
+// parseRepeated and parseSection are mutually recursive
+
+func (t *Template) parseRepeated(words []string) *repeatedElement {
+ r := new(repeatedElement)
+ t.elems.Push(r)
+ r.linenum = t.linenum
+ r.field = words[2]
+ // Scan section, collecting true and false (.or) blocks.
+ r.start = t.elems.Len()
+ r.or = -1
+ r.altstart = -1
+ r.altend = -1
+Loop:
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ t.parseError("missing .end for .repeated section")
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokEnd:
+ break Loop
+ case tokOr:
+ if r.or >= 0 {
+ t.parseError("extra .or in .repeated section")
+ break Loop
+ }
+ r.altend = t.elems.Len()
+ r.or = t.elems.Len()
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ case tokAlternates:
+ if r.altstart >= 0 {
+ t.parseError("extra .alternates in .repeated section")
+ break Loop
+ }
+ if r.or >= 0 {
+ t.parseError(".alternates inside .or block in .repeated section")
+ break Loop
+ }
+ r.altstart = t.elems.Len()
+ default:
+ t.parseError("internal error: unknown repeated section item: %s", item)
+ break Loop
+ }
+ }
+ if r.altend < 0 {
+ r.altend = t.elems.Len()
+ }
+ r.end = t.elems.Len()
+ return r
+}
+
+func (t *Template) parseSection(words []string) *sectionElement {
+ s := new(sectionElement)
+ t.elems.Push(s)
+ s.linenum = t.linenum
+ s.field = words[1]
+ // Scan section, collecting true and false (.or) blocks.
+ s.start = t.elems.Len()
+ s.or = -1
+Loop:
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ t.parseError("missing .end for .section")
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokEnd:
+ break Loop
+ case tokOr:
+ if s.or >= 0 {
+ t.parseError("extra .or in .section")
+ break Loop
+ }
+ s.or = t.elems.Len()
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ case tokAlternates:
+ t.parseError(".alternates not in .repeated")
+ default:
+ t.parseError("internal error: unknown section item: %s", item)
+ }
+ }
+ s.end = t.elems.Len()
+ return s
+}
+
+func (t *Template) parse() {
+ for {
+ item := t.nextItem()
+ if len(item) == 0 {
+ break
+ }
+ done, tok, w := t.parseSimple(item)
+ if done {
+ continue
+ }
+ switch tok {
+ case tokOr, tokEnd, tokAlternates:
+ t.parseError("unexpected %s", w[0])
+ case tokSection:
+ t.parseSection(w)
+ case tokRepeated:
+ t.parseRepeated(w)
+ default:
+ t.parseError("internal error: bad directive in parse: %s", item)
+ }
+ }
+}
+
+// -- Execution
+
+// Evaluate interfaces and pointers looking for a value that can look up the name, via a
+// struct field, method, or map key, and return the result of the lookup.
+func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value {
+ for v != nil {
+ typ := v.Type()
+ if n := v.Type().NumMethod(); n > 0 {
+ for i := 0; i < n; i++ {
+ m := typ.Method(i)
+ mtyp := m.Type
+ if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 {
+ if !isExported(name) {
+ t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
+ }
+ return v.Method(i).Call(nil)[0]
+ }
+ }
+ }
+ switch av := v.(type) {
+ case *reflect.PtrValue:
+ v = av.Elem()
+ case *reflect.InterfaceValue:
+ v = av.Elem()
+ case *reflect.StructValue:
+ if !isExported(name) {
+ t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
+ }
+ return av.FieldByName(name)
+ case *reflect.MapValue:
+ return av.Elem(reflect.NewValue(name))
+ default:
+ return nil
+ }
+ }
+ return v
+}
+
+// Walk v through pointers and interfaces, extracting the elements within.
+func indirect(v reflect.Value) reflect.Value {
+loop:
+ for v != nil {
+ switch av := v.(type) {
+ case *reflect.PtrValue:
+ v = av.Elem()
+ case *reflect.InterfaceValue:
+ v = av.Elem()
+ default:
+ break loop
+ }
+ }
+ return v
+}
+
+// If the data for this template is a struct, find the named variable.
+// Names of the form a.b.c are walked down the data tree.
+// The special name "@" (the "cursor") denotes the current data.
+// The value coming in (st.data) might need indirecting to reach
+// a struct while the return value is not indirected - that is,
+// it represents the actual named field.
+func (t *Template) findVar(st *state, s string) reflect.Value {
+ if s == "@" {
+ return st.data
+ }
+ data := st.data
+ for _, elem := range strings.Split(s, ".", -1) {
+ // Look up field; data must be a struct or map.
+ data = t.lookup(st, data, elem)
+ if data == nil {
+ return nil
+ }
+ }
+ return data
+}
+
+// Is there no data to look at?
+func empty(v reflect.Value) bool {
+ v = indirect(v)
+ if v == nil {
+ return true
+ }
+ switch v := v.(type) {
+ case *reflect.BoolValue:
+ return v.Get() == false
+ case *reflect.StringValue:
+ return v.Get() == ""
+ case *reflect.StructValue:
+ return false
+ case *reflect.MapValue:
+ return false
+ case *reflect.ArrayValue:
+ return v.Len() == 0
+ case *reflect.SliceValue:
+ return v.Len() == 0
+ }
+ return false
+}
+
+// Look up a variable or method, up through the parent if necessary.
+func (t *Template) varValue(name string, st *state) reflect.Value {
+ field := t.findVar(st, name)
+ if field == nil {
+ if st.parent == nil {
+ t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
+ }
+ return t.varValue(name, st.parent)
+ }
+ return field
+}
+
+// Evaluate a variable, looking up through the parent if necessary.
+// If it has a formatter attached ({var|formatter}) run that too.
+func (t *Template) writeVariable(v *variableElement, st *state) {
+ formatter := v.formatter
+ // Turn the words of the invocation into values.
+ val := make([]interface{}, len(v.word))
+ for i, word := range v.word {
+ val[i] = t.varValue(word, st).Interface()
+ }
+ // is it in user-supplied map?
+ if t.fmap != nil {
+ if fn, ok := t.fmap[formatter]; ok {
+ fn(st.wr, formatter, val...)
+ return
+ }
+ }
+ // is it in builtin map?
+ if fn, ok := builtins[formatter]; ok {
+ fn(st.wr, formatter, val...)
+ return
+ }
+ t.execError(st, v.linenum, "missing formatter %s for variable %s", formatter, v.word[0])
+}
+
+// Execute element i. Return next index to execute.
+func (t *Template) executeElement(i int, st *state) int {
+ switch elem := t.elems.At(i).(type) {
+ case *textElement:
+ st.wr.Write(elem.text)
+ return i + 1
+ case *literalElement:
+ st.wr.Write(elem.text)
+ return i + 1
+ case *variableElement:
+ t.writeVariable(elem, st)
+ return i + 1
+ case *sectionElement:
+ t.executeSection(elem, st)
+ return elem.end
+ case *repeatedElement:
+ t.executeRepeated(elem, st)
+ return elem.end
+ }
+ e := t.elems.At(i)
+ t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.NewValue(e).Interface(), e)
+ return 0
+}
+
+// Execute the template.
+func (t *Template) execute(start, end int, st *state) {
+ for i := start; i < end; {
+ i = t.executeElement(i, st)
+ }
+}
+
+// Execute a .section
+func (t *Template) executeSection(s *sectionElement, st *state) {
+ // Find driver data for this section. It must be in the current struct.
+ field := t.varValue(s.field, st)
+ if field == nil {
+ t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, st.data.Type())
+ }
+ st = st.clone(field)
+ start, end := s.start, s.or
+ if !empty(field) {
+ // Execute the normal block.
+ if end < 0 {
+ end = s.end
+ }
+ } else {
+ // Execute the .or block. If it's missing, do nothing.
+ start, end = s.or, s.end
+ if start < 0 {
+ return
+ }
+ }
+ for i := start; i < end; {
+ i = t.executeElement(i, st)
+ }
+}
+
+// Return the result of calling the Iter method on v, or nil.
+func iter(v reflect.Value) *reflect.ChanValue {
+ for j := 0; j < v.Type().NumMethod(); j++ {
+ mth := v.Type().Method(j)
+ fv := v.Method(j)
+ ft := fv.Type().(*reflect.FuncType)
+ // TODO(rsc): NumIn() should return 0 here, because ft is from a curried FuncValue.
+ if mth.Name != "Iter" || ft.NumIn() != 1 || ft.NumOut() != 1 {
+ continue
+ }
+ ct, ok := ft.Out(0).(*reflect.ChanType)
+ if !ok || ct.Dir()&reflect.RecvDir == 0 {
+ continue
+ }
+ return fv.Call(nil)[0].(*reflect.ChanValue)
+ }
+ return nil
+}
+
+// Execute a .repeated section
+func (t *Template) executeRepeated(r *repeatedElement, st *state) {
+ // Find driver data for this section. It must be in the current struct.
+ field := t.varValue(r.field, st)
+ if field == nil {
+ t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, st.data.Type())
+ }
+ field = indirect(field)
+
+ start, end := r.start, r.or
+ if end < 0 {
+ end = r.end
+ }
+ if r.altstart >= 0 {
+ end = r.altstart
+ }
+ first := true
+
+ // Code common to all the loops.
+ loopBody := func(newst *state) {
+ // .alternates between elements
+ if !first && r.altstart >= 0 {
+ for i := r.altstart; i < r.altend; {
+ i = t.executeElement(i, newst)
+ }
+ }
+ first = false
+ for i := start; i < end; {
+ i = t.executeElement(i, newst)
+ }
+ }
+
+ if array, ok := field.(reflect.ArrayOrSliceValue); ok {
+ for j := 0; j < array.Len(); j++ {
+ loopBody(st.clone(array.Elem(j)))
+ }
+ } else if m, ok := field.(*reflect.MapValue); ok {
+ for _, key := range m.Keys() {
+ loopBody(st.clone(m.Elem(key)))
+ }
+ } else if ch := iter(field); ch != nil {
+ for {
+ e := ch.Recv()
+ if ch.Closed() {
+ break
+ }
+ loopBody(st.clone(e))
+ }
+ } else {
+ t.execError(st, r.linenum, ".repeated: cannot repeat %s (type %s)",
+ r.field, field.Type())
+ }
+
+ if first {
+ // Empty. Execute the .or block, once. If it's missing, do nothing.
+ start, end := r.or, r.end
+ if start >= 0 {
+ newst := st.clone(field)
+ for i := start; i < end; {
+ i = t.executeElement(i, newst)
+ }
+ }
+ return
+ }
+}
+
+// A valid delimiter must contain no white space and be non-empty.
+func validDelim(d []byte) bool {
+ if len(d) == 0 {
+ return false
+ }
+ for _, c := range d {
+ if white(c) {
+ return false
+ }
+ }
+ return true
+}
+
+// checkError is a deferred function to turn a panic with type *Error into a plain error return.
+// Other panics are unexpected and so are re-enabled.
+func checkError(error *os.Error) {
+ if v := recover(); v != nil {
+ if e, ok := v.(*Error); ok {
+ *error = e
+ } else {
+ // runtime errors should crash
+ panic(v)
+ }
+ }
+}
+
+// -- Public interface
+
+// Parse initializes a Template by parsing its definition. The string
+// s contains the template text. If any errors occur, Parse returns
+// the error.
+func (t *Template) Parse(s string) (err os.Error) {
+ if t.elems == nil {
+ return &Error{1, "template not allocated with New"}
+ }
+ if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
+ return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
+ }
+ defer checkError(&err)
+ t.buf = []byte(s)
+ t.p = 0
+ t.linenum = 1
+ t.parse()
+ return nil
+}
+
+// ParseFile is like Parse but reads the template definition from the
+// named file.
+func (t *Template) ParseFile(filename string) (err os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return err
+ }
+ return t.Parse(string(b))
+}
+
+// Execute applies a parsed template to the specified data object,
+// generating output to wr.
+func (t *Template) Execute(data interface{}, wr io.Writer) (err os.Error) {
+ // Extract the driver data.
+ val := reflect.NewValue(data)
+ defer checkError(&err)
+ t.p = 0
+ t.execute(0, t.elems.Len(), &state{nil, val, wr})
+ return nil
+}
+
+// SetDelims sets the left and right delimiters for operations in the
+// template. They are validated during parsing. They could be
+// validated here but it's better to keep the routine simple. The
+// delimiters are very rarely invalid and Parse has the necessary
+// error-handling interface already.
+func (t *Template) SetDelims(left, right string) {
+ t.ldelim = []byte(left)
+ t.rdelim = []byte(right)
+}
+
+// Parse creates a Template with default parameters (such as {} for
+// metacharacters). The string s contains the template text while
+// the formatter map fmap, which may be nil, defines auxiliary functions
+// for formatting variables. The template is returned. If any errors
+// occur, err will be non-nil.
+func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
+ t = New(fmap)
+ err = t.Parse(s)
+ if err != nil {
+ t = nil
+ }
+ return
+}
+
+// ParseFile is a wrapper function that creates a Template with default
+// parameters (such as {} for metacharacters). The filename identifies
+// a file containing the template text, while the formatter map fmap, which
+// may be nil, defines auxiliary functions for formatting variables.
+// The template is returned. If any errors occur, err will be non-nil.
+func ParseFile(filename string, fmap FormatterMap) (t *Template, err os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return Parse(string(b), fmap)
+}
+
+// MustParse is like Parse but panics if the template cannot be parsed.
+func MustParse(s string, fmap FormatterMap) *Template {
+ t, err := Parse(s, fmap)
+ if err != nil {
+ panic("template.MustParse error: " + err.String())
+ }
+ return t
+}
+
+// MustParseFile is like ParseFile but panics if the file cannot be read
+// or the template cannot be parsed.
+func MustParseFile(filename string, fmap FormatterMap) *Template {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ panic("template.MustParseFile error: " + err.String())
+ }
+ return MustParse(string(b), fmap)
+}
diff --git a/libgo/go/template/template_test.go b/libgo/go/template/template_test.go
new file mode 100644
index 000000000..57f297e8f
--- /dev/null
+++ b/libgo/go/template/template_test.go
@@ -0,0 +1,660 @@
+// 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 template
+
+import (
+ "bytes"
+ "container/vector"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "json"
+ "os"
+ "strings"
+ "testing"
+)
+
+type Test struct {
+ in, out, err string
+}
+
+type T struct {
+ Item string
+ Value string
+}
+
+type U struct {
+ Mp map[string]int
+}
+
+type S struct {
+ Header string
+ Integer int
+ Raw string
+ InnerT T
+ InnerPointerT *T
+ Data []T
+ Pdata []*T
+ Empty []*T
+ Emptystring string
+ Null []*T
+ Vec *vector.Vector
+ True bool
+ False bool
+ Mp map[string]string
+ JSON interface{}
+ Innermap U
+ Stringmap map[string]string
+ Bytes []byte
+ Iface interface{}
+ Ifaceptr interface{}
+}
+
+func (s *S) PointerMethod() string { return "ptrmethod!" }
+
+func (s S) ValueMethod() string { return "valmethod!" }
+
+var t1 = T{"ItemNumber1", "ValueNumber1"}
+var t2 = T{"ItemNumber2", "ValueNumber2"}
+
+func uppercase(v interface{}) string {
+ s := v.(string)
+ t := ""
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if 'a' <= c && c <= 'z' {
+ c = c + 'A' - 'a'
+ }
+ t += string(c)
+ }
+ return t
+}
+
+func plus1(v interface{}) string {
+ i := v.(int)
+ return fmt.Sprint(i + 1)
+}
+
+func writer(f func(interface{}) string) func(io.Writer, string, ...interface{}) {
+ return func(w io.Writer, format string, v ...interface{}) {
+ if len(v) != 1 {
+ panic("test writer expected one arg")
+ }
+ io.WriteString(w, f(v[0]))
+ }
+}
+
+func multiword(w io.Writer, format string, value ...interface{}) {
+ for _, v := range value {
+ fmt.Fprintf(w, "<%v>", v)
+ }
+}
+
+var formatters = FormatterMap{
+ "uppercase": writer(uppercase),
+ "+1": writer(plus1),
+ "multiword": multiword,
+}
+
+var tests = []*Test{
+ // Simple
+ &Test{"", "", ""},
+ &Test{"abc", "abc", ""},
+ &Test{"abc\ndef\n", "abc\ndef\n", ""},
+ &Test{" {.meta-left} \n", "{", ""},
+ &Test{" {.meta-right} \n", "}", ""},
+ &Test{" {.space} \n", " ", ""},
+ &Test{" {.tab} \n", "\t", ""},
+ &Test{" {#comment} \n", "", ""},
+ &Test{"\tSome Text\t\n", "\tSome Text\t\n", ""},
+ &Test{" {.meta-right} {.meta-right} {.meta-right} \n", " } } } \n", ""},
+
+ // Variables at top level
+ &Test{
+ in: "{Header}={Integer}\n",
+
+ out: "Header=77\n",
+ },
+
+ // Method at top level
+ &Test{
+ in: "ptrmethod={PointerMethod}\n",
+
+ out: "ptrmethod=ptrmethod!\n",
+ },
+
+ &Test{
+ in: "valmethod={ValueMethod}\n",
+
+ out: "valmethod=valmethod!\n",
+ },
+
+ // Section
+ &Test{
+ in: "{.section Data }\n" +
+ "some text for the section\n" +
+ "{.end}\n",
+
+ out: "some text for the section\n",
+ },
+ &Test{
+ in: "{.section Data }\n" +
+ "{Header}={Integer}\n" +
+ "{.end}\n",
+
+ out: "Header=77\n",
+ },
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{Header}={Integer}\n" +
+ "{.end}\n",
+
+ out: "Header=77\n",
+ },
+ &Test{
+ in: "{.section Pdata }\n" +
+ "data present\n" +
+ "{.or}\n" +
+ "data not present\n" +
+ "{.end}\n",
+
+ out: "data present\n",
+ },
+ &Test{
+ in: "{.section Empty }\n" +
+ "data present\n" +
+ "{.or}\n" +
+ "data not present\n" +
+ "{.end}\n",
+
+ out: "data not present\n",
+ },
+ &Test{
+ in: "{.section Null }\n" +
+ "data present\n" +
+ "{.or}\n" +
+ "data not present\n" +
+ "{.end}\n",
+
+ out: "data not present\n",
+ },
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{Header}={Integer}\n" +
+ "{.section @ }\n" +
+ "{Header}={Integer}\n" +
+ "{.end}\n" +
+ "{.end}\n",
+
+ out: "Header=77\n" +
+ "Header=77\n",
+ },
+
+ &Test{
+ in: "{.section Data}{.end} {Header}\n",
+
+ out: " Header\n",
+ },
+
+ &Test{
+ in: "{.section Integer}{@}{.end}",
+
+ out: "77",
+ },
+
+
+ // Repeated
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{.repeated section @ }\n" +
+ "{Item}={Value}\n" +
+ "{.end}\n" +
+ "{.end}\n",
+
+ out: "ItemNumber1=ValueNumber1\n" +
+ "ItemNumber2=ValueNumber2\n",
+ },
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{.repeated section @ }\n" +
+ "{Item}={Value}\n" +
+ "{.or}\n" +
+ "this should not appear\n" +
+ "{.end}\n" +
+ "{.end}\n",
+
+ out: "ItemNumber1=ValueNumber1\n" +
+ "ItemNumber2=ValueNumber2\n",
+ },
+ &Test{
+ in: "{.section @ }\n" +
+ "{.repeated section Empty }\n" +
+ "{Item}={Value}\n" +
+ "{.or}\n" +
+ "this should appear: empty field\n" +
+ "{.end}\n" +
+ "{.end}\n",
+
+ out: "this should appear: empty field\n",
+ },
+ &Test{
+ in: "{.repeated section Pdata }\n" +
+ "{Item}\n" +
+ "{.alternates with}\n" +
+ "is\nover\nmultiple\nlines\n" +
+ "{.end}\n",
+
+ out: "ItemNumber1\n" +
+ "is\nover\nmultiple\nlines\n" +
+ "ItemNumber2\n",
+ },
+ &Test{
+ in: "{.repeated section Pdata }\n" +
+ "{Item}\n" +
+ "{.alternates with}\n" +
+ "is\nover\nmultiple\nlines\n" +
+ " {.end}\n",
+
+ out: "ItemNumber1\n" +
+ "is\nover\nmultiple\nlines\n" +
+ "ItemNumber2\n",
+ },
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{.repeated section @ }\n" +
+ "{Item}={Value}\n" +
+ "{.alternates with}DIVIDER\n" +
+ "{.or}\n" +
+ "this should not appear\n" +
+ "{.end}\n" +
+ "{.end}\n",
+
+ out: "ItemNumber1=ValueNumber1\n" +
+ "DIVIDER\n" +
+ "ItemNumber2=ValueNumber2\n",
+ },
+ &Test{
+ in: "{.repeated section Vec }\n" +
+ "{@}\n" +
+ "{.end}\n",
+
+ out: "elt1\n" +
+ "elt2\n",
+ },
+ // Same but with a space before {.end}: was a bug.
+ &Test{
+ in: "{.repeated section Vec }\n" +
+ "{@} {.end}\n",
+
+ out: "elt1 elt2 \n",
+ },
+ &Test{
+ in: "{.repeated section Integer}{.end}",
+
+ err: "line 1: .repeated: cannot repeat Integer (type int)",
+ },
+
+ // Nested names
+ &Test{
+ in: "{.section @ }\n" +
+ "{InnerT.Item}={InnerT.Value}\n" +
+ "{.end}",
+
+ out: "ItemNumber1=ValueNumber1\n",
+ },
+ &Test{
+ in: "{.section @ }\n" +
+ "{InnerT.Item}={.section InnerT}{.section Value}{@}{.end}{.end}\n" +
+ "{.end}",
+
+ out: "ItemNumber1=ValueNumber1\n",
+ },
+
+
+ // Formatters
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{Header|uppercase}={Integer|+1}\n" +
+ "{Header|html}={Integer|str}\n" +
+ "{.end}\n",
+
+ out: "HEADER=78\n" +
+ "Header=77\n",
+ },
+
+ &Test{
+ in: "{.section Pdata }\n" +
+ "{Header|uppercase}={Integer Header|multiword}\n" +
+ "{Header|html}={Header Integer|multiword}\n" +
+ "{Header|html}={Header Integer}\n" +
+ "{.end}\n",
+
+ out: "HEADER=<77><Header>\n" +
+ "Header=<Header><77>\n" +
+ "Header=Header77\n",
+ },
+
+ &Test{
+ in: "{Raw}\n" +
+ "{Raw|html}\n",
+
+ out: "&<>!@ #$%^\n" +
+ "&amp;&lt;&gt;!@ #$%^\n",
+ },
+
+ &Test{
+ in: "{.section Emptystring}emptystring{.end}\n" +
+ "{.section Header}header{.end}\n",
+
+ out: "\nheader\n",
+ },
+
+ &Test{
+ in: "{.section True}1{.or}2{.end}\n" +
+ "{.section False}3{.or}4{.end}\n",
+
+ out: "1\n4\n",
+ },
+
+ &Test{
+ in: "{Bytes}",
+
+ out: "hello",
+ },
+
+ // Maps
+
+ &Test{
+ in: "{Mp.mapkey}\n",
+
+ out: "Ahoy!\n",
+ },
+ &Test{
+ in: "{Innermap.Mp.innerkey}\n",
+
+ out: "55\n",
+ },
+ &Test{
+ in: "{.section Innermap}{.section Mp}{innerkey}{.end}{.end}\n",
+
+ out: "55\n",
+ },
+ &Test{
+ in: "{.section JSON}{.repeated section maps}{a}{b}{.end}{.end}\n",
+
+ out: "1234\n",
+ },
+ &Test{
+ in: "{Stringmap.stringkey1}\n",
+
+ out: "stringresult\n",
+ },
+ &Test{
+ in: "{.repeated section Stringmap}\n" +
+ "{@}\n" +
+ "{.end}",
+
+ out: "stringresult\n" +
+ "stringresult\n",
+ },
+ &Test{
+ in: "{.repeated section Stringmap}\n" +
+ "\t{@}\n" +
+ "{.end}",
+
+ out: "\tstringresult\n" +
+ "\tstringresult\n",
+ },
+
+ // Interface values
+
+ &Test{
+ in: "{Iface}",
+
+ out: "[1 2 3]",
+ },
+ &Test{
+ in: "{.repeated section Iface}{@}{.alternates with} {.end}",
+
+ out: "1 2 3",
+ },
+ &Test{
+ in: "{.section Iface}{@}{.end}",
+
+ out: "[1 2 3]",
+ },
+ &Test{
+ in: "{.section Ifaceptr}{Item} {Value}{.end}",
+
+ out: "Item Value",
+ },
+}
+
+func TestAll(t *testing.T) {
+ // Parse
+ testAll(t, func(test *Test) (*Template, os.Error) { return Parse(test.in, formatters) })
+ // ParseFile
+ testAll(t, func(test *Test) (*Template, os.Error) {
+ err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+ if err != nil {
+ t.Error("unexpected write error:", err)
+ return nil, err
+ }
+ return ParseFile("_test/test.tmpl", formatters)
+ })
+ // tmpl.ParseFile
+ testAll(t, func(test *Test) (*Template, os.Error) {
+ err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+ if err != nil {
+ t.Error("unexpected write error:", err)
+ return nil, err
+ }
+ tmpl := New(formatters)
+ return tmpl, tmpl.ParseFile("_test/test.tmpl")
+ })
+}
+
+func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
+ s := new(S)
+ // initialized by hand for clarity.
+ s.Header = "Header"
+ s.Integer = 77
+ s.Raw = "&<>!@ #$%^"
+ s.InnerT = t1
+ s.Data = []T{t1, t2}
+ s.Pdata = []*T{&t1, &t2}
+ s.Empty = []*T{}
+ s.Null = nil
+ s.Vec = new(vector.Vector)
+ s.Vec.Push("elt1")
+ s.Vec.Push("elt2")
+ s.True = true
+ s.False = false
+ s.Mp = make(map[string]string)
+ s.Mp["mapkey"] = "Ahoy!"
+ json.Unmarshal([]byte(`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`), &s.JSON)
+ s.Innermap.Mp = make(map[string]int)
+ s.Innermap.Mp["innerkey"] = 55
+ s.Stringmap = make(map[string]string)
+ s.Stringmap["stringkey1"] = "stringresult" // the same value so repeated section is order-independent
+ s.Stringmap["stringkey2"] = "stringresult"
+ s.Bytes = []byte("hello")
+ s.Iface = []int{1, 2, 3}
+ s.Ifaceptr = &T{"Item", "Value"}
+
+ var buf bytes.Buffer
+ for _, test := range tests {
+ buf.Reset()
+ tmpl, err := parseFunc(test)
+ if err != nil {
+ t.Error("unexpected parse error: ", err)
+ continue
+ }
+ err = tmpl.Execute(s, &buf)
+ if test.err == "" {
+ if err != nil {
+ t.Error("unexpected execute error:", err)
+ }
+ } else {
+ if err == nil {
+ t.Errorf("expected execute error %q, got nil", test.err)
+ } else if err.String() != test.err {
+ t.Errorf("expected execute error %q, got %q", test.err, err.String())
+ }
+ }
+ if buf.String() != test.out {
+ t.Errorf("for %q: expected %q got %q", test.in, test.out, buf.String())
+ }
+ }
+}
+
+func TestMapDriverType(t *testing.T) {
+ mp := map[string]string{"footer": "Ahoy!"}
+ tmpl, err := Parse("template: {footer}", nil)
+ if err != nil {
+ t.Error("unexpected parse error:", err)
+ }
+ var b bytes.Buffer
+ err = tmpl.Execute(mp, &b)
+ if err != nil {
+ t.Error("unexpected execute error:", err)
+ }
+ s := b.String()
+ expected := "template: Ahoy!"
+ if s != expected {
+ t.Errorf("failed passing string as data: expected %q got %q", "template: Ahoy!", s)
+ }
+}
+
+func TestStringDriverType(t *testing.T) {
+ tmpl, err := Parse("template: {@}", nil)
+ if err != nil {
+ t.Error("unexpected parse error:", err)
+ }
+ var b bytes.Buffer
+ err = tmpl.Execute("hello", &b)
+ if err != nil {
+ t.Error("unexpected execute error:", err)
+ }
+ s := b.String()
+ if s != "template: hello" {
+ t.Errorf("failed passing string as data: expected %q got %q", "template: hello", s)
+ }
+}
+
+func TestTwice(t *testing.T) {
+ tmpl, err := Parse("template: {@}", nil)
+ if err != nil {
+ t.Error("unexpected parse error:", err)
+ }
+ var b bytes.Buffer
+ err = tmpl.Execute("hello", &b)
+ if err != nil {
+ t.Error("unexpected parse error:", err)
+ }
+ s := b.String()
+ text := "template: hello"
+ if s != text {
+ t.Errorf("failed passing string as data: expected %q got %q", text, s)
+ }
+ err = tmpl.Execute("hello", &b)
+ if err != nil {
+ t.Error("unexpected parse error:", err)
+ }
+ s = b.String()
+ text += text
+ if s != text {
+ t.Errorf("failed passing string as data: expected %q got %q", text, s)
+ }
+}
+
+func TestCustomDelims(t *testing.T) {
+ // try various lengths. zero should catch error.
+ for i := 0; i < 7; i++ {
+ for j := 0; j < 7; j++ {
+ tmpl := New(nil)
+ // first two chars deliberately the same to test equal left and right delims
+ ldelim := "$!#$%^&"[0:i]
+ rdelim := "$*&^%$!"[0:j]
+ tmpl.SetDelims(ldelim, rdelim)
+ // if braces, this would be template: {@}{.meta-left}{.meta-right}
+ text := "template: " +
+ ldelim + "@" + rdelim +
+ ldelim + ".meta-left" + rdelim +
+ ldelim + ".meta-right" + rdelim
+ err := tmpl.Parse(text)
+ if err != nil {
+ if i == 0 || j == 0 { // expected
+ continue
+ }
+ t.Error("unexpected parse error:", err)
+ } else if i == 0 || j == 0 {
+ t.Errorf("expected parse error for empty delimiter: %d %d %q %q", i, j, ldelim, rdelim)
+ continue
+ }
+ var b bytes.Buffer
+ err = tmpl.Execute("hello", &b)
+ s := b.String()
+ if s != "template: hello"+ldelim+rdelim {
+ t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s)
+ }
+ }
+ }
+}
+
+// Test that a variable evaluates to the field itself and does not further indirection
+func TestVarIndirection(t *testing.T) {
+ s := new(S)
+ // initialized by hand for clarity.
+ s.InnerPointerT = &t1
+
+ var buf bytes.Buffer
+ input := "{.section @}{InnerPointerT}{.end}"
+ tmpl, err := Parse(input, nil)
+ if err != nil {
+ t.Fatal("unexpected parse error:", err)
+ }
+ err = tmpl.Execute(s, &buf)
+ if err != nil {
+ t.Fatal("unexpected execute error:", err)
+ }
+ expect := fmt.Sprintf("%v", &t1) // output should be hex address of t1
+ if buf.String() != expect {
+ t.Errorf("for %q: expected %q got %q", input, expect, buf.String())
+ }
+}
+
+func TestHTMLFormatterWithByte(t *testing.T) {
+ s := "Test string."
+ b := []byte(s)
+ var buf bytes.Buffer
+ HTMLFormatter(&buf, "", b)
+ bs := buf.String()
+ if bs != s {
+ t.Errorf("munged []byte, expected: %s got: %s", s, bs)
+ }
+}
+
+type UF struct {
+ I int
+ s string
+}
+
+func TestReferenceToUnexported(t *testing.T) {
+ u := &UF{3, "hello"}
+ var buf bytes.Buffer
+ input := "{.section @}{I}{s}{.end}"
+ tmpl, err := Parse(input, nil)
+ if err != nil {
+ t.Fatal("unexpected parse error:", err)
+ }
+ err = tmpl.Execute(u, &buf)
+ if err == nil {
+ t.Fatal("expected execute error, got none")
+ }
+ if strings.Index(err.String(), "not exported") < 0 {
+ t.Fatal("expected unexported error; got", err)
+ }
+}
diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go
new file mode 100644
index 000000000..ad938027d
--- /dev/null
+++ b/libgo/go/testing/benchmark.go
@@ -0,0 +1,195 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testing
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "time"
+)
+
+var matchBenchmarks = flag.String("benchmarks", "", "regular expression to select benchmarks to run")
+
+// An internal type but exported because it is cross-package; part of the implementation
+// of gotest.
+type InternalBenchmark struct {
+ Name string
+ F func(b *B)
+}
+
+// B is a type passed to Benchmark functions to manage benchmark
+// timing and to specify the number of iterations to run.
+type B struct {
+ N int
+ benchmark InternalBenchmark
+ ns int64
+ bytes int64
+ start int64
+}
+
+// StartTimer starts timing a test. This function is called automatically
+// before a benchmark starts, but it can also used to resume timing after
+// a call to StopTimer.
+func (b *B) StartTimer() { b.start = time.Nanoseconds() }
+
+// StopTimer stops timing a test. This can be used to pause the timer
+// while performing complex initialization that you don't
+// want to measure.
+func (b *B) StopTimer() {
+ if b.start > 0 {
+ b.ns += time.Nanoseconds() - b.start
+ }
+ b.start = 0
+}
+
+// ResetTimer stops the timer and sets the elapsed benchmark time to zero.
+func (b *B) ResetTimer() {
+ b.start = 0
+ b.ns = 0
+}
+
+// SetBytes records the number of bytes processed in a single operation.
+// If this is called, the benchmark will report ns/op and MB/s.
+func (b *B) SetBytes(n int64) { b.bytes = n }
+
+func (b *B) nsPerOp() int64 {
+ if b.N <= 0 {
+ return 0
+ }
+ return b.ns / int64(b.N)
+}
+
+// runN runs a single benchmark for the specified number of iterations.
+func (b *B) runN(n int) {
+ b.N = n
+ b.ResetTimer()
+ b.StartTimer()
+ b.benchmark.F(b)
+ b.StopTimer()
+}
+
+func min(x, y int) int {
+ if x > y {
+ return y
+ }
+ return x
+}
+
+func max(x, y int) int {
+ if x < y {
+ return y
+ }
+ return x
+}
+
+// roundDown10 rounds a number down to the nearest power of 10.
+func roundDown10(n int) int {
+ var tens = 0
+ // tens = floor(log_10(n))
+ for n > 10 {
+ n = n / 10
+ tens++
+ }
+ // result = 10^tens
+ result := 1
+ for i := 0; i < tens; i++ {
+ result *= 10
+ }
+ return result
+}
+
+// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
+func roundUp(n int) int {
+ base := roundDown10(n)
+ if n < (2 * base) {
+ return 2 * base
+ }
+ if n < (5 * base) {
+ return 5 * base
+ }
+ return 10 * base
+}
+
+// run times the benchmark function. It gradually increases the number
+// of benchmark iterations until the benchmark runs for a second in order
+// to get a reasonable measurement. It prints timing information in this form
+// testing.BenchmarkHello 100000 19 ns/op
+func (b *B) run() BenchmarkResult {
+ // Run the benchmark for a single iteration in case it's expensive.
+ n := 1
+ b.runN(n)
+ // Run the benchmark for at least a second.
+ for b.ns < 1e9 && n < 1e9 {
+ last := n
+ // Predict iterations/sec.
+ if b.nsPerOp() == 0 {
+ n = 1e9
+ } else {
+ n = 1e9 / int(b.nsPerOp())
+ }
+ // Run more iterations than we think we'll need for a second (1.5x).
+ // Don't grow too fast in case we had timing errors previously.
+ // Be sure to run at least one more than last time.
+ n = max(min(n+n/2, 100*last), last+1)
+ // Round up to something easy to read.
+ n = roundUp(n)
+ b.runN(n)
+ }
+ return BenchmarkResult{b.N, b.ns, b.bytes}
+
+}
+
+// The results of a benchmark run.
+type BenchmarkResult struct {
+ N int // The number of iterations.
+ Ns int64 // The total time taken.
+ Bytes int64 // The total number of bytes processed.
+}
+
+func (r BenchmarkResult) NsPerOp() int64 {
+ if r.N <= 0 {
+ return 0
+ }
+ return r.Ns / int64(r.N)
+}
+
+func (r BenchmarkResult) String() string {
+ ns := r.NsPerOp()
+ mb := ""
+ if ns > 0 && r.Bytes > 0 {
+ mb = fmt.Sprintf("\t%7.2f MB/s", (float64(r.Bytes)/1e6)/(float64(ns)/1e9))
+ }
+ return fmt.Sprintf("%8d\t%10d ns/op%s", r.N, ns, mb)
+}
+
+// An internal function but exported because it is cross-package; part of the implementation
+// of gotest.
+func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmarks []InternalBenchmark) {
+ // If no flag was specified, don't run benchmarks.
+ if len(*matchBenchmarks) == 0 {
+ return
+ }
+ for _, Benchmark := range benchmarks {
+ matched, err := matchString(*matchBenchmarks, Benchmark.Name)
+ if err != nil {
+ println("invalid regexp for -benchmarks:", err.String())
+ os.Exit(1)
+ }
+ if !matched {
+ continue
+ }
+ b := &B{benchmark: Benchmark}
+ r := b.run()
+ fmt.Printf("%s\t%v\n", Benchmark.Name, r)
+ }
+}
+
+// Benchmark benchmarks a single function. Useful for creating
+// custom benchmarks that do not use gotest.
+func Benchmark(f func(b *B)) BenchmarkResult {
+ b := &B{benchmark: InternalBenchmark{"", f}}
+ return b.run()
+}
diff --git a/libgo/go/testing/iotest/logger.go b/libgo/go/testing/iotest/logger.go
new file mode 100644
index 000000000..c3bf5df3c
--- /dev/null
+++ b/libgo/go/testing/iotest/logger.go
@@ -0,0 +1,55 @@
+// 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 iotest
+
+import (
+ "io"
+ "log"
+ "os"
+)
+
+type writeLogger struct {
+ prefix string
+ w io.Writer
+}
+
+func (l *writeLogger) Write(p []byte) (n int, err os.Error) {
+ n, err = l.w.Write(p)
+ if err != nil {
+ log.Printf("%s %x: %v", l.prefix, p[0:n], err)
+ } else {
+ log.Printf("%s %x", l.prefix, p[0:n])
+ }
+ return
+}
+
+// NewWriteLogger returns a writer that behaves like w except
+// that it logs (using log.Printf) each write to standard error,
+// printing the prefix and the hexadecimal data written.
+func NewWriteLogger(prefix string, w io.Writer) io.Writer {
+ return &writeLogger{prefix, w}
+}
+
+type readLogger struct {
+ prefix string
+ r io.Reader
+}
+
+func (l *readLogger) Read(p []byte) (n int, err os.Error) {
+ n, err = l.r.Read(p)
+ if err != nil {
+ log.Printf("%s %x: %v", l.prefix, p[0:n], err)
+ } else {
+ log.Printf("%s %x", l.prefix, p[0:n])
+ }
+ return
+}
+
+// NewReadLogger returns a reader that behaves like r except
+// that it logs (using log.Print) each read to standard error,
+// printing the prefix and the hexadecimal data written.
+func NewReadLogger(prefix string, r io.Reader) io.Reader {
+ return &readLogger{prefix, r}
+}
diff --git a/libgo/go/testing/iotest/reader.go b/libgo/go/testing/iotest/reader.go
new file mode 100644
index 000000000..647520a09
--- /dev/null
+++ b/libgo/go/testing/iotest/reader.go
@@ -0,0 +1,69 @@
+// 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.
+
+// The iotest package implements Readers and Writers
+// useful only for testing.
+package iotest
+
+import (
+ "io"
+ "os"
+)
+
+// OneByteReader returns a Reader that implements
+// each non-empty Read by reading one byte from r.
+func OneByteReader(r io.Reader) io.Reader { return &oneByteReader{r} }
+
+type oneByteReader struct {
+ r io.Reader
+}
+
+func (r *oneByteReader) Read(p []byte) (int, os.Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
+ return r.r.Read(p[0:1])
+}
+
+// HalfReader returns a Reader that implements Read
+// by reading half as many requested bytes from r.
+func HalfReader(r io.Reader) io.Reader { return &halfReader{r} }
+
+type halfReader struct {
+ r io.Reader
+}
+
+func (r *halfReader) Read(p []byte) (int, os.Error) {
+ return r.r.Read(p[0 : (len(p)+1)/2])
+}
+
+
+// DataErrReader returns a Reader that returns the final
+// error with the last data read, instead of by itself with
+// zero bytes of data.
+func DataErrReader(r io.Reader) io.Reader { return &dataErrReader{r, nil, make([]byte, 1024)} }
+
+type dataErrReader struct {
+ r io.Reader
+ unread []byte
+ data []byte
+}
+
+func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
+ // loop because first call needs two reads:
+ // one to get data and a second to look for an error.
+ for {
+ if len(r.unread) == 0 {
+ n1, err1 := r.r.Read(r.data)
+ r.unread = r.data[0:n1]
+ err = err1
+ }
+ if n > 0 {
+ break
+ }
+ n = copy(p, r.unread)
+ r.unread = r.unread[n:]
+ }
+ return
+}
diff --git a/libgo/go/testing/iotest/writer.go b/libgo/go/testing/iotest/writer.go
new file mode 100644
index 000000000..71f504ce2
--- /dev/null
+++ b/libgo/go/testing/iotest/writer.go
@@ -0,0 +1,38 @@
+// 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 iotest
+
+import (
+ "io"
+ "os"
+)
+
+// TruncateWriter returns a Writer that writes to w
+// but stops silently after n bytes.
+func TruncateWriter(w io.Writer, n int64) io.Writer {
+ return &truncateWriter{w, n}
+}
+
+type truncateWriter struct {
+ w io.Writer
+ n int64
+}
+
+func (t *truncateWriter) Write(p []byte) (n int, err os.Error) {
+ if t.n <= 0 {
+ return len(p), nil
+ }
+ // real write
+ n = len(p)
+ if int64(n) > t.n {
+ n = int(t.n)
+ }
+ n, err = t.w.Write(p[0:n])
+ t.n -= int64(n)
+ if err == nil {
+ n = len(p)
+ }
+ return
+}
diff --git a/libgo/go/testing/quick/quick.go b/libgo/go/testing/quick/quick.go
new file mode 100644
index 000000000..a5568b048
--- /dev/null
+++ b/libgo/go/testing/quick/quick.go
@@ -0,0 +1,364 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements utility functions to help with black box testing.
+package quick
+
+import (
+ "flag"
+ "fmt"
+ "math"
+ "os"
+ "rand"
+ "reflect"
+ "strings"
+)
+
+var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
+
+// A Generator can generate random values of its own type.
+type Generator interface {
+ // Generate returns a random instance of the type on which it is a
+ // method using the size as a size hint.
+ Generate(rand *rand.Rand, size int) reflect.Value
+}
+
+// randFloat32 generates a random float taking the full range of a float32.
+func randFloat32(rand *rand.Rand) float32 {
+ f := rand.Float64() * math.MaxFloat32
+ if rand.Int()&1 == 1 {
+ f = -f
+ }
+ return float32(f)
+}
+
+// randFloat64 generates a random float taking the full range of a float64.
+func randFloat64(rand *rand.Rand) float64 {
+ f := rand.Float64()
+ if rand.Int()&1 == 1 {
+ f = -f
+ }
+ return f
+}
+
+// randInt64 returns a random integer taking half the range of an int64.
+func randInt64(rand *rand.Rand) int64 { return rand.Int63() - 1<<62 }
+
+// complexSize is the maximum length of arbitrary values that contain other
+// values.
+const complexSize = 50
+
+// Value returns an arbitrary value of the given type.
+// If the type implements the Generator interface, that will be used.
+// Note: in order to create arbitrary values for structs, all the members must be public.
+func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
+ if m, ok := reflect.MakeZero(t).Interface().(Generator); ok {
+ return m.Generate(rand, complexSize), true
+ }
+
+ switch concrete := t.(type) {
+ case *reflect.BoolType:
+ return reflect.NewValue(rand.Int()&1 == 0), true
+ case *reflect.FloatType, *reflect.IntType, *reflect.UintType, *reflect.ComplexType:
+ switch t.Kind() {
+ case reflect.Float32:
+ return reflect.NewValue(randFloat32(rand)), true
+ case reflect.Float64:
+ return reflect.NewValue(randFloat64(rand)), true
+ case reflect.Complex64:
+ return reflect.NewValue(complex(randFloat32(rand), randFloat32(rand))), true
+ case reflect.Complex128:
+ return reflect.NewValue(complex(randFloat64(rand), randFloat64(rand))), true
+ case reflect.Int16:
+ return reflect.NewValue(int16(randInt64(rand))), true
+ case reflect.Int32:
+ return reflect.NewValue(int32(randInt64(rand))), true
+ case reflect.Int64:
+ return reflect.NewValue(randInt64(rand)), true
+ case reflect.Int8:
+ return reflect.NewValue(int8(randInt64(rand))), true
+ case reflect.Int:
+ return reflect.NewValue(int(randInt64(rand))), true
+ case reflect.Uint16:
+ return reflect.NewValue(uint16(randInt64(rand))), true
+ case reflect.Uint32:
+ return reflect.NewValue(uint32(randInt64(rand))), true
+ case reflect.Uint64:
+ return reflect.NewValue(uint64(randInt64(rand))), true
+ case reflect.Uint8:
+ return reflect.NewValue(uint8(randInt64(rand))), true
+ case reflect.Uint:
+ return reflect.NewValue(uint(randInt64(rand))), true
+ case reflect.Uintptr:
+ return reflect.NewValue(uintptr(randInt64(rand))), true
+ }
+ case *reflect.MapType:
+ numElems := rand.Intn(complexSize)
+ m := reflect.MakeMap(concrete)
+ for i := 0; i < numElems; i++ {
+ key, ok1 := Value(concrete.Key(), rand)
+ value, ok2 := Value(concrete.Elem(), rand)
+ if !ok1 || !ok2 {
+ return nil, false
+ }
+ m.SetElem(key, value)
+ }
+ return m, true
+ case *reflect.PtrType:
+ v, ok := Value(concrete.Elem(), rand)
+ if !ok {
+ return nil, false
+ }
+ p := reflect.MakeZero(concrete)
+ p.(*reflect.PtrValue).PointTo(v)
+ return p, true
+ case *reflect.SliceType:
+ numElems := rand.Intn(complexSize)
+ s := reflect.MakeSlice(concrete, numElems, numElems)
+ for i := 0; i < numElems; i++ {
+ v, ok := Value(concrete.Elem(), rand)
+ if !ok {
+ return nil, false
+ }
+ s.Elem(i).SetValue(v)
+ }
+ return s, true
+ case *reflect.StringType:
+ numChars := rand.Intn(complexSize)
+ codePoints := make([]int, numChars)
+ for i := 0; i < numChars; i++ {
+ codePoints[i] = rand.Intn(0x10ffff)
+ }
+ return reflect.NewValue(string(codePoints)), true
+ case *reflect.StructType:
+ s := reflect.MakeZero(t).(*reflect.StructValue)
+ for i := 0; i < s.NumField(); i++ {
+ v, ok := Value(concrete.Field(i).Type, rand)
+ if !ok {
+ return nil, false
+ }
+ s.Field(i).SetValue(v)
+ }
+ return s, true
+ default:
+ return nil, false
+ }
+
+ return
+}
+
+// A Config structure contains options for running a test.
+type Config struct {
+ // MaxCount sets the maximum number of iterations. If zero,
+ // MaxCountScale is used.
+ MaxCount int
+ // MaxCountScale is a non-negative scale factor applied to the default
+ // maximum. If zero, the default is unchanged.
+ MaxCountScale float64
+ // If non-nil, rand is a source of random numbers. Otherwise a default
+ // pseudo-random source will be used.
+ Rand *rand.Rand
+ // If non-nil, Values is a function which generates a slice of arbitrary
+ // Values that are congruent with the arguments to the function being
+ // tested. Otherwise, Values is used to generate the values.
+ Values func([]reflect.Value, *rand.Rand)
+}
+
+var defaultConfig Config
+
+// getRand returns the *rand.Rand to use for a given Config.
+func (c *Config) getRand() *rand.Rand {
+ if c.Rand == nil {
+ return rand.New(rand.NewSource(0))
+ }
+ return c.Rand
+}
+
+// getMaxCount returns the maximum number of iterations to run for a given
+// Config.
+func (c *Config) getMaxCount() (maxCount int) {
+ maxCount = c.MaxCount
+ if maxCount == 0 {
+ if c.MaxCountScale != 0 {
+ maxCount = int(c.MaxCountScale * float64(*defaultMaxCount))
+ } else {
+ maxCount = *defaultMaxCount
+ }
+ }
+
+ return
+}
+
+// A SetupError is the result of an error in the way that check is being
+// used, independent of the functions being tested.
+type SetupError string
+
+func (s SetupError) String() string { return string(s) }
+
+// A CheckError is the result of Check finding an error.
+type CheckError struct {
+ Count int
+ In []interface{}
+}
+
+func (s *CheckError) String() string {
+ return fmt.Sprintf("#%d: failed on input %s", s.Count, toString(s.In))
+}
+
+// A CheckEqualError is the result CheckEqual finding an error.
+type CheckEqualError struct {
+ CheckError
+ Out1 []interface{}
+ Out2 []interface{}
+}
+
+func (s *CheckEqualError) String() string {
+ return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", s.Count, toString(s.In), toString(s.Out1), toString(s.Out2))
+}
+
+// Check looks for an input to f, any function that returns bool,
+// such that f returns false. It calls f repeatedly, with arbitrary
+// values for each argument. If f returns false on a given input,
+// Check returns that input as a *CheckError.
+// For example:
+//
+// func TestOddMultipleOfThree(t *testing.T) {
+// f := func(x int) bool {
+// y := OddMultipleOfThree(x)
+// return y%2 == 1 && y%3 == 0
+// }
+// if err := quick.Check(f, nil); err != nil {
+// t.Error(err)
+// }
+// }
+func Check(function interface{}, config *Config) (err os.Error) {
+ if config == nil {
+ config = &defaultConfig
+ }
+
+ f, fType, ok := functionAndType(function)
+ if !ok {
+ err = SetupError("argument is not a function")
+ return
+ }
+
+ if fType.NumOut() != 1 {
+ err = SetupError("function returns more than one value.")
+ return
+ }
+ if _, ok := fType.Out(0).(*reflect.BoolType); !ok {
+ err = SetupError("function does not return a bool")
+ return
+ }
+
+ arguments := make([]reflect.Value, fType.NumIn())
+ rand := config.getRand()
+ maxCount := config.getMaxCount()
+
+ for i := 0; i < maxCount; i++ {
+ err = arbitraryValues(arguments, fType, config, rand)
+ if err != nil {
+ return
+ }
+
+ if !f.Call(arguments)[0].(*reflect.BoolValue).Get() {
+ err = &CheckError{i + 1, toInterfaces(arguments)}
+ return
+ }
+ }
+
+ return
+}
+
+// CheckEqual looks for an input on which f and g return different results.
+// It calls f and g repeatedly with arbitrary values for each argument.
+// If f and g return different answers, CheckEqual returns a *CheckEqualError
+// describing the input and the outputs.
+func CheckEqual(f, g interface{}, config *Config) (err os.Error) {
+ if config == nil {
+ config = &defaultConfig
+ }
+
+ x, xType, ok := functionAndType(f)
+ if !ok {
+ err = SetupError("f is not a function")
+ return
+ }
+ y, yType, ok := functionAndType(g)
+ if !ok {
+ err = SetupError("g is not a function")
+ return
+ }
+
+ if xType != yType {
+ err = SetupError("functions have different types")
+ return
+ }
+
+ arguments := make([]reflect.Value, xType.NumIn())
+ rand := config.getRand()
+ maxCount := config.getMaxCount()
+
+ for i := 0; i < maxCount; i++ {
+ err = arbitraryValues(arguments, xType, config, rand)
+ if err != nil {
+ return
+ }
+
+ xOut := toInterfaces(x.Call(arguments))
+ yOut := toInterfaces(y.Call(arguments))
+
+ if !reflect.DeepEqual(xOut, yOut) {
+ err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
+ return
+ }
+ }
+
+ return
+}
+
+// arbitraryValues writes Values to args such that args contains Values
+// suitable for calling f.
+func arbitraryValues(args []reflect.Value, f *reflect.FuncType, config *Config, rand *rand.Rand) (err os.Error) {
+ if config.Values != nil {
+ config.Values(args, rand)
+ return
+ }
+
+ for j := 0; j < len(args); j++ {
+ var ok bool
+ args[j], ok = Value(f.In(j), rand)
+ if !ok {
+ err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j))
+ return
+ }
+ }
+
+ return
+}
+
+func functionAndType(f interface{}) (v *reflect.FuncValue, t *reflect.FuncType, ok bool) {
+ v, ok = reflect.NewValue(f).(*reflect.FuncValue)
+ if !ok {
+ return
+ }
+ t = v.Type().(*reflect.FuncType)
+ return
+}
+
+func toInterfaces(values []reflect.Value) []interface{} {
+ ret := make([]interface{}, len(values))
+ for i, v := range values {
+ ret[i] = v.Interface()
+ }
+ return ret
+}
+
+func toString(interfaces []interface{}) string {
+ s := make([]string, len(interfaces))
+ for i, v := range interfaces {
+ s[i] = fmt.Sprintf("%#v", v)
+ }
+ return strings.Join(s, ", ")
+}
diff --git a/libgo/go/testing/quick/quick_test.go b/libgo/go/testing/quick/quick_test.go
new file mode 100644
index 000000000..b126e4a16
--- /dev/null
+++ b/libgo/go/testing/quick/quick_test.go
@@ -0,0 +1,147 @@
+// 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 quick
+
+import (
+ "rand"
+ "reflect"
+ "testing"
+ "os"
+)
+
+func fBool(a bool) bool { return a }
+
+func fFloat32(a float32) float32 { return a }
+
+func fFloat64(a float64) float64 { return a }
+
+func fComplex64(a complex64) complex64 { return a }
+
+func fComplex128(a complex128) complex128 { return a }
+
+func fInt16(a int16) int16 { return a }
+
+func fInt32(a int32) int32 { return a }
+
+func fInt64(a int64) int64 { return a }
+
+func fInt8(a int8) int8 { return a }
+
+func fInt(a int) int { return a }
+
+func fUInt8(a uint8) uint8 { return a }
+
+func fMap(a map[int]int) map[int]int { return a }
+
+func fSlice(a []byte) []byte { return a }
+
+func fString(a string) string { return a }
+
+type TestStruct struct {
+ A int
+ B string
+}
+
+func fStruct(a TestStruct) TestStruct { return a }
+
+func fUint16(a uint16) uint16 { return a }
+
+func fUint32(a uint32) uint32 { return a }
+
+func fUint64(a uint64) uint64 { return a }
+
+func fUint8(a uint8) uint8 { return a }
+
+func fUint(a uint) uint { return a }
+
+func fUintptr(a uintptr) uintptr { return a }
+
+func fIntptr(a *int) *int {
+ b := *a
+ return &b
+}
+
+func reportError(property string, err os.Error, t *testing.T) {
+ if err != nil {
+ t.Errorf("%s: %s", property, err)
+ }
+}
+
+func TestCheckEqual(t *testing.T) {
+ reportError("fBool", CheckEqual(fBool, fBool, nil), t)
+ reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t)
+ reportError("fFloat64", CheckEqual(fFloat64, fFloat64, nil), t)
+ reportError("fComplex64", CheckEqual(fComplex64, fComplex64, nil), t)
+ reportError("fComplex128", CheckEqual(fComplex128, fComplex128, nil), t)
+ reportError("fInt16", CheckEqual(fInt16, fInt16, nil), t)
+ reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t)
+ reportError("fInt64", CheckEqual(fInt64, fInt64, nil), t)
+ reportError("fInt8", CheckEqual(fInt8, fInt8, nil), t)
+ reportError("fInt", CheckEqual(fInt, fInt, nil), t)
+ reportError("fUInt8", CheckEqual(fUInt8, fUInt8, nil), t)
+ reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t)
+ reportError("fMap", CheckEqual(fMap, fMap, nil), t)
+ reportError("fSlice", CheckEqual(fSlice, fSlice, nil), t)
+ reportError("fString", CheckEqual(fString, fString, nil), t)
+ reportError("fStruct", CheckEqual(fStruct, fStruct, nil), t)
+ reportError("fUint16", CheckEqual(fUint16, fUint16, nil), t)
+ reportError("fUint32", CheckEqual(fUint32, fUint32, nil), t)
+ reportError("fUint64", CheckEqual(fUint64, fUint64, nil), t)
+ reportError("fUint8", CheckEqual(fUint8, fUint8, nil), t)
+ reportError("fUint", CheckEqual(fUint, fUint, nil), t)
+ reportError("fUintptr", CheckEqual(fUintptr, fUintptr, nil), t)
+ reportError("fIntptr", CheckEqual(fIntptr, fIntptr, nil), t)
+}
+
+// This tests that ArbitraryValue is working by checking that all the arbitrary
+// values of type MyStruct have x = 42.
+type myStruct struct {
+ x int
+}
+
+func (m myStruct) Generate(r *rand.Rand, _ int) reflect.Value {
+ return reflect.NewValue(myStruct{x: 42})
+}
+
+func myStructProperty(in myStruct) bool { return in.x == 42 }
+
+func TestCheckProperty(t *testing.T) {
+ reportError("myStructProperty", Check(myStructProperty, nil), t)
+}
+
+func TestFailure(t *testing.T) {
+ f := func(x int) bool { return false }
+ err := Check(f, nil)
+ if err == nil {
+ t.Errorf("Check didn't return an error")
+ }
+ if _, ok := err.(*CheckError); !ok {
+ t.Errorf("Error was not a CheckError: %s", err)
+ }
+
+ err = CheckEqual(fUint, fUint32, nil)
+ if err == nil {
+ t.Errorf("#1 CheckEqual didn't return an error")
+ }
+ if _, ok := err.(SetupError); !ok {
+ t.Errorf("#1 Error was not a SetupError: %s", err)
+ }
+
+ err = CheckEqual(func(x, y int) {}, func(x int) {}, nil)
+ if err == nil {
+ t.Errorf("#2 CheckEqual didn't return an error")
+ }
+ if _, ok := err.(SetupError); !ok {
+ t.Errorf("#2 Error was not a SetupError: %s", err)
+ }
+
+ err = CheckEqual(func(x int) int { return 0 }, func(x int) int32 { return 0 }, nil)
+ if err == nil {
+ t.Errorf("#3 CheckEqual didn't return an error")
+ }
+ if _, ok := err.(SetupError); !ok {
+ t.Errorf("#3 Error was not a SetupError: %s", err)
+ }
+}
diff --git a/libgo/go/testing/script/script.go b/libgo/go/testing/script/script.go
new file mode 100644
index 000000000..11f5a7425
--- /dev/null
+++ b/libgo/go/testing/script/script.go
@@ -0,0 +1,359 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package aids in the testing of code that uses channels.
+package script
+
+import (
+ "fmt"
+ "os"
+ "rand"
+ "reflect"
+ "strings"
+)
+
+// An Event is an element in a partially ordered set that either sends a value
+// to a channel or expects a value from a channel.
+type Event struct {
+ name string
+ occurred bool
+ predecessors []*Event
+ action action
+}
+
+type action interface {
+ // getSend returns nil if the action is not a send action.
+ getSend() sendAction
+ // getRecv returns nil if the action is not a receive action.
+ getRecv() recvAction
+ // getChannel returns the channel that the action operates on.
+ getChannel() interface{}
+}
+
+type recvAction interface {
+ recvMatch(interface{}) bool
+}
+
+type sendAction interface {
+ send()
+}
+
+// isReady returns true if all the predecessors of an Event have occurred.
+func (e Event) isReady() bool {
+ for _, predecessor := range e.predecessors {
+ if !predecessor.occurred {
+ return false
+ }
+ }
+
+ return true
+}
+
+// A Recv action reads a value from a channel and uses reflect.DeepMatch to
+// compare it with an expected value.
+type Recv struct {
+ Channel interface{}
+ Expected interface{}
+}
+
+func (r Recv) getRecv() recvAction { return r }
+
+func (Recv) getSend() sendAction { return nil }
+
+func (r Recv) getChannel() interface{} { return r.Channel }
+
+func (r Recv) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelRecv)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return reflect.DeepEqual(c.value, r.Expected)
+}
+
+// A RecvMatch action reads a value from a channel and calls a function to
+// determine if the value matches.
+type RecvMatch struct {
+ Channel interface{}
+ Match func(interface{}) bool
+}
+
+func (r RecvMatch) getRecv() recvAction { return r }
+
+func (RecvMatch) getSend() sendAction { return nil }
+
+func (r RecvMatch) getChannel() interface{} { return r.Channel }
+
+func (r RecvMatch) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelRecv)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return r.Match(c.value)
+}
+
+// A Closed action matches if the given channel is closed. The closing is
+// treated as an event, not a state, thus Closed will only match once for a
+// given channel.
+type Closed struct {
+ Channel interface{}
+}
+
+func (r Closed) getRecv() recvAction { return r }
+
+func (Closed) getSend() sendAction { return nil }
+
+func (r Closed) getChannel() interface{} { return r.Channel }
+
+func (r Closed) recvMatch(chanEvent interface{}) bool {
+ c, ok := chanEvent.(channelClosed)
+ if !ok || c.channel != r.Channel {
+ return false
+ }
+
+ return true
+}
+
+// A Send action sends a value to a channel. The value must match the
+// type of the channel exactly unless the channel if of type chan interface{}.
+type Send struct {
+ Channel interface{}
+ Value interface{}
+}
+
+func (Send) getRecv() recvAction { return nil }
+
+func (s Send) getSend() sendAction { return s }
+
+func (s Send) getChannel() interface{} { return s.Channel }
+
+type empty struct {
+ x interface{}
+}
+
+func newEmptyInterface(e empty) reflect.Value {
+ return reflect.NewValue(e).(*reflect.StructValue).Field(0)
+}
+
+func (s Send) send() {
+ // With reflect.ChanValue.Send, we must match the types exactly. So, if
+ // s.Channel is a chan interface{} we convert s.Value to an interface{}
+ // first.
+ c := reflect.NewValue(s.Channel).(*reflect.ChanValue)
+ var v reflect.Value
+ if iface, ok := c.Type().(*reflect.ChanType).Elem().(*reflect.InterfaceType); ok && iface.NumMethod() == 0 {
+ v = newEmptyInterface(empty{s.Value})
+ } else {
+ v = reflect.NewValue(s.Value)
+ }
+ c.Send(v)
+}
+
+// A Close action closes the given channel.
+type Close struct {
+ Channel interface{}
+}
+
+func (Close) getRecv() recvAction { return nil }
+
+func (s Close) getSend() sendAction { return s }
+
+func (s Close) getChannel() interface{} { return s.Channel }
+
+func (s Close) send() { reflect.NewValue(s.Channel).(*reflect.ChanValue).Close() }
+
+// A ReceivedUnexpected error results if no active Events match a value
+// received from a channel.
+type ReceivedUnexpected struct {
+ Value interface{}
+ ready []*Event
+}
+
+func (r ReceivedUnexpected) String() string {
+ names := make([]string, len(r.ready))
+ for i, v := range r.ready {
+ names[i] = v.name
+ }
+ return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", "))
+}
+
+// A SetupError results if there is a error with the configuration of a set of
+// Events.
+type SetupError string
+
+func (s SetupError) String() string { return string(s) }
+
+func NewEvent(name string, predecessors []*Event, action action) *Event {
+ e := &Event{name, false, predecessors, action}
+ return e
+}
+
+// Given a set of Events, Perform repeatedly iterates over the set and finds the
+// subset of ready Events (that is, all of their predecessors have
+// occurred). From that subset, it pseudo-randomly selects an Event to perform.
+// If the Event is a send event, the send occurs and Perform recalculates the ready
+// set. If the event is a receive event, Perform waits for a value from any of the
+// channels that are contained in any of the events. That value is then matched
+// against the ready events. The first event that matches is considered to
+// have occurred and Perform recalculates the ready set.
+//
+// Perform continues this until all Events have occurred.
+//
+// Note that uncollected goroutines may still be reading from any of the
+// channels read from after Perform returns.
+//
+// For example, consider the problem of testing a function that reads values on
+// one channel and echos them to two output channels. To test this we would
+// create three events: a send event and two receive events. Each of the
+// receive events must list the send event as a predecessor but there is no
+// ordering between the receive events.
+//
+// send := NewEvent("send", nil, Send{c, 1})
+// recv1 := NewEvent("recv 1", []*Event{send}, Recv{c, 1})
+// recv2 := NewEvent("recv 2", []*Event{send}, Recv{c, 1})
+// Perform(0, []*Event{send, recv1, recv2})
+//
+// At first, only the send event would be in the ready set and thus Perform will
+// send a value to the input channel. Now the two receive events are ready and
+// Perform will match each of them against the values read from the output channels.
+//
+// It would be invalid to list one of the receive events as a predecessor of
+// the other. At each receive step, all the receive channels are considered,
+// thus Perform may see a value from a channel that is not in the current ready
+// set and fail.
+func Perform(seed int64, events []*Event) (err os.Error) {
+ r := rand.New(rand.NewSource(seed))
+
+ channels, err := getChannels(events)
+ if err != nil {
+ return
+ }
+ multiplex := make(chan interface{})
+ for _, channel := range channels {
+ go recvValues(multiplex, channel)
+ }
+
+Outer:
+ for {
+ ready, err := readyEvents(events)
+ if err != nil {
+ return err
+ }
+
+ if len(ready) == 0 {
+ // All events occurred.
+ break
+ }
+
+ event := ready[r.Intn(len(ready))]
+ if send := event.action.getSend(); send != nil {
+ send.send()
+ event.occurred = true
+ continue
+ }
+
+ v := <-multiplex
+ for _, event := range ready {
+ if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) {
+ event.occurred = true
+ continue Outer
+ }
+ }
+
+ return ReceivedUnexpected{v, ready}
+ }
+
+ return nil
+}
+
+// getChannels returns all the channels listed in any receive events.
+func getChannels(events []*Event) ([]interface{}, os.Error) {
+ channels := make([]interface{}, len(events))
+
+ j := 0
+ for _, event := range events {
+ if recv := event.action.getRecv(); recv == nil {
+ continue
+ }
+ c := event.action.getChannel()
+ if _, ok := reflect.NewValue(c).(*reflect.ChanValue); !ok {
+ return nil, SetupError("one of the channel values is not a channel")
+ }
+
+ duplicate := false
+ for _, other := range channels[0:j] {
+ if c == other {
+ duplicate = true
+ break
+ }
+ }
+
+ if !duplicate {
+ channels[j] = c
+ j++
+ }
+ }
+
+ return channels[0:j], nil
+}
+
+// recvValues is a multiplexing helper function. It reads values from the given
+// channel repeatedly, wrapping them up as either a channelRecv or
+// channelClosed structure, and forwards them to the multiplex channel.
+func recvValues(multiplex chan<- interface{}, channel interface{}) {
+ c := reflect.NewValue(channel).(*reflect.ChanValue)
+
+ for {
+ v := c.Recv()
+ if c.Closed() {
+ multiplex <- channelClosed{channel}
+ return
+ }
+
+ multiplex <- channelRecv{channel, v.Interface()}
+ }
+}
+
+type channelClosed struct {
+ channel interface{}
+}
+
+type channelRecv struct {
+ channel interface{}
+ value interface{}
+}
+
+// readyEvents returns the subset of events that are ready.
+func readyEvents(events []*Event) ([]*Event, os.Error) {
+ ready := make([]*Event, len(events))
+
+ j := 0
+ eventsWaiting := false
+ for _, event := range events {
+ if event.occurred {
+ continue
+ }
+
+ eventsWaiting = true
+ if event.isReady() {
+ ready[j] = event
+ j++
+ }
+ }
+
+ if j == 0 && eventsWaiting {
+ names := make([]string, len(events))
+ for _, event := range events {
+ if event.occurred {
+ continue
+ }
+ names[j] = event.name
+ }
+
+ return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", "))
+ }
+
+ return ready[0:j], nil
+}
diff --git a/libgo/go/testing/script/script_test.go b/libgo/go/testing/script/script_test.go
new file mode 100644
index 000000000..e9ab142c2
--- /dev/null
+++ b/libgo/go/testing/script/script_test.go
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package script
+
+import (
+ "testing"
+)
+
+func TestNoop(t *testing.T) {
+ err := Perform(0, nil)
+ if err != nil {
+ t.Errorf("Got error: %s", err)
+ }
+}
+
+func TestSimple(t *testing.T) {
+ c := make(chan int)
+ defer close(c)
+
+ a := NewEvent("send", nil, Send{c, 1})
+ b := NewEvent("recv", []*Event{a}, Recv{c, 1})
+
+ err := Perform(0, []*Event{a, b})
+ if err != nil {
+ t.Errorf("Got error: %s", err)
+ }
+}
+
+func TestFail(t *testing.T) {
+ c := make(chan int)
+ defer close(c)
+
+ a := NewEvent("send", nil, Send{c, 2})
+ b := NewEvent("recv", []*Event{a}, Recv{c, 1})
+
+ err := Perform(0, []*Event{a, b})
+ if err == nil {
+ t.Errorf("Failed to get expected error")
+ } else if _, ok := err.(ReceivedUnexpected); !ok {
+ t.Errorf("Error returned was of the wrong type: %s", err)
+ }
+}
+
+func TestClose(t *testing.T) {
+ c := make(chan int)
+
+ a := NewEvent("close", nil, Close{c})
+ b := NewEvent("closed", []*Event{a}, Closed{c})
+
+ err := Perform(0, []*Event{a, b})
+ if err != nil {
+ t.Errorf("Got error: %s", err)
+ }
+}
+
+func matchOne(v interface{}) bool {
+ if i, ok := v.(int); ok && i == 1 {
+ return true
+ }
+ return false
+}
+
+func TestRecvMatch(t *testing.T) {
+ c := make(chan int)
+
+ a := NewEvent("send", nil, Send{c, 1})
+ b := NewEvent("recv", []*Event{a}, RecvMatch{c, matchOne})
+
+ err := Perform(0, []*Event{a, b})
+ if err != nil {
+ t.Errorf("Got error: %s", err)
+ }
+}
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
new file mode 100644
index 000000000..0e04935ce
--- /dev/null
+++ b/libgo/go/testing/testing.go
@@ -0,0 +1,174 @@
+// 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.
+
+// The testing package provides support for automated testing of Go packages.
+// It is intended to be used in concert with the ``gotest'' utility, which automates
+// execution of any function of the form
+// func TestXxx(*testing.T)
+// where Xxx can be any alphanumeric string (but the first letter must not be in
+// [a-z]) and serves to identify the test routine.
+// These TestXxx routines should be declared within the package they are testing.
+//
+// Functions of the form
+// func BenchmarkXxx(*testing.B)
+// are considered benchmarks, and are executed by gotest when the -benchmarks
+// flag is provided.
+//
+// A sample benchmark function looks like this:
+// func BenchmarkHello(b *testing.B) {
+// for i := 0; i < b.N; i++ {
+// fmt.Sprintf("hello")
+// }
+// }
+// The benchmark package will vary b.N until the benchmark function lasts
+// long enough to be timed reliably. The output
+// testing.BenchmarkHello 500000 4076 ns/op
+// means that the loop ran 500000 times at a speed of 4076 ns per loop.
+//
+// If a benchmark needs some expensive setup before running, the timer
+// may be stopped:
+// func BenchmarkBigLen(b *testing.B) {
+// b.StopTimer()
+// big := NewBig()
+// b.StartTimer()
+// for i := 0; i < b.N; i++ {
+// big.Len()
+// }
+// }
+package testing
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "runtime"
+)
+
+// Report as tests are run; default is silent for success.
+var chatty = flag.Bool("v", false, "verbose: print additional output")
+var match = flag.String("match", "", "regular expression to select tests to run")
+
+
+// Insert final newline if needed and tabs after internal newlines.
+func tabify(s string) string {
+ n := len(s)
+ if n > 0 && s[n-1] != '\n' {
+ s += "\n"
+ n++
+ }
+ for i := 0; i < n-1; i++ { // -1 to avoid final newline
+ if s[i] == '\n' {
+ return s[0:i+1] + "\t" + tabify(s[i+1:n])
+ }
+ }
+ return s
+}
+
+// T is a type passed to Test functions to manage test state and support formatted test logs.
+// Logs are accumulated during execution and dumped to standard error when done.
+type T struct {
+ errors string
+ failed bool
+ ch chan *T
+}
+
+// Fail marks the Test function as having failed but continues execution.
+func (t *T) Fail() { t.failed = true }
+
+// Failed returns whether the Test function has failed.
+func (t *T) Failed() bool { return t.failed }
+
+// FailNow marks the Test function as having failed and stops its execution.
+// Execution will continue at the next Test.
+func (t *T) FailNow() {
+ t.Fail()
+ t.ch <- t
+ runtime.Goexit()
+}
+
+// Log formats its arguments using default formatting, analogous to Print(),
+// and records the text in the error log.
+func (t *T) Log(args ...interface{}) { t.errors += "\t" + tabify(fmt.Sprintln(args...)) }
+
+// Log formats its arguments according to the format, analogous to Printf(),
+// and records the text in the error log.
+func (t *T) Logf(format string, args ...interface{}) {
+ t.errors += "\t" + tabify(fmt.Sprintf(format, args...))
+}
+
+// Error is equivalent to Log() followed by Fail().
+func (t *T) Error(args ...interface{}) {
+ t.Log(args...)
+ t.Fail()
+}
+
+// Errorf is equivalent to Logf() followed by Fail().
+func (t *T) Errorf(format string, args ...interface{}) {
+ t.Logf(format, args...)
+ t.Fail()
+}
+
+// Fatal is equivalent to Log() followed by FailNow().
+func (t *T) Fatal(args ...interface{}) {
+ t.Log(args...)
+ t.FailNow()
+}
+
+// Fatalf is equivalent to Logf() followed by FailNow().
+func (t *T) Fatalf(format string, args ...interface{}) {
+ t.Logf(format, args...)
+ t.FailNow()
+}
+
+// An internal type but exported because it is cross-package; part of the implementation
+// of gotest.
+type InternalTest struct {
+ Name string
+ F func(*T)
+}
+
+func tRunner(t *T, test *InternalTest) {
+ test.F(t)
+ t.ch <- t
+}
+
+// An internal function but exported because it is cross-package; part of the implementation
+// of gotest.
+func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTest) {
+ flag.Parse()
+ ok := true
+ if len(tests) == 0 {
+ println("testing: warning: no tests to run")
+ }
+ for i := 0; i < len(tests); i++ {
+ matched, err := matchString(*match, tests[i].Name)
+ if err != nil {
+ println("invalid regexp for -match:", err.String())
+ os.Exit(1)
+ }
+ if !matched {
+ continue
+ }
+ if *chatty {
+ println("=== RUN ", tests[i].Name)
+ }
+ t := new(T)
+ t.ch = make(chan *T)
+ go tRunner(t, &tests[i])
+ <-t.ch
+ if t.failed {
+ println("--- FAIL:", tests[i].Name)
+ print(t.errors)
+ ok = false
+ } else if *chatty {
+ println("--- PASS:", tests[i].Name)
+ print(t.errors)
+ }
+ }
+ if !ok {
+ println("FAIL")
+ os.Exit(1)
+ }
+ println("PASS")
+}
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
new file mode 100644
index 000000000..7b5a8f3b6
--- /dev/null
+++ b/libgo/go/time/format.go
@@ -0,0 +1,618 @@
+package time
+
+import (
+ "bytes"
+ "os"
+ "strconv"
+)
+
+const (
+ numeric = iota
+ alphabetic
+ separator
+ plus
+ minus
+)
+
+// These are predefined layouts for use in Time.Format.
+// The standard time used in the layouts is:
+// Mon Jan 2 15:04:05 MST 2006 (MST is GMT-0700)
+// which is Unix time 1136243045.
+// (Think of it as 01/02 03:04:05PM '06 -0700.)
+// To define your own format, write down what the standard
+// time would look like formatted your way.
+//
+// Within the format string, an underscore _ represents a space that may be
+// replaced by a digit if the following number (a day) has two digits; for
+// compatibility with fixed-width Unix time formats.
+//
+// Numeric time zone offsets format as follows:
+// -0700 ±hhmm
+// -07:00 ±hh:mm
+// Replacing the sign in the format with a Z triggers
+// the ISO 8601 behavior of printing Z instead of an
+// offset for the UTC zone. Thus:
+// Z0700 Z or ±hhmm
+// Z07:00 Z or ±hh:mm
+const (
+ ANSIC = "Mon Jan _2 15:04:05 2006"
+ UnixDate = "Mon Jan _2 15:04:05 MST 2006"
+ RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
+ RFC822 = "02 Jan 06 1504 MST"
+ // RFC822 with Zulu time.
+ RFC822Z = "02 Jan 06 1504 -0700"
+ RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
+ RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
+ RFC3339 = "2006-01-02T15:04:05Z07:00"
+ Kitchen = "3:04PM"
+)
+
+const (
+ stdLongMonth = "January"
+ stdMonth = "Jan"
+ stdNumMonth = "1"
+ stdZeroMonth = "01"
+ stdLongWeekDay = "Monday"
+ stdWeekDay = "Mon"
+ stdDay = "2"
+ stdUnderDay = "_2"
+ stdZeroDay = "02"
+ stdHour = "15"
+ stdHour12 = "3"
+ stdZeroHour12 = "03"
+ stdMinute = "4"
+ stdZeroMinute = "04"
+ stdSecond = "5"
+ stdZeroSecond = "05"
+ stdLongYear = "2006"
+ stdYear = "06"
+ stdPM = "PM"
+ stdpm = "pm"
+ stdTZ = "MST"
+ stdISO8601TZ = "Z0700" // prints Z for UTC
+ stdISO8601ColonTZ = "Z07:00" // prints Z for UTC
+ stdNumTZ = "-0700" // always numeric
+ stdNumShortTZ = "-07" // always numeric
+ stdNumColonTZ = "-07:00" // always numeric
+)
+
+// nextStdChunk finds the first occurrence of a std string in
+// layout and returns the text before, the std string, and the text after.
+func nextStdChunk(layout string) (prefix, std, suffix string) {
+ for i := 0; i < len(layout); i++ {
+ switch layout[i] {
+ case 'J': // January, Jan
+ if len(layout) >= i+7 && layout[i:i+7] == stdLongMonth {
+ return layout[0:i], stdLongMonth, layout[i+7:]
+ }
+ if len(layout) >= i+3 && layout[i:i+3] == stdMonth {
+ return layout[0:i], stdMonth, layout[i+3:]
+ }
+
+ case 'M': // Monday, Mon, MST
+ if len(layout) >= i+6 && layout[i:i+6] == stdLongWeekDay {
+ return layout[0:i], stdLongWeekDay, layout[i+6:]
+ }
+ if len(layout) >= i+3 {
+ if layout[i:i+3] == stdWeekDay {
+ return layout[0:i], stdWeekDay, layout[i+3:]
+ }
+ if layout[i:i+3] == stdTZ {
+ return layout[0:i], stdTZ, layout[i+3:]
+ }
+ }
+
+ case '0': // 01, 02, 03, 04, 05, 06
+ if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' {
+ return layout[0:i], layout[i : i+2], layout[i+2:]
+ }
+
+ case '1': // 15, 1
+ if len(layout) >= i+2 && layout[i+1] == '5' {
+ return layout[0:i], stdHour, layout[i+2:]
+ }
+ return layout[0:i], stdNumMonth, layout[i+1:]
+
+ case '2': // 2006, 2
+ if len(layout) >= i+4 && layout[i:i+4] == stdLongYear {
+ return layout[0:i], stdLongYear, layout[i+4:]
+ }
+ return layout[0:i], stdDay, layout[i+1:]
+
+ case '_': // _2
+ if len(layout) >= i+2 && layout[i+1] == '2' {
+ return layout[0:i], stdUnderDay, layout[i+2:]
+ }
+
+ case '3', '4', '5': // 3, 4, 5
+ return layout[0:i], layout[i : i+1], layout[i+1:]
+
+ case 'P': // PM
+ if len(layout) >= i+2 && layout[i+1] == 'M' {
+ return layout[0:i], layout[i : i+2], layout[i+2:]
+ }
+
+ case 'p': // pm
+ if len(layout) >= i+2 && layout[i+1] == 'm' {
+ return layout[0:i], layout[i : i+2], layout[i+2:]
+ }
+
+ case '-': // -0700, -07:00, -07
+ if len(layout) >= i+5 && layout[i:i+5] == stdNumTZ {
+ return layout[0:i], layout[i : i+5], layout[i+5:]
+ }
+ if len(layout) >= i+6 && layout[i:i+6] == stdNumColonTZ {
+ return layout[0:i], layout[i : i+6], layout[i+6:]
+ }
+ if len(layout) >= i+3 && layout[i:i+3] == stdNumShortTZ {
+ return layout[0:i], layout[i : i+3], layout[i+3:]
+ }
+ case 'Z': // Z0700, Z07:00
+ if len(layout) >= i+5 && layout[i:i+5] == stdISO8601TZ {
+ return layout[0:i], layout[i : i+5], layout[i+5:]
+ }
+ if len(layout) >= i+6 && layout[i:i+6] == stdISO8601ColonTZ {
+ return layout[0:i], layout[i : i+6], layout[i+6:]
+ }
+ }
+ }
+ return layout, "", ""
+}
+
+var longDayNames = []string{
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+}
+
+var shortDayNames = []string{
+ "Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat",
+}
+
+var shortMonthNames = []string{
+ "---",
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec",
+}
+
+var longMonthNames = []string{
+ "---",
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December",
+}
+
+func lookup(tab []string, val string) (int, string, os.Error) {
+ for i, v := range tab {
+ if len(val) >= len(v) && val[0:len(v)] == v {
+ return i, val[len(v):], nil
+ }
+ }
+ return -1, val, errBad
+}
+
+func pad(i int, padding string) string {
+ s := strconv.Itoa(i)
+ if i < 10 {
+ s = padding + s
+ }
+ return s
+}
+
+func zeroPad(i int) string { return pad(i, "0") }
+
+// Format returns a textual representation of the time value formatted
+// according to layout. The layout defines the format by showing the
+// representation of a standard time, which is then used to describe
+// the time to be formatted. Predefined layouts ANSIC, UnixDate,
+// RFC3339 and others describe standard representations. For more
+// information about the formats, see the documentation for ANSIC.
+func (t *Time) Format(layout string) string {
+ b := new(bytes.Buffer)
+ // Each iteration generates one std value.
+ for {
+ prefix, std, suffix := nextStdChunk(layout)
+ b.WriteString(prefix)
+ if std == "" {
+ break
+ }
+ var p string
+ switch std {
+ case stdYear:
+ p = strconv.Itoa64(t.Year % 100)
+ case stdLongYear:
+ p = strconv.Itoa64(t.Year)
+ case stdMonth:
+ p = shortMonthNames[t.Month]
+ case stdLongMonth:
+ p = longMonthNames[t.Month]
+ case stdNumMonth:
+ p = strconv.Itoa(t.Month)
+ case stdZeroMonth:
+ p = zeroPad(t.Month)
+ case stdWeekDay:
+ p = shortDayNames[t.Weekday]
+ case stdLongWeekDay:
+ p = longDayNames[t.Weekday]
+ case stdDay:
+ p = strconv.Itoa(t.Day)
+ case stdUnderDay:
+ p = pad(t.Day, " ")
+ case stdZeroDay:
+ p = zeroPad(t.Day)
+ case stdHour:
+ p = zeroPad(t.Hour)
+ case stdHour12:
+ p = strconv.Itoa(t.Hour % 12)
+ case stdZeroHour12:
+ p = zeroPad(t.Hour % 12)
+ case stdMinute:
+ p = strconv.Itoa(t.Minute)
+ case stdZeroMinute:
+ p = zeroPad(t.Minute)
+ case stdSecond:
+ p = strconv.Itoa(t.Second)
+ case stdZeroSecond:
+ p = zeroPad(t.Second)
+ case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumColonTZ:
+ // Ugly special case. We cheat and take the "Z" variants
+ // to mean "the time zone as formatted for ISO 8601".
+ if t.ZoneOffset == 0 && std[0] == 'Z' {
+ p = "Z"
+ break
+ }
+ zone := t.ZoneOffset / 60 // convert to minutes
+ if zone < 0 {
+ p = "-"
+ zone = -zone
+ } else {
+ p = "+"
+ }
+ p += zeroPad(zone / 60)
+ if std == stdISO8601ColonTZ || std == stdNumColonTZ {
+ p += ":"
+ }
+ p += zeroPad(zone % 60)
+ case stdPM:
+ if t.Hour >= 12 {
+ p = "PM"
+ } else {
+ p = "AM"
+ }
+ case stdpm:
+ if t.Hour >= 12 {
+ p = "pm"
+ } else {
+ p = "am"
+ }
+ case stdTZ:
+ if t.Zone != "" {
+ p = t.Zone
+ } else {
+ // No time zone known for this time, but we must print one.
+ // Use the -0700 format.
+ zone := t.ZoneOffset / 60 // convert to minutes
+ if zone < 0 {
+ p = "-"
+ zone = -zone
+ } else {
+ p = "+"
+ }
+ p += zeroPad(zone / 60)
+ p += zeroPad(zone % 60)
+ }
+ }
+ b.WriteString(p)
+ layout = suffix
+ }
+ return b.String()
+}
+
+// String returns a Unix-style representation of the time value.
+func (t *Time) String() string {
+ if t == nil {
+ return "<nil>"
+ }
+ return t.Format(UnixDate)
+}
+
+var errBad = os.ErrorString("bad") // just a marker; not returned to user
+
+// ParseError describes a problem parsing a time string.
+type ParseError struct {
+ Layout string
+ Value string
+ LayoutElem string
+ ValueElem string
+ Message string
+}
+
+// String is the string representation of a ParseError.
+func (e *ParseError) String() string {
+ if e.Message == "" {
+ return "parsing time " +
+ strconv.Quote(e.Value) + " as " +
+ strconv.Quote(e.Layout) + ": cannot parse " +
+ strconv.Quote(e.ValueElem) + " as " +
+ strconv.Quote(e.LayoutElem)
+ }
+ return "parsing time " +
+ strconv.Quote(e.Value) + e.Message
+}
+
+// getnum parses s[0:1] or s[0:2] (fixed forces the latter)
+// as a decimal integer and returns the integer and the
+// remainder of the string.
+func getnum(s string, fixed bool) (int, string, os.Error) {
+ if len(s) == 0 || s[0] < '0' || s[0] > '9' {
+ return 0, s, errBad
+ }
+ if len(s) == 1 || s[1] < '0' || s[1] > '9' {
+ if fixed {
+ return 0, s, errBad
+ }
+ return int(s[0] - '0'), s[1:], nil
+ }
+ return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil
+}
+
+func cutspace(s string) string {
+ for len(s) > 0 && s[0] == ' ' {
+ s = s[1:]
+ }
+ return s
+}
+
+// skip removes the given prefix from value,
+// treating runs of space characters as equivalent.
+func skip(value, prefix string) (string, os.Error) {
+ for len(prefix) > 0 {
+ if prefix[0] == ' ' {
+ if len(value) > 0 && value[0] != ' ' {
+ return "", errBad
+ }
+ prefix = cutspace(prefix)
+ value = cutspace(value)
+ continue
+ }
+ if len(value) == 0 || value[0] != prefix[0] {
+ return "", errBad
+ }
+ prefix = prefix[1:]
+ value = value[1:]
+ }
+ return value, nil
+}
+
+// Parse parses a formatted string and returns the time value it represents.
+// The layout defines the format by showing the representation of a standard
+// time, which is then used to describe the string to be parsed. Predefined
+// layouts ANSIC, UnixDate, RFC3339 and others describe standard
+// representations.For more information about the formats, see the
+// documentation for ANSIC.
+//
+// Only those elements present in the value will be set in the returned time
+// structure. Also, if the input string represents an inconsistent time
+// (such as having the wrong day of the week), the returned value will also
+// be inconsistent. In any case, the elements of the returned time will be
+// sane: hours in 0..23, minutes in 0..59, day of month in 0..31, etc.
+// Years must be in the range 0000..9999.
+func Parse(alayout, avalue string) (*Time, os.Error) {
+ var t Time
+ rangeErrString := "" // set if a value is out of range
+ pmSet := false // do we need to add 12 to the hour?
+ layout, value := alayout, avalue
+ // Each iteration processes one std value.
+ for {
+ var err os.Error
+ prefix, std, suffix := nextStdChunk(layout)
+ value, err = skip(value, prefix)
+ if err != nil {
+ return nil, &ParseError{alayout, avalue, prefix, value, ""}
+ }
+ if len(std) == 0 {
+ if len(value) != 0 {
+ return nil, &ParseError{alayout, avalue, "", value, ": extra text: " + value}
+ }
+ break
+ }
+ layout = suffix
+ var p string
+ switch std {
+ case stdYear:
+ if len(value) < 2 {
+ err = errBad
+ break
+ }
+ p, value = value[0:2], value[2:]
+ t.Year, err = strconv.Atoi64(p)
+ if t.Year >= 69 { // Unix time starts Dec 31 1969 in some time zones
+ t.Year += 1900
+ } else {
+ t.Year += 2000
+ }
+ case stdLongYear:
+ if len(value) < 4 || value[0] < '0' || value[0] > '9' {
+ err = errBad
+ break
+ }
+ p, value = value[0:4], value[4:]
+ t.Year, err = strconv.Atoi64(p)
+ case stdMonth:
+ t.Month, value, err = lookup(shortMonthNames, value)
+ case stdLongMonth:
+ t.Month, value, err = lookup(longMonthNames, value)
+ case stdNumMonth, stdZeroMonth:
+ t.Month, value, err = getnum(value, std == stdZeroMonth)
+ if t.Month <= 0 || 12 < t.Month {
+ rangeErrString = "month"
+ }
+ case stdWeekDay:
+ t.Weekday, value, err = lookup(shortDayNames, value)
+ case stdLongWeekDay:
+ t.Weekday, value, err = lookup(longDayNames, value)
+ case stdDay, stdUnderDay, stdZeroDay:
+ if std == stdUnderDay && len(value) > 0 && value[0] == ' ' {
+ value = value[1:]
+ }
+ t.Day, value, err = getnum(value, std == stdZeroDay)
+ if t.Day < 0 || 31 < t.Day {
+ // TODO: be more thorough in date check?
+ rangeErrString = "day"
+ }
+ case stdHour:
+ t.Hour, value, err = getnum(value, false)
+ if t.Hour < 0 || 24 <= t.Hour {
+ rangeErrString = "hour"
+ }
+ case stdHour12, stdZeroHour12:
+ t.Hour, value, err = getnum(value, std == stdZeroHour12)
+ if t.Hour < 0 || 12 < t.Hour {
+ rangeErrString = "hour"
+ }
+ case stdMinute, stdZeroMinute:
+ t.Minute, value, err = getnum(value, std == stdZeroMinute)
+ if t.Minute < 0 || 60 <= t.Minute {
+ rangeErrString = "minute"
+ }
+ case stdSecond, stdZeroSecond:
+ t.Second, value, err = getnum(value, std == stdZeroSecond)
+ if t.Second < 0 || 60 <= t.Second {
+ rangeErrString = "second"
+ }
+ case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ:
+ if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' {
+ value = value[1:]
+ t.Zone = "UTC"
+ break
+ }
+ var sign, hh, mm string
+ if std == stdISO8601ColonTZ || std == stdNumColonTZ {
+ if len(value) < 6 {
+ err = errBad
+ break
+ }
+ if value[3] != ':' {
+ err = errBad
+ break
+ }
+ sign, hh, mm, value = value[0:1], value[1:3], value[4:6], value[6:]
+ } else if std == stdNumShortTZ {
+ if len(value) < 3 {
+ err = errBad
+ break
+ }
+ sign, hh, mm, value = value[0:1], value[1:3], "00", value[3:]
+ } else {
+ if len(value) < 5 {
+ err = errBad
+ break
+ }
+ sign, hh, mm, value = value[0:1], value[1:3], value[3:5], value[5:]
+ }
+ var hr, min int
+ hr, err = strconv.Atoi(hh)
+ if err == nil {
+ min, err = strconv.Atoi(mm)
+ }
+ t.ZoneOffset = (hr*60 + min) * 60 // offset is in seconds
+ switch sign[0] {
+ case '+':
+ case '-':
+ t.ZoneOffset = -t.ZoneOffset
+ default:
+ err = errBad
+ }
+ case stdPM:
+ if len(value) < 2 {
+ err = errBad
+ break
+ }
+ p, value = value[0:2], value[2:]
+ if p == "PM" {
+ pmSet = true
+ } else if p != "AM" {
+ err = errBad
+ }
+ case stdpm:
+ if len(value) < 2 {
+ err = errBad
+ break
+ }
+ p, value = value[0:2], value[2:]
+ if p == "pm" {
+ pmSet = true
+ } else if p != "am" {
+ err = errBad
+ }
+ case stdTZ:
+ // Does it look like a time zone?
+ if len(value) >= 3 && value[0:3] == "UTC" {
+ t.Zone, value = value[0:3], value[3:]
+ break
+ }
+
+ if len(value) >= 3 && value[2] == 'T' {
+ p, value = value[0:3], value[3:]
+ } else if len(value) >= 4 && value[3] == 'T' {
+ p, value = value[0:4], value[4:]
+ } else {
+ err = errBad
+ break
+ }
+ for i := 0; i < len(p); i++ {
+ if p[i] < 'A' || 'Z' < p[i] {
+ err = errBad
+ }
+ }
+ if err != nil {
+ break
+ }
+ // It's a valid format.
+ t.Zone = p
+ // Can we find its offset?
+ if offset, found := lookupByName(p); found {
+ t.ZoneOffset = offset
+ }
+ }
+ if rangeErrString != "" {
+ return nil, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"}
+ }
+ if err != nil {
+ return nil, &ParseError{alayout, avalue, std, value, ""}
+ }
+ }
+ if pmSet && t.Hour < 12 {
+ t.Hour += 12
+ }
+ return &t, nil
+}
diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go
new file mode 100644
index 000000000..3538775ad
--- /dev/null
+++ b/libgo/go/time/sleep.go
@@ -0,0 +1,151 @@
+// 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 time
+
+import (
+ "os"
+ "syscall"
+ "sync"
+ "container/heap"
+)
+
+// The event type represents a single After or AfterFunc event.
+type event struct {
+ t int64 // The absolute time that the event should fire.
+ f func(int64) // The function to call when the event fires.
+ sleeping bool // A sleeper is sleeping for this event.
+}
+
+type eventHeap []*event
+
+var events eventHeap
+var eventMutex sync.Mutex
+
+func init() {
+ events.Push(&event{1 << 62, nil, true}) // sentinel
+}
+
+// Sleep pauses the current goroutine for at least ns nanoseconds.
+// Higher resolution sleeping may be provided by syscall.Nanosleep
+// on some operating systems.
+func Sleep(ns int64) os.Error {
+ _, err := sleep(Nanoseconds(), ns)
+ return err
+}
+
+// sleep takes the current time and a duration,
+// pauses for at least ns nanoseconds, and
+// returns the current time and an error.
+func sleep(t, ns int64) (int64, os.Error) {
+ // TODO(cw): use monotonic-time once it's available
+ end := t + ns
+ for t < end {
+ errno := syscall.Sleep(end - t)
+ if errno != 0 && errno != syscall.EINTR {
+ return 0, os.NewSyscallError("sleep", errno)
+ }
+ t = Nanoseconds()
+ }
+ return t, nil
+}
+
+// After waits at least ns nanoseconds before sending the current time
+// on the returned channel.
+func After(ns int64) <-chan int64 {
+ c := make(chan int64, 1)
+ after(ns, func(t int64) { c <- t })
+ return c
+}
+
+// AfterFunc waits at least ns nanoseconds before calling f
+// in its own goroutine.
+func AfterFunc(ns int64, f func()) {
+ after(ns, func(_ int64) {
+ go f()
+ })
+}
+
+// after is the implementation of After and AfterFunc.
+// When the current time is after ns, it calls f with the current time.
+// It assumes that f will not block.
+func after(ns int64, f func(int64)) {
+ t := Nanoseconds() + ns
+ eventMutex.Lock()
+ t0 := events[0].t
+ heap.Push(events, &event{t, f, false})
+ if t < t0 {
+ go sleeper()
+ }
+ eventMutex.Unlock()
+}
+
+// sleeper continually looks at the earliest event in the queue, marks it
+// as sleeping, waits until it happens, then removes any events
+// in the queue that are due. It stops when it finds an event that is
+// already marked as sleeping. When an event is inserted before the first item,
+// a new sleeper is started.
+//
+// Scheduling vagaries mean that sleepers may not wake up in
+// exactly the order of the events that they are waiting for,
+// but this does not matter as long as there are at least as
+// many sleepers as events marked sleeping (invariant). This ensures that
+// there is always a sleeper to service the remaining events.
+//
+// A sleeper will remove at least the event it has been waiting for
+// unless the event has already been removed by another sleeper. Both
+// cases preserve the invariant described above.
+func sleeper() {
+ eventMutex.Lock()
+ e := events[0]
+ for !e.sleeping {
+ t := Nanoseconds()
+ if dt := e.t - t; dt > 0 {
+ e.sleeping = true
+ eventMutex.Unlock()
+ if nt, err := sleep(t, dt); err != nil {
+ // If sleep has encountered an error,
+ // there's not much we can do. We pretend
+ // that time really has advanced by the required
+ // amount and lie to the rest of the system.
+ t = e.t
+ } else {
+ t = nt
+ }
+ eventMutex.Lock()
+ e = events[0]
+ }
+ for t >= e.t {
+ e.f(t)
+ heap.Pop(events)
+ e = events[0]
+ }
+ }
+ eventMutex.Unlock()
+}
+
+func (eventHeap) Len() int {
+ return len(events)
+}
+
+func (eventHeap) Less(i, j int) bool {
+ return events[i].t < events[j].t
+}
+
+func (eventHeap) Swap(i, j int) {
+ events[i], events[j] = events[j], events[i]
+}
+
+func (eventHeap) Push(x interface{}) {
+ events = append(events, x.(*event))
+}
+
+func (eventHeap) Pop() interface{} {
+ // TODO: possibly shrink array.
+ n := len(events) - 1
+ e := events[n]
+ events[n] = nil
+ events = events[0:n]
+ return e
+}
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
new file mode 100644
index 000000000..9e36288f8
--- /dev/null
+++ b/libgo/go/time/sleep_test.go
@@ -0,0 +1,134 @@
+// 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 time_test
+
+import (
+ "os"
+ "syscall"
+ "testing"
+ "sort"
+ . "time"
+)
+
+func TestSleep(t *testing.T) {
+ const delay = int64(100e6)
+ go func() {
+ Sleep(delay / 2)
+ syscall.Kill(os.Getpid(), syscall.SIGCHLD)
+ }()
+ start := Nanoseconds()
+ Sleep(delay)
+ duration := Nanoseconds() - start
+ if duration < delay {
+ t.Fatalf("Sleep(%d) slept for only %d ns", delay, duration)
+ }
+}
+
+// Test the basic function calling behavior. Correct queueing
+// behavior is tested elsewhere, since After and AfterFunc share
+// the same code.
+func TestAfterFunc(t *testing.T) {
+ i := 10
+ c := make(chan bool)
+ var f func()
+ f = func() {
+ i--
+ if i >= 0 {
+ AfterFunc(0, f)
+ Sleep(1e9)
+ } else {
+ c <- true
+ }
+ }
+
+ AfterFunc(0, f)
+ <-c
+}
+
+func BenchmarkAfterFunc(b *testing.B) {
+ i := b.N
+ c := make(chan bool)
+ var f func()
+ f = func() {
+ i--
+ if i >= 0 {
+ AfterFunc(0, f)
+ } else {
+ c <- true
+ }
+ }
+
+ AfterFunc(0, f)
+ <-c
+}
+
+func TestAfter(t *testing.T) {
+ const delay = int64(100e6)
+ start := Nanoseconds()
+ end := <-After(delay)
+ if duration := Nanoseconds() - start; duration < delay {
+ t.Fatalf("After(%d) slept for only %d ns", delay, duration)
+ }
+ if min := start + delay; end < min {
+ t.Fatalf("After(%d) expect >= %d, got %d", delay, min, end)
+ }
+}
+
+func TestAfterTick(t *testing.T) {
+ const (
+ Delta = 100 * 1e6
+ Count = 10
+ )
+ t0 := Nanoseconds()
+ for i := 0; i < Count; i++ {
+ <-After(Delta)
+ }
+ t1 := Nanoseconds()
+ ns := t1 - t0
+ target := int64(Delta * Count)
+ slop := target * 2 / 10
+ if ns < target-slop || ns > target+slop {
+ t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target))
+ }
+}
+
+var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8, 0}
+
+type afterResult struct {
+ slot int
+ t int64
+}
+
+func await(slot int, result chan<- afterResult, ac <-chan int64) {
+ result <- afterResult{slot, <-ac}
+}
+
+func TestAfterQueuing(t *testing.T) {
+ const (
+ Delta = 100 * 1e6
+ )
+ // make the result channel buffered because we don't want
+ // to depend on channel queueing semantics that might
+ // possibly change in the future.
+ result := make(chan afterResult, len(slots))
+
+ t0 := Nanoseconds()
+ for _, slot := range slots {
+ go await(slot, result, After(int64(slot)*Delta))
+ }
+ sort.SortInts(slots)
+ for _, slot := range slots {
+ r := <-result
+ if r.slot != slot {
+ t.Fatalf("after queue got slot %d, expected %d", r.slot, slot)
+ }
+ ns := r.t - t0
+ target := int64(slot * Delta)
+ slop := int64(Delta) / 4
+ if ns < target-slop || ns > target+slop {
+ t.Fatalf("after queue slot %d arrived at %g, expected [%g,%g]", slot, float64(ns), float64(target-slop), float64(target+slop))
+ }
+ }
+}
diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go
new file mode 100644
index 000000000..ddd727270
--- /dev/null
+++ b/libgo/go/time/tick.go
@@ -0,0 +1,171 @@
+// 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 time
+
+import (
+ "os"
+ "sync"
+)
+
+// A Ticker holds a synchronous channel that delivers `ticks' of a clock
+// at intervals.
+type Ticker struct {
+ C <-chan int64 // The channel on which the ticks are delivered.
+ c chan<- int64 // The same channel, but the end we use.
+ ns int64
+ shutdown chan bool // Buffered channel used to signal shutdown.
+ nextTick int64
+ next *Ticker
+}
+
+// Stop turns off a ticker. After Stop, no more ticks will be sent.
+func (t *Ticker) Stop() {
+ // Make it non-blocking so multiple Stops don't block.
+ _ = t.shutdown <- true
+}
+
+// Tick is a convenience wrapper for NewTicker providing access to the ticking
+// channel only. Useful for clients that have no need to shut down the ticker.
+func Tick(ns int64) <-chan int64 {
+ if ns <= 0 {
+ return nil
+ }
+ return NewTicker(ns).C
+}
+
+type alarmer struct {
+ wakeUp chan bool // wakeup signals sent/received here
+ wakeMeAt chan int64
+ wakeTime int64
+}
+
+// Set alarm to go off at time ns, if not already set earlier.
+func (a *alarmer) set(ns int64) {
+ switch {
+ case a.wakeTime > ns:
+ // Next tick we expect is too late; shut down the late runner
+ // and (after fallthrough) start a new wakeLoop.
+ close(a.wakeMeAt)
+ fallthrough
+ case a.wakeMeAt == nil:
+ // There's no wakeLoop, start one.
+ a.wakeMeAt = make(chan int64)
+ a.wakeUp = make(chan bool, 1)
+ go wakeLoop(a.wakeMeAt, a.wakeUp)
+ fallthrough
+ case a.wakeTime == 0:
+ // Nobody else is waiting; it's just us.
+ a.wakeTime = ns
+ a.wakeMeAt <- ns
+ default:
+ // There's already someone scheduled.
+ }
+}
+
+// Channel to notify tickerLoop of new Tickers being created.
+var newTicker chan *Ticker
+
+func startTickerLoop() {
+ newTicker = make(chan *Ticker)
+ go tickerLoop()
+}
+
+// wakeLoop delivers ticks at scheduled times, sleeping until the right moment.
+// If another, earlier Ticker is created while it sleeps, tickerLoop() will start a new
+// wakeLoop and signal that this one is done by closing the wakeMeAt channel.
+func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) {
+ for wakeAt := range wakeMeAt {
+ Sleep(wakeAt - Nanoseconds())
+ wakeUp <- true
+ }
+}
+
+// A single tickerLoop serves all ticks to Tickers. It waits for two events:
+// either the creation of a new Ticker or a tick from the alarm,
+// signalling a time to wake up one or more Tickers.
+func tickerLoop() {
+ // Represents the next alarm to be delivered.
+ var alarm alarmer
+ var now, wakeTime int64
+ var tickers *Ticker
+ for {
+ select {
+ case t := <-newTicker:
+ // Add Ticker to list
+ t.next = tickers
+ tickers = t
+ // Arrange for a new alarm if this one precedes the existing one.
+ alarm.set(t.nextTick)
+ case <-alarm.wakeUp:
+ now = Nanoseconds()
+ wakeTime = now + 1e15 // very long in the future
+ var prev *Ticker = nil
+ // Scan list of tickers, delivering updates to those
+ // that need it and determining the next wake time.
+ // TODO(r): list should be sorted in time order.
+ for t := tickers; t != nil; t = t.next {
+ if _, ok := <-t.shutdown; ok {
+ // Ticker is done; remove it from list.
+ if prev == nil {
+ tickers = t.next
+ } else {
+ prev.next = t.next
+ }
+ continue
+ }
+ if t.nextTick <= now {
+ if len(t.c) == 0 {
+ // Only send if there's room. We must not block.
+ // The channel is allocated with a one-element
+ // buffer, which is sufficient: if he hasn't picked
+ // up the last tick, no point in sending more.
+ t.c <- now
+ }
+ t.nextTick += t.ns
+ if t.nextTick <= now {
+ // Still behind; advance in one big step.
+ t.nextTick += (now - t.nextTick + t.ns) / t.ns * t.ns
+ }
+ }
+ if t.nextTick < wakeTime {
+ wakeTime = t.nextTick
+ }
+ prev = t
+ }
+ if tickers != nil {
+ // Please send wakeup at earliest required time.
+ // If there are no tickers, don't bother.
+ alarm.wakeTime = wakeTime
+ alarm.wakeMeAt <- wakeTime
+ } else {
+ alarm.wakeTime = 0
+ }
+ }
+ }
+}
+
+var onceStartTickerLoop sync.Once
+
+// NewTicker returns a new Ticker containing a channel that will
+// send the time, in nanoseconds, every ns nanoseconds. It adjusts the
+// intervals to make up for pauses in delivery of the ticks. The value of
+// ns must be greater than zero; if not, NewTicker will panic.
+func NewTicker(ns int64) *Ticker {
+ if ns <= 0 {
+ panic(os.ErrorString("non-positive interval for NewTicker"))
+ }
+ c := make(chan int64, 1) // See comment on send in tickerLoop
+ t := &Ticker{
+ C: c,
+ c: c,
+ ns: ns,
+ shutdown: make(chan bool, 1),
+ nextTick: Nanoseconds() + ns,
+ }
+ onceStartTickerLoop.Do(startTickerLoop)
+ // must be run in background so global Tickers can be created
+ go func() { newTicker <- t }()
+ return t
+}
diff --git a/libgo/go/time/tick_test.go b/libgo/go/time/tick_test.go
new file mode 100644
index 000000000..2a63a0f2b
--- /dev/null
+++ b/libgo/go/time/tick_test.go
@@ -0,0 +1,45 @@
+// 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 time_test
+
+import (
+ "testing"
+ . "time"
+)
+
+func TestTicker(t *testing.T) {
+ const (
+ Delta = 100 * 1e6
+ Count = 10
+ )
+ ticker := NewTicker(Delta)
+ t0 := Nanoseconds()
+ for i := 0; i < Count; i++ {
+ <-ticker.C
+ }
+ ticker.Stop()
+ t1 := Nanoseconds()
+ ns := t1 - t0
+ target := int64(Delta * Count)
+ slop := target * 2 / 10
+ if ns < target-slop || ns > target+slop {
+ t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target))
+ }
+ // Now test that the ticker stopped
+ Sleep(2 * Delta)
+ _, received := <-ticker.C
+ if received {
+ t.Fatal("Ticker did not shut down")
+ }
+}
+
+// Test that a bug tearing down a ticker has been fixed. This routine should not deadlock.
+func TestTeardown(t *testing.T) {
+ for i := 0; i < 3; i++ {
+ ticker := NewTicker(1e8)
+ <-ticker.C
+ ticker.Stop()
+ }
+}
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
new file mode 100644
index 000000000..4abd11230
--- /dev/null
+++ b/libgo/go/time/time.go
@@ -0,0 +1,229 @@
+// 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.
+
+// The time package provides functionality for measuring and
+// displaying time.
+package time
+
+import (
+ "os"
+)
+
+// Seconds reports the number of seconds since the Unix epoch,
+// January 1, 1970 00:00:00 UTC.
+func Seconds() int64 {
+ sec, _, err := os.Time()
+ if err != nil {
+ panic(err)
+ }
+ return sec
+}
+
+// Nanoseconds reports the number of nanoseconds since the Unix epoch,
+// January 1, 1970 00:00:00 UTC.
+func Nanoseconds() int64 {
+ sec, nsec, err := os.Time()
+ if err != nil {
+ panic(err)
+ }
+ return sec*1e9 + nsec
+}
+
+// Days of the week.
+const (
+ Sunday = iota
+ Monday
+ Tuesday
+ Wednesday
+ Thursday
+ Friday
+ Saturday
+)
+
+// Time is the struct representing a parsed time value.
+type Time struct {
+ Year int64 // 2006 is 2006
+ Month, Day int // Jan-2 is 1, 2
+ Hour, Minute, Second int // 15:04:05 is 15, 4, 5.
+ Weekday int // Sunday, Monday, ...
+ ZoneOffset int // seconds east of UTC, e.g. -7*60 for -0700
+ Zone string // e.g., "MST"
+}
+
+var nonleapyear = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+var leapyear = []int{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+
+func months(year int64) []int {
+ if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
+ return leapyear
+ }
+ return nonleapyear
+}
+
+const (
+ secondsPerDay = 24 * 60 * 60
+ daysPer400Years = 365*400 + 97
+ daysPer100Years = 365*100 + 24
+ daysPer4Years = 365*4 + 1
+ days1970To2001 = 31*365 + 8
+)
+
+// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
+// into a parsed Time value in the UTC time zone.
+func SecondsToUTC(sec int64) *Time {
+ t := new(Time)
+
+ // Split into time and day.
+ day := sec / secondsPerDay
+ sec -= day * secondsPerDay
+ if sec < 0 {
+ day--
+ sec += secondsPerDay
+ }
+
+ // Time
+ t.Hour = int(sec / 3600)
+ t.Minute = int((sec / 60) % 60)
+ t.Second = int(sec % 60)
+
+ // Day 0 = January 1, 1970 was a Thursday
+ t.Weekday = int((day + Thursday) % 7)
+ if t.Weekday < 0 {
+ t.Weekday += 7
+ }
+
+ // Change day from 0 = 1970 to 0 = 2001,
+ // to make leap year calculations easier
+ // (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
+ day -= days1970To2001
+
+ year := int64(2001)
+ if day < 0 {
+ // Go back enough 400 year cycles to make day positive.
+ n := -day/daysPer400Years + 1
+ year -= 400 * n
+ day += daysPer400Years * n
+ }
+
+ // Cut off 400 year cycles.
+ n := day / daysPer400Years
+ year += 400 * n
+ day -= daysPer400Years * n
+
+ // Cut off 100-year cycles
+ n = day / daysPer100Years
+ if n > 3 { // happens on last day of 400th year
+ n = 3
+ }
+ year += 100 * n
+ day -= daysPer100Years * n
+
+ // Cut off 4-year cycles
+ n = day / daysPer4Years
+ if n > 24 { // happens on last day of 100th year
+ n = 24
+ }
+ year += 4 * n
+ day -= daysPer4Years * n
+
+ // Cut off non-leap years.
+ n = day / 365
+ if n > 3 { // happens on last day of 4th year
+ n = 3
+ }
+ year += n
+ day -= 365 * n
+
+ t.Year = year
+
+ // If someone ever needs yearday,
+ // tyearday = day (+1?)
+
+ months := months(year)
+ var m int
+ yday := int(day)
+ for m = 0; m < 12 && yday >= months[m]; m++ {
+ yday -= months[m]
+ }
+ t.Month = m + 1
+ t.Day = yday + 1
+ t.Zone = "UTC"
+
+ return t
+}
+
+// UTC returns the current time as a parsed Time value in the UTC time zone.
+func UTC() *Time { return SecondsToUTC(Seconds()) }
+
+// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
+// into a parsed Time value in the local time zone.
+func SecondsToLocalTime(sec int64) *Time {
+ z, offset := lookupTimezone(sec)
+ t := SecondsToUTC(sec + int64(offset))
+ t.Zone = z
+ t.ZoneOffset = offset
+ return t
+}
+
+// LocalTime returns the current time as a parsed Time value in the local time zone.
+func LocalTime() *Time { return SecondsToLocalTime(Seconds()) }
+
+// Seconds returns the number of seconds since January 1, 1970 represented by the
+// parsed Time value.
+func (t *Time) Seconds() int64 {
+ // First, accumulate days since January 1, 2001.
+ // Using 2001 instead of 1970 makes the leap-year
+ // handling easier (see SecondsToUTC), because
+ // it is at the beginning of the 4-, 100-, and 400-year cycles.
+ day := int64(0)
+
+ // Rewrite year to be >= 2001.
+ year := t.Year
+ if year < 2001 {
+ n := (2001-year)/400 + 1
+ year += 400 * n
+ day -= daysPer400Years * n
+ }
+
+ // Add in days from 400-year cycles.
+ n := (year - 2001) / 400
+ year -= 400 * n
+ day += daysPer400Years * n
+
+ // Add in 100-year cycles.
+ n = (year - 2001) / 100
+ year -= 100 * n
+ day += daysPer100Years * n
+
+ // Add in 4-year cycles.
+ n = (year - 2001) / 4
+ year -= 4 * n
+ day += daysPer4Years * n
+
+ // Add in non-leap years.
+ n = year - 2001
+ day += 365 * n
+
+ // Add in days this year.
+ months := months(t.Year)
+ for m := 0; m < t.Month-1; m++ {
+ day += int64(months[m])
+ }
+ day += int64(t.Day - 1)
+
+ // Convert days to seconds since January 1, 2001.
+ sec := day * secondsPerDay
+
+ // Add in time elapsed today.
+ sec += int64(t.Hour) * 3600
+ sec += int64(t.Minute) * 60
+ sec += int64(t.Second)
+
+ // Convert from seconds since 2001 to seconds since 1970.
+ sec += days1970To2001 * secondsPerDay
+
+ // Account for local time zone.
+ sec -= int64(t.ZoneOffset)
+ return sec
+}
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
new file mode 100644
index 000000000..c86bca1b4
--- /dev/null
+++ b/libgo/go/time/time_test.go
@@ -0,0 +1,341 @@
+// 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 time_test
+
+import (
+ "os"
+ "strings"
+ "testing"
+ "testing/quick"
+ . "time"
+)
+
+func init() {
+ // Force US Pacific time for daylight-savings
+ // tests below (localtests). Needs to be set
+ // before the first call into the time library.
+ os.Setenv("TZ", "America/Los_Angeles")
+}
+
+type TimeTest struct {
+ seconds int64
+ golden Time
+}
+
+var utctests = []TimeTest{
+ {0, Time{1970, 1, 1, 0, 0, 0, Thursday, 0, "UTC"}},
+ {1221681866, Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}},
+ {-1221681866, Time{1931, 4, 16, 3, 55, 34, Thursday, 0, "UTC"}},
+ {-11644473600, Time{1601, 1, 1, 0, 0, 0, Monday, 0, "UTC"}},
+ {599529660, Time{1988, 12, 31, 0, 1, 0, Saturday, 0, "UTC"}},
+ {978220860, Time{2000, 12, 31, 0, 1, 0, Sunday, 0, "UTC"}},
+ {1e18, Time{31688740476, 10, 23, 1, 46, 40, Friday, 0, "UTC"}},
+ {-1e18, Time{-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "UTC"}},
+ {0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, Sunday, 0, "UTC"}},
+ {-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "UTC"}},
+}
+
+var localtests = []TimeTest{
+ {0, Time{1969, 12, 31, 16, 0, 0, Wednesday, -8 * 60 * 60, "PST"}},
+ {1221681866, Time{2008, 9, 17, 13, 4, 26, Wednesday, -7 * 60 * 60, "PDT"}},
+}
+
+func same(t, u *Time) bool {
+ return t.Year == u.Year &&
+ t.Month == u.Month &&
+ t.Day == u.Day &&
+ t.Hour == u.Hour &&
+ t.Minute == u.Minute &&
+ t.Second == u.Second &&
+ t.Weekday == u.Weekday &&
+ t.ZoneOffset == u.ZoneOffset &&
+ t.Zone == u.Zone
+}
+
+func TestSecondsToUTC(t *testing.T) {
+ for i := 0; i < len(utctests); i++ {
+ sec := utctests[i].seconds
+ golden := &utctests[i].golden
+ tm := SecondsToUTC(sec)
+ newsec := tm.Seconds()
+ if newsec != sec {
+ t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec)
+ }
+ if !same(tm, golden) {
+ t.Errorf("SecondsToUTC(%d):", sec)
+ t.Errorf(" want=%+v", *golden)
+ t.Errorf(" have=%+v", *tm)
+ }
+ }
+}
+
+func TestSecondsToLocalTime(t *testing.T) {
+ for i := 0; i < len(localtests); i++ {
+ sec := localtests[i].seconds
+ golden := &localtests[i].golden
+ tm := SecondsToLocalTime(sec)
+ newsec := tm.Seconds()
+ if newsec != sec {
+ t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec)
+ }
+ if !same(tm, golden) {
+ t.Errorf("SecondsToLocalTime(%d):", sec)
+ t.Errorf(" want=%+v", *golden)
+ t.Errorf(" have=%+v", *tm)
+ }
+ }
+}
+
+func TestSecondsToUTCAndBack(t *testing.T) {
+ f := func(sec int64) bool { return SecondsToUTC(sec).Seconds() == sec }
+ f32 := func(sec int32) bool { return f(int64(sec)) }
+ cfg := &quick.Config{MaxCount: 10000}
+
+ // Try a reasonable date first, then the huge ones.
+ if err := quick.Check(f32, cfg); err != nil {
+ t.Fatal(err)
+ }
+ if err := quick.Check(f, cfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+type TimeFormatTest struct {
+ time Time
+ formattedValue string
+}
+
+var rfc3339Formats = []TimeFormatTest{
+ {Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}, "2008-09-17T20:04:26Z"},
+ {Time{1994, 9, 17, 20, 4, 26, Wednesday, -18000, "EST"}, "1994-09-17T20:04:26-05:00"},
+ {Time{2000, 12, 26, 1, 15, 6, Wednesday, 15600, "OTO"}, "2000-12-26T01:15:06+04:20"},
+}
+
+func TestRFC3339Conversion(t *testing.T) {
+ for _, f := range rfc3339Formats {
+ if f.time.Format(RFC3339) != f.formattedValue {
+ t.Error("RFC3339:")
+ t.Errorf(" want=%+v", f.formattedValue)
+ t.Errorf(" have=%+v", f.time.Format(RFC3339))
+ }
+ }
+}
+
+type FormatTest struct {
+ name string
+ format string
+ result string
+}
+
+var formatTests = []FormatTest{
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010"},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010"},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010"},
+ {"RFC822", RFC822, "04 Feb 10 2100 PST"},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST"},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST"},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00"},
+ {"Kitchen", Kitchen, "9:00PM"},
+ {"am/pm", "3pm", "9pm"},
+ {"AM/PM", "3PM", "9PM"},
+}
+
+func TestFormat(t *testing.T) {
+ // The numeric time represents Thu Feb 4 21:00:57 PST 2010
+ time := SecondsToLocalTime(1265346057)
+ for _, test := range formatTests {
+ result := time.Format(test.format)
+ if result != test.result {
+ t.Errorf("%s expected %q got %q", test.name, test.result, result)
+ }
+ }
+}
+
+type ParseTest struct {
+ name string
+ format string
+ value string
+ hasTZ bool // contains a time zone
+ hasWD bool // contains a weekday
+ yearSign int64 // sign of year
+}
+
+var parseTests = []ParseTest{
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1},
+ {"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1},
+ // Amount of white space should not matter.
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1},
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1},
+}
+
+func TestParse(t *testing.T) {
+ for _, test := range parseTests {
+ time, err := Parse(test.format, test.value)
+ if err != nil {
+ t.Errorf("%s error: %v", test.name, err)
+ } else {
+ checkTime(time, &test, t)
+ }
+ }
+}
+
+var rubyTests = []ParseTest{
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1},
+ // Ignore the time zone in the test. If it parses, it'll be OK.
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1},
+}
+
+// Problematic time zone format needs special tests.
+func TestRubyParse(t *testing.T) {
+ for _, test := range rubyTests {
+ time, err := Parse(test.format, test.value)
+ if err != nil {
+ t.Errorf("%s error: %v", test.name, err)
+ } else {
+ checkTime(time, &test, t)
+ }
+ }
+}
+
+func checkTime(time *Time, test *ParseTest, t *testing.T) {
+ // The time should be Thu Feb 4 21:00:57 PST 2010
+ if test.yearSign*time.Year != 2010 {
+ t.Errorf("%s: bad year: %d not %d", test.name, time.Year, 2010)
+ }
+ if time.Month != 2 {
+ t.Errorf("%s: bad month: %d not %d", test.name, time.Month, 2)
+ }
+ if time.Day != 4 {
+ t.Errorf("%s: bad day: %d not %d", test.name, time.Day, 4)
+ }
+ if time.Hour != 21 {
+ t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour, 21)
+ }
+ if time.Minute != 0 {
+ t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute, 0)
+ }
+ if time.Second != 57 {
+ t.Errorf("%s: bad second: %d not %d", test.name, time.Second, 57)
+ }
+ if test.hasTZ && time.ZoneOffset != -28800 {
+ t.Errorf("%s: bad tz offset: %d not %d", test.name, time.ZoneOffset, -28800)
+ }
+ if test.hasWD && time.Weekday != 4 {
+ t.Errorf("%s: bad weekday: %d not %d", test.name, time.Weekday, 4)
+ }
+}
+
+func TestFormatAndParse(t *testing.T) {
+ const fmt = "Mon MST " + RFC3339 // all fields
+ f := func(sec int64) bool {
+ t1 := SecondsToLocalTime(sec)
+ if t1.Year < 1000 || t1.Year > 9999 {
+ // not required to work
+ return true
+ }
+ t2, err := Parse(fmt, t1.Format(fmt))
+ if err != nil {
+ t.Errorf("error: %s", err)
+ return false
+ }
+ if !same(t1, t2) {
+ t.Errorf("different: %q %q", t1, t2)
+ return false
+ }
+ return true
+ }
+ f32 := func(sec int32) bool { return f(int64(sec)) }
+ cfg := &quick.Config{MaxCount: 10000}
+
+ // Try a reasonable date first, then the huge ones.
+ if err := quick.Check(f32, cfg); err != nil {
+ t.Fatal(err)
+ }
+ if err := quick.Check(f, cfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+type ParseErrorTest struct {
+ format string
+ value string
+ expect string // must appear within the error
+}
+
+var parseErrorTests = []ParseErrorTest{
+ {ANSIC, "Feb 4 21:00:60 2010", "parse"}, // cannot parse Feb as Mon
+ {ANSIC, "Thu Feb 4 21:00:57 @2010", "parse"},
+ {ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"},
+ {ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"},
+ {ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"},
+}
+
+func TestParseErrors(t *testing.T) {
+ for _, test := range parseErrorTests {
+ _, err := Parse(test.format, test.value)
+ if err == nil {
+ t.Errorf("expected error for %q %q", test.format, test.value)
+ } else if strings.Index(err.String(), test.expect) < 0 {
+ t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
+ }
+ }
+}
+
+// Check that a time without a Zone still produces a (numeric) time zone
+// when formatted with MST as a requested zone.
+func TestMissingZone(t *testing.T) {
+ time, err := Parse(RubyDate, "Tue Feb 02 16:10:03 -0500 2006")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ expect := "Tue Feb 2 16:10:03 -0500 2006" // -0500 not EST
+ str := time.Format(UnixDate) // uses MST as its time zone
+ if str != expect {
+ t.Errorf("expected %q got %q", expect, str)
+ }
+}
+
+func TestMinutesInTimeZone(t *testing.T) {
+ time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ expected := (1*60 + 23) * 60
+ if time.ZoneOffset != expected {
+ t.Errorf("ZoneOffset incorrect, expected %d got %d", expected, time.ZoneOffset)
+ }
+}
+
+func BenchmarkSeconds(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Seconds()
+ }
+}
+
+func BenchmarkNanoseconds(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Nanoseconds()
+ }
+}
+
+func BenchmarkFormat(b *testing.B) {
+ time := SecondsToLocalTime(1265346057)
+ for i := 0; i < b.N; i++ {
+ time.Format("Mon Jan 2 15:04:05 2006")
+ }
+}
+
+func BenchmarkParse(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Parse(ANSIC, "Mon Jan 2 15:04:05 2006")
+ }
+}
diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go
new file mode 100644
index 000000000..6685da747
--- /dev/null
+++ b/libgo/go/time/zoneinfo_unix.go
@@ -0,0 +1,267 @@
+// 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.
+
+// Parse "zoneinfo" time zone file.
+// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
+// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
+// and ftp://munnari.oz.au/pub/oldtz/
+
+package time
+
+import (
+ "io/ioutil"
+ "os"
+ "sync"
+)
+
+const (
+ headerSize = 4 + 16 + 4*7
+ zoneDir = "/usr/share/zoneinfo/"
+ zoneDir2 = "/usr/share/lib/zoneinfo/"
+)
+
+// Simple I/O interface to binary blob of data.
+type data struct {
+ p []byte
+ error bool
+}
+
+
+func (d *data) read(n int) []byte {
+ if len(d.p) < n {
+ d.p = nil
+ d.error = true
+ return nil
+ }
+ p := d.p[0:n]
+ d.p = d.p[n:]
+ return p
+}
+
+func (d *data) big4() (n uint32, ok bool) {
+ p := d.read(4)
+ if len(p) < 4 {
+ d.error = true
+ return 0, false
+ }
+ return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
+}
+
+func (d *data) byte() (n byte, ok bool) {
+ p := d.read(1)
+ if len(p) < 1 {
+ d.error = true
+ return 0, false
+ }
+ return p[0], true
+}
+
+
+// Make a string by stopping at the first NUL
+func byteString(p []byte) string {
+ for i := 0; i < len(p); i++ {
+ if p[i] == 0 {
+ return string(p[0:i])
+ }
+ }
+ 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}
+
+ // 4-byte magic "TZif"
+ if magic := d.read(4); string(magic) != "TZif" {
+ return nil, false
+ }
+
+ // 1-byte version, then 15 bytes of padding
+ var p []byte
+ if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
+ return nil, false
+ }
+
+ // six big-endian 32-bit integers:
+ // number of UTC/local indicators
+ // number of standard/wall indicators
+ // number of leap seconds
+ // number of transition times
+ // number of local time zones
+ // number of characters of time zone abbrev strings
+ const (
+ NUTCLocal = iota
+ NStdWall
+ NLeap
+ NTime
+ NZone
+ NChar
+ )
+ var n [6]int
+ for i := 0; i < 6; i++ {
+ nn, ok := d.big4()
+ if !ok {
+ return nil, false
+ }
+ n[i] = int(nn)
+ }
+
+ // Transition times.
+ txtimes := data{d.read(n[NTime] * 4), false}
+
+ // Time zone indices for transition times.
+ txzones := d.read(n[NTime])
+
+ // Zone info structures
+ zonedata := data{d.read(n[NZone] * 6), false}
+
+ // Time zone abbreviations.
+ abbrev := d.read(n[NChar])
+
+ // Leap-second time pairs
+ d.read(n[NLeap] * 8)
+
+ // Whether tx times associated with local time types
+ // are specified as standard time or wall time.
+ isstd := d.read(n[NStdWall])
+
+ // Whether tx times associated with local time types
+ // are specified as UTC or local time.
+ isutc := d.read(n[NUTCLocal])
+
+ if d.error { // ran out of data
+ return nil, false
+ }
+
+ // If version == 2, the entire file repeats, this time using
+ // 8-byte ints for txtimes and leap seconds.
+ // We won't need those until 2106.
+
+ // Now we can build up a useful data structure.
+ // First the zone information.
+ // utcoff[4] isdst[1] nameindex[1]
+ z := make([]zone, n[NZone])
+ for i := 0; i < len(z); i++ {
+ var ok bool
+ var n uint32
+ if n, ok = zonedata.big4(); !ok {
+ return nil, false
+ }
+ z[i].utcoff = int(n)
+ var b byte
+ if b, ok = zonedata.byte(); !ok {
+ return nil, false
+ }
+ z[i].isdst = b != 0
+ if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
+ return nil, false
+ }
+ z[i].name = byteString(abbrev[b:])
+ }
+
+ // Now the transition time info.
+ zt = make([]zonetime, n[NTime])
+ for i := 0; i < len(zt); i++ {
+ var ok bool
+ var n uint32
+ if n, ok = txtimes.big4(); !ok {
+ return nil, false
+ }
+ zt[i].time = int32(n)
+ if int(txzones[i]) >= len(z) {
+ return nil, false
+ }
+ zt[i].zone = &z[txzones[i]]
+ if i < len(isstd) {
+ zt[i].isstd = isstd[i] != 0
+ }
+ if i < len(isutc) {
+ zt[i].isutc = isutc[i] != 0
+ }
+ }
+ return zt, true
+}
+
+func readinfofile(name string) ([]zonetime, bool) {
+ buf, err := ioutil.ReadFile(name)
+ if err != nil {
+ return nil, false
+ }
+ 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.
+ // $TZ="" means use UTC.
+ // $TZ="foo" means use /usr/share/zoneinfo/foo.
+
+ tz, err := os.Getenverror("TZ")
+ switch {
+ case err == os.ENOENV:
+ zones, _ = readinfofile("/etc/localtime")
+ case len(tz) > 0:
+ var ok bool
+ zones, ok = readinfofile(zoneDir + tz)
+ if !ok {
+ zones, _ = readinfofile(zoneDir2 + tz)
+ }
+ case len(tz) == 0:
+ // 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/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
new file mode 100644
index 000000000..c357eec62
--- /dev/null
+++ b/libgo/go/time/zoneinfo_windows.go
@@ -0,0 +1,192 @@
+// 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 time
+
+import (
+ "syscall"
+ "sync"
+ "os"
+)
+
+// BUG(brainman): The Windows implementation assumes that
+// this year's rules for daylight savings time apply to all previous
+// and future years as well.
+
+// TODO(brainman): use GetDynamicTimeZoneInformation, whenever posible (Vista and up),
+// to improve on situation described in the bug above.
+
+type zone struct {
+ name string
+ offset int
+ year int64
+ month, day, dayofweek int
+ hour, minute, second int
+ abssec int64
+ prev *zone
+}
+
+// Populate zone struct with Windows supplied information. Returns true, if data is valid.
+func (z *zone) populate(bias, biasdelta int32, d *syscall.Systemtime, name []uint16) (dateisgood bool) {
+ z.name = syscall.UTF16ToString(name)
+ z.offset = int(bias)
+ z.year = int64(d.Year)
+ z.month = int(d.Month)
+ z.day = int(d.Day)
+ z.dayofweek = int(d.DayOfWeek)
+ z.hour = int(d.Hour)
+ z.minute = int(d.Minute)
+ z.second = int(d.Second)
+ dateisgood = d.Month != 0
+ if dateisgood {
+ z.offset += int(biasdelta)
+ }
+ z.offset = -z.offset * 60
+ return
+}
+
+// Pre-calculte cutoff time in seconds since the Unix epoch, if data is supplied in "absolute" format.
+func (z *zone) preCalculateAbsSec() {
+ if z.year != 0 {
+ z.abssec = (&Time{z.year, int(z.month), int(z.day), int(z.hour), int(z.minute), int(z.second), 0, 0, ""}).Seconds()
+ // Time given is in "local" time. Adjust it for "utc".
+ z.abssec -= int64(z.prev.offset)
+ }
+}
+
+// Convert zone cutoff time to sec in number of seconds since the Unix epoch, given particualar year.
+func (z *zone) cutoffSeconds(year int64) int64 {
+ // Windows specifies daylight savings information in "day in month" format:
+ // z.month is month number (1-12)
+ // z.dayofweek is appropriate weekday (Sunday=0 to Saturday=6)
+ // z.day is week within the month (1 to 5, where 5 is last week of the month)
+ // z.hour, z.minute and z.second are absolute time
+ t := &Time{year, int(z.month), 1, int(z.hour), int(z.minute), int(z.second), 0, 0, ""}
+ t = SecondsToUTC(t.Seconds())
+ i := int(z.dayofweek) - t.Weekday
+ if i < 0 {
+ i += 7
+ }
+ t.Day += i
+ if week := int(z.day) - 1; week < 4 {
+ t.Day += week * 7
+ } else {
+ // "Last" instance of the day.
+ t.Day += 4 * 7
+ if t.Day > months(year)[t.Month] {
+ t.Day -= 7
+ }
+ }
+ // Result is in "local" time. Adjust it for "utc".
+ return t.Seconds() - int64(z.prev.offset)
+}
+
+// Is t before the cutoff for switching to z?
+func (z *zone) isBeforeCutoff(t *Time) bool {
+ var coff int64
+ if z.year == 0 {
+ // "day in month" format used
+ coff = z.cutoffSeconds(t.Year)
+ } else {
+ // "absolute" format used
+ coff = z.abssec
+ }
+ return t.Seconds() < coff
+}
+
+type zoneinfo struct {
+ disabled bool // daylight saving time is not used localy
+ offsetIfDisabled int
+ januaryIsStd bool // is january 1 standard time?
+ std, dst zone
+}
+
+// Pick zone (std or dst) t time belongs to.
+func (zi *zoneinfo) pickZone(t *Time) *zone {
+ z := &zi.std
+ if tz.januaryIsStd {
+ if !zi.dst.isBeforeCutoff(t) && zi.std.isBeforeCutoff(t) {
+ // after switch to daylight time and before the switch back to standard
+ z = &zi.dst
+ }
+ } else {
+ if zi.std.isBeforeCutoff(t) || !zi.dst.isBeforeCutoff(t) {
+ // before switch to standard time or after the switch back to daylight
+ z = &zi.dst
+ }
+ }
+ return z
+}
+
+var tz zoneinfo
+var initError os.Error
+var onceSetupZone sync.Once
+
+func setupZone() {
+ var i syscall.Timezoneinformation
+ if _, e := syscall.GetTimeZoneInformation(&i); e != 0 {
+ initError = os.NewSyscallError("GetTimeZoneInformation", e)
+ return
+ }
+ if !tz.std.populate(i.Bias, i.StandardBias, &i.StandardDate, i.StandardName[0:]) {
+ tz.disabled = true
+ tz.offsetIfDisabled = tz.std.offset
+ return
+ }
+ tz.std.prev = &tz.dst
+ tz.dst.populate(i.Bias, i.DaylightBias, &i.DaylightDate, i.DaylightName[0:])
+ tz.dst.prev = &tz.std
+ tz.std.preCalculateAbsSec()
+ tz.dst.preCalculateAbsSec()
+ // Is january 1 standard time this year?
+ t := UTC()
+ tz.januaryIsStd = tz.dst.cutoffSeconds(t.Year) < tz.std.cutoffSeconds(t.Year)
+}
+
+// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
+func lookupTimezone(sec int64) (zone string, offset int) {
+ onceSetupZone.Do(setupZone)
+ if initError != nil {
+ return "", 0
+ }
+ if tz.disabled {
+ return "", tz.offsetIfDisabled
+ }
+ t := SecondsToUTC(sec)
+ z := &tz.std
+ if tz.std.year == 0 {
+ // "day in month" format used
+ z = tz.pickZone(t)
+ } else {
+ // "absolute" format used
+ if tz.std.year == t.Year {
+ // we have rule for the year in question
+ z = tz.pickZone(t)
+ } else {
+ // we do not have any information for that year,
+ // will assume standard offset all year around
+ }
+ }
+ return z.name, z.offset
+}
+
+// lookupByName returns the time offset for the
+// time zone with the given abbreviation. It only considers
+// time zones that apply to the current system.
+func lookupByName(name string) (off int, found bool) {
+ onceSetupZone.Do(setupZone)
+ if initError != nil {
+ return 0, false
+ }
+ if tz.disabled {
+ return tz.offsetIfDisabled, false
+ }
+ switch name {
+ case tz.std.name:
+ return tz.std.offset, true
+ case tz.dst.name:
+ return tz.dst.offset, true
+ }
+ return 0, false
+}
diff --git a/libgo/go/try/try.go b/libgo/go/try/try.go
new file mode 100644
index 000000000..af31d0d2c
--- /dev/null
+++ b/libgo/go/try/try.go
@@ -0,0 +1,174 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package try contains the executable part of the gotry command.
+// It is not intended for general use.
+package try
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "unicode"
+)
+
+var output io.Writer = os.Stdout // redirected when testing
+
+// Main is called directly from the gotry-generated Go source file to perform
+// the evaluations.
+func Main(pkg, firstArg string, functions map[string]interface{}, args []interface{}) {
+ switch len(args) {
+ case 0:
+ // Nothing to do.
+ case 1:
+ // Compiler has already evaluated the expression; just print the result.
+ printSlice(firstArg, args)
+ default:
+ // See if methods satisfy the expressions.
+ tryMethods(pkg, firstArg, args)
+ // See if functions satisfy the expressions.
+ for name, fn := range functions {
+ tryFunction(pkg, name, fn, args)
+ }
+ }
+}
+
+// printSlice prints the zeroth element of the args slice, which should (by construction)
+// itself be a slice of interface{}.
+func printSlice(firstArg string, args []interface{}) {
+ // Args should be length 1 and a slice.
+ if len(args) != 1 {
+ return
+ }
+ arg, ok := args[0].([]interface{})
+ if !ok {
+ return
+ }
+ fmt.Fprintf(output, "%s = ", firstArg)
+ if len(arg) > 1 {
+ fmt.Fprint(output, "(")
+ }
+ for i, a := range arg {
+ if i > 0 {
+ fmt.Fprint(output, ", ")
+ }
+ fmt.Fprintf(output, "%#v", a)
+ }
+ if len(arg) > 1 {
+ fmt.Fprint(output, ")")
+ }
+ fmt.Fprint(output, "\n")
+}
+
+// tryMethods sees if the zeroth arg has methods, and if so treats them as potential
+// functions to satisfy the remaining arguments.
+func tryMethods(pkg, firstArg string, args []interface{}) {
+ defer func() { recover() }()
+ // Is the first argument something with methods?
+ v := reflect.NewValue(args[0])
+ typ := v.Type()
+ if typ.NumMethod() == 0 {
+ return
+ }
+ for i := 0; i < typ.NumMethod(); i++ {
+ if unicode.IsUpper(int(typ.Method(i).Name[0])) {
+ tryMethod(pkg, firstArg, typ.Method(i), args)
+ }
+ }
+}
+
+// tryMethod converts a method to a function for tryOneFunction.
+func tryMethod(pkg, firstArg string, method reflect.Method, args []interface{}) {
+ rfn := method.Func
+ typ := method.Type
+ name := method.Name
+ tryOneFunction(pkg, firstArg, name, typ, rfn, args)
+}
+
+// tryFunction sees if fn satisfies the arguments.
+func tryFunction(pkg, name string, fn interface{}, args []interface{}) {
+ defer func() { recover() }()
+ rfn := reflect.NewValue(fn).(*reflect.FuncValue)
+ typ := rfn.Type().(*reflect.FuncType)
+ tryOneFunction(pkg, "", name, typ, rfn, args)
+}
+
+// tryOneFunction is the common code for tryMethod and tryFunction.
+func tryOneFunction(pkg, firstArg, name string, typ *reflect.FuncType, rfn *reflect.FuncValue, args []interface{}) {
+ // Any results?
+ if typ.NumOut() == 0 {
+ return // Nothing to do.
+ }
+ // Right number of arguments + results?
+ if typ.NumIn()+typ.NumOut() != len(args) {
+ return
+ }
+ // Right argument and result types?
+ for i, a := range args {
+ if i < typ.NumIn() {
+ if !compatible(a, typ.In(i)) {
+ return
+ }
+ } else {
+ if !compatible(a, typ.Out(i-typ.NumIn())) {
+ return
+ }
+ }
+ }
+ // Build the call args.
+ argsVal := make([]reflect.Value, typ.NumIn()+typ.NumOut())
+ for i, a := range args {
+ argsVal[i] = reflect.NewValue(a)
+ }
+ // Call the function and see if the results are as expected.
+ resultVal := rfn.Call(argsVal[:typ.NumIn()])
+ for i, v := range resultVal {
+ if !reflect.DeepEqual(v.Interface(), args[i+typ.NumIn()]) {
+ return
+ }
+ }
+ // Present the result including a godoc command to get more information.
+ firstIndex := 0
+ if firstArg != "" {
+ fmt.Fprintf(output, "%s.%s(", firstArg, name)
+ firstIndex = 1
+ } else {
+ fmt.Fprintf(output, "%s.%s(", pkg, name)
+ }
+ for i := firstIndex; i < typ.NumIn(); i++ {
+ if i > firstIndex {
+ fmt.Fprint(output, ", ")
+ }
+ fmt.Fprintf(output, "%#v", args[i])
+ }
+ fmt.Fprint(output, ") = ")
+ if typ.NumOut() > 1 {
+ fmt.Fprint(output, "(")
+ }
+ for i := 0; i < typ.NumOut(); i++ {
+ if i > 0 {
+ fmt.Fprint(output, ", ")
+ }
+ fmt.Fprintf(output, "%#v", resultVal[i].Interface())
+ }
+ if typ.NumOut() > 1 {
+ fmt.Fprint(output, ")")
+ }
+ fmt.Fprintf(output, " // godoc %s %s\n", pkg, name)
+}
+
+// compatible reports whether the argument is compatible with the type.
+func compatible(arg interface{}, typ reflect.Type) bool {
+ if reflect.Typeof(arg) == typ {
+ return true
+ }
+ if arg == nil {
+ // nil is OK if the type is an interface.
+ if _, ok := typ.(*reflect.InterfaceType); ok {
+ return true
+ }
+ }
+ return false
+}
diff --git a/libgo/go/try/try_test.go b/libgo/go/try/try_test.go
new file mode 100644
index 000000000..617b2c7c3
--- /dev/null
+++ b/libgo/go/try/try_test.go
@@ -0,0 +1,60 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package try
+
+import (
+ "bytes"
+ "regexp" // Used as the package to try.
+ "testing"
+)
+
+// The global functions in package regexp at time of writing.
+// Doesn't need to be updated unless the entries in this list become invalid.
+var functions = map[string]interface{}{
+ "Compile": regexp.Compile,
+ "Match": regexp.Match,
+ "MatchString": regexp.MatchString,
+ "MustCompile": regexp.MustCompile,
+ "QuoteMeta": regexp.QuoteMeta,
+}
+
+// A wraps arguments to make the test cases nicer to read.
+func A(args ...interface{}) []interface{} {
+ return args
+}
+
+type Test struct {
+ firstArg string // only needed if there is exactly one argument
+ result string // minus final newline; might be just the godoc string
+ args []interface{}
+}
+
+var testRE = regexp.MustCompile("a(.)(.)d")
+
+var tests = []Test{
+ // A simple expression. The final value is a slice in case the expression is multivalue.
+ {"3+4", "3+4 = 7", A([]interface{}{7})},
+ // A search for a function.
+ {"", "regexp QuoteMeta", A("([])", `\(\[\]\)`)},
+ // A search for a function with multiple return values.
+ {"", "regexp MatchString", A("abc", "xabcd", true, nil)},
+ // Searches for methods.
+ {"", "regexp MatchString", A(testRE, "xabcde", true)},
+ {"", "regexp NumSubexp", A(testRE, 2)},
+}
+
+func TestAll(t *testing.T) {
+ re := regexp.MustCompile(".*// godoc ")
+ for _, test := range tests {
+ b := new(bytes.Buffer)
+ output = b
+ Main("regexp", test.firstArg, functions, test.args)
+ expect := test.result + "\n"
+ got := re.ReplaceAllString(b.String(), "")
+ if got != expect {
+ t.Errorf("expected %q; got %q", expect, got)
+ }
+ }
+}
diff --git a/libgo/go/unicode/casetables.go b/libgo/go/unicode/casetables.go
new file mode 100644
index 000000000..66440705b
--- /dev/null
+++ b/libgo/go/unicode/casetables.go
@@ -0,0 +1,21 @@
+// 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.
+
+// TODO: This file contains the special casing rules for Turkish and Azeri only.
+// It should encompass all the languages with special casing rules
+// and be generated automatically, but that requires some API
+// development first.
+
+package unicode
+
+
+var TurkishCase = _TurkishCase
+var _TurkishCase = SpecialCase{
+ CaseRange{0x0049, 0x0049, d{0, 0x131 - 0x49, 0}},
+ CaseRange{0x0069, 0x0069, d{0x130 - 0x69, 0, 0x130 - 0x69}},
+ CaseRange{0x0130, 0x0130, d{0, 0x69 - 0x130, 0}},
+ CaseRange{0x0131, 0x0131, d{0x49 - 0x131, 0, 0x49 - 0x131}},
+}
+
+var AzeriCase = _TurkishCase
diff --git a/libgo/go/unicode/digit.go b/libgo/go/unicode/digit.go
new file mode 100644
index 000000000..471c4dfdc
--- /dev/null
+++ b/libgo/go/unicode/digit.go
@@ -0,0 +1,13 @@
+// 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 unicode
+
+// IsDigit reports whether the rune is a decimal digit.
+func IsDigit(rune int) bool {
+ if rune < 0x100 { // quick ASCII (Latin-1, really) check
+ return '0' <= rune && rune <= '9'
+ }
+ return Is(Digit, rune)
+}
diff --git a/libgo/go/unicode/digit_test.go b/libgo/go/unicode/digit_test.go
new file mode 100644
index 000000000..9bbccde92
--- /dev/null
+++ b/libgo/go/unicode/digit_test.go
@@ -0,0 +1,126 @@
+// 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 unicode_test
+
+import (
+ "testing"
+ . "unicode"
+)
+
+var testDigit = []int{
+ 0x0030,
+ 0x0039,
+ 0x0661,
+ 0x06F1,
+ 0x07C9,
+ 0x0966,
+ 0x09EF,
+ 0x0A66,
+ 0x0AEF,
+ 0x0B66,
+ 0x0B6F,
+ 0x0BE6,
+ 0x0BEF,
+ 0x0C66,
+ 0x0CEF,
+ 0x0D66,
+ 0x0D6F,
+ 0x0E50,
+ 0x0E59,
+ 0x0ED0,
+ 0x0ED9,
+ 0x0F20,
+ 0x0F29,
+ 0x1040,
+ 0x1049,
+ 0x1090,
+ 0x1091,
+ 0x1099,
+ 0x17E0,
+ 0x17E9,
+ 0x1810,
+ 0x1819,
+ 0x1946,
+ 0x194F,
+ 0x19D0,
+ 0x19D9,
+ 0x1B50,
+ 0x1B59,
+ 0x1BB0,
+ 0x1BB9,
+ 0x1C40,
+ 0x1C49,
+ 0x1C50,
+ 0x1C59,
+ 0xA620,
+ 0xA629,
+ 0xA8D0,
+ 0xA8D9,
+ 0xA900,
+ 0xA909,
+ 0xAA50,
+ 0xAA59,
+ 0xFF10,
+ 0xFF19,
+ 0x104A1,
+ 0x1D7CE,
+}
+
+var testLetter = []int{
+ 0x0041,
+ 0x0061,
+ 0x00AA,
+ 0x00BA,
+ 0x00C8,
+ 0x00DB,
+ 0x00F9,
+ 0x02EC,
+ 0x0535,
+ 0x06E6,
+ 0x093D,
+ 0x0A15,
+ 0x0B99,
+ 0x0DC0,
+ 0x0EDD,
+ 0x1000,
+ 0x1200,
+ 0x1312,
+ 0x1401,
+ 0x1885,
+ 0x2C00,
+ 0xA800,
+ 0xF900,
+ 0xFA30,
+ 0xFFDA,
+ 0xFFDC,
+ 0x10000,
+ 0x10300,
+ 0x10400,
+ 0x20000,
+ 0x2F800,
+ 0x2FA1D,
+}
+
+func TestDigit(t *testing.T) {
+ for _, r := range testDigit {
+ if !IsDigit(r) {
+ t.Errorf("IsDigit(U+%04X) = false, want true", r)
+ }
+ }
+ for _, r := range testLetter {
+ if IsDigit(r) {
+ t.Errorf("IsDigit(U+%04X) = true, want false", r)
+ }
+ }
+}
+
+// Test that the special case in IsDigit agrees with the table
+func TestDigitOptimization(t *testing.T) {
+ for i := 0; i < 0x100; i++ {
+ if Is(Digit, i) != IsDigit(i) {
+ t.Errorf("IsDigit(U+%04X) disagrees with Is(Digit)", i)
+ }
+ }
+}
diff --git a/libgo/go/unicode/letter.go b/libgo/go/unicode/letter.go
new file mode 100644
index 000000000..9380624fd
--- /dev/null
+++ b/libgo/go/unicode/letter.go
@@ -0,0 +1,241 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package provides data and functions to test some properties of Unicode code points.
+package unicode
+
+const (
+ MaxRune = 0x10FFFF // Maximum valid Unicode code point.
+ ReplacementChar = 0xFFFD // Represents invalid code points.
+)
+
+
+// The representation of a range of Unicode code points. The range runs from Lo to Hi
+// inclusive and has the specified stride.
+type Range struct {
+ Lo int
+ Hi int
+ Stride int
+}
+
+// CaseRange represents a range of Unicode code points for simple (one
+// code point to one code point) case conversion.
+// The range runs from Lo to Hi inclusive, with a fixed stride of 1. Deltas
+// are the number to add to the code point to reach the code point for a
+// different case for that character. They may be negative. If zero, it
+// means the character is in the corresponding case. There is a special
+// case representing sequences of alternating corresponding Upper and Lower
+// pairs. It appears with a fixed Delta of
+// {UpperLower, UpperLower, UpperLower}
+// The constant UpperLower has an otherwise impossible delta value.
+type CaseRange struct {
+ Lo int
+ Hi int
+ Delta d
+}
+
+// SpecialCase represents language-specific case mappings such as Turkish.
+// Methods of SpecialCase customize (by overriding) the standard mappings.
+type SpecialCase []CaseRange
+
+//BUG(r): Provide a mechanism for full case folding (those that involve
+// multiple runes in the input or output).
+
+// Indices into the Delta arrays inside CaseRanges for case mapping.
+const (
+ UpperCase = iota
+ LowerCase
+ TitleCase
+ MaxCase
+)
+
+type d [MaxCase]int32 // to make the CaseRanges text shorter
+
+// If the Delta field of a CaseRange is UpperLower or LowerUpper, it means
+// this CaseRange represents a sequence of the form (say)
+// Upper Lower Upper Lower.
+const (
+ UpperLower = MaxRune + 1 // (Cannot be a valid delta.)
+)
+
+// Is tests whether rune is in the specified table of ranges.
+func Is(ranges []Range, rune int) bool {
+ // common case: rune is ASCII or Latin-1
+ if rune < 0x100 {
+ for _, r := range ranges {
+ if rune > r.Hi {
+ continue
+ }
+ if rune < r.Lo {
+ return false
+ }
+ return (rune-r.Lo)%r.Stride == 0
+ }
+ return false
+ }
+
+ // binary search over ranges
+ lo := 0
+ hi := len(ranges)
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ r := ranges[m]
+ if r.Lo <= rune && rune <= r.Hi {
+ return (rune-r.Lo)%r.Stride == 0
+ }
+ if rune < r.Lo {
+ hi = m
+ } else {
+ lo = m + 1
+ }
+ }
+ return false
+}
+
+// IsUpper reports whether the rune is an upper case letter.
+func IsUpper(rune int) bool {
+ if rune < 0x80 { // quick ASCII check
+ return 'A' <= rune && rune <= 'Z'
+ }
+ return Is(Upper, rune)
+}
+
+// IsLower reports whether the rune is a lower case letter.
+func IsLower(rune int) bool {
+ if rune < 0x80 { // quick ASCII check
+ return 'a' <= rune && rune <= 'z'
+ }
+ return Is(Lower, rune)
+}
+
+// IsTitle reports whether the rune is a title case letter.
+func IsTitle(rune int) bool {
+ if rune < 0x80 { // quick ASCII check
+ return false
+ }
+ return Is(Title, rune)
+}
+
+// IsLetter reports whether the rune is a letter.
+func IsLetter(rune int) bool {
+ if rune < 0x80 { // quick ASCII check
+ rune &^= 'a' - 'A'
+ return 'A' <= rune && rune <= 'Z'
+ }
+ return Is(Letter, rune)
+}
+
+// IsSpace reports whether the rune is a white space character.
+func IsSpace(rune int) bool {
+ if rune <= 0xFF { // quick Latin-1 check
+ switch rune {
+ case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
+ return true
+ }
+ return false
+ }
+ return Is(White_Space, rune)
+}
+
+// to maps the rune using the specified case mapping.
+func to(_case int, rune int, caseRange []CaseRange) int {
+ if _case < 0 || MaxCase <= _case {
+ return ReplacementChar // as reasonable an error as any
+ }
+ // binary search over ranges
+ lo := 0
+ hi := len(caseRange)
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ r := caseRange[m]
+ if r.Lo <= rune && rune <= r.Hi {
+ delta := int(r.Delta[_case])
+ if delta > MaxRune {
+ // In an Upper-Lower sequence, which always starts with
+ // an UpperCase letter, the real deltas always look like:
+ // {0, 1, 0} UpperCase (Lower is next)
+ // {-1, 0, -1} LowerCase (Upper, Title are previous)
+ // The characters at even offsets from the beginning of the
+ // sequence are upper case; the ones at odd offsets are lower.
+ // The correct mapping can be done by clearing or setting the low
+ // bit in the sequence offset.
+ // The constants UpperCase and TitleCase are even while LowerCase
+ // is odd so we take the low bit from _case.
+ return r.Lo + ((rune-r.Lo)&^1 | _case&1)
+ }
+ return rune + delta
+ }
+ if rune < r.Lo {
+ hi = m
+ } else {
+ lo = m + 1
+ }
+ }
+ return rune
+}
+
+// To maps the rune to the specified case: UpperCase, LowerCase, or TitleCase.
+func To(_case int, rune int) int {
+ return to(_case, rune, CaseRanges)
+}
+
+// ToUpper maps the rune to upper case.
+func ToUpper(rune int) int {
+ if rune < 0x80 { // quick ASCII check
+ if 'a' <= rune && rune <= 'z' {
+ rune -= 'a' - 'A'
+ }
+ return rune
+ }
+ return To(UpperCase, rune)
+}
+
+// ToLower maps the rune to lower case.
+func ToLower(rune int) int {
+ if rune < 0x80 { // quick ASCII check
+ if 'A' <= rune && rune <= 'Z' {
+ rune += 'a' - 'A'
+ }
+ return rune
+ }
+ return To(LowerCase, rune)
+}
+
+// ToTitle maps the rune to title case.
+func ToTitle(rune int) int {
+ if rune < 0x80 { // quick ASCII check
+ if 'a' <= rune && rune <= 'z' { // title case is upper case for ASCII
+ rune -= 'a' - 'A'
+ }
+ return rune
+ }
+ return To(TitleCase, rune)
+}
+
+// ToUpper maps the rune to upper case giving priority to the special mapping.
+func (special SpecialCase) ToUpper(rune int) int {
+ r := to(UpperCase, rune, []CaseRange(special))
+ if r == rune {
+ r = ToUpper(rune)
+ }
+ return r
+}
+
+// ToTitle maps the rune to title case giving priority to the special mapping.
+func (special SpecialCase) ToTitle(rune int) int {
+ r := to(TitleCase, rune, []CaseRange(special))
+ if r == rune {
+ r = ToTitle(rune)
+ }
+ return r
+}
+
+// ToLower maps the rune to lower case giving priority to the special mapping.
+func (special SpecialCase) ToLower(rune int) int {
+ r := to(LowerCase, rune, []CaseRange(special))
+ if r == rune {
+ r = ToLower(rune)
+ }
+ return r
+}
diff --git a/libgo/go/unicode/letter_test.go b/libgo/go/unicode/letter_test.go
new file mode 100644
index 000000000..b8ef64827
--- /dev/null
+++ b/libgo/go/unicode/letter_test.go
@@ -0,0 +1,377 @@
+// 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 unicode_test
+
+import (
+ "testing"
+ . "unicode"
+)
+
+var upperTest = []int{
+ 0x41,
+ 0xc0,
+ 0xd8,
+ 0x100,
+ 0x139,
+ 0x14a,
+ 0x178,
+ 0x181,
+ 0x376,
+ 0x3cf,
+ 0x1f2a,
+ 0x2102,
+ 0x2c00,
+ 0x2c10,
+ 0x2c20,
+ 0xa650,
+ 0xa722,
+ 0xff3a,
+ 0x10400,
+ 0x1d400,
+ 0x1d7ca,
+}
+
+var notupperTest = []int{
+ 0x40,
+ 0x5b,
+ 0x61,
+ 0x185,
+ 0x1b0,
+ 0x377,
+ 0x387,
+ 0x2150,
+ 0xffff,
+ 0x10000,
+}
+
+var letterTest = []int{
+ 0x41,
+ 0x61,
+ 0xaa,
+ 0xba,
+ 0xc8,
+ 0xdb,
+ 0xf9,
+ 0x2ec,
+ 0x535,
+ 0x6e6,
+ 0x93d,
+ 0xa15,
+ 0xb99,
+ 0xdc0,
+ 0xedd,
+ 0x1000,
+ 0x1200,
+ 0x1312,
+ 0x1401,
+ 0x1885,
+ 0x2c00,
+ 0xa800,
+ 0xf900,
+ 0xfa30,
+ 0xffda,
+ 0xffdc,
+ 0x10000,
+ 0x10300,
+ 0x10400,
+ 0x20000,
+ 0x2f800,
+ 0x2fa1d,
+}
+
+var notletterTest = []int{
+ 0x20,
+ 0x35,
+ 0x375,
+ 0x620,
+ 0x700,
+ 0xfffe,
+ 0x1ffff,
+ 0x10ffff,
+}
+
+// Contains all the special cased Latin-1 chars.
+var spaceTest = []int{
+ 0x09,
+ 0x0a,
+ 0x0b,
+ 0x0c,
+ 0x0d,
+ 0x20,
+ 0x85,
+ 0xA0,
+ 0x2000,
+ 0x3000,
+}
+
+type caseT struct {
+ cas, in, out int
+}
+
+var caseTest = []caseT{
+ // errors
+ {-1, '\n', 0xFFFD},
+ {UpperCase, -1, -1},
+ {UpperCase, 1 << 30, 1 << 30},
+
+ // ASCII (special-cased so test carefully)
+ {UpperCase, '\n', '\n'},
+ {UpperCase, 'a', 'A'},
+ {UpperCase, 'A', 'A'},
+ {UpperCase, '7', '7'},
+ {LowerCase, '\n', '\n'},
+ {LowerCase, 'a', 'a'},
+ {LowerCase, 'A', 'a'},
+ {LowerCase, '7', '7'},
+ {TitleCase, '\n', '\n'},
+ {TitleCase, 'a', 'A'},
+ {TitleCase, 'A', 'A'},
+ {TitleCase, '7', '7'},
+
+ // Latin-1: easy to read the tests!
+ {UpperCase, 0x80, 0x80},
+ {UpperCase, 'Å', 'Å'},
+ {UpperCase, 'å', 'Å'},
+ {LowerCase, 0x80, 0x80},
+ {LowerCase, 'Å', 'å'},
+ {LowerCase, 'å', 'å'},
+ {TitleCase, 0x80, 0x80},
+ {TitleCase, 'Å', 'Å'},
+ {TitleCase, 'å', 'Å'},
+
+ // 0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049
+ {UpperCase, 0x0131, 'I'},
+ {LowerCase, 0x0131, 0x0131},
+ {TitleCase, 0x0131, 'I'},
+
+ // 0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132
+ {UpperCase, 0x0133, 0x0132},
+ {LowerCase, 0x0133, 0x0133},
+ {TitleCase, 0x0133, 0x0132},
+
+ // 212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B;
+ {UpperCase, 0x212A, 0x212A},
+ {LowerCase, 0x212A, 'k'},
+ {TitleCase, 0x212A, 0x212A},
+
+ // From an UpperLower sequence
+ // A640;CYRILLIC CAPITAL LETTER ZEMLYA;Lu;0;L;;;;;N;;;;A641;
+ {UpperCase, 0xA640, 0xA640},
+ {LowerCase, 0xA640, 0xA641},
+ {TitleCase, 0xA640, 0xA640},
+ // A641;CYRILLIC SMALL LETTER ZEMLYA;Ll;0;L;;;;;N;;;A640;;A640
+ {UpperCase, 0xA641, 0xA640},
+ {LowerCase, 0xA641, 0xA641},
+ {TitleCase, 0xA641, 0xA640},
+ // A64E;CYRILLIC CAPITAL LETTER NEUTRAL YER;Lu;0;L;;;;;N;;;;A64F;
+ {UpperCase, 0xA64E, 0xA64E},
+ {LowerCase, 0xA64E, 0xA64F},
+ {TitleCase, 0xA64E, 0xA64E},
+ // A65F;CYRILLIC SMALL LETTER YN;Ll;0;L;;;;;N;;;A65E;;A65E
+ {UpperCase, 0xA65F, 0xA65E},
+ {LowerCase, 0xA65F, 0xA65F},
+ {TitleCase, 0xA65F, 0xA65E},
+
+ // From another UpperLower sequence
+ // 0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A;
+ {UpperCase, 0x0139, 0x0139},
+ {LowerCase, 0x0139, 0x013A},
+ {TitleCase, 0x0139, 0x0139},
+ // 013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140;
+ {UpperCase, 0x013f, 0x013f},
+ {LowerCase, 0x013f, 0x0140},
+ {TitleCase, 0x013f, 0x013f},
+ // 0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147
+ {UpperCase, 0x0148, 0x0147},
+ {LowerCase, 0x0148, 0x0148},
+ {TitleCase, 0x0148, 0x0147},
+
+ // Last block in the 5.1.0 table
+ // 10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;
+ {UpperCase, 0x10400, 0x10400},
+ {LowerCase, 0x10400, 0x10428},
+ {TitleCase, 0x10400, 0x10400},
+ // 10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F;
+ {UpperCase, 0x10427, 0x10427},
+ {LowerCase, 0x10427, 0x1044F},
+ {TitleCase, 0x10427, 0x10427},
+ // 10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400
+ {UpperCase, 0x10428, 0x10400},
+ {LowerCase, 0x10428, 0x10428},
+ {TitleCase, 0x10428, 0x10400},
+ // 1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427
+ {UpperCase, 0x1044F, 0x10427},
+ {LowerCase, 0x1044F, 0x1044F},
+ {TitleCase, 0x1044F, 0x10427},
+
+ // First one not in the 5.1.0 table
+ // 10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;;
+ {UpperCase, 0x10450, 0x10450},
+ {LowerCase, 0x10450, 0x10450},
+ {TitleCase, 0x10450, 0x10450},
+}
+
+func TestIsLetter(t *testing.T) {
+ for _, r := range upperTest {
+ if !IsLetter(r) {
+ t.Errorf("IsLetter(U+%04X) = false, want true", r)
+ }
+ }
+ for _, r := range letterTest {
+ if !IsLetter(r) {
+ t.Errorf("IsLetter(U+%04X) = false, want true", r)
+ }
+ }
+ for _, r := range notletterTest {
+ if IsLetter(r) {
+ t.Errorf("IsLetter(U+%04X) = true, want false", r)
+ }
+ }
+}
+
+func TestIsUpper(t *testing.T) {
+ for _, r := range upperTest {
+ if !IsUpper(r) {
+ t.Errorf("IsUpper(U+%04X) = false, want true", r)
+ }
+ }
+ for _, r := range notupperTest {
+ if IsUpper(r) {
+ t.Errorf("IsUpper(U+%04X) = true, want false", r)
+ }
+ }
+ for _, r := range notletterTest {
+ if IsUpper(r) {
+ t.Errorf("IsUpper(U+%04X) = true, want false", r)
+ }
+ }
+}
+
+func caseString(c int) string {
+ switch c {
+ case UpperCase:
+ return "UpperCase"
+ case LowerCase:
+ return "LowerCase"
+ case TitleCase:
+ return "TitleCase"
+ }
+ return "ErrorCase"
+}
+
+func TestTo(t *testing.T) {
+ for _, c := range caseTest {
+ r := To(c.cas, c.in)
+ if c.out != r {
+ t.Errorf("To(U+%04X, %s) = U+%04X want U+%04X", c.in, caseString(c.cas), r, c.out)
+ }
+ }
+}
+
+func TestToUpperCase(t *testing.T) {
+ for _, c := range caseTest {
+ if c.cas != UpperCase {
+ continue
+ }
+ r := ToUpper(c.in)
+ if c.out != r {
+ t.Errorf("ToUpper(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
+ }
+ }
+}
+
+func TestToLowerCase(t *testing.T) {
+ for _, c := range caseTest {
+ if c.cas != LowerCase {
+ continue
+ }
+ r := ToLower(c.in)
+ if c.out != r {
+ t.Errorf("ToLower(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
+ }
+ }
+}
+
+func TestToTitleCase(t *testing.T) {
+ for _, c := range caseTest {
+ if c.cas != TitleCase {
+ continue
+ }
+ r := ToTitle(c.in)
+ if c.out != r {
+ t.Errorf("ToTitle(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
+ }
+ }
+}
+
+func TestIsSpace(t *testing.T) {
+ for _, c := range spaceTest {
+ if !IsSpace(c) {
+ t.Errorf("IsSpace(U+%04X) = false; want true", c)
+ }
+ }
+ for _, c := range letterTest {
+ if IsSpace(c) {
+ t.Errorf("IsSpace(U+%04X) = true; want false", c)
+ }
+ }
+}
+
+// Check that the optimizations for IsLetter etc. agree with the tables.
+// We only need to check the Latin-1 range.
+func TestLetterOptimizations(t *testing.T) {
+ for i := 0; i < 0x100; i++ {
+ if Is(Letter, i) != IsLetter(i) {
+ t.Errorf("IsLetter(U+%04X) disagrees with Is(Letter)", i)
+ }
+ if Is(Upper, i) != IsUpper(i) {
+ t.Errorf("IsUpper(U+%04X) disagrees with Is(Upper)", i)
+ }
+ if Is(Lower, i) != IsLower(i) {
+ t.Errorf("IsLower(U+%04X) disagrees with Is(Lower)", i)
+ }
+ if Is(Title, i) != IsTitle(i) {
+ t.Errorf("IsTitle(U+%04X) disagrees with Is(Title)", i)
+ }
+ if Is(White_Space, i) != IsSpace(i) {
+ t.Errorf("IsSpace(U+%04X) disagrees with Is(White_Space)", i)
+ }
+ if To(UpperCase, i) != ToUpper(i) {
+ t.Errorf("ToUpper(U+%04X) disagrees with To(Upper)", i)
+ }
+ if To(LowerCase, i) != ToLower(i) {
+ t.Errorf("ToLower(U+%04X) disagrees with To(Lower)", i)
+ }
+ if To(TitleCase, i) != ToTitle(i) {
+ t.Errorf("ToTitle(U+%04X) disagrees with To(Title)", i)
+ }
+ }
+}
+
+func TestTurkishCase(t *testing.T) {
+ lower := []int("abcçdefgğhıijklmnoöprsştuüvyz")
+ upper := []int("ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ")
+ for i, l := range lower {
+ u := upper[i]
+ if TurkishCase.ToLower(l) != l {
+ t.Errorf("lower(U+%04X) is U+%04X not U+%04X", l, TurkishCase.ToLower(l), l)
+ }
+ if TurkishCase.ToUpper(u) != u {
+ t.Errorf("upper(U+%04X) is U+%04X not U+%04X", u, TurkishCase.ToUpper(u), u)
+ }
+ if TurkishCase.ToUpper(l) != u {
+ t.Errorf("upper(U+%04X) is U+%04X not U+%04X", l, TurkishCase.ToUpper(l), u)
+ }
+ if TurkishCase.ToLower(u) != l {
+ t.Errorf("lower(U+%04X) is U+%04X not U+%04X", u, TurkishCase.ToLower(l), l)
+ }
+ if TurkishCase.ToTitle(u) != u {
+ t.Errorf("title(U+%04X) is U+%04X not U+%04X", u, TurkishCase.ToTitle(u), u)
+ }
+ if TurkishCase.ToTitle(l) != u {
+ t.Errorf("title(U+%04X) is U+%04X not U+%04X", l, TurkishCase.ToTitle(l), u)
+ }
+ }
+}
diff --git a/libgo/go/unicode/script_test.go b/libgo/go/unicode/script_test.go
new file mode 100644
index 000000000..ffdc40dc0
--- /dev/null
+++ b/libgo/go/unicode/script_test.go
@@ -0,0 +1,247 @@
+// 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 unicode_test
+
+import (
+ "testing"
+ . "unicode"
+)
+
+type T struct {
+ rune int
+ script string
+}
+
+// Hand-chosen tests from Unicode 5.1.0, mostly to discover when new
+// scripts and categories arise.
+var inTest = []T{
+ {0x06e2, "Arabic"},
+ {0x0567, "Armenian"},
+ {0x10b20, "Avestan"},
+ {0x1b37, "Balinese"},
+ {0xa6af, "Bamum"},
+ {0x09c2, "Bengali"},
+ {0x3115, "Bopomofo"},
+ {0x282d, "Braille"},
+ {0x1a1a, "Buginese"},
+ {0x1747, "Buhid"},
+ {0x156d, "Canadian_Aboriginal"},
+ {0x102a9, "Carian"},
+ {0xaa4d, "Cham"},
+ {0x13c2, "Cherokee"},
+ {0x0020, "Common"},
+ {0x1d4a5, "Common"},
+ {0x2cfc, "Coptic"},
+ {0x12420, "Cuneiform"},
+ {0x1080c, "Cypriot"},
+ {0xa663, "Cyrillic"},
+ {0x10430, "Deseret"},
+ {0x094a, "Devanagari"},
+ {0x13001, "Egyptian_Hieroglyphs"},
+ {0x1271, "Ethiopic"},
+ {0x10fc, "Georgian"},
+ {0x2c40, "Glagolitic"},
+ {0x10347, "Gothic"},
+ {0x03ae, "Greek"},
+ {0x0abf, "Gujarati"},
+ {0x0a24, "Gurmukhi"},
+ {0x3028, "Han"},
+ {0x11b8, "Hangul"},
+ {0x1727, "Hanunoo"},
+ {0x05a0, "Hebrew"},
+ {0x3058, "Hiragana"},
+ {0x10841, "Imperial_Aramaic"},
+ {0x20e6, "Inherited"},
+ {0x10b70, "Inscriptional_Pahlavi"},
+ {0x10b5a, "Inscriptional_Parthian"},
+ {0xa9d0, "Javanese"},
+ {0x1109f, "Kaithi"},
+ {0x0cbd, "Kannada"},
+ {0x30a6, "Katakana"},
+ {0xa928, "Kayah_Li"},
+ {0x10a11, "Kharoshthi"},
+ {0x17c6, "Khmer"},
+ {0x0eaa, "Lao"},
+ {0x1d79, "Latin"},
+ {0x1c10, "Lepcha"},
+ {0x1930, "Limbu"},
+ {0x1003c, "Linear_B"},
+ {0xa4e1, "Lisu"},
+ {0x10290, "Lycian"},
+ {0x10930, "Lydian"},
+ {0x0d42, "Malayalam"},
+ {0xabd0, "Meetei_Mayek"},
+ {0x1822, "Mongolian"},
+ {0x104c, "Myanmar"},
+ {0x19c3, "New_Tai_Lue"},
+ {0x07f8, "Nko"},
+ {0x169b, "Ogham"},
+ {0x1c6a, "Ol_Chiki"},
+ {0x10310, "Old_Italic"},
+ {0x103c9, "Old_Persian"},
+ {0x10a6f, "Old_South_Arabian"},
+ {0x10c20, "Old_Turkic"},
+ {0x0b3e, "Oriya"},
+ {0x10491, "Osmanya"},
+ {0xa860, "Phags_Pa"},
+ {0x10918, "Phoenician"},
+ {0xa949, "Rejang"},
+ {0x16c0, "Runic"},
+ {0x081d, "Samaritan"},
+ {0xa892, "Saurashtra"},
+ {0x10463, "Shavian"},
+ {0x0dbd, "Sinhala"},
+ {0x1ba3, "Sundanese"},
+ {0xa803, "Syloti_Nagri"},
+ {0x070f, "Syriac"},
+ {0x170f, "Tagalog"},
+ {0x176f, "Tagbanwa"},
+ {0x1972, "Tai_Le"},
+ {0x1a62, "Tai_Tham"},
+ {0xaadc, "Tai_Viet"},
+ {0x0bbf, "Tamil"},
+ {0x0c55, "Telugu"},
+ {0x07a7, "Thaana"},
+ {0x0e46, "Thai"},
+ {0x0f36, "Tibetan"},
+ {0x2d55, "Tifinagh"},
+ {0x10388, "Ugaritic"},
+ {0xa60e, "Vai"},
+ {0xa216, "Yi"},
+}
+
+var outTest = []T{ // not really worth being thorough
+ {0x20, "Telugu"},
+}
+
+var inCategoryTest = []T{
+ {0x0081, "Cc"},
+ {0x17b4, "Cf"},
+ {0xf0000, "Co"},
+ {0xdb80, "Cs"},
+ {0x0236, "Ll"},
+ {0x1d9d, "Lm"},
+ {0x07cf, "Lo"},
+ {0x1f8a, "Lt"},
+ {0x03ff, "Lu"},
+ {0x0bc1, "Mc"},
+ {0x20df, "Me"},
+ {0x07f0, "Mn"},
+ {0x1bb2, "Nd"},
+ {0x10147, "Nl"},
+ {0x2478, "No"},
+ {0xfe33, "Pc"},
+ {0x2011, "Pd"},
+ {0x301e, "Pe"},
+ {0x2e03, "Pf"},
+ {0x2e02, "Pi"},
+ {0x0022, "Po"},
+ {0x2770, "Ps"},
+ {0x00a4, "Sc"},
+ {0xa711, "Sk"},
+ {0x25f9, "Sm"},
+ {0x2108, "So"},
+ {0x2028, "Zl"},
+ {0x2029, "Zp"},
+ {0x202f, "Zs"},
+ {0x04aa, "letter"},
+}
+
+var inPropTest = []T{
+ {0x0046, "ASCII_Hex_Digit"},
+ {0x200F, "Bidi_Control"},
+ {0x2212, "Dash"},
+ {0xE0001, "Deprecated"},
+ {0x00B7, "Diacritic"},
+ {0x30FE, "Extender"},
+ {0xFF46, "Hex_Digit"},
+ {0x2E17, "Hyphen"},
+ {0x2FFB, "IDS_Binary_Operator"},
+ {0x2FF3, "IDS_Trinary_Operator"},
+ {0xFA6A, "Ideographic"},
+ {0x200D, "Join_Control"},
+ {0x0EC4, "Logical_Order_Exception"},
+ {0x2FFFF, "Noncharacter_Code_Point"},
+ {0x065E, "Other_Alphabetic"},
+ {0x2069, "Other_Default_Ignorable_Code_Point"},
+ {0x0BD7, "Other_Grapheme_Extend"},
+ {0x0387, "Other_ID_Continue"},
+ {0x212E, "Other_ID_Start"},
+ {0x2094, "Other_Lowercase"},
+ {0x2040, "Other_Math"},
+ {0x216F, "Other_Uppercase"},
+ {0x0027, "Pattern_Syntax"},
+ {0x0020, "Pattern_White_Space"},
+ {0x300D, "Quotation_Mark"},
+ {0x2EF3, "Radical"},
+ {0x061F, "STerm"},
+ {0x2071, "Soft_Dotted"},
+ {0x003A, "Terminal_Punctuation"},
+ {0x9FC3, "Unified_Ideograph"},
+ {0xFE0F, "Variation_Selector"},
+ {0x0020, "White_Space"},
+}
+
+func TestScripts(t *testing.T) {
+ notTested := make(map[string]bool)
+ for k := range Scripts {
+ notTested[k] = true
+ }
+ for _, test := range inTest {
+ if _, ok := Scripts[test.script]; !ok {
+ t.Fatal(test.script, "not a known script")
+ }
+ if !Is(Scripts[test.script], test.rune) {
+ t.Errorf("IsScript(%#x, %s) = false, want true", test.rune, test.script)
+ }
+ notTested[test.script] = false, false
+ }
+ for _, test := range outTest {
+ if Is(Scripts[test.script], test.rune) {
+ t.Errorf("IsScript(%#x, %s) = true, want false", test.rune, test.script)
+ }
+ }
+ for k := range notTested {
+ t.Error("not tested:", k)
+ }
+}
+
+func TestCategories(t *testing.T) {
+ notTested := make(map[string]bool)
+ for k := range Categories {
+ notTested[k] = true
+ }
+ for _, test := range inCategoryTest {
+ if _, ok := Categories[test.script]; !ok {
+ t.Fatal(test.script, "not a known category")
+ }
+ if !Is(Categories[test.script], test.rune) {
+ t.Errorf("IsCategory(%#x, %s) = false, want true", test.rune, test.script)
+ }
+ notTested[test.script] = false, false
+ }
+ for k := range notTested {
+ t.Error("not tested:", k)
+ }
+}
+
+func TestProperties(t *testing.T) {
+ notTested := make(map[string]bool)
+ for k := range Properties {
+ notTested[k] = true
+ }
+ for _, test := range inPropTest {
+ if _, ok := Properties[test.script]; !ok {
+ t.Fatal(test.script, "not a known prop")
+ }
+ if !Is(Properties[test.script], test.rune) {
+ t.Errorf("IsCategory(%#x, %s) = false, want true", test.rune, test.script)
+ }
+ notTested[test.script] = false, false
+ }
+ for k := range notTested {
+ t.Error("not tested:", k)
+ }
+}
diff --git a/libgo/go/unicode/tables.go b/libgo/go/unicode/tables.go
new file mode 100644
index 000000000..b56c9bd03
--- /dev/null
+++ b/libgo/go/unicode/tables.go
@@ -0,0 +1,4238 @@
+// Generated by running
+// maketables --tables=all --data=http://www.unicode.org/Public/5.2.0/ucd/UnicodeData.txt
+// DO NOT EDIT
+
+package unicode
+
+// Version is the Unicode edition from which the tables are derived.
+const Version = "5.2.0"
+
+// Categories is the set of Unicode data tables.
+var Categories = map[string][]Range{
+ "Lm": Lm,
+ "Ll": Ll,
+ "Me": Me,
+ "Mc": Mc,
+ "Mn": Mn,
+ "Zl": Zl,
+ "letter": letter,
+ "Zp": Zp,
+ "Zs": Zs,
+ "Cs": Cs,
+ "Co": Co,
+ "Cf": Cf,
+ "Cc": Cc,
+ "Po": Po,
+ "Pi": Pi,
+ "Pf": Pf,
+ "Pe": Pe,
+ "Pd": Pd,
+ "Pc": Pc,
+ "Ps": Ps,
+ "Nd": Nd,
+ "Nl": Nl,
+ "No": No,
+ "So": So,
+ "Sm": Sm,
+ "Sk": Sk,
+ "Sc": Sc,
+ "Lu": Lu,
+ "Lt": Lt,
+ "Lo": Lo,
+}
+
+var _Lm = []Range{
+ {0x02b0, 0x02c1, 1},
+ {0x02c6, 0x02d1, 1},
+ {0x02e0, 0x02e4, 1},
+ {0x02ec, 0x02ee, 2},
+ {0x0374, 0x037a, 6},
+ {0x0559, 0x0640, 231},
+ {0x06e5, 0x06e6, 1},
+ {0x07f4, 0x07f5, 1},
+ {0x07fa, 0x081a, 32},
+ {0x0824, 0x0828, 4},
+ {0x0971, 0x0e46, 1237},
+ {0x0ec6, 0x10fc, 566},
+ {0x17d7, 0x1843, 108},
+ {0x1aa7, 0x1c78, 465},
+ {0x1c79, 0x1c7d, 1},
+ {0x1d2c, 0x1d61, 1},
+ {0x1d78, 0x1d9b, 35},
+ {0x1d9c, 0x1dbf, 1},
+ {0x2071, 0x207f, 14},
+ {0x2090, 0x2094, 1},
+ {0x2c7d, 0x2d6f, 242},
+ {0x2e2f, 0x3005, 470},
+ {0x3031, 0x3035, 1},
+ {0x303b, 0x309d, 98},
+ {0x309e, 0x30fc, 94},
+ {0x30fd, 0x30fe, 1},
+ {0xa015, 0xa4f8, 1251},
+ {0xa4f9, 0xa4fd, 1},
+ {0xa60c, 0xa67f, 115},
+ {0xa717, 0xa71f, 1},
+ {0xa770, 0xa788, 24},
+ {0xa9cf, 0xaa70, 161},
+ {0xaadd, 0xff70, 21651},
+ {0xff9e, 0xff9f, 1},
+}
+
+var _Ll = []Range{
+ {0x0061, 0x007a, 1},
+ {0x00aa, 0x00b5, 11},
+ {0x00ba, 0x00df, 37},
+ {0x00e0, 0x00f6, 1},
+ {0x00f8, 0x00ff, 1},
+ {0x0101, 0x0137, 2},
+ {0x0138, 0x0148, 2},
+ {0x0149, 0x0177, 2},
+ {0x017a, 0x017e, 2},
+ {0x017f, 0x0180, 1},
+ {0x0183, 0x0185, 2},
+ {0x0188, 0x018c, 4},
+ {0x018d, 0x0192, 5},
+ {0x0195, 0x0199, 4},
+ {0x019a, 0x019b, 1},
+ {0x019e, 0x01a1, 3},
+ {0x01a3, 0x01a5, 2},
+ {0x01a8, 0x01aa, 2},
+ {0x01ab, 0x01ad, 2},
+ {0x01b0, 0x01b4, 4},
+ {0x01b6, 0x01b9, 3},
+ {0x01ba, 0x01bd, 3},
+ {0x01be, 0x01bf, 1},
+ {0x01c6, 0x01cc, 3},
+ {0x01ce, 0x01dc, 2},
+ {0x01dd, 0x01ef, 2},
+ {0x01f0, 0x01f3, 3},
+ {0x01f5, 0x01f9, 4},
+ {0x01fb, 0x0233, 2},
+ {0x0234, 0x0239, 1},
+ {0x023c, 0x023f, 3},
+ {0x0240, 0x0242, 2},
+ {0x0247, 0x024f, 2},
+ {0x0250, 0x0293, 1},
+ {0x0295, 0x02af, 1},
+ {0x0371, 0x0373, 2},
+ {0x0377, 0x037b, 4},
+ {0x037c, 0x037d, 1},
+ {0x0390, 0x03ac, 28},
+ {0x03ad, 0x03ce, 1},
+ {0x03d0, 0x03d1, 1},
+ {0x03d5, 0x03d7, 1},
+ {0x03d9, 0x03ef, 2},
+ {0x03f0, 0x03f3, 1},
+ {0x03f5, 0x03fb, 3},
+ {0x03fc, 0x0430, 52},
+ {0x0431, 0x045f, 1},
+ {0x0461, 0x0481, 2},
+ {0x048b, 0x04bf, 2},
+ {0x04c2, 0x04ce, 2},
+ {0x04cf, 0x0525, 2},
+ {0x0561, 0x0587, 1},
+ {0x1d00, 0x1d2b, 1},
+ {0x1d62, 0x1d77, 1},
+ {0x1d79, 0x1d9a, 1},
+ {0x1e01, 0x1e95, 2},
+ {0x1e96, 0x1e9d, 1},
+ {0x1e9f, 0x1eff, 2},
+ {0x1f00, 0x1f07, 1},
+ {0x1f10, 0x1f15, 1},
+ {0x1f20, 0x1f27, 1},
+ {0x1f30, 0x1f37, 1},
+ {0x1f40, 0x1f45, 1},
+ {0x1f50, 0x1f57, 1},
+ {0x1f60, 0x1f67, 1},
+ {0x1f70, 0x1f7d, 1},
+ {0x1f80, 0x1f87, 1},
+ {0x1f90, 0x1f97, 1},
+ {0x1fa0, 0x1fa7, 1},
+ {0x1fb0, 0x1fb4, 1},
+ {0x1fb6, 0x1fb7, 1},
+ {0x1fbe, 0x1fc2, 4},
+ {0x1fc3, 0x1fc4, 1},
+ {0x1fc6, 0x1fc7, 1},
+ {0x1fd0, 0x1fd3, 1},
+ {0x1fd6, 0x1fd7, 1},
+ {0x1fe0, 0x1fe7, 1},
+ {0x1ff2, 0x1ff4, 1},
+ {0x1ff6, 0x1ff7, 1},
+ {0x210a, 0x210e, 4},
+ {0x210f, 0x2113, 4},
+ {0x212f, 0x2139, 5},
+ {0x213c, 0x213d, 1},
+ {0x2146, 0x2149, 1},
+ {0x214e, 0x2184, 54},
+ {0x2c30, 0x2c5e, 1},
+ {0x2c61, 0x2c65, 4},
+ {0x2c66, 0x2c6c, 2},
+ {0x2c71, 0x2c73, 2},
+ {0x2c74, 0x2c76, 2},
+ {0x2c77, 0x2c7c, 1},
+ {0x2c81, 0x2ce3, 2},
+ {0x2ce4, 0x2cec, 8},
+ {0x2cee, 0x2d00, 18},
+ {0x2d01, 0x2d25, 1},
+ {0xa641, 0xa65f, 2},
+ {0xa663, 0xa66d, 2},
+ {0xa681, 0xa697, 2},
+ {0xa723, 0xa72f, 2},
+ {0xa730, 0xa731, 1},
+ {0xa733, 0xa771, 2},
+ {0xa772, 0xa778, 1},
+ {0xa77a, 0xa77c, 2},
+ {0xa77f, 0xa787, 2},
+ {0xa78c, 0xfb00, 21364},
+ {0xfb01, 0xfb06, 1},
+ {0xfb13, 0xfb17, 1},
+ {0xff41, 0xff5a, 1},
+ {0x10428, 0x1044f, 1},
+ {0x1d41a, 0x1d433, 1},
+ {0x1d44e, 0x1d454, 1},
+ {0x1d456, 0x1d467, 1},
+ {0x1d482, 0x1d49b, 1},
+ {0x1d4b6, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bd, 2},
+ {0x1d4be, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d4cf, 1},
+ {0x1d4ea, 0x1d503, 1},
+ {0x1d51e, 0x1d537, 1},
+ {0x1d552, 0x1d56b, 1},
+ {0x1d586, 0x1d59f, 1},
+ {0x1d5ba, 0x1d5d3, 1},
+ {0x1d5ee, 0x1d607, 1},
+ {0x1d622, 0x1d63b, 1},
+ {0x1d656, 0x1d66f, 1},
+ {0x1d68a, 0x1d6a5, 1},
+ {0x1d6c2, 0x1d6da, 1},
+ {0x1d6dc, 0x1d6e1, 1},
+ {0x1d6fc, 0x1d714, 1},
+ {0x1d716, 0x1d71b, 1},
+ {0x1d736, 0x1d74e, 1},
+ {0x1d750, 0x1d755, 1},
+ {0x1d770, 0x1d788, 1},
+ {0x1d78a, 0x1d78f, 1},
+ {0x1d7aa, 0x1d7c2, 1},
+ {0x1d7c4, 0x1d7c9, 1},
+ {0x1d7cb, 0x1d7cb, 1},
+}
+
+var _Me = []Range{
+ {0x0488, 0x0489, 1},
+ {0x06de, 0x20dd, 6655},
+ {0x20de, 0x20e0, 1},
+ {0x20e2, 0x20e4, 1},
+ {0xa670, 0xa672, 1},
+}
+
+var _Mc = []Range{
+ {0x0903, 0x093e, 59},
+ {0x093f, 0x0940, 1},
+ {0x0949, 0x094c, 1},
+ {0x094e, 0x0982, 52},
+ {0x0983, 0x09be, 59},
+ {0x09bf, 0x09c0, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09cc, 1},
+ {0x09d7, 0x0a03, 44},
+ {0x0a3e, 0x0a40, 1},
+ {0x0a83, 0x0abe, 59},
+ {0x0abf, 0x0ac0, 1},
+ {0x0ac9, 0x0acb, 2},
+ {0x0acc, 0x0b02, 54},
+ {0x0b03, 0x0b3e, 59},
+ {0x0b40, 0x0b47, 7},
+ {0x0b48, 0x0b4b, 3},
+ {0x0b4c, 0x0b57, 11},
+ {0x0bbe, 0x0bbf, 1},
+ {0x0bc1, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcc, 1},
+ {0x0bd7, 0x0c01, 42},
+ {0x0c02, 0x0c03, 1},
+ {0x0c41, 0x0c44, 1},
+ {0x0c82, 0x0c83, 1},
+ {0x0cbe, 0x0cc0, 2},
+ {0x0cc1, 0x0cc4, 1},
+ {0x0cc7, 0x0cc8, 1},
+ {0x0cca, 0x0ccb, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0d02, 0x0d03, 1},
+ {0x0d3e, 0x0d40, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4c, 1},
+ {0x0d57, 0x0d82, 43},
+ {0x0d83, 0x0dcf, 76},
+ {0x0dd0, 0x0dd1, 1},
+ {0x0dd8, 0x0ddf, 1},
+ {0x0df2, 0x0df3, 1},
+ {0x0f3e, 0x0f3f, 1},
+ {0x0f7f, 0x102b, 172},
+ {0x102c, 0x1031, 5},
+ {0x1038, 0x103b, 3},
+ {0x103c, 0x1056, 26},
+ {0x1057, 0x1062, 11},
+ {0x1063, 0x1064, 1},
+ {0x1067, 0x106d, 1},
+ {0x1083, 0x1084, 1},
+ {0x1087, 0x108c, 1},
+ {0x108f, 0x109a, 11},
+ {0x109b, 0x109c, 1},
+ {0x17b6, 0x17be, 8},
+ {0x17bf, 0x17c5, 1},
+ {0x17c7, 0x17c8, 1},
+ {0x1923, 0x1926, 1},
+ {0x1929, 0x192b, 1},
+ {0x1930, 0x1931, 1},
+ {0x1933, 0x1938, 1},
+ {0x19b0, 0x19c0, 1},
+ {0x19c8, 0x19c9, 1},
+ {0x1a19, 0x1a1b, 1},
+ {0x1a55, 0x1a57, 2},
+ {0x1a61, 0x1a63, 2},
+ {0x1a64, 0x1a6d, 9},
+ {0x1a6e, 0x1a72, 1},
+ {0x1b04, 0x1b35, 49},
+ {0x1b3b, 0x1b3d, 2},
+ {0x1b3e, 0x1b41, 1},
+ {0x1b43, 0x1b44, 1},
+ {0x1b82, 0x1ba1, 31},
+ {0x1ba6, 0x1ba7, 1},
+ {0x1baa, 0x1c24, 122},
+ {0x1c25, 0x1c2b, 1},
+ {0x1c34, 0x1c35, 1},
+ {0x1ce1, 0x1cf2, 17},
+ {0xa823, 0xa824, 1},
+ {0xa827, 0xa880, 89},
+ {0xa881, 0xa8b4, 51},
+ {0xa8b5, 0xa8c3, 1},
+ {0xa952, 0xa953, 1},
+ {0xa983, 0xa9b4, 49},
+ {0xa9b5, 0xa9ba, 5},
+ {0xa9bb, 0xa9bd, 2},
+ {0xa9be, 0xa9c0, 1},
+ {0xaa2f, 0xaa30, 1},
+ {0xaa33, 0xaa34, 1},
+ {0xaa4d, 0xaa7b, 46},
+ {0xabe3, 0xabe4, 1},
+ {0xabe6, 0xabe7, 1},
+ {0xabe9, 0xabea, 1},
+ {0xabec, 0x11082, 25750},
+ {0x110b0, 0x110b2, 1},
+ {0x110b7, 0x110b8, 1},
+ {0x1d165, 0x1d166, 1},
+ {0x1d16d, 0x1d172, 1},
+}
+
+var _Mn = []Range{
+ {0x0300, 0x036f, 1},
+ {0x0483, 0x0487, 1},
+ {0x0591, 0x05bd, 1},
+ {0x05bf, 0x05c1, 2},
+ {0x05c2, 0x05c4, 2},
+ {0x05c5, 0x05c7, 2},
+ {0x0610, 0x061a, 1},
+ {0x064b, 0x065e, 1},
+ {0x0670, 0x06d6, 102},
+ {0x06d7, 0x06dc, 1},
+ {0x06df, 0x06e4, 1},
+ {0x06e7, 0x06e8, 1},
+ {0x06ea, 0x06ed, 1},
+ {0x0711, 0x0730, 31},
+ {0x0731, 0x074a, 1},
+ {0x07a6, 0x07b0, 1},
+ {0x07eb, 0x07f3, 1},
+ {0x0816, 0x0819, 1},
+ {0x081b, 0x0823, 1},
+ {0x0825, 0x0827, 1},
+ {0x0829, 0x082d, 1},
+ {0x0900, 0x0902, 1},
+ {0x093c, 0x0941, 5},
+ {0x0942, 0x0948, 1},
+ {0x094d, 0x0951, 4},
+ {0x0952, 0x0955, 1},
+ {0x0962, 0x0963, 1},
+ {0x0981, 0x09bc, 59},
+ {0x09c1, 0x09c4, 1},
+ {0x09cd, 0x09e2, 21},
+ {0x09e3, 0x0a01, 30},
+ {0x0a02, 0x0a3c, 58},
+ {0x0a41, 0x0a42, 1},
+ {0x0a47, 0x0a48, 1},
+ {0x0a4b, 0x0a4d, 1},
+ {0x0a51, 0x0a70, 31},
+ {0x0a71, 0x0a75, 4},
+ {0x0a81, 0x0a82, 1},
+ {0x0abc, 0x0ac1, 5},
+ {0x0ac2, 0x0ac5, 1},
+ {0x0ac7, 0x0ac8, 1},
+ {0x0acd, 0x0ae2, 21},
+ {0x0ae3, 0x0b01, 30},
+ {0x0b3c, 0x0b3f, 3},
+ {0x0b41, 0x0b44, 1},
+ {0x0b4d, 0x0b56, 9},
+ {0x0b62, 0x0b63, 1},
+ {0x0b82, 0x0bc0, 62},
+ {0x0bcd, 0x0c3e, 113},
+ {0x0c3f, 0x0c40, 1},
+ {0x0c46, 0x0c48, 1},
+ {0x0c4a, 0x0c4d, 1},
+ {0x0c55, 0x0c56, 1},
+ {0x0c62, 0x0c63, 1},
+ {0x0cbc, 0x0cbf, 3},
+ {0x0cc6, 0x0ccc, 6},
+ {0x0ccd, 0x0ce2, 21},
+ {0x0ce3, 0x0d41, 94},
+ {0x0d42, 0x0d44, 1},
+ {0x0d4d, 0x0d62, 21},
+ {0x0d63, 0x0dca, 103},
+ {0x0dd2, 0x0dd4, 1},
+ {0x0dd6, 0x0e31, 91},
+ {0x0e34, 0x0e3a, 1},
+ {0x0e47, 0x0e4e, 1},
+ {0x0eb1, 0x0eb4, 3},
+ {0x0eb5, 0x0eb9, 1},
+ {0x0ebb, 0x0ebc, 1},
+ {0x0ec8, 0x0ecd, 1},
+ {0x0f18, 0x0f19, 1},
+ {0x0f35, 0x0f39, 2},
+ {0x0f71, 0x0f7e, 1},
+ {0x0f80, 0x0f84, 1},
+ {0x0f86, 0x0f87, 1},
+ {0x0f90, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x0fc6, 0x102d, 103},
+ {0x102e, 0x1030, 1},
+ {0x1032, 0x1037, 1},
+ {0x1039, 0x103a, 1},
+ {0x103d, 0x103e, 1},
+ {0x1058, 0x1059, 1},
+ {0x105e, 0x1060, 1},
+ {0x1071, 0x1074, 1},
+ {0x1082, 0x1085, 3},
+ {0x1086, 0x108d, 7},
+ {0x109d, 0x135f, 706},
+ {0x1712, 0x1714, 1},
+ {0x1732, 0x1734, 1},
+ {0x1752, 0x1753, 1},
+ {0x1772, 0x1773, 1},
+ {0x17b7, 0x17bd, 1},
+ {0x17c6, 0x17c9, 3},
+ {0x17ca, 0x17d3, 1},
+ {0x17dd, 0x180b, 46},
+ {0x180c, 0x180d, 1},
+ {0x18a9, 0x1920, 119},
+ {0x1921, 0x1922, 1},
+ {0x1927, 0x1928, 1},
+ {0x1932, 0x1939, 7},
+ {0x193a, 0x193b, 1},
+ {0x1a17, 0x1a18, 1},
+ {0x1a56, 0x1a58, 2},
+ {0x1a59, 0x1a5e, 1},
+ {0x1a60, 0x1a62, 2},
+ {0x1a65, 0x1a6c, 1},
+ {0x1a73, 0x1a7c, 1},
+ {0x1a7f, 0x1b00, 129},
+ {0x1b01, 0x1b03, 1},
+ {0x1b34, 0x1b36, 2},
+ {0x1b37, 0x1b3a, 1},
+ {0x1b3c, 0x1b42, 6},
+ {0x1b6b, 0x1b73, 1},
+ {0x1b80, 0x1b81, 1},
+ {0x1ba2, 0x1ba5, 1},
+ {0x1ba8, 0x1ba9, 1},
+ {0x1c2c, 0x1c33, 1},
+ {0x1c36, 0x1c37, 1},
+ {0x1cd0, 0x1cd2, 1},
+ {0x1cd4, 0x1ce0, 1},
+ {0x1ce2, 0x1ce8, 1},
+ {0x1ced, 0x1dc0, 211},
+ {0x1dc1, 0x1de6, 1},
+ {0x1dfd, 0x1dff, 1},
+ {0x20d0, 0x20dc, 1},
+ {0x20e1, 0x20e5, 4},
+ {0x20e6, 0x20f0, 1},
+ {0x2cef, 0x2cf1, 1},
+ {0x2de0, 0x2dff, 1},
+ {0x302a, 0x302f, 1},
+ {0x3099, 0x309a, 1},
+ {0xa66f, 0xa67c, 13},
+ {0xa67d, 0xa6f0, 115},
+ {0xa6f1, 0xa802, 273},
+ {0xa806, 0xa80b, 5},
+ {0xa825, 0xa826, 1},
+ {0xa8c4, 0xa8e0, 28},
+ {0xa8e1, 0xa8f1, 1},
+ {0xa926, 0xa92d, 1},
+ {0xa947, 0xa951, 1},
+ {0xa980, 0xa982, 1},
+ {0xa9b3, 0xa9b6, 3},
+ {0xa9b7, 0xa9b9, 1},
+ {0xa9bc, 0xaa29, 109},
+ {0xaa2a, 0xaa2e, 1},
+ {0xaa31, 0xaa32, 1},
+ {0xaa35, 0xaa36, 1},
+ {0xaa43, 0xaa4c, 9},
+ {0xaab0, 0xaab2, 2},
+ {0xaab3, 0xaab4, 1},
+ {0xaab7, 0xaab8, 1},
+ {0xaabe, 0xaabf, 1},
+ {0xaac1, 0xabe5, 292},
+ {0xabe8, 0xabed, 5},
+ {0xfb1e, 0xfe00, 738},
+ {0xfe01, 0xfe0f, 1},
+ {0xfe20, 0xfe26, 1},
+ {0x101fd, 0x10a01, 2052},
+ {0x10a02, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a0f, 1},
+ {0x10a38, 0x10a3a, 1},
+ {0x10a3f, 0x11080, 1601},
+ {0x11081, 0x110b3, 50},
+ {0x110b4, 0x110b6, 1},
+ {0x110b9, 0x110ba, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ {0x1d242, 0x1d244, 1},
+ {0xe0100, 0xe01ef, 1},
+}
+
+var _Zl = []Range{
+ {0x2028, 0x2028, 1},
+}
+
+var letter = []Range{
+ {0x0041, 0x005a, 1},
+ {0x0061, 0x007a, 1},
+ {0x00aa, 0x00b5, 11},
+ {0x00ba, 0x00c0, 6},
+ {0x00c1, 0x00d6, 1},
+ {0x00d8, 0x00f6, 1},
+ {0x00f8, 0x02c1, 1},
+ {0x02c6, 0x02d1, 1},
+ {0x02e0, 0x02e4, 1},
+ {0x02ec, 0x02ee, 2},
+ {0x0370, 0x0374, 1},
+ {0x0376, 0x0377, 1},
+ {0x037a, 0x037d, 1},
+ {0x0386, 0x0388, 2},
+ {0x0389, 0x038a, 1},
+ {0x038c, 0x038e, 2},
+ {0x038f, 0x03a1, 1},
+ {0x03a3, 0x03f5, 1},
+ {0x03f7, 0x0481, 1},
+ {0x048a, 0x0525, 1},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x0561, 8},
+ {0x0562, 0x0587, 1},
+ {0x05d0, 0x05ea, 1},
+ {0x05f0, 0x05f2, 1},
+ {0x0621, 0x064a, 1},
+ {0x066e, 0x066f, 1},
+ {0x0671, 0x06d3, 1},
+ {0x06d5, 0x06e5, 16},
+ {0x06e6, 0x06ee, 8},
+ {0x06ef, 0x06fa, 11},
+ {0x06fb, 0x06fc, 1},
+ {0x06ff, 0x0710, 17},
+ {0x0712, 0x072f, 1},
+ {0x074d, 0x07a5, 1},
+ {0x07b1, 0x07ca, 25},
+ {0x07cb, 0x07ea, 1},
+ {0x07f4, 0x07f5, 1},
+ {0x07fa, 0x0800, 6},
+ {0x0801, 0x0815, 1},
+ {0x081a, 0x0824, 10},
+ {0x0828, 0x0904, 220},
+ {0x0905, 0x0939, 1},
+ {0x093d, 0x0950, 19},
+ {0x0958, 0x0961, 1},
+ {0x0971, 0x0972, 1},
+ {0x0979, 0x097f, 1},
+ {0x0985, 0x098c, 1},
+ {0x098f, 0x0990, 1},
+ {0x0993, 0x09a8, 1},
+ {0x09aa, 0x09b0, 1},
+ {0x09b2, 0x09b6, 4},
+ {0x09b7, 0x09b9, 1},
+ {0x09bd, 0x09ce, 17},
+ {0x09dc, 0x09dd, 1},
+ {0x09df, 0x09e1, 1},
+ {0x09f0, 0x09f1, 1},
+ {0x0a05, 0x0a0a, 1},
+ {0x0a0f, 0x0a10, 1},
+ {0x0a13, 0x0a28, 1},
+ {0x0a2a, 0x0a30, 1},
+ {0x0a32, 0x0a33, 1},
+ {0x0a35, 0x0a36, 1},
+ {0x0a38, 0x0a39, 1},
+ {0x0a59, 0x0a5c, 1},
+ {0x0a5e, 0x0a72, 20},
+ {0x0a73, 0x0a74, 1},
+ {0x0a85, 0x0a8d, 1},
+ {0x0a8f, 0x0a91, 1},
+ {0x0a93, 0x0aa8, 1},
+ {0x0aaa, 0x0ab0, 1},
+ {0x0ab2, 0x0ab3, 1},
+ {0x0ab5, 0x0ab9, 1},
+ {0x0abd, 0x0ad0, 19},
+ {0x0ae0, 0x0ae1, 1},
+ {0x0b05, 0x0b0c, 1},
+ {0x0b0f, 0x0b10, 1},
+ {0x0b13, 0x0b28, 1},
+ {0x0b2a, 0x0b30, 1},
+ {0x0b32, 0x0b33, 1},
+ {0x0b35, 0x0b39, 1},
+ {0x0b3d, 0x0b5c, 31},
+ {0x0b5d, 0x0b5f, 2},
+ {0x0b60, 0x0b61, 1},
+ {0x0b71, 0x0b83, 18},
+ {0x0b85, 0x0b8a, 1},
+ {0x0b8e, 0x0b90, 1},
+ {0x0b92, 0x0b95, 1},
+ {0x0b99, 0x0b9a, 1},
+ {0x0b9c, 0x0b9e, 2},
+ {0x0b9f, 0x0ba3, 4},
+ {0x0ba4, 0x0ba8, 4},
+ {0x0ba9, 0x0baa, 1},
+ {0x0bae, 0x0bb9, 1},
+ {0x0bd0, 0x0c05, 53},
+ {0x0c06, 0x0c0c, 1},
+ {0x0c0e, 0x0c10, 1},
+ {0x0c12, 0x0c28, 1},
+ {0x0c2a, 0x0c33, 1},
+ {0x0c35, 0x0c39, 1},
+ {0x0c3d, 0x0c58, 27},
+ {0x0c59, 0x0c60, 7},
+ {0x0c61, 0x0c85, 36},
+ {0x0c86, 0x0c8c, 1},
+ {0x0c8e, 0x0c90, 1},
+ {0x0c92, 0x0ca8, 1},
+ {0x0caa, 0x0cb3, 1},
+ {0x0cb5, 0x0cb9, 1},
+ {0x0cbd, 0x0cde, 33},
+ {0x0ce0, 0x0ce1, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d28, 1},
+ {0x0d2a, 0x0d39, 1},
+ {0x0d3d, 0x0d60, 35},
+ {0x0d61, 0x0d7a, 25},
+ {0x0d7b, 0x0d7f, 1},
+ {0x0d85, 0x0d96, 1},
+ {0x0d9a, 0x0db1, 1},
+ {0x0db3, 0x0dbb, 1},
+ {0x0dbd, 0x0dc0, 3},
+ {0x0dc1, 0x0dc6, 1},
+ {0x0e01, 0x0e30, 1},
+ {0x0e32, 0x0e33, 1},
+ {0x0e40, 0x0e46, 1},
+ {0x0e81, 0x0e82, 1},
+ {0x0e84, 0x0e87, 3},
+ {0x0e88, 0x0e8a, 2},
+ {0x0e8d, 0x0e94, 7},
+ {0x0e95, 0x0e97, 1},
+ {0x0e99, 0x0e9f, 1},
+ {0x0ea1, 0x0ea3, 1},
+ {0x0ea5, 0x0ea7, 2},
+ {0x0eaa, 0x0eab, 1},
+ {0x0ead, 0x0eb0, 1},
+ {0x0eb2, 0x0eb3, 1},
+ {0x0ebd, 0x0ec0, 3},
+ {0x0ec1, 0x0ec4, 1},
+ {0x0ec6, 0x0edc, 22},
+ {0x0edd, 0x0f00, 35},
+ {0x0f40, 0x0f47, 1},
+ {0x0f49, 0x0f6c, 1},
+ {0x0f88, 0x0f8b, 1},
+ {0x1000, 0x102a, 1},
+ {0x103f, 0x1050, 17},
+ {0x1051, 0x1055, 1},
+ {0x105a, 0x105d, 1},
+ {0x1061, 0x1065, 4},
+ {0x1066, 0x106e, 8},
+ {0x106f, 0x1070, 1},
+ {0x1075, 0x1081, 1},
+ {0x108e, 0x10a0, 18},
+ {0x10a1, 0x10c5, 1},
+ {0x10d0, 0x10fa, 1},
+ {0x10fc, 0x1100, 4},
+ {0x1101, 0x1248, 1},
+ {0x124a, 0x124d, 1},
+ {0x1250, 0x1256, 1},
+ {0x1258, 0x125a, 2},
+ {0x125b, 0x125d, 1},
+ {0x1260, 0x1288, 1},
+ {0x128a, 0x128d, 1},
+ {0x1290, 0x12b0, 1},
+ {0x12b2, 0x12b5, 1},
+ {0x12b8, 0x12be, 1},
+ {0x12c0, 0x12c2, 2},
+ {0x12c3, 0x12c5, 1},
+ {0x12c8, 0x12d6, 1},
+ {0x12d8, 0x1310, 1},
+ {0x1312, 0x1315, 1},
+ {0x1318, 0x135a, 1},
+ {0x1380, 0x138f, 1},
+ {0x13a0, 0x13f4, 1},
+ {0x1401, 0x166c, 1},
+ {0x166f, 0x167f, 1},
+ {0x1681, 0x169a, 1},
+ {0x16a0, 0x16ea, 1},
+ {0x1700, 0x170c, 1},
+ {0x170e, 0x1711, 1},
+ {0x1720, 0x1731, 1},
+ {0x1740, 0x1751, 1},
+ {0x1760, 0x176c, 1},
+ {0x176e, 0x1770, 1},
+ {0x1780, 0x17b3, 1},
+ {0x17d7, 0x17dc, 5},
+ {0x1820, 0x1877, 1},
+ {0x1880, 0x18a8, 1},
+ {0x18aa, 0x18b0, 6},
+ {0x18b1, 0x18f5, 1},
+ {0x1900, 0x191c, 1},
+ {0x1950, 0x196d, 1},
+ {0x1970, 0x1974, 1},
+ {0x1980, 0x19ab, 1},
+ {0x19c1, 0x19c7, 1},
+ {0x1a00, 0x1a16, 1},
+ {0x1a20, 0x1a54, 1},
+ {0x1aa7, 0x1b05, 94},
+ {0x1b06, 0x1b33, 1},
+ {0x1b45, 0x1b4b, 1},
+ {0x1b83, 0x1ba0, 1},
+ {0x1bae, 0x1baf, 1},
+ {0x1c00, 0x1c23, 1},
+ {0x1c4d, 0x1c4f, 1},
+ {0x1c5a, 0x1c7d, 1},
+ {0x1ce9, 0x1cec, 1},
+ {0x1cee, 0x1cf1, 1},
+ {0x1d00, 0x1dbf, 1},
+ {0x1e00, 0x1f15, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f20, 0x1f45, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f50, 0x1f57, 1},
+ {0x1f59, 0x1f5f, 2},
+ {0x1f60, 0x1f7d, 1},
+ {0x1f80, 0x1fb4, 1},
+ {0x1fb6, 0x1fbc, 1},
+ {0x1fbe, 0x1fc2, 4},
+ {0x1fc3, 0x1fc4, 1},
+ {0x1fc6, 0x1fcc, 1},
+ {0x1fd0, 0x1fd3, 1},
+ {0x1fd6, 0x1fdb, 1},
+ {0x1fe0, 0x1fec, 1},
+ {0x1ff2, 0x1ff4, 1},
+ {0x1ff6, 0x1ffc, 1},
+ {0x2071, 0x207f, 14},
+ {0x2090, 0x2094, 1},
+ {0x2102, 0x2107, 5},
+ {0x210a, 0x2113, 1},
+ {0x2115, 0x2119, 4},
+ {0x211a, 0x211d, 1},
+ {0x2124, 0x212a, 2},
+ {0x212b, 0x212d, 1},
+ {0x212f, 0x2139, 1},
+ {0x213c, 0x213f, 1},
+ {0x2145, 0x2149, 1},
+ {0x214e, 0x2183, 53},
+ {0x2184, 0x2c00, 2684},
+ {0x2c01, 0x2c2e, 1},
+ {0x2c30, 0x2c5e, 1},
+ {0x2c60, 0x2ce4, 1},
+ {0x2ceb, 0x2cee, 1},
+ {0x2d00, 0x2d25, 1},
+ {0x2d30, 0x2d65, 1},
+ {0x2d6f, 0x2d80, 17},
+ {0x2d81, 0x2d96, 1},
+ {0x2da0, 0x2da6, 1},
+ {0x2da8, 0x2dae, 1},
+ {0x2db0, 0x2db6, 1},
+ {0x2db8, 0x2dbe, 1},
+ {0x2dc0, 0x2dc6, 1},
+ {0x2dc8, 0x2dce, 1},
+ {0x2dd0, 0x2dd6, 1},
+ {0x2dd8, 0x2dde, 1},
+ {0x2e2f, 0x3005, 470},
+ {0x3006, 0x3031, 43},
+ {0x3032, 0x3035, 1},
+ {0x303b, 0x303c, 1},
+ {0x3041, 0x3096, 1},
+ {0x309d, 0x309f, 1},
+ {0x30a1, 0x30fa, 1},
+ {0x30fc, 0x30ff, 1},
+ {0x3105, 0x312d, 1},
+ {0x3131, 0x318e, 1},
+ {0x31a0, 0x31b7, 1},
+ {0x31f0, 0x31ff, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xa000, 0xa48c, 1},
+ {0xa4d0, 0xa4fd, 1},
+ {0xa500, 0xa60c, 1},
+ {0xa610, 0xa61f, 1},
+ {0xa62a, 0xa62b, 1},
+ {0xa640, 0xa65f, 1},
+ {0xa662, 0xa66e, 1},
+ {0xa67f, 0xa697, 1},
+ {0xa6a0, 0xa6e5, 1},
+ {0xa717, 0xa71f, 1},
+ {0xa722, 0xa788, 1},
+ {0xa78b, 0xa78c, 1},
+ {0xa7fb, 0xa801, 1},
+ {0xa803, 0xa805, 1},
+ {0xa807, 0xa80a, 1},
+ {0xa80c, 0xa822, 1},
+ {0xa840, 0xa873, 1},
+ {0xa882, 0xa8b3, 1},
+ {0xa8f2, 0xa8f7, 1},
+ {0xa8fb, 0xa90a, 15},
+ {0xa90b, 0xa925, 1},
+ {0xa930, 0xa946, 1},
+ {0xa960, 0xa97c, 1},
+ {0xa984, 0xa9b2, 1},
+ {0xa9cf, 0xaa00, 49},
+ {0xaa01, 0xaa28, 1},
+ {0xaa40, 0xaa42, 1},
+ {0xaa44, 0xaa4b, 1},
+ {0xaa60, 0xaa76, 1},
+ {0xaa7a, 0xaa80, 6},
+ {0xaa81, 0xaaaf, 1},
+ {0xaab1, 0xaab5, 4},
+ {0xaab6, 0xaab9, 3},
+ {0xaaba, 0xaabd, 1},
+ {0xaac0, 0xaac2, 2},
+ {0xaadb, 0xaadd, 1},
+ {0xabc0, 0xabe2, 1},
+ {0xac00, 0xd7a3, 1},
+ {0xd7b0, 0xd7c6, 1},
+ {0xd7cb, 0xd7fb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
+ {0xfb00, 0xfb06, 1},
+ {0xfb13, 0xfb17, 1},
+ {0xfb1d, 0xfb1f, 2},
+ {0xfb20, 0xfb28, 1},
+ {0xfb2a, 0xfb36, 1},
+ {0xfb38, 0xfb3c, 1},
+ {0xfb3e, 0xfb40, 2},
+ {0xfb41, 0xfb43, 2},
+ {0xfb44, 0xfb46, 2},
+ {0xfb47, 0xfbb1, 1},
+ {0xfbd3, 0xfd3d, 1},
+ {0xfd50, 0xfd8f, 1},
+ {0xfd92, 0xfdc7, 1},
+ {0xfdf0, 0xfdfb, 1},
+ {0xfe70, 0xfe74, 1},
+ {0xfe76, 0xfefc, 1},
+ {0xff21, 0xff3a, 1},
+ {0xff41, 0xff5a, 1},
+ {0xff66, 0xffbe, 1},
+ {0xffc2, 0xffc7, 1},
+ {0xffca, 0xffcf, 1},
+ {0xffd2, 0xffd7, 1},
+ {0xffda, 0xffdc, 1},
+ {0x10000, 0x1000b, 1},
+ {0x1000d, 0x10026, 1},
+ {0x10028, 0x1003a, 1},
+ {0x1003c, 0x1003d, 1},
+ {0x1003f, 0x1004d, 1},
+ {0x10050, 0x1005d, 1},
+ {0x10080, 0x100fa, 1},
+ {0x10280, 0x1029c, 1},
+ {0x102a0, 0x102d0, 1},
+ {0x10300, 0x1031e, 1},
+ {0x10330, 0x10340, 1},
+ {0x10342, 0x10349, 1},
+ {0x10380, 0x1039d, 1},
+ {0x103a0, 0x103c3, 1},
+ {0x103c8, 0x103cf, 1},
+ {0x10400, 0x1049d, 1},
+ {0x10800, 0x10805, 1},
+ {0x10808, 0x1080a, 2},
+ {0x1080b, 0x10835, 1},
+ {0x10837, 0x10838, 1},
+ {0x1083c, 0x1083f, 3},
+ {0x10840, 0x10855, 1},
+ {0x10900, 0x10915, 1},
+ {0x10920, 0x10939, 1},
+ {0x10a00, 0x10a10, 16},
+ {0x10a11, 0x10a13, 1},
+ {0x10a15, 0x10a17, 1},
+ {0x10a19, 0x10a33, 1},
+ {0x10a60, 0x10a7c, 1},
+ {0x10b00, 0x10b35, 1},
+ {0x10b40, 0x10b55, 1},
+ {0x10b60, 0x10b72, 1},
+ {0x10c00, 0x10c48, 1},
+ {0x11083, 0x110af, 1},
+ {0x12000, 0x1236e, 1},
+ {0x13000, 0x1342e, 1},
+ {0x1d400, 0x1d454, 1},
+ {0x1d456, 0x1d49c, 1},
+ {0x1d49e, 0x1d49f, 1},
+ {0x1d4a2, 0x1d4a5, 3},
+ {0x1d4a6, 0x1d4a9, 3},
+ {0x1d4aa, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bd, 2},
+ {0x1d4be, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d51e, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d54a, 4},
+ {0x1d54b, 0x1d550, 1},
+ {0x1d552, 0x1d6a5, 1},
+ {0x1d6a8, 0x1d6c0, 1},
+ {0x1d6c2, 0x1d6da, 1},
+ {0x1d6dc, 0x1d6fa, 1},
+ {0x1d6fc, 0x1d714, 1},
+ {0x1d716, 0x1d734, 1},
+ {0x1d736, 0x1d74e, 1},
+ {0x1d750, 0x1d76e, 1},
+ {0x1d770, 0x1d788, 1},
+ {0x1d78a, 0x1d7a8, 1},
+ {0x1d7aa, 0x1d7c2, 1},
+ {0x1d7c4, 0x1d7cb, 1},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2f800, 0x2fa1d, 1},
+}
+
+var _Zp = []Range{
+ {0x2029, 0x2029, 1},
+}
+
+var _Zs = []Range{
+ {0x0020, 0x00a0, 128},
+ {0x1680, 0x180e, 398},
+ {0x2000, 0x200a, 1},
+ {0x202f, 0x205f, 48},
+ {0x3000, 0x3000, 1},
+}
+
+var _Cs = []Range{
+ {0xd800, 0xdfff, 1},
+}
+
+var _Co = []Range{
+ {0xe000, 0xf8ff, 1},
+ {0xf0000, 0xffffd, 1},
+ {0x100000, 0x10fffd, 1},
+}
+
+var _Cf = []Range{
+ {0x00ad, 0x0600, 1363},
+ {0x0601, 0x0603, 1},
+ {0x06dd, 0x070f, 50},
+ {0x17b4, 0x17b5, 1},
+ {0x200b, 0x200f, 1},
+ {0x202a, 0x202e, 1},
+ {0x2060, 0x2064, 1},
+ {0x206a, 0x206f, 1},
+ {0xfeff, 0xfff9, 250},
+ {0xfffa, 0xfffb, 1},
+ {0x110bd, 0x1d173, 49334},
+ {0x1d174, 0x1d17a, 1},
+ {0xe0001, 0xe0020, 31},
+ {0xe0021, 0xe007f, 1},
+}
+
+var _Cc = []Range{
+ {0x0001, 0x001f, 1},
+ {0x007f, 0x009f, 1},
+}
+
+var _Po = []Range{
+ {0x0021, 0x0023, 1},
+ {0x0025, 0x0027, 1},
+ {0x002a, 0x002e, 2},
+ {0x002f, 0x003a, 11},
+ {0x003b, 0x003f, 4},
+ {0x0040, 0x005c, 28},
+ {0x00a1, 0x00b7, 22},
+ {0x00bf, 0x037e, 703},
+ {0x0387, 0x055a, 467},
+ {0x055b, 0x055f, 1},
+ {0x0589, 0x05c0, 55},
+ {0x05c3, 0x05c6, 3},
+ {0x05f3, 0x05f4, 1},
+ {0x0609, 0x060a, 1},
+ {0x060c, 0x060d, 1},
+ {0x061b, 0x061e, 3},
+ {0x061f, 0x066a, 75},
+ {0x066b, 0x066d, 1},
+ {0x06d4, 0x0700, 44},
+ {0x0701, 0x070d, 1},
+ {0x07f7, 0x07f9, 1},
+ {0x0830, 0x083e, 1},
+ {0x0964, 0x0965, 1},
+ {0x0970, 0x0df4, 1156},
+ {0x0e4f, 0x0e5a, 11},
+ {0x0e5b, 0x0f04, 169},
+ {0x0f05, 0x0f12, 1},
+ {0x0f85, 0x0fd0, 75},
+ {0x0fd1, 0x0fd4, 1},
+ {0x104a, 0x104f, 1},
+ {0x10fb, 0x1361, 614},
+ {0x1362, 0x1368, 1},
+ {0x166d, 0x166e, 1},
+ {0x16eb, 0x16ed, 1},
+ {0x1735, 0x1736, 1},
+ {0x17d4, 0x17d6, 1},
+ {0x17d8, 0x17da, 1},
+ {0x1800, 0x1805, 1},
+ {0x1807, 0x180a, 1},
+ {0x1944, 0x1945, 1},
+ {0x19de, 0x19df, 1},
+ {0x1a1e, 0x1a1f, 1},
+ {0x1aa0, 0x1aa6, 1},
+ {0x1aa8, 0x1aad, 1},
+ {0x1b5a, 0x1b60, 1},
+ {0x1c3b, 0x1c3f, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x1cd3, 0x2016, 835},
+ {0x2017, 0x2020, 9},
+ {0x2021, 0x2027, 1},
+ {0x2030, 0x2038, 1},
+ {0x203b, 0x203e, 1},
+ {0x2041, 0x2043, 1},
+ {0x2047, 0x2051, 1},
+ {0x2053, 0x2055, 2},
+ {0x2056, 0x205e, 1},
+ {0x2cf9, 0x2cfc, 1},
+ {0x2cfe, 0x2cff, 1},
+ {0x2e00, 0x2e01, 1},
+ {0x2e06, 0x2e08, 1},
+ {0x2e0b, 0x2e0e, 3},
+ {0x2e0f, 0x2e16, 1},
+ {0x2e18, 0x2e19, 1},
+ {0x2e1b, 0x2e1e, 3},
+ {0x2e1f, 0x2e2a, 11},
+ {0x2e2b, 0x2e2e, 1},
+ {0x2e30, 0x2e31, 1},
+ {0x3001, 0x3003, 1},
+ {0x303d, 0x30fb, 190},
+ {0xa4fe, 0xa4ff, 1},
+ {0xa60d, 0xa60f, 1},
+ {0xa673, 0xa67e, 11},
+ {0xa6f2, 0xa6f7, 1},
+ {0xa874, 0xa877, 1},
+ {0xa8ce, 0xa8cf, 1},
+ {0xa8f8, 0xa8fa, 1},
+ {0xa92e, 0xa92f, 1},
+ {0xa95f, 0xa9c1, 98},
+ {0xa9c2, 0xa9cd, 1},
+ {0xa9de, 0xa9df, 1},
+ {0xaa5c, 0xaa5f, 1},
+ {0xaade, 0xaadf, 1},
+ {0xabeb, 0xfe10, 21029},
+ {0xfe11, 0xfe16, 1},
+ {0xfe19, 0xfe30, 23},
+ {0xfe45, 0xfe46, 1},
+ {0xfe49, 0xfe4c, 1},
+ {0xfe50, 0xfe52, 1},
+ {0xfe54, 0xfe57, 1},
+ {0xfe5f, 0xfe61, 1},
+ {0xfe68, 0xfe6a, 2},
+ {0xfe6b, 0xff01, 150},
+ {0xff02, 0xff03, 1},
+ {0xff05, 0xff07, 1},
+ {0xff0a, 0xff0e, 2},
+ {0xff0f, 0xff1a, 11},
+ {0xff1b, 0xff1f, 4},
+ {0xff20, 0xff3c, 28},
+ {0xff61, 0xff64, 3},
+ {0xff65, 0x10100, 411},
+ {0x10101, 0x1039f, 670},
+ {0x103d0, 0x10857, 1159},
+ {0x1091f, 0x1093f, 32},
+ {0x10a50, 0x10a58, 1},
+ {0x10a7f, 0x10b39, 186},
+ {0x10b3a, 0x10b3f, 1},
+ {0x110bb, 0x110bc, 1},
+ {0x110be, 0x110c1, 1},
+ {0x12470, 0x12473, 1},
+}
+
+var _Pi = []Range{
+ {0x00ab, 0x2018, 8045},
+ {0x201b, 0x201c, 1},
+ {0x201f, 0x2039, 26},
+ {0x2e02, 0x2e04, 2},
+ {0x2e09, 0x2e0c, 3},
+ {0x2e1c, 0x2e20, 4},
+}
+
+var _Pf = []Range{
+ {0x00bb, 0x2019, 8030},
+ {0x201d, 0x203a, 29},
+ {0x2e03, 0x2e05, 2},
+ {0x2e0a, 0x2e0d, 3},
+ {0x2e1d, 0x2e21, 4},
+}
+
+var _Pe = []Range{
+ {0x0029, 0x005d, 52},
+ {0x007d, 0x0f3b, 3774},
+ {0x0f3d, 0x169c, 1887},
+ {0x2046, 0x207e, 56},
+ {0x208e, 0x232a, 668},
+ {0x2769, 0x2775, 2},
+ {0x27c6, 0x27e7, 33},
+ {0x27e9, 0x27ef, 2},
+ {0x2984, 0x2998, 2},
+ {0x29d9, 0x29db, 2},
+ {0x29fd, 0x2e23, 1062},
+ {0x2e25, 0x2e29, 2},
+ {0x3009, 0x3011, 2},
+ {0x3015, 0x301b, 2},
+ {0x301e, 0x301f, 1},
+ {0xfd3f, 0xfe18, 217},
+ {0xfe36, 0xfe44, 2},
+ {0xfe48, 0xfe5a, 18},
+ {0xfe5c, 0xfe5e, 2},
+ {0xff09, 0xff3d, 52},
+ {0xff5d, 0xff63, 3},
+}
+
+var _Pd = []Range{
+ {0x002d, 0x058a, 1373},
+ {0x05be, 0x1400, 3650},
+ {0x1806, 0x2010, 2058},
+ {0x2011, 0x2015, 1},
+ {0x2e17, 0x2e1a, 3},
+ {0x301c, 0x3030, 20},
+ {0x30a0, 0xfe31, 52625},
+ {0xfe32, 0xfe58, 38},
+ {0xfe63, 0xff0d, 170},
+}
+
+var _Pc = []Range{
+ {0x005f, 0x203f, 8160},
+ {0x2040, 0x2054, 20},
+ {0xfe33, 0xfe34, 1},
+ {0xfe4d, 0xfe4f, 1},
+ {0xff3f, 0xff3f, 1},
+}
+
+var _Ps = []Range{
+ {0x0028, 0x005b, 51},
+ {0x007b, 0x0f3a, 3775},
+ {0x0f3c, 0x169b, 1887},
+ {0x201a, 0x201e, 4},
+ {0x2045, 0x207d, 56},
+ {0x208d, 0x2329, 668},
+ {0x2768, 0x2774, 2},
+ {0x27c5, 0x27e6, 33},
+ {0x27e8, 0x27ee, 2},
+ {0x2983, 0x2997, 2},
+ {0x29d8, 0x29da, 2},
+ {0x29fc, 0x2e22, 1062},
+ {0x2e24, 0x2e28, 2},
+ {0x3008, 0x3010, 2},
+ {0x3014, 0x301a, 2},
+ {0x301d, 0xfd3e, 52513},
+ {0xfe17, 0xfe35, 30},
+ {0xfe37, 0xfe43, 2},
+ {0xfe47, 0xfe59, 18},
+ {0xfe5b, 0xfe5d, 2},
+ {0xff08, 0xff3b, 51},
+ {0xff5b, 0xff5f, 4},
+ {0xff62, 0xff62, 1},
+}
+
+var _Nd = []Range{
+ {0x0030, 0x0039, 1},
+ {0x0660, 0x0669, 1},
+ {0x06f0, 0x06f9, 1},
+ {0x07c0, 0x07c9, 1},
+ {0x0966, 0x096f, 1},
+ {0x09e6, 0x09ef, 1},
+ {0x0a66, 0x0a6f, 1},
+ {0x0ae6, 0x0aef, 1},
+ {0x0b66, 0x0b6f, 1},
+ {0x0be6, 0x0bef, 1},
+ {0x0c66, 0x0c6f, 1},
+ {0x0ce6, 0x0cef, 1},
+ {0x0d66, 0x0d6f, 1},
+ {0x0e50, 0x0e59, 1},
+ {0x0ed0, 0x0ed9, 1},
+ {0x0f20, 0x0f29, 1},
+ {0x1040, 0x1049, 1},
+ {0x1090, 0x1099, 1},
+ {0x17e0, 0x17e9, 1},
+ {0x1810, 0x1819, 1},
+ {0x1946, 0x194f, 1},
+ {0x19d0, 0x19da, 1},
+ {0x1a80, 0x1a89, 1},
+ {0x1a90, 0x1a99, 1},
+ {0x1b50, 0x1b59, 1},
+ {0x1bb0, 0x1bb9, 1},
+ {0x1c40, 0x1c49, 1},
+ {0x1c50, 0x1c59, 1},
+ {0xa620, 0xa629, 1},
+ {0xa8d0, 0xa8d9, 1},
+ {0xa900, 0xa909, 1},
+ {0xa9d0, 0xa9d9, 1},
+ {0xaa50, 0xaa59, 1},
+ {0xabf0, 0xabf9, 1},
+ {0xff10, 0xff19, 1},
+ {0x104a0, 0x104a9, 1},
+ {0x1d7ce, 0x1d7ff, 1},
+}
+
+var _Nl = []Range{
+ {0x16ee, 0x16f0, 1},
+ {0x2160, 0x2182, 1},
+ {0x2185, 0x2188, 1},
+ {0x3007, 0x3021, 26},
+ {0x3022, 0x3029, 1},
+ {0x3038, 0x303a, 1},
+ {0xa6e6, 0xa6ef, 1},
+ {0x10140, 0x10174, 1},
+ {0x10341, 0x1034a, 9},
+ {0x103d1, 0x103d5, 1},
+ {0x12400, 0x12462, 1},
+}
+
+var _No = []Range{
+ {0x00b2, 0x00b3, 1},
+ {0x00b9, 0x00bc, 3},
+ {0x00bd, 0x00be, 1},
+ {0x09f4, 0x09f9, 1},
+ {0x0bf0, 0x0bf2, 1},
+ {0x0c78, 0x0c7e, 1},
+ {0x0d70, 0x0d75, 1},
+ {0x0f2a, 0x0f33, 1},
+ {0x1369, 0x137c, 1},
+ {0x17f0, 0x17f9, 1},
+ {0x2070, 0x2074, 4},
+ {0x2075, 0x2079, 1},
+ {0x2080, 0x2089, 1},
+ {0x2150, 0x215f, 1},
+ {0x2189, 0x2460, 727},
+ {0x2461, 0x249b, 1},
+ {0x24ea, 0x24ff, 1},
+ {0x2776, 0x2793, 1},
+ {0x2cfd, 0x3192, 1173},
+ {0x3193, 0x3195, 1},
+ {0x3220, 0x3229, 1},
+ {0x3251, 0x325f, 1},
+ {0x3280, 0x3289, 1},
+ {0x32b1, 0x32bf, 1},
+ {0xa830, 0xa835, 1},
+ {0x10107, 0x10133, 1},
+ {0x10175, 0x10178, 1},
+ {0x1018a, 0x10320, 406},
+ {0x10321, 0x10323, 1},
+ {0x10858, 0x1085f, 1},
+ {0x10916, 0x1091b, 1},
+ {0x10a40, 0x10a47, 1},
+ {0x10a7d, 0x10a7e, 1},
+ {0x10b58, 0x10b5f, 1},
+ {0x10b78, 0x10b7f, 1},
+ {0x10e60, 0x10e7e, 1},
+ {0x1d360, 0x1d371, 1},
+ {0x1f100, 0x1f10a, 1},
+}
+
+var _So = []Range{
+ {0x00a6, 0x00a7, 1},
+ {0x00a9, 0x00ae, 5},
+ {0x00b0, 0x00b6, 6},
+ {0x0482, 0x060e, 396},
+ {0x060f, 0x06e9, 218},
+ {0x06fd, 0x06fe, 1},
+ {0x07f6, 0x09fa, 516},
+ {0x0b70, 0x0bf3, 131},
+ {0x0bf4, 0x0bf8, 1},
+ {0x0bfa, 0x0c7f, 133},
+ {0x0cf1, 0x0cf2, 1},
+ {0x0d79, 0x0f01, 392},
+ {0x0f02, 0x0f03, 1},
+ {0x0f13, 0x0f17, 1},
+ {0x0f1a, 0x0f1f, 1},
+ {0x0f34, 0x0f38, 2},
+ {0x0fbe, 0x0fc5, 1},
+ {0x0fc7, 0x0fcc, 1},
+ {0x0fce, 0x0fcf, 1},
+ {0x0fd5, 0x0fd8, 1},
+ {0x109e, 0x109f, 1},
+ {0x1360, 0x1390, 48},
+ {0x1391, 0x1399, 1},
+ {0x1940, 0x19e0, 160},
+ {0x19e1, 0x19ff, 1},
+ {0x1b61, 0x1b6a, 1},
+ {0x1b74, 0x1b7c, 1},
+ {0x2100, 0x2101, 1},
+ {0x2103, 0x2106, 1},
+ {0x2108, 0x2109, 1},
+ {0x2114, 0x2116, 2},
+ {0x2117, 0x2118, 1},
+ {0x211e, 0x2123, 1},
+ {0x2125, 0x2129, 2},
+ {0x212e, 0x213a, 12},
+ {0x213b, 0x214a, 15},
+ {0x214c, 0x214d, 1},
+ {0x214f, 0x2195, 70},
+ {0x2196, 0x2199, 1},
+ {0x219c, 0x219f, 1},
+ {0x21a1, 0x21a2, 1},
+ {0x21a4, 0x21a5, 1},
+ {0x21a7, 0x21ad, 1},
+ {0x21af, 0x21cd, 1},
+ {0x21d0, 0x21d1, 1},
+ {0x21d3, 0x21d5, 2},
+ {0x21d6, 0x21f3, 1},
+ {0x2300, 0x2307, 1},
+ {0x230c, 0x231f, 1},
+ {0x2322, 0x2328, 1},
+ {0x232b, 0x237b, 1},
+ {0x237d, 0x239a, 1},
+ {0x23b4, 0x23db, 1},
+ {0x23e2, 0x23e8, 1},
+ {0x2400, 0x2426, 1},
+ {0x2440, 0x244a, 1},
+ {0x249c, 0x24e9, 1},
+ {0x2500, 0x25b6, 1},
+ {0x25b8, 0x25c0, 1},
+ {0x25c2, 0x25f7, 1},
+ {0x2600, 0x266e, 1},
+ {0x2670, 0x26cd, 1},
+ {0x26cf, 0x26e1, 1},
+ {0x26e3, 0x26e8, 5},
+ {0x26e9, 0x26ff, 1},
+ {0x2701, 0x2704, 1},
+ {0x2706, 0x2709, 1},
+ {0x270c, 0x2727, 1},
+ {0x2729, 0x274b, 1},
+ {0x274d, 0x274f, 2},
+ {0x2750, 0x2752, 1},
+ {0x2756, 0x275e, 1},
+ {0x2761, 0x2767, 1},
+ {0x2794, 0x2798, 4},
+ {0x2799, 0x27af, 1},
+ {0x27b1, 0x27be, 1},
+ {0x2800, 0x28ff, 1},
+ {0x2b00, 0x2b2f, 1},
+ {0x2b45, 0x2b46, 1},
+ {0x2b50, 0x2b59, 1},
+ {0x2ce5, 0x2cea, 1},
+ {0x2e80, 0x2e99, 1},
+ {0x2e9b, 0x2ef3, 1},
+ {0x2f00, 0x2fd5, 1},
+ {0x2ff0, 0x2ffb, 1},
+ {0x3004, 0x3012, 14},
+ {0x3013, 0x3020, 13},
+ {0x3036, 0x3037, 1},
+ {0x303e, 0x303f, 1},
+ {0x3190, 0x3191, 1},
+ {0x3196, 0x319f, 1},
+ {0x31c0, 0x31e3, 1},
+ {0x3200, 0x321e, 1},
+ {0x322a, 0x3250, 1},
+ {0x3260, 0x327f, 1},
+ {0x328a, 0x32b0, 1},
+ {0x32c0, 0x32fe, 1},
+ {0x3300, 0x33ff, 1},
+ {0x4dc0, 0x4dff, 1},
+ {0xa490, 0xa4c6, 1},
+ {0xa828, 0xa82b, 1},
+ {0xa836, 0xa837, 1},
+ {0xa839, 0xaa77, 574},
+ {0xaa78, 0xaa79, 1},
+ {0xfdfd, 0xffe4, 487},
+ {0xffe8, 0xffed, 5},
+ {0xffee, 0xfffc, 14},
+ {0xfffd, 0x10102, 261},
+ {0x10137, 0x1013f, 1},
+ {0x10179, 0x10189, 1},
+ {0x10190, 0x1019b, 1},
+ {0x101d0, 0x101fc, 1},
+ {0x1d000, 0x1d0f5, 1},
+ {0x1d100, 0x1d126, 1},
+ {0x1d129, 0x1d164, 1},
+ {0x1d16a, 0x1d16c, 1},
+ {0x1d183, 0x1d184, 1},
+ {0x1d18c, 0x1d1a9, 1},
+ {0x1d1ae, 0x1d1dd, 1},
+ {0x1d200, 0x1d241, 1},
+ {0x1d245, 0x1d300, 187},
+ {0x1d301, 0x1d356, 1},
+ {0x1f000, 0x1f02b, 1},
+ {0x1f030, 0x1f093, 1},
+ {0x1f110, 0x1f12e, 1},
+ {0x1f131, 0x1f13d, 12},
+ {0x1f13f, 0x1f142, 3},
+ {0x1f146, 0x1f14a, 4},
+ {0x1f14b, 0x1f14e, 1},
+ {0x1f157, 0x1f15f, 8},
+ {0x1f179, 0x1f17b, 2},
+ {0x1f17c, 0x1f17f, 3},
+ {0x1f18a, 0x1f18d, 1},
+ {0x1f190, 0x1f200, 112},
+ {0x1f210, 0x1f231, 1},
+ {0x1f240, 0x1f248, 1},
+}
+
+var _Sm = []Range{
+ {0x002b, 0x003c, 17},
+ {0x003d, 0x003e, 1},
+ {0x007c, 0x007e, 2},
+ {0x00ac, 0x00b1, 5},
+ {0x00d7, 0x00f7, 32},
+ {0x03f6, 0x0606, 528},
+ {0x0607, 0x0608, 1},
+ {0x2044, 0x2052, 14},
+ {0x207a, 0x207c, 1},
+ {0x208a, 0x208c, 1},
+ {0x2140, 0x2144, 1},
+ {0x214b, 0x2190, 69},
+ {0x2191, 0x2194, 1},
+ {0x219a, 0x219b, 1},
+ {0x21a0, 0x21a6, 3},
+ {0x21ae, 0x21ce, 32},
+ {0x21cf, 0x21d2, 3},
+ {0x21d4, 0x21f4, 32},
+ {0x21f5, 0x22ff, 1},
+ {0x2308, 0x230b, 1},
+ {0x2320, 0x2321, 1},
+ {0x237c, 0x239b, 31},
+ {0x239c, 0x23b3, 1},
+ {0x23dc, 0x23e1, 1},
+ {0x25b7, 0x25c1, 10},
+ {0x25f8, 0x25ff, 1},
+ {0x266f, 0x27c0, 337},
+ {0x27c1, 0x27c4, 1},
+ {0x27c7, 0x27ca, 1},
+ {0x27cc, 0x27d0, 4},
+ {0x27d1, 0x27e5, 1},
+ {0x27f0, 0x27ff, 1},
+ {0x2900, 0x2982, 1},
+ {0x2999, 0x29d7, 1},
+ {0x29dc, 0x29fb, 1},
+ {0x29fe, 0x2aff, 1},
+ {0x2b30, 0x2b44, 1},
+ {0x2b47, 0x2b4c, 1},
+ {0xfb29, 0xfe62, 825},
+ {0xfe64, 0xfe66, 1},
+ {0xff0b, 0xff1c, 17},
+ {0xff1d, 0xff1e, 1},
+ {0xff5c, 0xff5e, 2},
+ {0xffe2, 0xffe9, 7},
+ {0xffea, 0xffec, 1},
+ {0x1d6c1, 0x1d6db, 26},
+ {0x1d6fb, 0x1d715, 26},
+ {0x1d735, 0x1d74f, 26},
+ {0x1d76f, 0x1d789, 26},
+ {0x1d7a9, 0x1d7c3, 26},
+}
+
+var _Sk = []Range{
+ {0x005e, 0x0060, 2},
+ {0x00a8, 0x00af, 7},
+ {0x00b4, 0x00b8, 4},
+ {0x02c2, 0x02c5, 1},
+ {0x02d2, 0x02df, 1},
+ {0x02e5, 0x02eb, 1},
+ {0x02ed, 0x02ef, 2},
+ {0x02f0, 0x02ff, 1},
+ {0x0375, 0x0384, 15},
+ {0x0385, 0x1fbd, 7224},
+ {0x1fbf, 0x1fc1, 1},
+ {0x1fcd, 0x1fcf, 1},
+ {0x1fdd, 0x1fdf, 1},
+ {0x1fed, 0x1fef, 1},
+ {0x1ffd, 0x1ffe, 1},
+ {0x309b, 0x309c, 1},
+ {0xa700, 0xa716, 1},
+ {0xa720, 0xa721, 1},
+ {0xa789, 0xa78a, 1},
+ {0xff3e, 0xff40, 2},
+ {0xffe3, 0xffe3, 1},
+}
+
+var _Sc = []Range{
+ {0x0024, 0x00a2, 126},
+ {0x00a3, 0x00a5, 1},
+ {0x060b, 0x09f2, 999},
+ {0x09f3, 0x09fb, 8},
+ {0x0af1, 0x0bf9, 264},
+ {0x0e3f, 0x17db, 2460},
+ {0x20a0, 0x20b8, 1},
+ {0xa838, 0xfdfc, 21956},
+ {0xfe69, 0xff04, 155},
+ {0xffe0, 0xffe1, 1},
+ {0xffe5, 0xffe6, 1},
+}
+
+var _Lu = []Range{
+ {0x0041, 0x005a, 1},
+ {0x00c0, 0x00d6, 1},
+ {0x00d8, 0x00de, 1},
+ {0x0100, 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, 0x01cd, 3},
+ {0x01cf, 0x01db, 2},
+ {0x01de, 0x01ee, 2},
+ {0x01f1, 0x01f4, 3},
+ {0x01f6, 0x01f8, 1},
+ {0x01fa, 0x0232, 2},
+ {0x023a, 0x023b, 1},
+ {0x023d, 0x023e, 1},
+ {0x0241, 0x0243, 2},
+ {0x0244, 0x0246, 1},
+ {0x0248, 0x024e, 2},
+ {0x0370, 0x0372, 2},
+ {0x0376, 0x0386, 16},
+ {0x0388, 0x038a, 1},
+ {0x038c, 0x038e, 2},
+ {0x038f, 0x0391, 2},
+ {0x0392, 0x03a1, 1},
+ {0x03a3, 0x03ab, 1},
+ {0x03cf, 0x03d2, 3},
+ {0x03d3, 0x03d4, 1},
+ {0x03d8, 0x03ee, 2},
+ {0x03f4, 0x03f7, 3},
+ {0x03f9, 0x03fa, 1},
+ {0x03fd, 0x042f, 1},
+ {0x0460, 0x0480, 2},
+ {0x048a, 0x04c0, 2},
+ {0x04c1, 0x04cd, 2},
+ {0x04d0, 0x0524, 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},
+ {0x1fb8, 0x1fbb, 1},
+ {0x1fc8, 0x1fcb, 1},
+ {0x1fd8, 0x1fdb, 1},
+ {0x1fe8, 0x1fec, 1},
+ {0x1ff8, 0x1ffb, 1},
+ {0x2102, 0x2107, 5},
+ {0x210b, 0x210d, 1},
+ {0x2110, 0x2112, 1},
+ {0x2115, 0x2119, 4},
+ {0x211a, 0x211d, 1},
+ {0x2124, 0x212a, 2},
+ {0x212b, 0x212d, 1},
+ {0x2130, 0x2133, 1},
+ {0x213e, 0x213f, 1},
+ {0x2145, 0x2183, 62},
+ {0x2c00, 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, 0xa65e, 2},
+ {0xa662, 0xa66c, 2},
+ {0xa680, 0xa696, 2},
+ {0xa722, 0xa72e, 2},
+ {0xa732, 0xa76e, 2},
+ {0xa779, 0xa77d, 2},
+ {0xa77e, 0xa786, 2},
+ {0xa78b, 0xff21, 22422},
+ {0xff22, 0xff3a, 1},
+ {0x10400, 0x10427, 1},
+ {0x1d400, 0x1d419, 1},
+ {0x1d434, 0x1d44d, 1},
+ {0x1d468, 0x1d481, 1},
+ {0x1d49c, 0x1d49e, 2},
+ {0x1d49f, 0x1d4a5, 3},
+ {0x1d4a6, 0x1d4a9, 3},
+ {0x1d4aa, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b5, 1},
+ {0x1d4d0, 0x1d4e9, 1},
+ {0x1d504, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d538, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d54a, 4},
+ {0x1d54b, 0x1d550, 1},
+ {0x1d56c, 0x1d585, 1},
+ {0x1d5a0, 0x1d5b9, 1},
+ {0x1d5d4, 0x1d5ed, 1},
+ {0x1d608, 0x1d621, 1},
+ {0x1d63c, 0x1d655, 1},
+ {0x1d670, 0x1d689, 1},
+ {0x1d6a8, 0x1d6c0, 1},
+ {0x1d6e2, 0x1d6fa, 1},
+ {0x1d71c, 0x1d734, 1},
+ {0x1d756, 0x1d76e, 1},
+ {0x1d790, 0x1d7a8, 1},
+ {0x1d7ca, 0x1d7ca, 1},
+}
+
+var _Lt = []Range{
+ {0x01c5, 0x01cb, 3},
+ {0x01f2, 0x1f88, 7574},
+ {0x1f89, 0x1f8f, 1},
+ {0x1f98, 0x1f9f, 1},
+ {0x1fa8, 0x1faf, 1},
+ {0x1fbc, 0x1fcc, 16},
+ {0x1ffc, 0x1ffc, 1},
+}
+
+var _Lo = []Range{
+ {0x01bb, 0x01c0, 5},
+ {0x01c1, 0x01c3, 1},
+ {0x0294, 0x05d0, 828},
+ {0x05d1, 0x05ea, 1},
+ {0x05f0, 0x05f2, 1},
+ {0x0621, 0x063f, 1},
+ {0x0641, 0x064a, 1},
+ {0x066e, 0x066f, 1},
+ {0x0671, 0x06d3, 1},
+ {0x06d5, 0x06ee, 25},
+ {0x06ef, 0x06fa, 11},
+ {0x06fb, 0x06fc, 1},
+ {0x06ff, 0x0710, 17},
+ {0x0712, 0x072f, 1},
+ {0x074d, 0x07a5, 1},
+ {0x07b1, 0x07ca, 25},
+ {0x07cb, 0x07ea, 1},
+ {0x0800, 0x0815, 1},
+ {0x0904, 0x0939, 1},
+ {0x093d, 0x0950, 19},
+ {0x0958, 0x0961, 1},
+ {0x0972, 0x0979, 7},
+ {0x097a, 0x097f, 1},
+ {0x0985, 0x098c, 1},
+ {0x098f, 0x0990, 1},
+ {0x0993, 0x09a8, 1},
+ {0x09aa, 0x09b0, 1},
+ {0x09b2, 0x09b6, 4},
+ {0x09b7, 0x09b9, 1},
+ {0x09bd, 0x09ce, 17},
+ {0x09dc, 0x09dd, 1},
+ {0x09df, 0x09e1, 1},
+ {0x09f0, 0x09f1, 1},
+ {0x0a05, 0x0a0a, 1},
+ {0x0a0f, 0x0a10, 1},
+ {0x0a13, 0x0a28, 1},
+ {0x0a2a, 0x0a30, 1},
+ {0x0a32, 0x0a33, 1},
+ {0x0a35, 0x0a36, 1},
+ {0x0a38, 0x0a39, 1},
+ {0x0a59, 0x0a5c, 1},
+ {0x0a5e, 0x0a72, 20},
+ {0x0a73, 0x0a74, 1},
+ {0x0a85, 0x0a8d, 1},
+ {0x0a8f, 0x0a91, 1},
+ {0x0a93, 0x0aa8, 1},
+ {0x0aaa, 0x0ab0, 1},
+ {0x0ab2, 0x0ab3, 1},
+ {0x0ab5, 0x0ab9, 1},
+ {0x0abd, 0x0ad0, 19},
+ {0x0ae0, 0x0ae1, 1},
+ {0x0b05, 0x0b0c, 1},
+ {0x0b0f, 0x0b10, 1},
+ {0x0b13, 0x0b28, 1},
+ {0x0b2a, 0x0b30, 1},
+ {0x0b32, 0x0b33, 1},
+ {0x0b35, 0x0b39, 1},
+ {0x0b3d, 0x0b5c, 31},
+ {0x0b5d, 0x0b5f, 2},
+ {0x0b60, 0x0b61, 1},
+ {0x0b71, 0x0b83, 18},
+ {0x0b85, 0x0b8a, 1},
+ {0x0b8e, 0x0b90, 1},
+ {0x0b92, 0x0b95, 1},
+ {0x0b99, 0x0b9a, 1},
+ {0x0b9c, 0x0b9e, 2},
+ {0x0b9f, 0x0ba3, 4},
+ {0x0ba4, 0x0ba8, 4},
+ {0x0ba9, 0x0baa, 1},
+ {0x0bae, 0x0bb9, 1},
+ {0x0bd0, 0x0c05, 53},
+ {0x0c06, 0x0c0c, 1},
+ {0x0c0e, 0x0c10, 1},
+ {0x0c12, 0x0c28, 1},
+ {0x0c2a, 0x0c33, 1},
+ {0x0c35, 0x0c39, 1},
+ {0x0c3d, 0x0c58, 27},
+ {0x0c59, 0x0c60, 7},
+ {0x0c61, 0x0c85, 36},
+ {0x0c86, 0x0c8c, 1},
+ {0x0c8e, 0x0c90, 1},
+ {0x0c92, 0x0ca8, 1},
+ {0x0caa, 0x0cb3, 1},
+ {0x0cb5, 0x0cb9, 1},
+ {0x0cbd, 0x0cde, 33},
+ {0x0ce0, 0x0ce1, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d28, 1},
+ {0x0d2a, 0x0d39, 1},
+ {0x0d3d, 0x0d60, 35},
+ {0x0d61, 0x0d7a, 25},
+ {0x0d7b, 0x0d7f, 1},
+ {0x0d85, 0x0d96, 1},
+ {0x0d9a, 0x0db1, 1},
+ {0x0db3, 0x0dbb, 1},
+ {0x0dbd, 0x0dc0, 3},
+ {0x0dc1, 0x0dc6, 1},
+ {0x0e01, 0x0e30, 1},
+ {0x0e32, 0x0e33, 1},
+ {0x0e40, 0x0e45, 1},
+ {0x0e81, 0x0e82, 1},
+ {0x0e84, 0x0e87, 3},
+ {0x0e88, 0x0e8a, 2},
+ {0x0e8d, 0x0e94, 7},
+ {0x0e95, 0x0e97, 1},
+ {0x0e99, 0x0e9f, 1},
+ {0x0ea1, 0x0ea3, 1},
+ {0x0ea5, 0x0ea7, 2},
+ {0x0eaa, 0x0eab, 1},
+ {0x0ead, 0x0eb0, 1},
+ {0x0eb2, 0x0eb3, 1},
+ {0x0ebd, 0x0ec0, 3},
+ {0x0ec1, 0x0ec4, 1},
+ {0x0edc, 0x0edd, 1},
+ {0x0f00, 0x0f40, 64},
+ {0x0f41, 0x0f47, 1},
+ {0x0f49, 0x0f6c, 1},
+ {0x0f88, 0x0f8b, 1},
+ {0x1000, 0x102a, 1},
+ {0x103f, 0x1050, 17},
+ {0x1051, 0x1055, 1},
+ {0x105a, 0x105d, 1},
+ {0x1061, 0x1065, 4},
+ {0x1066, 0x106e, 8},
+ {0x106f, 0x1070, 1},
+ {0x1075, 0x1081, 1},
+ {0x108e, 0x10d0, 66},
+ {0x10d1, 0x10fa, 1},
+ {0x1100, 0x1248, 1},
+ {0x124a, 0x124d, 1},
+ {0x1250, 0x1256, 1},
+ {0x1258, 0x125a, 2},
+ {0x125b, 0x125d, 1},
+ {0x1260, 0x1288, 1},
+ {0x128a, 0x128d, 1},
+ {0x1290, 0x12b0, 1},
+ {0x12b2, 0x12b5, 1},
+ {0x12b8, 0x12be, 1},
+ {0x12c0, 0x12c2, 2},
+ {0x12c3, 0x12c5, 1},
+ {0x12c8, 0x12d6, 1},
+ {0x12d8, 0x1310, 1},
+ {0x1312, 0x1315, 1},
+ {0x1318, 0x135a, 1},
+ {0x1380, 0x138f, 1},
+ {0x13a0, 0x13f4, 1},
+ {0x1401, 0x166c, 1},
+ {0x166f, 0x167f, 1},
+ {0x1681, 0x169a, 1},
+ {0x16a0, 0x16ea, 1},
+ {0x1700, 0x170c, 1},
+ {0x170e, 0x1711, 1},
+ {0x1720, 0x1731, 1},
+ {0x1740, 0x1751, 1},
+ {0x1760, 0x176c, 1},
+ {0x176e, 0x1770, 1},
+ {0x1780, 0x17b3, 1},
+ {0x17dc, 0x1820, 68},
+ {0x1821, 0x1842, 1},
+ {0x1844, 0x1877, 1},
+ {0x1880, 0x18a8, 1},
+ {0x18aa, 0x18b0, 6},
+ {0x18b1, 0x18f5, 1},
+ {0x1900, 0x191c, 1},
+ {0x1950, 0x196d, 1},
+ {0x1970, 0x1974, 1},
+ {0x1980, 0x19ab, 1},
+ {0x19c1, 0x19c7, 1},
+ {0x1a00, 0x1a16, 1},
+ {0x1a20, 0x1a54, 1},
+ {0x1b05, 0x1b33, 1},
+ {0x1b45, 0x1b4b, 1},
+ {0x1b83, 0x1ba0, 1},
+ {0x1bae, 0x1baf, 1},
+ {0x1c00, 0x1c23, 1},
+ {0x1c4d, 0x1c4f, 1},
+ {0x1c5a, 0x1c77, 1},
+ {0x1ce9, 0x1cec, 1},
+ {0x1cee, 0x1cf1, 1},
+ {0x2135, 0x2138, 1},
+ {0x2d30, 0x2d65, 1},
+ {0x2d80, 0x2d96, 1},
+ {0x2da0, 0x2da6, 1},
+ {0x2da8, 0x2dae, 1},
+ {0x2db0, 0x2db6, 1},
+ {0x2db8, 0x2dbe, 1},
+ {0x2dc0, 0x2dc6, 1},
+ {0x2dc8, 0x2dce, 1},
+ {0x2dd0, 0x2dd6, 1},
+ {0x2dd8, 0x2dde, 1},
+ {0x3006, 0x303c, 54},
+ {0x3041, 0x3096, 1},
+ {0x309f, 0x30a1, 2},
+ {0x30a2, 0x30fa, 1},
+ {0x30ff, 0x3105, 6},
+ {0x3106, 0x312d, 1},
+ {0x3131, 0x318e, 1},
+ {0x31a0, 0x31b7, 1},
+ {0x31f0, 0x31ff, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xa000, 0xa014, 1},
+ {0xa016, 0xa48c, 1},
+ {0xa4d0, 0xa4f7, 1},
+ {0xa500, 0xa60b, 1},
+ {0xa610, 0xa61f, 1},
+ {0xa62a, 0xa62b, 1},
+ {0xa66e, 0xa6a0, 50},
+ {0xa6a1, 0xa6e5, 1},
+ {0xa7fb, 0xa801, 1},
+ {0xa803, 0xa805, 1},
+ {0xa807, 0xa80a, 1},
+ {0xa80c, 0xa822, 1},
+ {0xa840, 0xa873, 1},
+ {0xa882, 0xa8b3, 1},
+ {0xa8f2, 0xa8f7, 1},
+ {0xa8fb, 0xa90a, 15},
+ {0xa90b, 0xa925, 1},
+ {0xa930, 0xa946, 1},
+ {0xa960, 0xa97c, 1},
+ {0xa984, 0xa9b2, 1},
+ {0xaa00, 0xaa28, 1},
+ {0xaa40, 0xaa42, 1},
+ {0xaa44, 0xaa4b, 1},
+ {0xaa60, 0xaa6f, 1},
+ {0xaa71, 0xaa76, 1},
+ {0xaa7a, 0xaa80, 6},
+ {0xaa81, 0xaaaf, 1},
+ {0xaab1, 0xaab5, 4},
+ {0xaab6, 0xaab9, 3},
+ {0xaaba, 0xaabd, 1},
+ {0xaac0, 0xaac2, 2},
+ {0xaadb, 0xaadc, 1},
+ {0xabc0, 0xabe2, 1},
+ {0xac00, 0xd7a3, 1},
+ {0xd7b0, 0xd7c6, 1},
+ {0xd7cb, 0xd7fb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
+ {0xfb1d, 0xfb1f, 2},
+ {0xfb20, 0xfb28, 1},
+ {0xfb2a, 0xfb36, 1},
+ {0xfb38, 0xfb3c, 1},
+ {0xfb3e, 0xfb40, 2},
+ {0xfb41, 0xfb43, 2},
+ {0xfb44, 0xfb46, 2},
+ {0xfb47, 0xfbb1, 1},
+ {0xfbd3, 0xfd3d, 1},
+ {0xfd50, 0xfd8f, 1},
+ {0xfd92, 0xfdc7, 1},
+ {0xfdf0, 0xfdfb, 1},
+ {0xfe70, 0xfe74, 1},
+ {0xfe76, 0xfefc, 1},
+ {0xff66, 0xff6f, 1},
+ {0xff71, 0xff9d, 1},
+ {0xffa0, 0xffbe, 1},
+ {0xffc2, 0xffc7, 1},
+ {0xffca, 0xffcf, 1},
+ {0xffd2, 0xffd7, 1},
+ {0xffda, 0xffdc, 1},
+ {0x10000, 0x1000b, 1},
+ {0x1000d, 0x10026, 1},
+ {0x10028, 0x1003a, 1},
+ {0x1003c, 0x1003d, 1},
+ {0x1003f, 0x1004d, 1},
+ {0x10050, 0x1005d, 1},
+ {0x10080, 0x100fa, 1},
+ {0x10280, 0x1029c, 1},
+ {0x102a0, 0x102d0, 1},
+ {0x10300, 0x1031e, 1},
+ {0x10330, 0x10340, 1},
+ {0x10342, 0x10349, 1},
+ {0x10380, 0x1039d, 1},
+ {0x103a0, 0x103c3, 1},
+ {0x103c8, 0x103cf, 1},
+ {0x10450, 0x1049d, 1},
+ {0x10800, 0x10805, 1},
+ {0x10808, 0x1080a, 2},
+ {0x1080b, 0x10835, 1},
+ {0x10837, 0x10838, 1},
+ {0x1083c, 0x1083f, 3},
+ {0x10840, 0x10855, 1},
+ {0x10900, 0x10915, 1},
+ {0x10920, 0x10939, 1},
+ {0x10a00, 0x10a10, 16},
+ {0x10a11, 0x10a13, 1},
+ {0x10a15, 0x10a17, 1},
+ {0x10a19, 0x10a33, 1},
+ {0x10a60, 0x10a7c, 1},
+ {0x10b00, 0x10b35, 1},
+ {0x10b40, 0x10b55, 1},
+ {0x10b60, 0x10b72, 1},
+ {0x10c00, 0x10c48, 1},
+ {0x11083, 0x110af, 1},
+ {0x12000, 0x1236e, 1},
+ {0x13000, 0x1342e, 1},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2f800, 0x2fa1d, 1},
+}
+
+var (
+ Cc = _Cc // Cc is the set of Unicode characters in category Cc.
+ Cf = _Cf // Cf is the set of Unicode characters in category Cf.
+ Co = _Co // Co is the set of Unicode characters in category Co.
+ Cs = _Cs // Cs is the set of Unicode characters in category Cs.
+ Digit = _Nd // Digit is the set of Unicode characters with the "decimal digit" property.
+ Nd = _Nd // Nd is the set of Unicode characters in category Nd.
+ Letter = letter // Letter is the set of Unicode letters.
+ Lm = _Lm // Lm is the set of Unicode characters in category Lm.
+ Lo = _Lo // Lo is the set of Unicode characters in category Lo.
+ Lower = _Ll // Lower is the set of Unicode lower case letters.
+ Ll = _Ll // Ll is the set of Unicode characters in category Ll.
+ Mc = _Mc // Mc is the set of Unicode characters in category Mc.
+ Me = _Me // Me is the set of Unicode characters in category Me.
+ Mn = _Mn // Mn is the set of Unicode characters in category Mn.
+ Nl = _Nl // Nl is the set of Unicode characters in category Nl.
+ No = _No // No is the set of Unicode characters in category No.
+ Pc = _Pc // Pc is the set of Unicode characters in category Pc.
+ Pd = _Pd // Pd is the set of Unicode characters in category Pd.
+ Pe = _Pe // Pe is the set of Unicode characters in category Pe.
+ Pf = _Pf // Pf is the set of Unicode characters in category Pf.
+ Pi = _Pi // Pi is the set of Unicode characters in category Pi.
+ Po = _Po // Po is the set of Unicode characters in category Po.
+ Ps = _Ps // Ps is the set of Unicode characters in category Ps.
+ Sc = _Sc // Sc is the set of Unicode characters in category Sc.
+ Sk = _Sk // Sk is the set of Unicode characters in category Sk.
+ Sm = _Sm // Sm is the set of Unicode characters in category Sm.
+ So = _So // So is the set of Unicode characters in category So.
+ Title = _Lt // Title is the set of Unicode title case letters.
+ Lt = _Lt // Lt is the set of Unicode characters in category Lt.
+ Upper = _Lu // Upper is the set of Unicode upper case letters.
+ Lu = _Lu // Lu is the set of Unicode characters in category Lu.
+ Zl = _Zl // Zl is the set of Unicode characters in category Zl.
+ Zp = _Zp // Zp is the set of Unicode characters in category Zp.
+ Zs = _Zs // Zs is the set of Unicode characters in category Zs.
+)
+
+// Generated by running
+// maketables --scripts=all --url=http://www.unicode.org/Public/5.2.0/ucd/
+// DO NOT EDIT
+
+// Scripts is the set of Unicode script tables.
+var Scripts = map[string][]Range{
+ "Katakana": Katakana,
+ "Malayalam": Malayalam,
+ "Phags_Pa": Phags_Pa,
+ "Inscriptional_Parthian": Inscriptional_Parthian,
+ "Latin": Latin,
+ "Inscriptional_Pahlavi": Inscriptional_Pahlavi,
+ "Osmanya": Osmanya,
+ "Khmer": Khmer,
+ "Inherited": Inherited,
+ "Telugu": Telugu,
+ "Samaritan": Samaritan,
+ "Bopomofo": Bopomofo,
+ "Imperial_Aramaic": Imperial_Aramaic,
+ "Kaithi": Kaithi,
+ "Old_South_Arabian": Old_South_Arabian,
+ "Kayah_Li": Kayah_Li,
+ "New_Tai_Lue": New_Tai_Lue,
+ "Tai_Le": Tai_Le,
+ "Kharoshthi": Kharoshthi,
+ "Common": Common,
+ "Kannada": Kannada,
+ "Old_Turkic": Old_Turkic,
+ "Tamil": Tamil,
+ "Tagalog": Tagalog,
+ "Arabic": Arabic,
+ "Tagbanwa": Tagbanwa,
+ "Canadian_Aboriginal": Canadian_Aboriginal,
+ "Tibetan": Tibetan,
+ "Coptic": Coptic,
+ "Hiragana": Hiragana,
+ "Limbu": Limbu,
+ "Egyptian_Hieroglyphs": Egyptian_Hieroglyphs,
+ "Avestan": Avestan,
+ "Myanmar": Myanmar,
+ "Armenian": Armenian,
+ "Sinhala": Sinhala,
+ "Bengali": Bengali,
+ "Greek": Greek,
+ "Cham": Cham,
+ "Hebrew": Hebrew,
+ "Meetei_Mayek": Meetei_Mayek,
+ "Saurashtra": Saurashtra,
+ "Hangul": Hangul,
+ "Runic": Runic,
+ "Deseret": Deseret,
+ "Lisu": Lisu,
+ "Sundanese": Sundanese,
+ "Glagolitic": Glagolitic,
+ "Oriya": Oriya,
+ "Buhid": Buhid,
+ "Ethiopic": Ethiopic,
+ "Javanese": Javanese,
+ "Syloti_Nagri": Syloti_Nagri,
+ "Vai": Vai,
+ "Cherokee": Cherokee,
+ "Ogham": Ogham,
+ "Syriac": Syriac,
+ "Gurmukhi": Gurmukhi,
+ "Tai_Tham": Tai_Tham,
+ "Ol_Chiki": Ol_Chiki,
+ "Mongolian": Mongolian,
+ "Hanunoo": Hanunoo,
+ "Cypriot": Cypriot,
+ "Buginese": Buginese,
+ "Bamum": Bamum,
+ "Lepcha": Lepcha,
+ "Thaana": Thaana,
+ "Old_Persian": Old_Persian,
+ "Cuneiform": Cuneiform,
+ "Rejang": Rejang,
+ "Georgian": Georgian,
+ "Shavian": Shavian,
+ "Lycian": Lycian,
+ "Nko": Nko,
+ "Yi": Yi,
+ "Lao": Lao,
+ "Linear_B": Linear_B,
+ "Old_Italic": Old_Italic,
+ "Tai_Viet": Tai_Viet,
+ "Devanagari": Devanagari,
+ "Lydian": Lydian,
+ "Tifinagh": Tifinagh,
+ "Ugaritic": Ugaritic,
+ "Thai": Thai,
+ "Cyrillic": Cyrillic,
+ "Gujarati": Gujarati,
+ "Carian": Carian,
+ "Phoenician": Phoenician,
+ "Balinese": Balinese,
+ "Braille": Braille,
+ "Han": Han,
+ "Gothic": Gothic,
+}
+
+var _Katakana = []Range{
+ {0x30a1, 0x30fa, 1},
+ {0x30fd, 0x30ff, 1},
+ {0x31f0, 0x31ff, 1},
+ {0x32d0, 0x32fe, 1},
+ {0x3300, 0x3357, 1},
+ {0xff66, 0xff6f, 1},
+ {0xff71, 0xff9d, 1},
+}
+
+var _Malayalam = []Range{
+ {0x0d02, 0x0d03, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d28, 1},
+ {0x0d2a, 0x0d39, 1},
+ {0x0d3d, 0x0d44, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4d, 1},
+ {0x0d57, 0x0d57, 1},
+ {0x0d60, 0x0d63, 1},
+ {0x0d66, 0x0d75, 1},
+ {0x0d79, 0x0d7f, 1},
+}
+
+var _Phags_Pa = []Range{
+ {0xa840, 0xa877, 1},
+}
+
+var _Inscriptional_Parthian = []Range{
+ {0x10b40, 0x10b55, 1},
+ {0x10b58, 0x10b5f, 1},
+}
+
+var _Latin = []Range{
+ {0x0041, 0x005a, 1},
+ {0x0061, 0x007a, 1},
+ {0x00aa, 0x00aa, 1},
+ {0x00ba, 0x00ba, 1},
+ {0x00c0, 0x00d6, 1},
+ {0x00d8, 0x00f6, 1},
+ {0x00f8, 0x02b8, 1},
+ {0x02e0, 0x02e4, 1},
+ {0x1d00, 0x1d25, 1},
+ {0x1d2c, 0x1d5c, 1},
+ {0x1d62, 0x1d65, 1},
+ {0x1d6b, 0x1d77, 1},
+ {0x1d79, 0x1dbe, 1},
+ {0x1e00, 0x1eff, 1},
+ {0x2071, 0x2071, 1},
+ {0x207f, 0x207f, 1},
+ {0x2090, 0x2094, 1},
+ {0x212a, 0x212b, 1},
+ {0x2132, 0x2132, 1},
+ {0x214e, 0x214e, 1},
+ {0x2160, 0x2188, 1},
+ {0x2c60, 0x2c7f, 1},
+ {0xa722, 0xa787, 1},
+ {0xa78b, 0xa78c, 1},
+ {0xa7fb, 0xa7ff, 1},
+ {0xfb00, 0xfb06, 1},
+ {0xff21, 0xff3a, 1},
+ {0xff41, 0xff5a, 1},
+}
+
+var _Inscriptional_Pahlavi = []Range{
+ {0x10b60, 0x10b72, 1},
+ {0x10b78, 0x10b7f, 1},
+}
+
+var _Osmanya = []Range{
+ {0x10480, 0x1049d, 1},
+ {0x104a0, 0x104a9, 1},
+}
+
+var _Khmer = []Range{
+ {0x1780, 0x17dd, 1},
+ {0x17e0, 0x17e9, 1},
+ {0x17f0, 0x17f9, 1},
+ {0x19e0, 0x19ff, 1},
+}
+
+var _Inherited = []Range{
+ {0x0300, 0x036f, 1},
+ {0x0485, 0x0486, 1},
+ {0x064b, 0x0655, 1},
+ {0x0670, 0x0670, 1},
+ {0x0951, 0x0952, 1},
+ {0x1cd0, 0x1cd2, 1},
+ {0x1cd4, 0x1ce0, 1},
+ {0x1ce2, 0x1ce8, 1},
+ {0x1ced, 0x1ced, 1},
+ {0x1dc0, 0x1de6, 1},
+ {0x1dfd, 0x1dff, 1},
+ {0x200c, 0x200d, 1},
+ {0x20d0, 0x20f0, 1},
+ {0x302a, 0x302f, 1},
+ {0x3099, 0x309a, 1},
+ {0xfe00, 0xfe0f, 1},
+ {0xfe20, 0xfe26, 1},
+ {0x101fd, 0x101fd, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ {0xe0100, 0xe01ef, 1},
+}
+
+var _Telugu = []Range{
+ {0x0c01, 0x0c03, 1},
+ {0x0c05, 0x0c0c, 1},
+ {0x0c0e, 0x0c10, 1},
+ {0x0c12, 0x0c28, 1},
+ {0x0c2a, 0x0c33, 1},
+ {0x0c35, 0x0c39, 1},
+ {0x0c3d, 0x0c44, 1},
+ {0x0c46, 0x0c48, 1},
+ {0x0c4a, 0x0c4d, 1},
+ {0x0c55, 0x0c56, 1},
+ {0x0c58, 0x0c59, 1},
+ {0x0c60, 0x0c63, 1},
+ {0x0c66, 0x0c6f, 1},
+ {0x0c78, 0x0c7f, 1},
+}
+
+var _Samaritan = []Range{
+ {0x0800, 0x082d, 1},
+ {0x0830, 0x083e, 1},
+}
+
+var _Bopomofo = []Range{
+ {0x3105, 0x312d, 1},
+ {0x31a0, 0x31b7, 1},
+}
+
+var _Imperial_Aramaic = []Range{
+ {0x10840, 0x10855, 1},
+ {0x10857, 0x1085f, 1},
+}
+
+var _Kaithi = []Range{
+ {0x11080, 0x110c1, 1},
+}
+
+var _Old_South_Arabian = []Range{
+ {0x10a60, 0x10a7f, 1},
+}
+
+var _Kayah_Li = []Range{
+ {0xa900, 0xa92f, 1},
+}
+
+var _New_Tai_Lue = []Range{
+ {0x1980, 0x19ab, 1},
+ {0x19b0, 0x19c9, 1},
+ {0x19d0, 0x19da, 1},
+ {0x19de, 0x19df, 1},
+}
+
+var _Tai_Le = []Range{
+ {0x1950, 0x196d, 1},
+ {0x1970, 0x1974, 1},
+}
+
+var _Kharoshthi = []Range{
+ {0x10a00, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a13, 1},
+ {0x10a15, 0x10a17, 1},
+ {0x10a19, 0x10a33, 1},
+ {0x10a38, 0x10a3a, 1},
+ {0x10a3f, 0x10a47, 1},
+ {0x10a50, 0x10a58, 1},
+}
+
+var _Common = []Range{
+ {0x0000, 0x0040, 1},
+ {0x005b, 0x0060, 1},
+ {0x007b, 0x00a9, 1},
+ {0x00ab, 0x00b9, 1},
+ {0x00bb, 0x00bf, 1},
+ {0x00d7, 0x00d7, 1},
+ {0x00f7, 0x00f7, 1},
+ {0x02b9, 0x02df, 1},
+ {0x02e5, 0x02ff, 1},
+ {0x0374, 0x0374, 1},
+ {0x037e, 0x037e, 1},
+ {0x0385, 0x0385, 1},
+ {0x0387, 0x0387, 1},
+ {0x0589, 0x0589, 1},
+ {0x0600, 0x0603, 1},
+ {0x060c, 0x060c, 1},
+ {0x061b, 0x061b, 1},
+ {0x061f, 0x061f, 1},
+ {0x0640, 0x0640, 1},
+ {0x0660, 0x0669, 1},
+ {0x06dd, 0x06dd, 1},
+ {0x0964, 0x0965, 1},
+ {0x0970, 0x0970, 1},
+ {0x0cf1, 0x0cf2, 1},
+ {0x0e3f, 0x0e3f, 1},
+ {0x0fd5, 0x0fd8, 1},
+ {0x10fb, 0x10fb, 1},
+ {0x16eb, 0x16ed, 1},
+ {0x1735, 0x1736, 1},
+ {0x1802, 0x1803, 1},
+ {0x1805, 0x1805, 1},
+ {0x1cd3, 0x1cd3, 1},
+ {0x1ce1, 0x1ce1, 1},
+ {0x1ce9, 0x1cec, 1},
+ {0x1cee, 0x1cf2, 1},
+ {0x2000, 0x200b, 1},
+ {0x200e, 0x2064, 1},
+ {0x206a, 0x2070, 1},
+ {0x2074, 0x207e, 1},
+ {0x2080, 0x208e, 1},
+ {0x20a0, 0x20b8, 1},
+ {0x2100, 0x2125, 1},
+ {0x2127, 0x2129, 1},
+ {0x212c, 0x2131, 1},
+ {0x2133, 0x214d, 1},
+ {0x214f, 0x215f, 1},
+ {0x2189, 0x2189, 1},
+ {0x2190, 0x23e8, 1},
+ {0x2400, 0x2426, 1},
+ {0x2440, 0x244a, 1},
+ {0x2460, 0x26cd, 1},
+ {0x26cf, 0x26e1, 1},
+ {0x26e3, 0x26e3, 1},
+ {0x26e8, 0x26ff, 1},
+ {0x2701, 0x2704, 1},
+ {0x2706, 0x2709, 1},
+ {0x270c, 0x2727, 1},
+ {0x2729, 0x274b, 1},
+ {0x274d, 0x274d, 1},
+ {0x274f, 0x2752, 1},
+ {0x2756, 0x275e, 1},
+ {0x2761, 0x2794, 1},
+ {0x2798, 0x27af, 1},
+ {0x27b1, 0x27be, 1},
+ {0x27c0, 0x27ca, 1},
+ {0x27cc, 0x27cc, 1},
+ {0x27d0, 0x27ff, 1},
+ {0x2900, 0x2b4c, 1},
+ {0x2b50, 0x2b59, 1},
+ {0x2e00, 0x2e31, 1},
+ {0x2ff0, 0x2ffb, 1},
+ {0x3000, 0x3004, 1},
+ {0x3006, 0x3006, 1},
+ {0x3008, 0x3020, 1},
+ {0x3030, 0x3037, 1},
+ {0x303c, 0x303f, 1},
+ {0x309b, 0x309c, 1},
+ {0x30a0, 0x30a0, 1},
+ {0x30fb, 0x30fc, 1},
+ {0x3190, 0x319f, 1},
+ {0x31c0, 0x31e3, 1},
+ {0x3220, 0x325f, 1},
+ {0x327f, 0x32cf, 1},
+ {0x3358, 0x33ff, 1},
+ {0x4dc0, 0x4dff, 1},
+ {0xa700, 0xa721, 1},
+ {0xa788, 0xa78a, 1},
+ {0xa830, 0xa839, 1},
+ {0xfd3e, 0xfd3f, 1},
+ {0xfdfd, 0xfdfd, 1},
+ {0xfe10, 0xfe19, 1},
+ {0xfe30, 0xfe52, 1},
+ {0xfe54, 0xfe66, 1},
+ {0xfe68, 0xfe6b, 1},
+ {0xfeff, 0xfeff, 1},
+ {0xff01, 0xff20, 1},
+ {0xff3b, 0xff40, 1},
+ {0xff5b, 0xff65, 1},
+ {0xff70, 0xff70, 1},
+ {0xff9e, 0xff9f, 1},
+ {0xffe0, 0xffe6, 1},
+ {0xffe8, 0xffee, 1},
+ {0xfff9, 0xfffd, 1},
+ {0x10100, 0x10102, 1},
+ {0x10107, 0x10133, 1},
+ {0x10137, 0x1013f, 1},
+ {0x10190, 0x1019b, 1},
+ {0x101d0, 0x101fc, 1},
+ {0x1d000, 0x1d0f5, 1},
+ {0x1d100, 0x1d126, 1},
+ {0x1d129, 0x1d166, 1},
+ {0x1d16a, 0x1d17a, 1},
+ {0x1d183, 0x1d184, 1},
+ {0x1d18c, 0x1d1a9, 1},
+ {0x1d1ae, 0x1d1dd, 1},
+ {0x1d300, 0x1d356, 1},
+ {0x1d360, 0x1d371, 1},
+ {0x1d400, 0x1d454, 1},
+ {0x1d456, 0x1d49c, 1},
+ {0x1d49e, 0x1d49f, 1},
+ {0x1d4a2, 0x1d4a2, 1},
+ {0x1d4a5, 0x1d4a6, 1},
+ {0x1d4a9, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bb, 1},
+ {0x1d4bd, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d51e, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d546, 1},
+ {0x1d54a, 0x1d550, 1},
+ {0x1d552, 0x1d6a5, 1},
+ {0x1d6a8, 0x1d7cb, 1},
+ {0x1d7ce, 0x1d7ff, 1},
+ {0x1f000, 0x1f02b, 1},
+ {0x1f030, 0x1f093, 1},
+ {0x1f100, 0x1f10a, 1},
+ {0x1f110, 0x1f12e, 1},
+ {0x1f131, 0x1f131, 1},
+ {0x1f13d, 0x1f13d, 1},
+ {0x1f13f, 0x1f13f, 1},
+ {0x1f142, 0x1f142, 1},
+ {0x1f146, 0x1f146, 1},
+ {0x1f14a, 0x1f14e, 1},
+ {0x1f157, 0x1f157, 1},
+ {0x1f15f, 0x1f15f, 1},
+ {0x1f179, 0x1f179, 1},
+ {0x1f17b, 0x1f17c, 1},
+ {0x1f17f, 0x1f17f, 1},
+ {0x1f18a, 0x1f18d, 1},
+ {0x1f190, 0x1f190, 1},
+ {0x1f210, 0x1f231, 1},
+ {0x1f240, 0x1f248, 1},
+ {0xe0001, 0xe0001, 1},
+ {0xe0020, 0xe007f, 1},
+}
+
+var _Kannada = []Range{
+ {0x0c82, 0x0c83, 1},
+ {0x0c85, 0x0c8c, 1},
+ {0x0c8e, 0x0c90, 1},
+ {0x0c92, 0x0ca8, 1},
+ {0x0caa, 0x0cb3, 1},
+ {0x0cb5, 0x0cb9, 1},
+ {0x0cbc, 0x0cc4, 1},
+ {0x0cc6, 0x0cc8, 1},
+ {0x0cca, 0x0ccd, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0cde, 0x0cde, 1},
+ {0x0ce0, 0x0ce3, 1},
+ {0x0ce6, 0x0cef, 1},
+}
+
+var _Old_Turkic = []Range{
+ {0x10c00, 0x10c48, 1},
+}
+
+var _Tamil = []Range{
+ {0x0b82, 0x0b83, 1},
+ {0x0b85, 0x0b8a, 1},
+ {0x0b8e, 0x0b90, 1},
+ {0x0b92, 0x0b95, 1},
+ {0x0b99, 0x0b9a, 1},
+ {0x0b9c, 0x0b9c, 1},
+ {0x0b9e, 0x0b9f, 1},
+ {0x0ba3, 0x0ba4, 1},
+ {0x0ba8, 0x0baa, 1},
+ {0x0bae, 0x0bb9, 1},
+ {0x0bbe, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcd, 1},
+ {0x0bd0, 0x0bd0, 1},
+ {0x0bd7, 0x0bd7, 1},
+ {0x0be6, 0x0bfa, 1},
+}
+
+var _Tagalog = []Range{
+ {0x1700, 0x170c, 1},
+ {0x170e, 0x1714, 1},
+}
+
+var _Arabic = []Range{
+ {0x0606, 0x060b, 1},
+ {0x060d, 0x061a, 1},
+ {0x061e, 0x061e, 1},
+ {0x0621, 0x063f, 1},
+ {0x0641, 0x064a, 1},
+ {0x0656, 0x065e, 1},
+ {0x066a, 0x066f, 1},
+ {0x0671, 0x06dc, 1},
+ {0x06de, 0x06ff, 1},
+ {0x0750, 0x077f, 1},
+ {0xfb50, 0xfbb1, 1},
+ {0xfbd3, 0xfd3d, 1},
+ {0xfd50, 0xfd8f, 1},
+ {0xfd92, 0xfdc7, 1},
+ {0xfdf0, 0xfdfc, 1},
+ {0xfe70, 0xfe74, 1},
+ {0xfe76, 0xfefc, 1},
+ {0x10e60, 0x10e7e, 1},
+}
+
+var _Tagbanwa = []Range{
+ {0x1760, 0x176c, 1},
+ {0x176e, 0x1770, 1},
+ {0x1772, 0x1773, 1},
+}
+
+var _Canadian_Aboriginal = []Range{
+ {0x1400, 0x167f, 1},
+ {0x18b0, 0x18f5, 1},
+}
+
+var _Tibetan = []Range{
+ {0x0f00, 0x0f47, 1},
+ {0x0f49, 0x0f6c, 1},
+ {0x0f71, 0x0f8b, 1},
+ {0x0f90, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x0fbe, 0x0fcc, 1},
+ {0x0fce, 0x0fd4, 1},
+}
+
+var _Coptic = []Range{
+ {0x03e2, 0x03ef, 1},
+ {0x2c80, 0x2cf1, 1},
+ {0x2cf9, 0x2cff, 1},
+}
+
+var _Hiragana = []Range{
+ {0x3041, 0x3096, 1},
+ {0x309d, 0x309f, 1},
+ {0x1f200, 0x1f200, 1},
+}
+
+var _Limbu = []Range{
+ {0x1900, 0x191c, 1},
+ {0x1920, 0x192b, 1},
+ {0x1930, 0x193b, 1},
+ {0x1940, 0x1940, 1},
+ {0x1944, 0x194f, 1},
+}
+
+var _Egyptian_Hieroglyphs = []Range{
+ {0x13000, 0x1342e, 1},
+}
+
+var _Avestan = []Range{
+ {0x10b00, 0x10b35, 1},
+ {0x10b39, 0x10b3f, 1},
+}
+
+var _Myanmar = []Range{
+ {0x1000, 0x109f, 1},
+ {0xaa60, 0xaa7b, 1},
+}
+
+var _Armenian = []Range{
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x055f, 1},
+ {0x0561, 0x0587, 1},
+ {0x058a, 0x058a, 1},
+ {0xfb13, 0xfb17, 1},
+}
+
+var _Sinhala = []Range{
+ {0x0d82, 0x0d83, 1},
+ {0x0d85, 0x0d96, 1},
+ {0x0d9a, 0x0db1, 1},
+ {0x0db3, 0x0dbb, 1},
+ {0x0dbd, 0x0dbd, 1},
+ {0x0dc0, 0x0dc6, 1},
+ {0x0dca, 0x0dca, 1},
+ {0x0dcf, 0x0dd4, 1},
+ {0x0dd6, 0x0dd6, 1},
+ {0x0dd8, 0x0ddf, 1},
+ {0x0df2, 0x0df4, 1},
+}
+
+var _Bengali = []Range{
+ {0x0981, 0x0983, 1},
+ {0x0985, 0x098c, 1},
+ {0x098f, 0x0990, 1},
+ {0x0993, 0x09a8, 1},
+ {0x09aa, 0x09b0, 1},
+ {0x09b2, 0x09b2, 1},
+ {0x09b6, 0x09b9, 1},
+ {0x09bc, 0x09c4, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09ce, 1},
+ {0x09d7, 0x09d7, 1},
+ {0x09dc, 0x09dd, 1},
+ {0x09df, 0x09e3, 1},
+ {0x09e6, 0x09fb, 1},
+}
+
+var _Greek = []Range{
+ {0x0370, 0x0373, 1},
+ {0x0375, 0x0377, 1},
+ {0x037a, 0x037d, 1},
+ {0x0384, 0x0384, 1},
+ {0x0386, 0x0386, 1},
+ {0x0388, 0x038a, 1},
+ {0x038c, 0x038c, 1},
+ {0x038e, 0x03a1, 1},
+ {0x03a3, 0x03e1, 1},
+ {0x03f0, 0x03ff, 1},
+ {0x1d26, 0x1d2a, 1},
+ {0x1d5d, 0x1d61, 1},
+ {0x1d66, 0x1d6a, 1},
+ {0x1dbf, 0x1dbf, 1},
+ {0x1f00, 0x1f15, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f20, 0x1f45, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f50, 0x1f57, 1},
+ {0x1f59, 0x1f59, 1},
+ {0x1f5b, 0x1f5b, 1},
+ {0x1f5d, 0x1f5d, 1},
+ {0x1f5f, 0x1f7d, 1},
+ {0x1f80, 0x1fb4, 1},
+ {0x1fb6, 0x1fc4, 1},
+ {0x1fc6, 0x1fd3, 1},
+ {0x1fd6, 0x1fdb, 1},
+ {0x1fdd, 0x1fef, 1},
+ {0x1ff2, 0x1ff4, 1},
+ {0x1ff6, 0x1ffe, 1},
+ {0x2126, 0x2126, 1},
+ {0x10140, 0x1018a, 1},
+ {0x1d200, 0x1d245, 1},
+}
+
+var _Cham = []Range{
+ {0xaa00, 0xaa36, 1},
+ {0xaa40, 0xaa4d, 1},
+ {0xaa50, 0xaa59, 1},
+ {0xaa5c, 0xaa5f, 1},
+}
+
+var _Hebrew = []Range{
+ {0x0591, 0x05c7, 1},
+ {0x05d0, 0x05ea, 1},
+ {0x05f0, 0x05f4, 1},
+ {0xfb1d, 0xfb36, 1},
+ {0xfb38, 0xfb3c, 1},
+ {0xfb3e, 0xfb3e, 1},
+ {0xfb40, 0xfb41, 1},
+ {0xfb43, 0xfb44, 1},
+ {0xfb46, 0xfb4f, 1},
+}
+
+var _Meetei_Mayek = []Range{
+ {0xabc0, 0xabed, 1},
+ {0xabf0, 0xabf9, 1},
+}
+
+var _Saurashtra = []Range{
+ {0xa880, 0xa8c4, 1},
+ {0xa8ce, 0xa8d9, 1},
+}
+
+var _Hangul = []Range{
+ {0x1100, 0x11ff, 1},
+ {0x3131, 0x318e, 1},
+ {0x3200, 0x321e, 1},
+ {0x3260, 0x327e, 1},
+ {0xa960, 0xa97c, 1},
+ {0xac00, 0xd7a3, 1},
+ {0xd7b0, 0xd7c6, 1},
+ {0xd7cb, 0xd7fb, 1},
+ {0xffa0, 0xffbe, 1},
+ {0xffc2, 0xffc7, 1},
+ {0xffca, 0xffcf, 1},
+ {0xffd2, 0xffd7, 1},
+ {0xffda, 0xffdc, 1},
+}
+
+var _Runic = []Range{
+ {0x16a0, 0x16ea, 1},
+ {0x16ee, 0x16f0, 1},
+}
+
+var _Deseret = []Range{
+ {0x10400, 0x1044f, 1},
+}
+
+var _Lisu = []Range{
+ {0xa4d0, 0xa4ff, 1},
+}
+
+var _Sundanese = []Range{
+ {0x1b80, 0x1baa, 1},
+ {0x1bae, 0x1bb9, 1},
+}
+
+var _Glagolitic = []Range{
+ {0x2c00, 0x2c2e, 1},
+ {0x2c30, 0x2c5e, 1},
+}
+
+var _Oriya = []Range{
+ {0x0b01, 0x0b03, 1},
+ {0x0b05, 0x0b0c, 1},
+ {0x0b0f, 0x0b10, 1},
+ {0x0b13, 0x0b28, 1},
+ {0x0b2a, 0x0b30, 1},
+ {0x0b32, 0x0b33, 1},
+ {0x0b35, 0x0b39, 1},
+ {0x0b3c, 0x0b44, 1},
+ {0x0b47, 0x0b48, 1},
+ {0x0b4b, 0x0b4d, 1},
+ {0x0b56, 0x0b57, 1},
+ {0x0b5c, 0x0b5d, 1},
+ {0x0b5f, 0x0b63, 1},
+ {0x0b66, 0x0b71, 1},
+}
+
+var _Buhid = []Range{
+ {0x1740, 0x1753, 1},
+}
+
+var _Ethiopic = []Range{
+ {0x1200, 0x1248, 1},
+ {0x124a, 0x124d, 1},
+ {0x1250, 0x1256, 1},
+ {0x1258, 0x1258, 1},
+ {0x125a, 0x125d, 1},
+ {0x1260, 0x1288, 1},
+ {0x128a, 0x128d, 1},
+ {0x1290, 0x12b0, 1},
+ {0x12b2, 0x12b5, 1},
+ {0x12b8, 0x12be, 1},
+ {0x12c0, 0x12c0, 1},
+ {0x12c2, 0x12c5, 1},
+ {0x12c8, 0x12d6, 1},
+ {0x12d8, 0x1310, 1},
+ {0x1312, 0x1315, 1},
+ {0x1318, 0x135a, 1},
+ {0x135f, 0x137c, 1},
+ {0x1380, 0x1399, 1},
+ {0x2d80, 0x2d96, 1},
+ {0x2da0, 0x2da6, 1},
+ {0x2da8, 0x2dae, 1},
+ {0x2db0, 0x2db6, 1},
+ {0x2db8, 0x2dbe, 1},
+ {0x2dc0, 0x2dc6, 1},
+ {0x2dc8, 0x2dce, 1},
+ {0x2dd0, 0x2dd6, 1},
+ {0x2dd8, 0x2dde, 1},
+}
+
+var _Javanese = []Range{
+ {0xa980, 0xa9cd, 1},
+ {0xa9cf, 0xa9d9, 1},
+ {0xa9de, 0xa9df, 1},
+}
+
+var _Syloti_Nagri = []Range{
+ {0xa800, 0xa82b, 1},
+}
+
+var _Vai = []Range{
+ {0xa500, 0xa62b, 1},
+}
+
+var _Cherokee = []Range{
+ {0x13a0, 0x13f4, 1},
+}
+
+var _Ogham = []Range{
+ {0x1680, 0x169c, 1},
+}
+
+var _Syriac = []Range{
+ {0x0700, 0x070d, 1},
+ {0x070f, 0x074a, 1},
+ {0x074d, 0x074f, 1},
+}
+
+var _Gurmukhi = []Range{
+ {0x0a01, 0x0a03, 1},
+ {0x0a05, 0x0a0a, 1},
+ {0x0a0f, 0x0a10, 1},
+ {0x0a13, 0x0a28, 1},
+ {0x0a2a, 0x0a30, 1},
+ {0x0a32, 0x0a33, 1},
+ {0x0a35, 0x0a36, 1},
+ {0x0a38, 0x0a39, 1},
+ {0x0a3c, 0x0a3c, 1},
+ {0x0a3e, 0x0a42, 1},
+ {0x0a47, 0x0a48, 1},
+ {0x0a4b, 0x0a4d, 1},
+ {0x0a51, 0x0a51, 1},
+ {0x0a59, 0x0a5c, 1},
+ {0x0a5e, 0x0a5e, 1},
+ {0x0a66, 0x0a75, 1},
+}
+
+var _Tai_Tham = []Range{
+ {0x1a20, 0x1a5e, 1},
+ {0x1a60, 0x1a7c, 1},
+ {0x1a7f, 0x1a89, 1},
+ {0x1a90, 0x1a99, 1},
+ {0x1aa0, 0x1aad, 1},
+}
+
+var _Ol_Chiki = []Range{
+ {0x1c50, 0x1c7f, 1},
+}
+
+var _Mongolian = []Range{
+ {0x1800, 0x1801, 1},
+ {0x1804, 0x1804, 1},
+ {0x1806, 0x180e, 1},
+ {0x1810, 0x1819, 1},
+ {0x1820, 0x1877, 1},
+ {0x1880, 0x18aa, 1},
+}
+
+var _Hanunoo = []Range{
+ {0x1720, 0x1734, 1},
+}
+
+var _Cypriot = []Range{
+ {0x10800, 0x10805, 1},
+ {0x10808, 0x10808, 1},
+ {0x1080a, 0x10835, 1},
+ {0x10837, 0x10838, 1},
+ {0x1083c, 0x1083c, 1},
+ {0x1083f, 0x1083f, 1},
+}
+
+var _Buginese = []Range{
+ {0x1a00, 0x1a1b, 1},
+ {0x1a1e, 0x1a1f, 1},
+}
+
+var _Bamum = []Range{
+ {0xa6a0, 0xa6f7, 1},
+}
+
+var _Lepcha = []Range{
+ {0x1c00, 0x1c37, 1},
+ {0x1c3b, 0x1c49, 1},
+ {0x1c4d, 0x1c4f, 1},
+}
+
+var _Thaana = []Range{
+ {0x0780, 0x07b1, 1},
+}
+
+var _Old_Persian = []Range{
+ {0x103a0, 0x103c3, 1},
+ {0x103c8, 0x103d5, 1},
+}
+
+var _Cuneiform = []Range{
+ {0x12000, 0x1236e, 1},
+ {0x12400, 0x12462, 1},
+ {0x12470, 0x12473, 1},
+}
+
+var _Rejang = []Range{
+ {0xa930, 0xa953, 1},
+ {0xa95f, 0xa95f, 1},
+}
+
+var _Georgian = []Range{
+ {0x10a0, 0x10c5, 1},
+ {0x10d0, 0x10fa, 1},
+ {0x10fc, 0x10fc, 1},
+ {0x2d00, 0x2d25, 1},
+}
+
+var _Shavian = []Range{
+ {0x10450, 0x1047f, 1},
+}
+
+var _Lycian = []Range{
+ {0x10280, 0x1029c, 1},
+}
+
+var _Nko = []Range{
+ {0x07c0, 0x07fa, 1},
+}
+
+var _Yi = []Range{
+ {0xa000, 0xa48c, 1},
+ {0xa490, 0xa4c6, 1},
+}
+
+var _Lao = []Range{
+ {0x0e81, 0x0e82, 1},
+ {0x0e84, 0x0e84, 1},
+ {0x0e87, 0x0e88, 1},
+ {0x0e8a, 0x0e8a, 1},
+ {0x0e8d, 0x0e8d, 1},
+ {0x0e94, 0x0e97, 1},
+ {0x0e99, 0x0e9f, 1},
+ {0x0ea1, 0x0ea3, 1},
+ {0x0ea5, 0x0ea5, 1},
+ {0x0ea7, 0x0ea7, 1},
+ {0x0eaa, 0x0eab, 1},
+ {0x0ead, 0x0eb9, 1},
+ {0x0ebb, 0x0ebd, 1},
+ {0x0ec0, 0x0ec4, 1},
+ {0x0ec6, 0x0ec6, 1},
+ {0x0ec8, 0x0ecd, 1},
+ {0x0ed0, 0x0ed9, 1},
+ {0x0edc, 0x0edd, 1},
+}
+
+var _Linear_B = []Range{
+ {0x10000, 0x1000b, 1},
+ {0x1000d, 0x10026, 1},
+ {0x10028, 0x1003a, 1},
+ {0x1003c, 0x1003d, 1},
+ {0x1003f, 0x1004d, 1},
+ {0x10050, 0x1005d, 1},
+ {0x10080, 0x100fa, 1},
+}
+
+var _Old_Italic = []Range{
+ {0x10300, 0x1031e, 1},
+ {0x10320, 0x10323, 1},
+}
+
+var _Tai_Viet = []Range{
+ {0xaa80, 0xaac2, 1},
+ {0xaadb, 0xaadf, 1},
+}
+
+var _Devanagari = []Range{
+ {0x0900, 0x0939, 1},
+ {0x093c, 0x094e, 1},
+ {0x0950, 0x0950, 1},
+ {0x0953, 0x0955, 1},
+ {0x0958, 0x0963, 1},
+ {0x0966, 0x096f, 1},
+ {0x0971, 0x0972, 1},
+ {0x0979, 0x097f, 1},
+ {0xa8e0, 0xa8fb, 1},
+}
+
+var _Lydian = []Range{
+ {0x10920, 0x10939, 1},
+ {0x1093f, 0x1093f, 1},
+}
+
+var _Tifinagh = []Range{
+ {0x2d30, 0x2d65, 1},
+ {0x2d6f, 0x2d6f, 1},
+}
+
+var _Ugaritic = []Range{
+ {0x10380, 0x1039d, 1},
+ {0x1039f, 0x1039f, 1},
+}
+
+var _Thai = []Range{
+ {0x0e01, 0x0e3a, 1},
+ {0x0e40, 0x0e5b, 1},
+}
+
+var _Cyrillic = []Range{
+ {0x0400, 0x0484, 1},
+ {0x0487, 0x0525, 1},
+ {0x1d2b, 0x1d2b, 1},
+ {0x1d78, 0x1d78, 1},
+ {0x2de0, 0x2dff, 1},
+ {0xa640, 0xa65f, 1},
+ {0xa662, 0xa673, 1},
+ {0xa67c, 0xa697, 1},
+}
+
+var _Gujarati = []Range{
+ {0x0a81, 0x0a83, 1},
+ {0x0a85, 0x0a8d, 1},
+ {0x0a8f, 0x0a91, 1},
+ {0x0a93, 0x0aa8, 1},
+ {0x0aaa, 0x0ab0, 1},
+ {0x0ab2, 0x0ab3, 1},
+ {0x0ab5, 0x0ab9, 1},
+ {0x0abc, 0x0ac5, 1},
+ {0x0ac7, 0x0ac9, 1},
+ {0x0acb, 0x0acd, 1},
+ {0x0ad0, 0x0ad0, 1},
+ {0x0ae0, 0x0ae3, 1},
+ {0x0ae6, 0x0aef, 1},
+ {0x0af1, 0x0af1, 1},
+}
+
+var _Carian = []Range{
+ {0x102a0, 0x102d0, 1},
+}
+
+var _Phoenician = []Range{
+ {0x10900, 0x1091b, 1},
+ {0x1091f, 0x1091f, 1},
+}
+
+var _Balinese = []Range{
+ {0x1b00, 0x1b4b, 1},
+ {0x1b50, 0x1b7c, 1},
+}
+
+var _Braille = []Range{
+ {0x2800, 0x28ff, 1},
+}
+
+var _Han = []Range{
+ {0x2e80, 0x2e99, 1},
+ {0x2e9b, 0x2ef3, 1},
+ {0x2f00, 0x2fd5, 1},
+ {0x3005, 0x3005, 1},
+ {0x3007, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3038, 0x303b, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2f800, 0x2fa1d, 1},
+}
+
+var _Gothic = []Range{
+ {0x10330, 0x1034a, 1},
+}
+
+var (
+ Arabic = _Arabic // Arabic is the set of Unicode characters in script Arabic.
+ Armenian = _Armenian // Armenian is the set of Unicode characters in script Armenian.
+ Avestan = _Avestan // Avestan is the set of Unicode characters in script Avestan.
+ Balinese = _Balinese // Balinese is the set of Unicode characters in script Balinese.
+ Bamum = _Bamum // Bamum is the set of Unicode characters in script Bamum.
+ Bengali = _Bengali // Bengali is the set of Unicode characters in script Bengali.
+ Bopomofo = _Bopomofo // Bopomofo is the set of Unicode characters in script Bopomofo.
+ Braille = _Braille // Braille is the set of Unicode characters in script Braille.
+ Buginese = _Buginese // Buginese is the set of Unicode characters in script Buginese.
+ Buhid = _Buhid // Buhid is the set of Unicode characters in script Buhid.
+ Canadian_Aboriginal = _Canadian_Aboriginal // Canadian_Aboriginal is the set of Unicode characters in script Canadian_Aboriginal.
+ Carian = _Carian // Carian is the set of Unicode characters in script Carian.
+ Cham = _Cham // Cham is the set of Unicode characters in script Cham.
+ Cherokee = _Cherokee // Cherokee is the set of Unicode characters in script Cherokee.
+ Common = _Common // Common is the set of Unicode characters in script Common.
+ Coptic = _Coptic // Coptic is the set of Unicode characters in script Coptic.
+ Cuneiform = _Cuneiform // Cuneiform is the set of Unicode characters in script Cuneiform.
+ Cypriot = _Cypriot // Cypriot is the set of Unicode characters in script Cypriot.
+ Cyrillic = _Cyrillic // Cyrillic is the set of Unicode characters in script Cyrillic.
+ Deseret = _Deseret // Deseret is the set of Unicode characters in script Deseret.
+ Devanagari = _Devanagari // Devanagari is the set of Unicode characters in script Devanagari.
+ Egyptian_Hieroglyphs = _Egyptian_Hieroglyphs // Egyptian_Hieroglyphs is the set of Unicode characters in script Egyptian_Hieroglyphs.
+ Ethiopic = _Ethiopic // Ethiopic is the set of Unicode characters in script Ethiopic.
+ Georgian = _Georgian // Georgian is the set of Unicode characters in script Georgian.
+ Glagolitic = _Glagolitic // Glagolitic is the set of Unicode characters in script Glagolitic.
+ Gothic = _Gothic // Gothic is the set of Unicode characters in script Gothic.
+ Greek = _Greek // Greek is the set of Unicode characters in script Greek.
+ Gujarati = _Gujarati // Gujarati is the set of Unicode characters in script Gujarati.
+ Gurmukhi = _Gurmukhi // Gurmukhi is the set of Unicode characters in script Gurmukhi.
+ Han = _Han // Han is the set of Unicode characters in script Han.
+ Hangul = _Hangul // Hangul is the set of Unicode characters in script Hangul.
+ Hanunoo = _Hanunoo // Hanunoo is the set of Unicode characters in script Hanunoo.
+ Hebrew = _Hebrew // Hebrew is the set of Unicode characters in script Hebrew.
+ Hiragana = _Hiragana // Hiragana is the set of Unicode characters in script Hiragana.
+ Imperial_Aramaic = _Imperial_Aramaic // Imperial_Aramaic is the set of Unicode characters in script Imperial_Aramaic.
+ Inherited = _Inherited // Inherited is the set of Unicode characters in script Inherited.
+ Inscriptional_Pahlavi = _Inscriptional_Pahlavi // Inscriptional_Pahlavi is the set of Unicode characters in script Inscriptional_Pahlavi.
+ Inscriptional_Parthian = _Inscriptional_Parthian // Inscriptional_Parthian is the set of Unicode characters in script Inscriptional_Parthian.
+ Javanese = _Javanese // Javanese is the set of Unicode characters in script Javanese.
+ Kaithi = _Kaithi // Kaithi is the set of Unicode characters in script Kaithi.
+ Kannada = _Kannada // Kannada is the set of Unicode characters in script Kannada.
+ Katakana = _Katakana // Katakana is the set of Unicode characters in script Katakana.
+ Kayah_Li = _Kayah_Li // Kayah_Li is the set of Unicode characters in script Kayah_Li.
+ Kharoshthi = _Kharoshthi // Kharoshthi is the set of Unicode characters in script Kharoshthi.
+ Khmer = _Khmer // Khmer is the set of Unicode characters in script Khmer.
+ Lao = _Lao // Lao is the set of Unicode characters in script Lao.
+ Latin = _Latin // Latin is the set of Unicode characters in script Latin.
+ Lepcha = _Lepcha // Lepcha is the set of Unicode characters in script Lepcha.
+ Limbu = _Limbu // Limbu is the set of Unicode characters in script Limbu.
+ Linear_B = _Linear_B // Linear_B is the set of Unicode characters in script Linear_B.
+ Lisu = _Lisu // Lisu is the set of Unicode characters in script Lisu.
+ Lycian = _Lycian // Lycian is the set of Unicode characters in script Lycian.
+ Lydian = _Lydian // Lydian is the set of Unicode characters in script Lydian.
+ Malayalam = _Malayalam // Malayalam is the set of Unicode characters in script Malayalam.
+ Meetei_Mayek = _Meetei_Mayek // Meetei_Mayek is the set of Unicode characters in script Meetei_Mayek.
+ Mongolian = _Mongolian // Mongolian is the set of Unicode characters in script Mongolian.
+ Myanmar = _Myanmar // Myanmar is the set of Unicode characters in script Myanmar.
+ New_Tai_Lue = _New_Tai_Lue // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue.
+ Nko = _Nko // Nko is the set of Unicode characters in script Nko.
+ Ogham = _Ogham // Ogham is the set of Unicode characters in script Ogham.
+ Ol_Chiki = _Ol_Chiki // Ol_Chiki is the set of Unicode characters in script Ol_Chiki.
+ Old_Italic = _Old_Italic // Old_Italic is the set of Unicode characters in script Old_Italic.
+ Old_Persian = _Old_Persian // Old_Persian is the set of Unicode characters in script Old_Persian.
+ Old_South_Arabian = _Old_South_Arabian // Old_South_Arabian is the set of Unicode characters in script Old_South_Arabian.
+ Old_Turkic = _Old_Turkic // Old_Turkic is the set of Unicode characters in script Old_Turkic.
+ Oriya = _Oriya // Oriya is the set of Unicode characters in script Oriya.
+ Osmanya = _Osmanya // Osmanya is the set of Unicode characters in script Osmanya.
+ Phags_Pa = _Phags_Pa // Phags_Pa is the set of Unicode characters in script Phags_Pa.
+ Phoenician = _Phoenician // Phoenician is the set of Unicode characters in script Phoenician.
+ Rejang = _Rejang // Rejang is the set of Unicode characters in script Rejang.
+ Runic = _Runic // Runic is the set of Unicode characters in script Runic.
+ Samaritan = _Samaritan // Samaritan is the set of Unicode characters in script Samaritan.
+ Saurashtra = _Saurashtra // Saurashtra is the set of Unicode characters in script Saurashtra.
+ Shavian = _Shavian // Shavian is the set of Unicode characters in script Shavian.
+ Sinhala = _Sinhala // Sinhala is the set of Unicode characters in script Sinhala.
+ Sundanese = _Sundanese // Sundanese is the set of Unicode characters in script Sundanese.
+ Syloti_Nagri = _Syloti_Nagri // Syloti_Nagri is the set of Unicode characters in script Syloti_Nagri.
+ Syriac = _Syriac // Syriac is the set of Unicode characters in script Syriac.
+ Tagalog = _Tagalog // Tagalog is the set of Unicode characters in script Tagalog.
+ Tagbanwa = _Tagbanwa // Tagbanwa is the set of Unicode characters in script Tagbanwa.
+ Tai_Le = _Tai_Le // Tai_Le is the set of Unicode characters in script Tai_Le.
+ Tai_Tham = _Tai_Tham // Tai_Tham is the set of Unicode characters in script Tai_Tham.
+ Tai_Viet = _Tai_Viet // Tai_Viet is the set of Unicode characters in script Tai_Viet.
+ Tamil = _Tamil // Tamil is the set of Unicode characters in script Tamil.
+ Telugu = _Telugu // Telugu is the set of Unicode characters in script Telugu.
+ Thaana = _Thaana // Thaana is the set of Unicode characters in script Thaana.
+ Thai = _Thai // Thai is the set of Unicode characters in script Thai.
+ Tibetan = _Tibetan // Tibetan is the set of Unicode characters in script Tibetan.
+ Tifinagh = _Tifinagh // Tifinagh is the set of Unicode characters in script Tifinagh.
+ Ugaritic = _Ugaritic // Ugaritic is the set of Unicode characters in script Ugaritic.
+ Vai = _Vai // Vai is the set of Unicode characters in script Vai.
+ Yi = _Yi // Yi is the set of Unicode characters in script Yi.
+)
+
+// Generated by running
+// maketables --props=all --url=http://www.unicode.org/Public/5.2.0/ucd/
+// DO NOT EDIT
+
+// Properties is the set of Unicode property tables.
+var Properties = map[string][]Range{
+ "Pattern_Syntax": Pattern_Syntax,
+ "Other_ID_Start": Other_ID_Start,
+ "Pattern_White_Space": Pattern_White_Space,
+ "Other_Lowercase": Other_Lowercase,
+ "Soft_Dotted": Soft_Dotted,
+ "Hex_Digit": Hex_Digit,
+ "ASCII_Hex_Digit": ASCII_Hex_Digit,
+ "Deprecated": Deprecated,
+ "Terminal_Punctuation": Terminal_Punctuation,
+ "Quotation_Mark": Quotation_Mark,
+ "Other_ID_Continue": Other_ID_Continue,
+ "Bidi_Control": Bidi_Control,
+ "Variation_Selector": Variation_Selector,
+ "Noncharacter_Code_Point": Noncharacter_Code_Point,
+ "Other_Math": Other_Math,
+ "Unified_Ideograph": Unified_Ideograph,
+ "Hyphen": Hyphen,
+ "IDS_Binary_Operator": IDS_Binary_Operator,
+ "Logical_Order_Exception": Logical_Order_Exception,
+ "Radical": Radical,
+ "Other_Uppercase": Other_Uppercase,
+ "STerm": STerm,
+ "Other_Alphabetic": Other_Alphabetic,
+ "Diacritic": Diacritic,
+ "Extender": Extender,
+ "Join_Control": Join_Control,
+ "Ideographic": Ideographic,
+ "Dash": Dash,
+ "IDS_Trinary_Operator": IDS_Trinary_Operator,
+ "Other_Grapheme_Extend": Other_Grapheme_Extend,
+ "Other_Default_Ignorable_Code_Point": Other_Default_Ignorable_Code_Point,
+ "White_Space": White_Space,
+}
+
+var _Pattern_Syntax = []Range{
+ {0x0021, 0x002f, 1},
+ {0x003a, 0x0040, 1},
+ {0x005b, 0x005e, 1},
+ {0x0060, 0x0060, 1},
+ {0x007b, 0x007e, 1},
+ {0x00a1, 0x00a7, 1},
+ {0x00a9, 0x00a9, 1},
+ {0x00ab, 0x00ac, 1},
+ {0x00ae, 0x00ae, 1},
+ {0x00b0, 0x00b1, 1},
+ {0x00b6, 0x00b6, 1},
+ {0x00bb, 0x00bb, 1},
+ {0x00bf, 0x00bf, 1},
+ {0x00d7, 0x00d7, 1},
+ {0x00f7, 0x00f7, 1},
+ {0x2010, 0x2027, 1},
+ {0x2030, 0x203e, 1},
+ {0x2041, 0x2053, 1},
+ {0x2055, 0x205e, 1},
+ {0x2190, 0x245f, 1},
+ {0x2500, 0x2775, 1},
+ {0x2794, 0x2bff, 1},
+ {0x2e00, 0x2e7f, 1},
+ {0x3001, 0x3003, 1},
+ {0x3008, 0x3020, 1},
+ {0x3030, 0x3030, 1},
+ {0xfd3e, 0xfd3f, 1},
+ {0xfe45, 0xfe46, 1},
+}
+
+var _Other_ID_Start = []Range{
+ {0x2118, 0x2118, 1},
+ {0x212e, 0x212e, 1},
+ {0x309b, 0x309c, 1},
+}
+
+var _Pattern_White_Space = []Range{
+ {0x0009, 0x000d, 1},
+ {0x0020, 0x0020, 1},
+ {0x0085, 0x0085, 1},
+ {0x200e, 0x200f, 1},
+ {0x2028, 0x2029, 1},
+}
+
+var _Other_Lowercase = []Range{
+ {0x02b0, 0x02b8, 1},
+ {0x02c0, 0x02c1, 1},
+ {0x02e0, 0x02e4, 1},
+ {0x0345, 0x0345, 1},
+ {0x037a, 0x037a, 1},
+ {0x1d2c, 0x1d61, 1},
+ {0x1d78, 0x1d78, 1},
+ {0x1d9b, 0x1dbf, 1},
+ {0x2090, 0x2094, 1},
+ {0x2170, 0x217f, 1},
+ {0x24d0, 0x24e9, 1},
+ {0x2c7d, 0x2c7d, 1},
+ {0xa770, 0xa770, 1},
+}
+
+var _Soft_Dotted = []Range{
+ {0x0069, 0x006a, 1},
+ {0x012f, 0x012f, 1},
+ {0x0249, 0x0249, 1},
+ {0x0268, 0x0268, 1},
+ {0x029d, 0x029d, 1},
+ {0x02b2, 0x02b2, 1},
+ {0x03f3, 0x03f3, 1},
+ {0x0456, 0x0456, 1},
+ {0x0458, 0x0458, 1},
+ {0x1d62, 0x1d62, 1},
+ {0x1d96, 0x1d96, 1},
+ {0x1da4, 0x1da4, 1},
+ {0x1da8, 0x1da8, 1},
+ {0x1e2d, 0x1e2d, 1},
+ {0x1ecb, 0x1ecb, 1},
+ {0x2071, 0x2071, 1},
+ {0x2148, 0x2149, 1},
+ {0x2c7c, 0x2c7c, 1},
+ {0x1d422, 0x1d423, 1},
+ {0x1d456, 0x1d457, 1},
+ {0x1d48a, 0x1d48b, 1},
+ {0x1d4be, 0x1d4bf, 1},
+ {0x1d4f2, 0x1d4f3, 1},
+ {0x1d526, 0x1d527, 1},
+ {0x1d55a, 0x1d55b, 1},
+ {0x1d58e, 0x1d58f, 1},
+ {0x1d5c2, 0x1d5c3, 1},
+ {0x1d5f6, 0x1d5f7, 1},
+ {0x1d62a, 0x1d62b, 1},
+ {0x1d65e, 0x1d65f, 1},
+ {0x1d692, 0x1d693, 1},
+}
+
+var _Hex_Digit = []Range{
+ {0x0030, 0x0039, 1},
+ {0x0041, 0x0046, 1},
+ {0x0061, 0x0066, 1},
+ {0xff10, 0xff19, 1},
+ {0xff21, 0xff26, 1},
+ {0xff41, 0xff46, 1},
+}
+
+var _ASCII_Hex_Digit = []Range{
+ {0x0030, 0x0039, 1},
+ {0x0041, 0x0046, 1},
+ {0x0061, 0x0066, 1},
+}
+
+var _Deprecated = []Range{
+ {0x0149, 0x0149, 1},
+ {0x0f77, 0x0f77, 1},
+ {0x0f79, 0x0f79, 1},
+ {0x17a3, 0x17a4, 1},
+ {0x206a, 0x206f, 1},
+ {0x2329, 0x232a, 1},
+ {0xe0001, 0xe0001, 1},
+ {0xe0020, 0xe007f, 1},
+}
+
+var _Terminal_Punctuation = []Range{
+ {0x0021, 0x0021, 1},
+ {0x002c, 0x002c, 1},
+ {0x002e, 0x002e, 1},
+ {0x003a, 0x003b, 1},
+ {0x003f, 0x003f, 1},
+ {0x037e, 0x037e, 1},
+ {0x0387, 0x0387, 1},
+ {0x0589, 0x0589, 1},
+ {0x05c3, 0x05c3, 1},
+ {0x060c, 0x060c, 1},
+ {0x061b, 0x061b, 1},
+ {0x061f, 0x061f, 1},
+ {0x06d4, 0x06d4, 1},
+ {0x0700, 0x070a, 1},
+ {0x070c, 0x070c, 1},
+ {0x07f8, 0x07f9, 1},
+ {0x0830, 0x083e, 1},
+ {0x0964, 0x0965, 1},
+ {0x0e5a, 0x0e5b, 1},
+ {0x0f08, 0x0f08, 1},
+ {0x0f0d, 0x0f12, 1},
+ {0x104a, 0x104b, 1},
+ {0x1361, 0x1368, 1},
+ {0x166d, 0x166e, 1},
+ {0x16eb, 0x16ed, 1},
+ {0x17d4, 0x17d6, 1},
+ {0x17da, 0x17da, 1},
+ {0x1802, 0x1805, 1},
+ {0x1808, 0x1809, 1},
+ {0x1944, 0x1945, 1},
+ {0x1aa8, 0x1aab, 1},
+ {0x1b5a, 0x1b5b, 1},
+ {0x1b5d, 0x1b5f, 1},
+ {0x1c3b, 0x1c3f, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x203c, 0x203d, 1},
+ {0x2047, 0x2049, 1},
+ {0x2e2e, 0x2e2e, 1},
+ {0x3001, 0x3002, 1},
+ {0xa4fe, 0xa4ff, 1},
+ {0xa60d, 0xa60f, 1},
+ {0xa6f3, 0xa6f7, 1},
+ {0xa876, 0xa877, 1},
+ {0xa8ce, 0xa8cf, 1},
+ {0xa92f, 0xa92f, 1},
+ {0xa9c7, 0xa9c9, 1},
+ {0xaa5d, 0xaa5f, 1},
+ {0xaadf, 0xaadf, 1},
+ {0xabeb, 0xabeb, 1},
+ {0xfe50, 0xfe52, 1},
+ {0xfe54, 0xfe57, 1},
+ {0xff01, 0xff01, 1},
+ {0xff0c, 0xff0c, 1},
+ {0xff0e, 0xff0e, 1},
+ {0xff1a, 0xff1b, 1},
+ {0xff1f, 0xff1f, 1},
+ {0xff61, 0xff61, 1},
+ {0xff64, 0xff64, 1},
+ {0x1039f, 0x1039f, 1},
+ {0x103d0, 0x103d0, 1},
+ {0x10857, 0x10857, 1},
+ {0x1091f, 0x1091f, 1},
+ {0x10b3a, 0x10b3f, 1},
+ {0x110be, 0x110c1, 1},
+ {0x12470, 0x12473, 1},
+}
+
+var _Quotation_Mark = []Range{
+ {0x0022, 0x0022, 1},
+ {0x0027, 0x0027, 1},
+ {0x00ab, 0x00ab, 1},
+ {0x00bb, 0x00bb, 1},
+ {0x2018, 0x201f, 1},
+ {0x2039, 0x203a, 1},
+ {0x300c, 0x300f, 1},
+ {0x301d, 0x301f, 1},
+ {0xfe41, 0xfe44, 1},
+ {0xff02, 0xff02, 1},
+ {0xff07, 0xff07, 1},
+ {0xff62, 0xff63, 1},
+}
+
+var _Other_ID_Continue = []Range{
+ {0x00b7, 0x00b7, 1},
+ {0x0387, 0x0387, 1},
+ {0x1369, 0x1371, 1},
+}
+
+var _Bidi_Control = []Range{
+ {0x200e, 0x200f, 1},
+ {0x202a, 0x202e, 1},
+}
+
+var _Variation_Selector = []Range{
+ {0x180b, 0x180d, 1},
+ {0xfe00, 0xfe0f, 1},
+ {0xe0100, 0xe01ef, 1},
+}
+
+var _Noncharacter_Code_Point = []Range{
+ {0xfdd0, 0xfdef, 1},
+ {0xfffe, 0xffff, 1},
+ {0x1fffe, 0x1ffff, 1},
+ {0x2fffe, 0x2ffff, 1},
+ {0x3fffe, 0x3ffff, 1},
+ {0x4fffe, 0x4ffff, 1},
+ {0x5fffe, 0x5ffff, 1},
+ {0x6fffe, 0x6ffff, 1},
+ {0x7fffe, 0x7ffff, 1},
+ {0x8fffe, 0x8ffff, 1},
+ {0x9fffe, 0x9ffff, 1},
+ {0xafffe, 0xaffff, 1},
+ {0xbfffe, 0xbffff, 1},
+ {0xcfffe, 0xcffff, 1},
+ {0xdfffe, 0xdffff, 1},
+ {0xefffe, 0xeffff, 1},
+ {0xffffe, 0xfffff, 1},
+ {0x10fffe, 0x10ffff, 1},
+}
+
+var _Other_Math = []Range{
+ {0x005e, 0x005e, 1},
+ {0x03d0, 0x03d2, 1},
+ {0x03d5, 0x03d5, 1},
+ {0x03f0, 0x03f1, 1},
+ {0x03f4, 0x03f5, 1},
+ {0x2016, 0x2016, 1},
+ {0x2032, 0x2034, 1},
+ {0x2040, 0x2040, 1},
+ {0x2061, 0x2064, 1},
+ {0x207d, 0x207e, 1},
+ {0x208d, 0x208e, 1},
+ {0x20d0, 0x20dc, 1},
+ {0x20e1, 0x20e1, 1},
+ {0x20e5, 0x20e6, 1},
+ {0x20eb, 0x20ef, 1},
+ {0x2102, 0x2102, 1},
+ {0x210a, 0x2113, 1},
+ {0x2115, 0x2115, 1},
+ {0x2119, 0x211d, 1},
+ {0x2124, 0x2124, 1},
+ {0x2128, 0x2129, 1},
+ {0x212c, 0x212d, 1},
+ {0x212f, 0x2131, 1},
+ {0x2133, 0x2138, 1},
+ {0x213c, 0x213f, 1},
+ {0x2145, 0x2149, 1},
+ {0x2195, 0x2199, 1},
+ {0x219c, 0x219f, 1},
+ {0x21a1, 0x21a2, 1},
+ {0x21a4, 0x21a5, 1},
+ {0x21a7, 0x21a7, 1},
+ {0x21a9, 0x21ad, 1},
+ {0x21b0, 0x21b1, 1},
+ {0x21b6, 0x21b7, 1},
+ {0x21bc, 0x21cd, 1},
+ {0x21d0, 0x21d1, 1},
+ {0x21d3, 0x21d3, 1},
+ {0x21d5, 0x21db, 1},
+ {0x21dd, 0x21dd, 1},
+ {0x21e4, 0x21e5, 1},
+ {0x23b4, 0x23b5, 1},
+ {0x23b7, 0x23b7, 1},
+ {0x23d0, 0x23d0, 1},
+ {0x23e2, 0x23e2, 1},
+ {0x25a0, 0x25a1, 1},
+ {0x25ae, 0x25b6, 1},
+ {0x25bc, 0x25c0, 1},
+ {0x25c6, 0x25c7, 1},
+ {0x25ca, 0x25cb, 1},
+ {0x25cf, 0x25d3, 1},
+ {0x25e2, 0x25e2, 1},
+ {0x25e4, 0x25e4, 1},
+ {0x25e7, 0x25ec, 1},
+ {0x2605, 0x2606, 1},
+ {0x2640, 0x2640, 1},
+ {0x2642, 0x2642, 1},
+ {0x2660, 0x2663, 1},
+ {0x266d, 0x266e, 1},
+ {0x27c5, 0x27c6, 1},
+ {0x27e6, 0x27ef, 1},
+ {0x2983, 0x2998, 1},
+ {0x29d8, 0x29db, 1},
+ {0x29fc, 0x29fd, 1},
+ {0xfe61, 0xfe61, 1},
+ {0xfe63, 0xfe63, 1},
+ {0xfe68, 0xfe68, 1},
+ {0xff3c, 0xff3c, 1},
+ {0xff3e, 0xff3e, 1},
+ {0x1d400, 0x1d454, 1},
+ {0x1d456, 0x1d49c, 1},
+ {0x1d49e, 0x1d49f, 1},
+ {0x1d4a2, 0x1d4a2, 1},
+ {0x1d4a5, 0x1d4a6, 1},
+ {0x1d4a9, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bb, 1},
+ {0x1d4bd, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d51e, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d546, 1},
+ {0x1d54a, 0x1d550, 1},
+ {0x1d552, 0x1d6a5, 1},
+ {0x1d6a8, 0x1d6c0, 1},
+ {0x1d6c2, 0x1d6da, 1},
+ {0x1d6dc, 0x1d6fa, 1},
+ {0x1d6fc, 0x1d714, 1},
+ {0x1d716, 0x1d734, 1},
+ {0x1d736, 0x1d74e, 1},
+ {0x1d750, 0x1d76e, 1},
+ {0x1d770, 0x1d788, 1},
+ {0x1d78a, 0x1d7a8, 1},
+ {0x1d7aa, 0x1d7c2, 1},
+ {0x1d7c4, 0x1d7cb, 1},
+ {0x1d7ce, 0x1d7ff, 1},
+}
+
+var _Unified_Ideograph = []Range{
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xfa0e, 0xfa0f, 1},
+ {0xfa11, 0xfa11, 1},
+ {0xfa13, 0xfa14, 1},
+ {0xfa1f, 0xfa1f, 1},
+ {0xfa21, 0xfa21, 1},
+ {0xfa23, 0xfa24, 1},
+ {0xfa27, 0xfa29, 1},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+}
+
+var _Hyphen = []Range{
+ {0x002d, 0x002d, 1},
+ {0x00ad, 0x00ad, 1},
+ {0x058a, 0x058a, 1},
+ {0x1806, 0x1806, 1},
+ {0x2010, 0x2011, 1},
+ {0x2e17, 0x2e17, 1},
+ {0x30fb, 0x30fb, 1},
+ {0xfe63, 0xfe63, 1},
+ {0xff0d, 0xff0d, 1},
+ {0xff65, 0xff65, 1},
+}
+
+var _IDS_Binary_Operator = []Range{
+ {0x2ff0, 0x2ff1, 1},
+ {0x2ff4, 0x2ffb, 1},
+}
+
+var _Logical_Order_Exception = []Range{
+ {0x0e40, 0x0e44, 1},
+ {0x0ec0, 0x0ec4, 1},
+ {0xaab5, 0xaab6, 1},
+ {0xaab9, 0xaab9, 1},
+ {0xaabb, 0xaabc, 1},
+}
+
+var _Radical = []Range{
+ {0x2e80, 0x2e99, 1},
+ {0x2e9b, 0x2ef3, 1},
+ {0x2f00, 0x2fd5, 1},
+}
+
+var _Other_Uppercase = []Range{
+ {0x2160, 0x216f, 1},
+ {0x24b6, 0x24cf, 1},
+}
+
+var _STerm = []Range{
+ {0x0021, 0x0021, 1},
+ {0x002e, 0x002e, 1},
+ {0x003f, 0x003f, 1},
+ {0x055c, 0x055c, 1},
+ {0x055e, 0x055e, 1},
+ {0x0589, 0x0589, 1},
+ {0x061f, 0x061f, 1},
+ {0x06d4, 0x06d4, 1},
+ {0x0700, 0x0702, 1},
+ {0x07f9, 0x07f9, 1},
+ {0x0964, 0x0965, 1},
+ {0x104a, 0x104b, 1},
+ {0x1362, 0x1362, 1},
+ {0x1367, 0x1368, 1},
+ {0x166e, 0x166e, 1},
+ {0x1803, 0x1803, 1},
+ {0x1809, 0x1809, 1},
+ {0x1944, 0x1945, 1},
+ {0x1b5a, 0x1b5b, 1},
+ {0x1b5e, 0x1b5f, 1},
+ {0x1c3b, 0x1c3c, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x203c, 0x203d, 1},
+ {0x2047, 0x2049, 1},
+ {0x2e2e, 0x2e2e, 1},
+ {0x3002, 0x3002, 1},
+ {0xa4ff, 0xa4ff, 1},
+ {0xa60e, 0xa60f, 1},
+ {0xa6f3, 0xa6f3, 1},
+ {0xa6f7, 0xa6f7, 1},
+ {0xa876, 0xa877, 1},
+ {0xa8ce, 0xa8cf, 1},
+ {0xa92f, 0xa92f, 1},
+ {0xa9c8, 0xa9c9, 1},
+ {0xaa5d, 0xaa5f, 1},
+ {0xabeb, 0xabeb, 1},
+ {0xfe52, 0xfe52, 1},
+ {0xfe56, 0xfe57, 1},
+ {0xff01, 0xff01, 1},
+ {0xff0e, 0xff0e, 1},
+ {0xff1f, 0xff1f, 1},
+ {0xff61, 0xff61, 1},
+ {0x110be, 0x110c1, 1},
+}
+
+var _Other_Alphabetic = []Range{
+ {0x0345, 0x0345, 1},
+ {0x05b0, 0x05bd, 1},
+ {0x05bf, 0x05bf, 1},
+ {0x05c1, 0x05c2, 1},
+ {0x05c4, 0x05c5, 1},
+ {0x05c7, 0x05c7, 1},
+ {0x0610, 0x061a, 1},
+ {0x064b, 0x0657, 1},
+ {0x0659, 0x065e, 1},
+ {0x0670, 0x0670, 1},
+ {0x06d6, 0x06dc, 1},
+ {0x06e1, 0x06e4, 1},
+ {0x06e7, 0x06e8, 1},
+ {0x06ed, 0x06ed, 1},
+ {0x0711, 0x0711, 1},
+ {0x0730, 0x073f, 1},
+ {0x07a6, 0x07b0, 1},
+ {0x0816, 0x0817, 1},
+ {0x081b, 0x0823, 1},
+ {0x0825, 0x0827, 1},
+ {0x0829, 0x082c, 1},
+ {0x0900, 0x0903, 1},
+ {0x093e, 0x094c, 1},
+ {0x094e, 0x094e, 1},
+ {0x0955, 0x0955, 1},
+ {0x0962, 0x0963, 1},
+ {0x0981, 0x0983, 1},
+ {0x09be, 0x09c4, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09cc, 1},
+ {0x09d7, 0x09d7, 1},
+ {0x09e2, 0x09e3, 1},
+ {0x0a01, 0x0a03, 1},
+ {0x0a3e, 0x0a42, 1},
+ {0x0a47, 0x0a48, 1},
+ {0x0a4b, 0x0a4c, 1},
+ {0x0a51, 0x0a51, 1},
+ {0x0a70, 0x0a71, 1},
+ {0x0a75, 0x0a75, 1},
+ {0x0a81, 0x0a83, 1},
+ {0x0abe, 0x0ac5, 1},
+ {0x0ac7, 0x0ac9, 1},
+ {0x0acb, 0x0acc, 1},
+ {0x0ae2, 0x0ae3, 1},
+ {0x0b01, 0x0b03, 1},
+ {0x0b3e, 0x0b44, 1},
+ {0x0b47, 0x0b48, 1},
+ {0x0b4b, 0x0b4c, 1},
+ {0x0b56, 0x0b57, 1},
+ {0x0b62, 0x0b63, 1},
+ {0x0b82, 0x0b82, 1},
+ {0x0bbe, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcc, 1},
+ {0x0bd7, 0x0bd7, 1},
+ {0x0c01, 0x0c03, 1},
+ {0x0c3e, 0x0c44, 1},
+ {0x0c46, 0x0c48, 1},
+ {0x0c4a, 0x0c4c, 1},
+ {0x0c55, 0x0c56, 1},
+ {0x0c62, 0x0c63, 1},
+ {0x0c82, 0x0c83, 1},
+ {0x0cbe, 0x0cc4, 1},
+ {0x0cc6, 0x0cc8, 1},
+ {0x0cca, 0x0ccc, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0ce2, 0x0ce3, 1},
+ {0x0d02, 0x0d03, 1},
+ {0x0d3e, 0x0d44, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4c, 1},
+ {0x0d57, 0x0d57, 1},
+ {0x0d62, 0x0d63, 1},
+ {0x0d82, 0x0d83, 1},
+ {0x0dcf, 0x0dd4, 1},
+ {0x0dd6, 0x0dd6, 1},
+ {0x0dd8, 0x0ddf, 1},
+ {0x0df2, 0x0df3, 1},
+ {0x0e31, 0x0e31, 1},
+ {0x0e34, 0x0e3a, 1},
+ {0x0e4d, 0x0e4d, 1},
+ {0x0eb1, 0x0eb1, 1},
+ {0x0eb4, 0x0eb9, 1},
+ {0x0ebb, 0x0ebc, 1},
+ {0x0ecd, 0x0ecd, 1},
+ {0x0f71, 0x0f81, 1},
+ {0x0f90, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x102b, 0x1036, 1},
+ {0x1038, 0x1038, 1},
+ {0x103b, 0x103e, 1},
+ {0x1056, 0x1059, 1},
+ {0x105e, 0x1060, 1},
+ {0x1062, 0x1062, 1},
+ {0x1067, 0x1068, 1},
+ {0x1071, 0x1074, 1},
+ {0x1082, 0x1086, 1},
+ {0x109c, 0x109d, 1},
+ {0x135f, 0x135f, 1},
+ {0x1712, 0x1713, 1},
+ {0x1732, 0x1733, 1},
+ {0x1752, 0x1753, 1},
+ {0x1772, 0x1773, 1},
+ {0x17b6, 0x17c8, 1},
+ {0x18a9, 0x18a9, 1},
+ {0x1920, 0x192b, 1},
+ {0x1930, 0x1938, 1},
+ {0x19b0, 0x19c0, 1},
+ {0x19c8, 0x19c9, 1},
+ {0x1a17, 0x1a1b, 1},
+ {0x1a55, 0x1a5e, 1},
+ {0x1a61, 0x1a74, 1},
+ {0x1b00, 0x1b04, 1},
+ {0x1b35, 0x1b43, 1},
+ {0x1b80, 0x1b82, 1},
+ {0x1ba1, 0x1ba9, 1},
+ {0x1c24, 0x1c35, 1},
+ {0x1cf2, 0x1cf2, 1},
+ {0x24b6, 0x24e9, 1},
+ {0x2de0, 0x2dff, 1},
+ {0xa823, 0xa827, 1},
+ {0xa880, 0xa881, 1},
+ {0xa8b4, 0xa8c3, 1},
+ {0xa926, 0xa92a, 1},
+ {0xa947, 0xa952, 1},
+ {0xa980, 0xa983, 1},
+ {0xa9b3, 0xa9bf, 1},
+ {0xaa29, 0xaa36, 1},
+ {0xaa43, 0xaa43, 1},
+ {0xaa4c, 0xaa4d, 1},
+ {0xaab0, 0xaab0, 1},
+ {0xaab2, 0xaab4, 1},
+ {0xaab7, 0xaab8, 1},
+ {0xaabe, 0xaabe, 1},
+ {0xabe3, 0xabea, 1},
+ {0xfb1e, 0xfb1e, 1},
+ {0x10a01, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a0f, 1},
+ {0x11082, 0x11082, 1},
+ {0x110b0, 0x110b8, 1},
+}
+
+var _Diacritic = []Range{
+ {0x005e, 0x005e, 1},
+ {0x0060, 0x0060, 1},
+ {0x00a8, 0x00a8, 1},
+ {0x00af, 0x00af, 1},
+ {0x00b4, 0x00b4, 1},
+ {0x00b7, 0x00b8, 1},
+ {0x02b0, 0x034e, 1},
+ {0x0350, 0x0357, 1},
+ {0x035d, 0x0362, 1},
+ {0x0374, 0x0375, 1},
+ {0x037a, 0x037a, 1},
+ {0x0384, 0x0385, 1},
+ {0x0483, 0x0487, 1},
+ {0x0559, 0x0559, 1},
+ {0x0591, 0x05a1, 1},
+ {0x05a3, 0x05bd, 1},
+ {0x05bf, 0x05bf, 1},
+ {0x05c1, 0x05c2, 1},
+ {0x05c4, 0x05c4, 1},
+ {0x064b, 0x0652, 1},
+ {0x0657, 0x0658, 1},
+ {0x06df, 0x06e0, 1},
+ {0x06e5, 0x06e6, 1},
+ {0x06ea, 0x06ec, 1},
+ {0x0730, 0x074a, 1},
+ {0x07a6, 0x07b0, 1},
+ {0x07eb, 0x07f5, 1},
+ {0x0818, 0x0819, 1},
+ {0x093c, 0x093c, 1},
+ {0x094d, 0x094d, 1},
+ {0x0951, 0x0954, 1},
+ {0x0971, 0x0971, 1},
+ {0x09bc, 0x09bc, 1},
+ {0x09cd, 0x09cd, 1},
+ {0x0a3c, 0x0a3c, 1},
+ {0x0a4d, 0x0a4d, 1},
+ {0x0abc, 0x0abc, 1},
+ {0x0acd, 0x0acd, 1},
+ {0x0b3c, 0x0b3c, 1},
+ {0x0b4d, 0x0b4d, 1},
+ {0x0bcd, 0x0bcd, 1},
+ {0x0c4d, 0x0c4d, 1},
+ {0x0cbc, 0x0cbc, 1},
+ {0x0ccd, 0x0ccd, 1},
+ {0x0d4d, 0x0d4d, 1},
+ {0x0dca, 0x0dca, 1},
+ {0x0e47, 0x0e4c, 1},
+ {0x0e4e, 0x0e4e, 1},
+ {0x0ec8, 0x0ecc, 1},
+ {0x0f18, 0x0f19, 1},
+ {0x0f35, 0x0f35, 1},
+ {0x0f37, 0x0f37, 1},
+ {0x0f39, 0x0f39, 1},
+ {0x0f3e, 0x0f3f, 1},
+ {0x0f82, 0x0f84, 1},
+ {0x0f86, 0x0f87, 1},
+ {0x0fc6, 0x0fc6, 1},
+ {0x1037, 0x1037, 1},
+ {0x1039, 0x103a, 1},
+ {0x1087, 0x108d, 1},
+ {0x108f, 0x108f, 1},
+ {0x109a, 0x109b, 1},
+ {0x17c9, 0x17d3, 1},
+ {0x17dd, 0x17dd, 1},
+ {0x1939, 0x193b, 1},
+ {0x1a75, 0x1a7c, 1},
+ {0x1a7f, 0x1a7f, 1},
+ {0x1b34, 0x1b34, 1},
+ {0x1b44, 0x1b44, 1},
+ {0x1b6b, 0x1b73, 1},
+ {0x1baa, 0x1baa, 1},
+ {0x1c36, 0x1c37, 1},
+ {0x1c78, 0x1c7d, 1},
+ {0x1cd0, 0x1ce8, 1},
+ {0x1ced, 0x1ced, 1},
+ {0x1d2c, 0x1d6a, 1},
+ {0x1dc4, 0x1dcf, 1},
+ {0x1dfd, 0x1dff, 1},
+ {0x1fbd, 0x1fbd, 1},
+ {0x1fbf, 0x1fc1, 1},
+ {0x1fcd, 0x1fcf, 1},
+ {0x1fdd, 0x1fdf, 1},
+ {0x1fed, 0x1fef, 1},
+ {0x1ffd, 0x1ffe, 1},
+ {0x2cef, 0x2cf1, 1},
+ {0x2e2f, 0x2e2f, 1},
+ {0x302a, 0x302f, 1},
+ {0x3099, 0x309c, 1},
+ {0x30fc, 0x30fc, 1},
+ {0xa66f, 0xa66f, 1},
+ {0xa67c, 0xa67d, 1},
+ {0xa67f, 0xa67f, 1},
+ {0xa6f0, 0xa6f1, 1},
+ {0xa717, 0xa721, 1},
+ {0xa788, 0xa788, 1},
+ {0xa8c4, 0xa8c4, 1},
+ {0xa8e0, 0xa8f1, 1},
+ {0xa92b, 0xa92e, 1},
+ {0xa953, 0xa953, 1},
+ {0xa9b3, 0xa9b3, 1},
+ {0xa9c0, 0xa9c0, 1},
+ {0xaa7b, 0xaa7b, 1},
+ {0xaabf, 0xaac2, 1},
+ {0xabec, 0xabed, 1},
+ {0xfb1e, 0xfb1e, 1},
+ {0xfe20, 0xfe26, 1},
+ {0xff3e, 0xff3e, 1},
+ {0xff40, 0xff40, 1},
+ {0xff70, 0xff70, 1},
+ {0xff9e, 0xff9f, 1},
+ {0xffe3, 0xffe3, 1},
+ {0x110b9, 0x110ba, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d16d, 0x1d172, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+}
+
+var _Extender = []Range{
+ {0x00b7, 0x00b7, 1},
+ {0x02d0, 0x02d1, 1},
+ {0x0640, 0x0640, 1},
+ {0x07fa, 0x07fa, 1},
+ {0x0e46, 0x0e46, 1},
+ {0x0ec6, 0x0ec6, 1},
+ {0x1843, 0x1843, 1},
+ {0x1aa7, 0x1aa7, 1},
+ {0x1c36, 0x1c36, 1},
+ {0x1c7b, 0x1c7b, 1},
+ {0x3005, 0x3005, 1},
+ {0x3031, 0x3035, 1},
+ {0x309d, 0x309e, 1},
+ {0x30fc, 0x30fe, 1},
+ {0xa015, 0xa015, 1},
+ {0xa60c, 0xa60c, 1},
+ {0xa9cf, 0xa9cf, 1},
+ {0xaa70, 0xaa70, 1},
+ {0xaadd, 0xaadd, 1},
+ {0xff70, 0xff70, 1},
+}
+
+var _Join_Control = []Range{
+ {0x200c, 0x200d, 1},
+}
+
+var _Ideographic = []Range{
+ {0x3006, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3038, 0x303a, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2f800, 0x2fa1d, 1},
+}
+
+var _Dash = []Range{
+ {0x002d, 0x002d, 1},
+ {0x058a, 0x058a, 1},
+ {0x05be, 0x05be, 1},
+ {0x1400, 0x1400, 1},
+ {0x1806, 0x1806, 1},
+ {0x2010, 0x2015, 1},
+ {0x2053, 0x2053, 1},
+ {0x207b, 0x207b, 1},
+ {0x208b, 0x208b, 1},
+ {0x2212, 0x2212, 1},
+ {0x2e17, 0x2e17, 1},
+ {0x2e1a, 0x2e1a, 1},
+ {0x301c, 0x301c, 1},
+ {0x3030, 0x3030, 1},
+ {0x30a0, 0x30a0, 1},
+ {0xfe31, 0xfe32, 1},
+ {0xfe58, 0xfe58, 1},
+ {0xfe63, 0xfe63, 1},
+ {0xff0d, 0xff0d, 1},
+}
+
+var _IDS_Trinary_Operator = []Range{
+ {0x2ff2, 0x2ff3, 1},
+}
+
+var _Other_Grapheme_Extend = []Range{
+ {0x09be, 0x09be, 1},
+ {0x09d7, 0x09d7, 1},
+ {0x0b3e, 0x0b3e, 1},
+ {0x0b57, 0x0b57, 1},
+ {0x0bbe, 0x0bbe, 1},
+ {0x0bd7, 0x0bd7, 1},
+ {0x0cc2, 0x0cc2, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0d3e, 0x0d3e, 1},
+ {0x0d57, 0x0d57, 1},
+ {0x0dcf, 0x0dcf, 1},
+ {0x0ddf, 0x0ddf, 1},
+ {0x200c, 0x200d, 1},
+ {0xff9e, 0xff9f, 1},
+ {0x1d165, 0x1d165, 1},
+ {0x1d16e, 0x1d172, 1},
+}
+
+var _Other_Default_Ignorable_Code_Point = []Range{
+ {0x034f, 0x034f, 1},
+ {0x115f, 0x1160, 1},
+ {0x2065, 0x2069, 1},
+ {0x3164, 0x3164, 1},
+ {0xffa0, 0xffa0, 1},
+ {0xfff0, 0xfff8, 1},
+ {0xe0000, 0xe0000, 1},
+ {0xe0002, 0xe001f, 1},
+ {0xe0080, 0xe00ff, 1},
+ {0xe01f0, 0xe0fff, 1},
+}
+
+var _White_Space = []Range{
+ {0x0009, 0x000d, 1},
+ {0x0020, 0x0020, 1},
+ {0x0085, 0x0085, 1},
+ {0x00a0, 0x00a0, 1},
+ {0x1680, 0x1680, 1},
+ {0x180e, 0x180e, 1},
+ {0x2000, 0x200a, 1},
+ {0x2028, 0x2029, 1},
+ {0x202f, 0x202f, 1},
+ {0x205f, 0x205f, 1},
+ {0x3000, 0x3000, 1},
+}
+
+var (
+ ASCII_Hex_Digit = _ASCII_Hex_Digit // ASCII_Hex_Digit is the set of Unicode characters with property ASCII_Hex_Digit.
+ Bidi_Control = _Bidi_Control // Bidi_Control is the set of Unicode characters with property Bidi_Control.
+ Dash = _Dash // Dash is the set of Unicode characters with property Dash.
+ Deprecated = _Deprecated // Deprecated is the set of Unicode characters with property Deprecated.
+ Diacritic = _Diacritic // Diacritic is the set of Unicode characters with property Diacritic.
+ Extender = _Extender // Extender is the set of Unicode characters with property Extender.
+ Hex_Digit = _Hex_Digit // Hex_Digit is the set of Unicode characters with property Hex_Digit.
+ Hyphen = _Hyphen // Hyphen is the set of Unicode characters with property Hyphen.
+ IDS_Binary_Operator = _IDS_Binary_Operator // IDS_Binary_Operator is the set of Unicode characters with property IDS_Binary_Operator.
+ IDS_Trinary_Operator = _IDS_Trinary_Operator // IDS_Trinary_Operator is the set of Unicode characters with property IDS_Trinary_Operator.
+ Ideographic = _Ideographic // Ideographic is the set of Unicode characters with property Ideographic.
+ Join_Control = _Join_Control // Join_Control is the set of Unicode characters with property Join_Control.
+ Logical_Order_Exception = _Logical_Order_Exception // Logical_Order_Exception is the set of Unicode characters with property Logical_Order_Exception.
+ Noncharacter_Code_Point = _Noncharacter_Code_Point // Noncharacter_Code_Point is the set of Unicode characters with property Noncharacter_Code_Point.
+ Other_Alphabetic = _Other_Alphabetic // Other_Alphabetic is the set of Unicode characters with property Other_Alphabetic.
+ Other_Default_Ignorable_Code_Point = _Other_Default_Ignorable_Code_Point // Other_Default_Ignorable_Code_Point is the set of Unicode characters with property Other_Default_Ignorable_Code_Point.
+ Other_Grapheme_Extend = _Other_Grapheme_Extend // Other_Grapheme_Extend is the set of Unicode characters with property Other_Grapheme_Extend.
+ Other_ID_Continue = _Other_ID_Continue // Other_ID_Continue is the set of Unicode characters with property Other_ID_Continue.
+ Other_ID_Start = _Other_ID_Start // Other_ID_Start is the set of Unicode characters with property Other_ID_Start.
+ Other_Lowercase = _Other_Lowercase // Other_Lowercase is the set of Unicode characters with property Other_Lowercase.
+ Other_Math = _Other_Math // Other_Math is the set of Unicode characters with property Other_Math.
+ Other_Uppercase = _Other_Uppercase // Other_Uppercase is the set of Unicode characters with property Other_Uppercase.
+ Pattern_Syntax = _Pattern_Syntax // Pattern_Syntax is the set of Unicode characters with property Pattern_Syntax.
+ Pattern_White_Space = _Pattern_White_Space // Pattern_White_Space is the set of Unicode characters with property Pattern_White_Space.
+ Quotation_Mark = _Quotation_Mark // Quotation_Mark is the set of Unicode characters with property Quotation_Mark.
+ Radical = _Radical // Radical is the set of Unicode characters with property Radical.
+ STerm = _STerm // STerm is the set of Unicode characters with property STerm.
+ Soft_Dotted = _Soft_Dotted // Soft_Dotted is the set of Unicode characters with property Soft_Dotted.
+ Terminal_Punctuation = _Terminal_Punctuation // Terminal_Punctuation is the set of Unicode characters with property Terminal_Punctuation.
+ Unified_Ideograph = _Unified_Ideograph // Unified_Ideograph is the set of Unicode characters with property Unified_Ideograph.
+ Variation_Selector = _Variation_Selector // Variation_Selector is the set of Unicode characters with property Variation_Selector.
+ White_Space = _White_Space // White_Space is the set of Unicode characters with property White_Space.
+)
+
+// Generated by running
+// maketables --data=http://www.unicode.org/Public/5.2.0/ucd/UnicodeData.txt
+// DO NOT EDIT
+
+// CaseRanges is the table describing case mappings for all letters with
+// non-self mappings.
+var CaseRanges = _CaseRanges
+var _CaseRanges = []CaseRange{
+ {0x0041, 0x005A, d{0, 32, 0}},
+ {0x0061, 0x007A, d{-32, 0, -32}},
+ {0x00B5, 0x00B5, d{743, 0, 743}},
+ {0x00C0, 0x00D6, d{0, 32, 0}},
+ {0x00D8, 0x00DE, d{0, 32, 0}},
+ {0x00E0, 0x00F6, d{-32, 0, -32}},
+ {0x00F8, 0x00FE, d{-32, 0, -32}},
+ {0x00FF, 0x00FF, d{121, 0, 121}},
+ {0x0100, 0x012F, d{UpperLower, UpperLower, UpperLower}},
+ {0x0130, 0x0130, d{0, -199, 0}},
+ {0x0131, 0x0131, d{-232, 0, -232}},
+ {0x0132, 0x0137, d{UpperLower, UpperLower, UpperLower}},
+ {0x0139, 0x0148, d{UpperLower, UpperLower, UpperLower}},
+ {0x014A, 0x0177, d{UpperLower, UpperLower, UpperLower}},
+ {0x0178, 0x0178, d{0, -121, 0}},
+ {0x0179, 0x017E, d{UpperLower, UpperLower, UpperLower}},
+ {0x017F, 0x017F, d{-300, 0, -300}},
+ {0x0180, 0x0180, d{195, 0, 195}},
+ {0x0181, 0x0181, d{0, 210, 0}},
+ {0x0182, 0x0185, d{UpperLower, UpperLower, UpperLower}},
+ {0x0186, 0x0186, d{0, 206, 0}},
+ {0x0187, 0x0188, d{UpperLower, UpperLower, UpperLower}},
+ {0x0189, 0x018A, d{0, 205, 0}},
+ {0x018B, 0x018C, d{UpperLower, UpperLower, UpperLower}},
+ {0x018E, 0x018E, d{0, 79, 0}},
+ {0x018F, 0x018F, d{0, 202, 0}},
+ {0x0190, 0x0190, d{0, 203, 0}},
+ {0x0191, 0x0192, d{UpperLower, UpperLower, UpperLower}},
+ {0x0193, 0x0193, d{0, 205, 0}},
+ {0x0194, 0x0194, d{0, 207, 0}},
+ {0x0195, 0x0195, d{97, 0, 97}},
+ {0x0196, 0x0196, d{0, 211, 0}},
+ {0x0197, 0x0197, d{0, 209, 0}},
+ {0x0198, 0x0199, d{UpperLower, UpperLower, UpperLower}},
+ {0x019A, 0x019A, d{163, 0, 163}},
+ {0x019C, 0x019C, d{0, 211, 0}},
+ {0x019D, 0x019D, d{0, 213, 0}},
+ {0x019E, 0x019E, d{130, 0, 130}},
+ {0x019F, 0x019F, d{0, 214, 0}},
+ {0x01A0, 0x01A5, d{UpperLower, UpperLower, UpperLower}},
+ {0x01A6, 0x01A6, d{0, 218, 0}},
+ {0x01A7, 0x01A8, d{UpperLower, UpperLower, UpperLower}},
+ {0x01A9, 0x01A9, d{0, 218, 0}},
+ {0x01AC, 0x01AD, d{UpperLower, UpperLower, UpperLower}},
+ {0x01AE, 0x01AE, d{0, 218, 0}},
+ {0x01AF, 0x01B0, d{UpperLower, UpperLower, UpperLower}},
+ {0x01B1, 0x01B2, d{0, 217, 0}},
+ {0x01B3, 0x01B6, d{UpperLower, UpperLower, UpperLower}},
+ {0x01B7, 0x01B7, d{0, 219, 0}},
+ {0x01B8, 0x01B9, d{UpperLower, UpperLower, UpperLower}},
+ {0x01BC, 0x01BD, d{UpperLower, UpperLower, UpperLower}},
+ {0x01BF, 0x01BF, d{56, 0, 56}},
+ {0x01C4, 0x01C4, d{0, 2, 1}},
+ {0x01C5, 0x01C5, d{-1, 1, 0}},
+ {0x01C6, 0x01C6, d{-2, 0, -1}},
+ {0x01C7, 0x01C7, d{0, 2, 1}},
+ {0x01C8, 0x01C8, d{-1, 1, 0}},
+ {0x01C9, 0x01C9, d{-2, 0, -1}},
+ {0x01CA, 0x01CA, d{0, 2, 1}},
+ {0x01CB, 0x01CB, d{-1, 1, 0}},
+ {0x01CC, 0x01CC, d{-2, 0, -1}},
+ {0x01CD, 0x01DC, d{UpperLower, UpperLower, UpperLower}},
+ {0x01DD, 0x01DD, d{-79, 0, -79}},
+ {0x01DE, 0x01EF, d{UpperLower, UpperLower, UpperLower}},
+ {0x01F1, 0x01F1, d{0, 2, 1}},
+ {0x01F2, 0x01F2, d{-1, 1, 0}},
+ {0x01F3, 0x01F3, d{-2, 0, -1}},
+ {0x01F4, 0x01F5, d{UpperLower, UpperLower, UpperLower}},
+ {0x01F6, 0x01F6, d{0, -97, 0}},
+ {0x01F7, 0x01F7, d{0, -56, 0}},
+ {0x01F8, 0x021F, d{UpperLower, UpperLower, UpperLower}},
+ {0x0220, 0x0220, d{0, -130, 0}},
+ {0x0222, 0x0233, d{UpperLower, UpperLower, UpperLower}},
+ {0x023A, 0x023A, d{0, 10795, 0}},
+ {0x023B, 0x023C, d{UpperLower, UpperLower, UpperLower}},
+ {0x023D, 0x023D, d{0, -163, 0}},
+ {0x023E, 0x023E, d{0, 10792, 0}},
+ {0x023F, 0x0240, d{10815, 0, 10815}},
+ {0x0241, 0x0242, d{UpperLower, UpperLower, UpperLower}},
+ {0x0243, 0x0243, d{0, -195, 0}},
+ {0x0244, 0x0244, d{0, 69, 0}},
+ {0x0245, 0x0245, d{0, 71, 0}},
+ {0x0246, 0x024F, d{UpperLower, UpperLower, UpperLower}},
+ {0x0250, 0x0250, d{10783, 0, 10783}},
+ {0x0251, 0x0251, d{10780, 0, 10780}},
+ {0x0252, 0x0252, d{10782, 0, 10782}},
+ {0x0253, 0x0253, d{-210, 0, -210}},
+ {0x0254, 0x0254, d{-206, 0, -206}},
+ {0x0256, 0x0257, d{-205, 0, -205}},
+ {0x0259, 0x0259, d{-202, 0, -202}},
+ {0x025B, 0x025B, d{-203, 0, -203}},
+ {0x0260, 0x0260, d{-205, 0, -205}},
+ {0x0263, 0x0263, d{-207, 0, -207}},
+ {0x0268, 0x0268, d{-209, 0, -209}},
+ {0x0269, 0x0269, d{-211, 0, -211}},
+ {0x026B, 0x026B, d{10743, 0, 10743}},
+ {0x026F, 0x026F, d{-211, 0, -211}},
+ {0x0271, 0x0271, d{10749, 0, 10749}},
+ {0x0272, 0x0272, d{-213, 0, -213}},
+ {0x0275, 0x0275, d{-214, 0, -214}},
+ {0x027D, 0x027D, d{10727, 0, 10727}},
+ {0x0280, 0x0280, d{-218, 0, -218}},
+ {0x0283, 0x0283, d{-218, 0, -218}},
+ {0x0288, 0x0288, d{-218, 0, -218}},
+ {0x0289, 0x0289, d{-69, 0, -69}},
+ {0x028A, 0x028B, d{-217, 0, -217}},
+ {0x028C, 0x028C, d{-71, 0, -71}},
+ {0x0292, 0x0292, d{-219, 0, -219}},
+ {0x0370, 0x0373, d{UpperLower, UpperLower, UpperLower}},
+ {0x0376, 0x0377, d{UpperLower, UpperLower, UpperLower}},
+ {0x037B, 0x037D, d{130, 0, 130}},
+ {0x0386, 0x0386, d{0, 38, 0}},
+ {0x0388, 0x038A, d{0, 37, 0}},
+ {0x038C, 0x038C, d{0, 64, 0}},
+ {0x038E, 0x038F, d{0, 63, 0}},
+ {0x0391, 0x03A1, d{0, 32, 0}},
+ {0x03A3, 0x03AB, d{0, 32, 0}},
+ {0x03AC, 0x03AC, d{-38, 0, -38}},
+ {0x03AD, 0x03AF, d{-37, 0, -37}},
+ {0x03B1, 0x03C1, d{-32, 0, -32}},
+ {0x03C2, 0x03C2, d{-31, 0, -31}},
+ {0x03C3, 0x03CB, d{-32, 0, -32}},
+ {0x03CC, 0x03CC, d{-64, 0, -64}},
+ {0x03CD, 0x03CE, d{-63, 0, -63}},
+ {0x03CF, 0x03CF, d{0, 8, 0}},
+ {0x03D0, 0x03D0, d{-62, 0, -62}},
+ {0x03D1, 0x03D1, d{-57, 0, -57}},
+ {0x03D5, 0x03D5, d{-47, 0, -47}},
+ {0x03D6, 0x03D6, d{-54, 0, -54}},
+ {0x03D7, 0x03D7, d{-8, 0, -8}},
+ {0x03D8, 0x03EF, d{UpperLower, UpperLower, UpperLower}},
+ {0x03F0, 0x03F0, d{-86, 0, -86}},
+ {0x03F1, 0x03F1, d{-80, 0, -80}},
+ {0x03F2, 0x03F2, d{7, 0, 7}},
+ {0x03F4, 0x03F4, d{0, -60, 0}},
+ {0x03F5, 0x03F5, d{-96, 0, -96}},
+ {0x03F7, 0x03F8, d{UpperLower, UpperLower, UpperLower}},
+ {0x03F9, 0x03F9, d{0, -7, 0}},
+ {0x03FA, 0x03FB, d{UpperLower, UpperLower, UpperLower}},
+ {0x03FD, 0x03FF, d{0, -130, 0}},
+ {0x0400, 0x040F, d{0, 80, 0}},
+ {0x0410, 0x042F, d{0, 32, 0}},
+ {0x0430, 0x044F, d{-32, 0, -32}},
+ {0x0450, 0x045F, d{-80, 0, -80}},
+ {0x0460, 0x0481, d{UpperLower, UpperLower, UpperLower}},
+ {0x048A, 0x04BF, d{UpperLower, UpperLower, UpperLower}},
+ {0x04C0, 0x04C0, d{0, 15, 0}},
+ {0x04C1, 0x04CE, d{UpperLower, UpperLower, UpperLower}},
+ {0x04CF, 0x04CF, d{-15, 0, -15}},
+ {0x04D0, 0x0525, d{UpperLower, UpperLower, UpperLower}},
+ {0x0531, 0x0556, d{0, 48, 0}},
+ {0x0561, 0x0586, d{-48, 0, -48}},
+ {0x10A0, 0x10C5, d{0, 7264, 0}},
+ {0x1D79, 0x1D79, d{35332, 0, 35332}},
+ {0x1D7D, 0x1D7D, d{3814, 0, 3814}},
+ {0x1E00, 0x1E95, d{UpperLower, UpperLower, UpperLower}},
+ {0x1E9B, 0x1E9B, d{-59, 0, -59}},
+ {0x1E9E, 0x1E9E, d{0, -7615, 0}},
+ {0x1EA0, 0x1EFF, d{UpperLower, UpperLower, UpperLower}},
+ {0x1F00, 0x1F07, d{8, 0, 8}},
+ {0x1F08, 0x1F0F, d{0, -8, 0}},
+ {0x1F10, 0x1F15, d{8, 0, 8}},
+ {0x1F18, 0x1F1D, d{0, -8, 0}},
+ {0x1F20, 0x1F27, d{8, 0, 8}},
+ {0x1F28, 0x1F2F, d{0, -8, 0}},
+ {0x1F30, 0x1F37, d{8, 0, 8}},
+ {0x1F38, 0x1F3F, d{0, -8, 0}},
+ {0x1F40, 0x1F45, d{8, 0, 8}},
+ {0x1F48, 0x1F4D, d{0, -8, 0}},
+ {0x1F51, 0x1F51, d{8, 0, 8}},
+ {0x1F53, 0x1F53, d{8, 0, 8}},
+ {0x1F55, 0x1F55, d{8, 0, 8}},
+ {0x1F57, 0x1F57, d{8, 0, 8}},
+ {0x1F59, 0x1F59, d{0, -8, 0}},
+ {0x1F5B, 0x1F5B, d{0, -8, 0}},
+ {0x1F5D, 0x1F5D, d{0, -8, 0}},
+ {0x1F5F, 0x1F5F, d{0, -8, 0}},
+ {0x1F60, 0x1F67, d{8, 0, 8}},
+ {0x1F68, 0x1F6F, d{0, -8, 0}},
+ {0x1F70, 0x1F71, d{74, 0, 74}},
+ {0x1F72, 0x1F75, d{86, 0, 86}},
+ {0x1F76, 0x1F77, d{100, 0, 100}},
+ {0x1F78, 0x1F79, d{128, 0, 128}},
+ {0x1F7A, 0x1F7B, d{112, 0, 112}},
+ {0x1F7C, 0x1F7D, d{126, 0, 126}},
+ {0x1F80, 0x1F87, d{8, 0, 8}},
+ {0x1F88, 0x1F8F, d{0, -8, 0}},
+ {0x1F90, 0x1F97, d{8, 0, 8}},
+ {0x1F98, 0x1F9F, d{0, -8, 0}},
+ {0x1FA0, 0x1FA7, d{8, 0, 8}},
+ {0x1FA8, 0x1FAF, d{0, -8, 0}},
+ {0x1FB0, 0x1FB1, d{8, 0, 8}},
+ {0x1FB3, 0x1FB3, d{9, 0, 9}},
+ {0x1FB8, 0x1FB9, d{0, -8, 0}},
+ {0x1FBA, 0x1FBB, d{0, -74, 0}},
+ {0x1FBC, 0x1FBC, d{0, -9, 0}},
+ {0x1FBE, 0x1FBE, d{-7205, 0, -7205}},
+ {0x1FC3, 0x1FC3, d{9, 0, 9}},
+ {0x1FC8, 0x1FCB, d{0, -86, 0}},
+ {0x1FCC, 0x1FCC, d{0, -9, 0}},
+ {0x1FD0, 0x1FD1, d{8, 0, 8}},
+ {0x1FD8, 0x1FD9, d{0, -8, 0}},
+ {0x1FDA, 0x1FDB, d{0, -100, 0}},
+ {0x1FE0, 0x1FE1, d{8, 0, 8}},
+ {0x1FE5, 0x1FE5, d{7, 0, 7}},
+ {0x1FE8, 0x1FE9, d{0, -8, 0}},
+ {0x1FEA, 0x1FEB, d{0, -112, 0}},
+ {0x1FEC, 0x1FEC, d{0, -7, 0}},
+ {0x1FF3, 0x1FF3, d{9, 0, 9}},
+ {0x1FF8, 0x1FF9, d{0, -128, 0}},
+ {0x1FFA, 0x1FFB, d{0, -126, 0}},
+ {0x1FFC, 0x1FFC, d{0, -9, 0}},
+ {0x2126, 0x2126, d{0, -7517, 0}},
+ {0x212A, 0x212A, d{0, -8383, 0}},
+ {0x212B, 0x212B, d{0, -8262, 0}},
+ {0x2132, 0x2132, d{0, 28, 0}},
+ {0x214E, 0x214E, d{-28, 0, -28}},
+ {0x2183, 0x2184, d{UpperLower, UpperLower, UpperLower}},
+ {0x2C00, 0x2C2E, d{0, 48, 0}},
+ {0x2C30, 0x2C5E, d{-48, 0, -48}},
+ {0x2C60, 0x2C61, d{UpperLower, UpperLower, UpperLower}},
+ {0x2C62, 0x2C62, d{0, -10743, 0}},
+ {0x2C63, 0x2C63, d{0, -3814, 0}},
+ {0x2C64, 0x2C64, d{0, -10727, 0}},
+ {0x2C65, 0x2C65, d{-10795, 0, -10795}},
+ {0x2C66, 0x2C66, d{-10792, 0, -10792}},
+ {0x2C67, 0x2C6C, d{UpperLower, UpperLower, UpperLower}},
+ {0x2C6D, 0x2C6D, d{0, -10780, 0}},
+ {0x2C6E, 0x2C6E, d{0, -10749, 0}},
+ {0x2C6F, 0x2C6F, d{0, -10783, 0}},
+ {0x2C70, 0x2C70, d{0, -10782, 0}},
+ {0x2C72, 0x2C73, d{UpperLower, UpperLower, UpperLower}},
+ {0x2C75, 0x2C76, d{UpperLower, UpperLower, UpperLower}},
+ {0x2C7E, 0x2C7F, d{0, -10815, 0}},
+ {0x2C80, 0x2CE3, d{UpperLower, UpperLower, UpperLower}},
+ {0x2CEB, 0x2CEE, d{UpperLower, UpperLower, UpperLower}},
+ {0x2D00, 0x2D25, d{-7264, 0, -7264}},
+ {0xA640, 0xA65F, d{UpperLower, UpperLower, UpperLower}},
+ {0xA662, 0xA66D, d{UpperLower, UpperLower, UpperLower}},
+ {0xA680, 0xA697, d{UpperLower, UpperLower, UpperLower}},
+ {0xA722, 0xA72F, d{UpperLower, UpperLower, UpperLower}},
+ {0xA732, 0xA76F, d{UpperLower, UpperLower, UpperLower}},
+ {0xA779, 0xA77C, d{UpperLower, UpperLower, UpperLower}},
+ {0xA77D, 0xA77D, d{0, -35332, 0}},
+ {0xA77E, 0xA787, d{UpperLower, UpperLower, UpperLower}},
+ {0xA78B, 0xA78C, d{UpperLower, UpperLower, UpperLower}},
+ {0xFF21, 0xFF3A, d{0, 32, 0}},
+ {0xFF41, 0xFF5A, d{-32, 0, -32}},
+ {0x10400, 0x10427, d{0, 40, 0}},
+ {0x10428, 0x1044F, d{-40, 0, -40}},
+}
diff --git a/libgo/go/utf16/utf16.go b/libgo/go/utf16/utf16.go
new file mode 100644
index 000000000..372e38a71
--- /dev/null
+++ b/libgo/go/utf16/utf16.go
@@ -0,0 +1,101 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package utf16 implements encoding and decoding of UTF-16 sequences.
+package utf16
+
+import "unicode"
+
+const (
+ // 0xd800-0xdc00 encodes the high 10 bits of a pair.
+ // 0xdc00-0xe000 encodes the low 10 bits of a pair.
+ // the value is those 20 bits plus 0x10000.
+ surr1 = 0xd800
+ surr2 = 0xdc00
+ surr3 = 0xe000
+
+ surrSelf = 0x10000
+)
+
+// IsSurrogate returns true if the specified Unicode code point
+// can appear in a surrogate pair.
+func IsSurrogate(rune int) bool {
+ return surr1 <= rune && rune < surr3
+}
+
+// DecodeRune returns the UTF-16 decoding of a surrogate pair.
+// If the pair is not a valid UTF-16 surrogate pair, DecodeRune returns
+// the Unicode replacement code point U+FFFD.
+func DecodeRune(r1, r2 int) int {
+ if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 {
+ return (int(r1)-surr1)<<10 | (int(r2) - surr2) + 0x10000
+ }
+ return unicode.ReplacementChar
+}
+
+// EncodeRune returns the UTF-16 surrogate pair r1, r2 for the given rune.
+// If the rune is not a valid Unicode code point or does not need encoding,
+// EncodeRune returns U+FFFD, U+FFFD.
+func EncodeRune(rune int) (r1, r2 int) {
+ if rune < surrSelf || rune > unicode.MaxRune || IsSurrogate(rune) {
+ return unicode.ReplacementChar, unicode.ReplacementChar
+ }
+ rune -= surrSelf
+ return surr1 + (rune>>10)&0x3ff, surr2 + rune&0x3ff
+}
+
+// Encode returns the UTF-16 encoding of the Unicode code point sequence s.
+func Encode(s []int) []uint16 {
+ n := len(s)
+ for _, v := range s {
+ if v >= surrSelf {
+ n++
+ }
+ }
+
+ a := make([]uint16, n)
+ n = 0
+ for _, v := range s {
+ switch {
+ case v < 0, surr1 <= v && v < surr3, v > unicode.MaxRune:
+ v = unicode.ReplacementChar
+ fallthrough
+ case v < surrSelf:
+ a[n] = uint16(v)
+ n++
+ default:
+ r1, r2 := EncodeRune(v)
+ a[n] = uint16(r1)
+ a[n+1] = uint16(r2)
+ n += 2
+ }
+ }
+ return a[0:n]
+}
+
+// Decode returns the Unicode code point sequence represented
+// by the UTF-16 encoding s.
+func Decode(s []uint16) []int {
+ a := make([]int, len(s))
+ n := 0
+ for i := 0; i < len(s); i++ {
+ switch r := s[i]; {
+ case surr1 <= r && r < surr2 && i+1 < len(s) &&
+ surr2 <= s[i+1] && s[i+1] < surr3:
+ // valid surrogate sequence
+ a[n] = DecodeRune(int(r), int(s[i+1]))
+ i++
+ n++
+ case surr1 <= r && r < surr3:
+ // invalid surrogate sequence
+ a[n] = unicode.ReplacementChar
+ n++
+ default:
+ // normal rune
+ a[n] = int(r)
+ n++
+ }
+ }
+ return a[0:n]
+}
diff --git a/libgo/go/utf16/utf16_test.go b/libgo/go/utf16/utf16_test.go
new file mode 100644
index 000000000..2b9fb3d87
--- /dev/null
+++ b/libgo/go/utf16/utf16_test.go
@@ -0,0 +1,118 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf16_test
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+ "unicode"
+ . "utf16"
+)
+
+type encodeTest struct {
+ in []int
+ out []uint16
+}
+
+var encodeTests = []encodeTest{
+ {[]int{1, 2, 3, 4}, []uint16{1, 2, 3, 4}},
+ {[]int{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff},
+ []uint16{0xffff, 0xd800, 0xdc00, 0xd800, 0xdc01, 0xd808, 0xdf45, 0xdbff, 0xdfff}},
+ {[]int{'a', 'b', 0xd7ff, 0xd800, 0xdfff, 0xe000, 0x110000, -1},
+ []uint16{'a', 'b', 0xd7ff, 0xfffd, 0xfffd, 0xe000, 0xfffd, 0xfffd}},
+}
+
+func TestEncode(t *testing.T) {
+ for _, tt := range encodeTests {
+ out := Encode(tt.in)
+ if !reflect.DeepEqual(out, tt.out) {
+ t.Errorf("Encode(%v) = %v; want %v", hex(tt.in), hex16(out), hex16(tt.out))
+ }
+ }
+}
+
+func TestEncodeRune(t *testing.T) {
+ for i, tt := range encodeTests {
+ j := 0
+ for _, r := range tt.in {
+ r1, r2 := EncodeRune(r)
+ if r < 0x10000 || r > unicode.MaxRune {
+ if j >= len(tt.out) {
+ t.Errorf("#%d: ran out of tt.out", i)
+ break
+ }
+ if r1 != unicode.ReplacementChar || r2 != unicode.ReplacementChar {
+ t.Errorf("EncodeRune(%#x) = %#x, %#x; want 0xfffd, 0xfffd", r, r1, r2)
+ }
+ j++
+ } else {
+ if j+1 >= len(tt.out) {
+ t.Errorf("#%d: ran out of tt.out", i)
+ break
+ }
+ if r1 != int(tt.out[j]) || r2 != int(tt.out[j+1]) {
+ t.Errorf("EncodeRune(%#x) = %#x, %#x; want %#x, %#x", r, r1, r2, tt.out[j], tt.out[j+1])
+ }
+ j += 2
+ dec := DecodeRune(r1, r2)
+ if dec != r {
+ t.Errorf("DecodeRune(%#x, %#x) = %#x; want %#x", r1, r2, dec, r)
+ }
+ }
+ }
+ if j != len(tt.out) {
+ t.Errorf("#%d: EncodeRune didn't generate enough output", i)
+ }
+ }
+}
+
+type decodeTest struct {
+ in []uint16
+ out []int
+}
+
+var decodeTests = []decodeTest{
+ {[]uint16{1, 2, 3, 4}, []int{1, 2, 3, 4}},
+ {[]uint16{0xffff, 0xd800, 0xdc00, 0xd800, 0xdc01, 0xd808, 0xdf45, 0xdbff, 0xdfff},
+ []int{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff}},
+ {[]uint16{0xd800, 'a'}, []int{0xfffd, 'a'}},
+ {[]uint16{0xdfff}, []int{0xfffd}},
+}
+
+func TestDecode(t *testing.T) {
+ for _, tt := range decodeTests {
+ out := Decode(tt.in)
+ if !reflect.DeepEqual(out, tt.out) {
+ t.Errorf("Decode(%v) = %v; want %v", hex16(tt.in), hex(out), hex(tt.out))
+ }
+ }
+}
+
+type hex []int
+
+func (h hex) Format(f fmt.State, c int) {
+ fmt.Fprint(f, "[")
+ for i, v := range h {
+ if i > 0 {
+ fmt.Fprint(f, " ")
+ }
+ fmt.Fprintf(f, "%x", v)
+ }
+ fmt.Fprint(f, "]")
+}
+
+type hex16 []uint16
+
+func (h hex16) Format(f fmt.State, c int) {
+ fmt.Fprint(f, "[")
+ for i, v := range h {
+ if i > 0 {
+ fmt.Fprint(f, " ")
+ }
+ fmt.Fprintf(f, "%x", v)
+ }
+ fmt.Fprint(f, "]")
+}
diff --git a/libgo/go/utf8/string.go b/libgo/go/utf8/string.go
new file mode 100644
index 000000000..83b56b944
--- /dev/null
+++ b/libgo/go/utf8/string.go
@@ -0,0 +1,211 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf8
+
+// String wraps a regular string with a small structure that provides more
+// efficient indexing by code point index, as opposed to byte index.
+// Scanning incrementally forwards or backwards is O(1) per index operation
+// (although not as fast a range clause going forwards). Random access is
+// O(N) in the length of the string, but the overhead is less than always
+// scanning from the beginning.
+// If the string is ASCII, random access is O(1).
+// Unlike the built-in string type, String has internal mutable state and
+// is not thread-safe.
+type String struct {
+ str string
+ numRunes int
+ // If width > 0, the rune at runePos starts at bytePos and has the specified width.
+ width int
+ bytePos int
+ runePos int
+ nonASCII int // byte index of the first non-ASCII rune.
+}
+
+// NewString returns a new UTF-8 string with the provided contents.
+func NewString(contents string) *String {
+ return new(String).Init(contents)
+}
+
+// Init initializes an existing String to hold the provided contents.
+// It returns a pointer to the initialized String.
+func (s *String) Init(contents string) *String {
+ s.str = contents
+ s.bytePos = 0
+ s.runePos = 0
+ for i := 0; i < len(contents); i++ {
+ if contents[i] >= RuneSelf {
+ // Not ASCII.
+ s.numRunes = RuneCountInString(contents)
+ _, s.width = DecodeRuneInString(contents)
+ s.nonASCII = i
+ return s
+ }
+ }
+ // ASCII is simple. Also, the empty string is ASCII.
+ s.numRunes = len(contents)
+ s.width = 0
+ s.nonASCII = len(contents)
+ return s
+}
+
+// String returns the contents of the String. This method also means the
+// String is directly printable by fmt.Print.
+func (s *String) String() string {
+ return s.str
+}
+
+// RuneCount returns the number of runes (Unicode code points) in the String.
+func (s *String) RuneCount() int {
+ return s.numRunes
+}
+
+// IsASCII returns a boolean indicating whether the String contains only ASCII bytes.
+func (s *String) IsASCII() bool {
+ return s.width == 0
+}
+
+// Slice returns the string sliced at rune positions [i:j].
+func (s *String) Slice(i, j int) string {
+ // ASCII is easy. Let the compiler catch the indexing error if there is one.
+ if j < s.nonASCII {
+ return s.str[i:j]
+ }
+ if i < 0 || j > s.numRunes || i > j {
+ panic(sliceOutOfRange)
+ }
+ if i == j {
+ return ""
+ }
+ // For non-ASCII, after At(i), bytePos is always the position of the indexed character.
+ var low, high int
+ switch {
+ case i < s.nonASCII:
+ low = i
+ case i == s.numRunes:
+ low = len(s.str)
+ default:
+ s.At(i)
+ low = s.bytePos
+ }
+ switch {
+ case j == s.numRunes:
+ high = len(s.str)
+ default:
+ s.At(j)
+ high = s.bytePos
+ }
+ return s.str[low:high]
+}
+
+// At returns the rune with index i in the String. The sequence of runes is the same
+// as iterating over the contents with a "for range" clause.
+func (s *String) At(i int) int {
+ // ASCII is easy. Let the compiler catch the indexing error if there is one.
+ if i < s.nonASCII {
+ return int(s.str[i])
+ }
+
+ // Now we do need to know the index is valid.
+ if i < 0 || i >= s.numRunes {
+ panic(outOfRange)
+ }
+
+ var rune int
+
+ // Five easy common cases: within 1 spot of bytePos/runePos, or the beginning, or the end.
+ // With these cases, all scans from beginning or end work in O(1) time per rune.
+ switch {
+
+ case i == s.runePos-1: // backing up one rune
+ rune, s.width = DecodeLastRuneInString(s.str[0:s.bytePos])
+ s.runePos = i
+ s.bytePos -= s.width
+ return rune
+ case i == s.runePos+1: // moving ahead one rune
+ s.runePos = i
+ s.bytePos += s.width
+ fallthrough
+ case i == s.runePos:
+ rune, s.width = DecodeRuneInString(s.str[s.bytePos:])
+ return rune
+ case i == 0: // start of string
+ rune, s.width = DecodeRuneInString(s.str)
+ s.runePos = 0
+ s.bytePos = 0
+ return rune
+
+ case i == s.numRunes-1: // last rune in string
+ rune, s.width = DecodeLastRuneInString(s.str)
+ s.runePos = i
+ s.bytePos = len(s.str) - s.width
+ return rune
+ }
+
+ // We need to do a linear scan. There are three places to start from:
+ // 1) The beginning
+ // 2) bytePos/runePos.
+ // 3) The end
+ // Choose the closest in rune count, scanning backwards if necessary.
+ forward := true
+ if i < s.runePos {
+ // Between beginning and pos. Which is closer?
+ // Since both i and runePos are guaranteed >= nonASCII, that's the
+ // lowest location we need to start from.
+ if i < (s.runePos-s.nonASCII)/2 {
+ // Scan forward from beginning
+ s.bytePos, s.runePos = s.nonASCII, s.nonASCII
+ } else {
+ // Scan backwards from where we are
+ forward = false
+ }
+ } else {
+ // Between pos and end. Which is closer?
+ if i-s.runePos < (s.numRunes-s.runePos)/2 {
+ // Scan forward from pos
+ } else {
+ // Scan backwards from end
+ s.bytePos, s.runePos = len(s.str), s.numRunes
+ forward = false
+ }
+ }
+ if forward {
+ // TODO: Is it much faster to use a range loop for this scan?
+ for {
+ rune, s.width = DecodeRuneInString(s.str[s.bytePos:])
+ if s.runePos == i {
+ break
+ }
+ s.runePos++
+ s.bytePos += s.width
+ }
+ } else {
+ for {
+ rune, s.width = DecodeLastRuneInString(s.str[0:s.bytePos])
+ s.runePos--
+ s.bytePos -= s.width
+ if s.runePos == i {
+ break
+ }
+ }
+ }
+ return rune
+}
+
+// We want the panic in At(i) to satisfy os.Error, because that's what
+// runtime panics satisfy, but we can't import os. This is our solution.
+
+// error is the type of the error returned if a user calls String.At(i) with i out of range.
+// It satisfies os.Error and runtime.Error.
+type error string
+
+func (err error) String() string {
+ return string(err)
+}
+
+func (err error) RunTimeError() {
+}
+
+var outOfRange = error("utf8.String: index out of range")
+var sliceOutOfRange = error("utf8.String: slice index out of range")
diff --git a/libgo/go/utf8/string_test.go b/libgo/go/utf8/string_test.go
new file mode 100644
index 000000000..9dd847247
--- /dev/null
+++ b/libgo/go/utf8/string_test.go
@@ -0,0 +1,109 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf8_test
+
+import (
+ "rand"
+ "testing"
+ . "utf8"
+)
+
+func TestScanForwards(t *testing.T) {
+ for _, s := range testStrings {
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for i, expect := range runes {
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+func TestScanBackwards(t *testing.T) {
+ for _, s := range testStrings {
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for i := len(runes) - 1; i >= 0; i-- {
+ expect := runes[i]
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+const randCount = 100000
+
+func TestRandomAccess(t *testing.T) {
+ for _, s := range testStrings {
+ if len(s) == 0 {
+ continue
+ }
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for j := 0; j < randCount; j++ {
+ i := rand.Intn(len(runes))
+ expect := runes[i]
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+func TestRandomSliceAccess(t *testing.T) {
+ for _, s := range testStrings {
+ if len(s) == 0 || s[0] == '\x80' { // the bad-UTF-8 string fools this simple test
+ continue
+ }
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for k := 0; k < randCount; k++ {
+ i := rand.Intn(len(runes))
+ j := rand.Intn(len(runes) + 1)
+ if i > j { // include empty strings
+ continue
+ }
+ expect := string(runes[i:j])
+ got := str.Slice(i, j)
+ if got != expect {
+ t.Errorf("%s[%d:%d]: expected %q got %q", s, i, j, expect, got)
+ }
+ }
+ }
+}
+
+func TestLimitSliceAccess(t *testing.T) {
+ for _, s := range testStrings {
+ str := NewString(s)
+ if str.Slice(0, 0) != "" {
+ t.Error("failure with empty slice at beginning")
+ }
+ nr := RuneCountInString(s)
+ if str.Slice(nr, nr) != "" {
+ t.Error("failure with empty slice at end")
+ }
+ }
+}
diff --git a/libgo/go/utf8/utf8.go b/libgo/go/utf8/utf8.go
new file mode 100644
index 000000000..455499e4d
--- /dev/null
+++ b/libgo/go/utf8/utf8.go
@@ -0,0 +1,356 @@
+// 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.
+
+// Functions and constants to support text encoded in UTF-8.
+// This package calls a Unicode character a rune for brevity.
+package utf8
+
+import "unicode" // only needed for a couple of constants
+
+// Numbers fundamental to the encoding.
+const (
+ RuneError = unicode.ReplacementChar // the "error" Rune or "replacement character".
+ RuneSelf = 0x80 // characters below Runeself are represented as themselves in a single byte.
+ UTFMax = 4 // maximum number of bytes of a UTF-8 encoded Unicode character.
+)
+
+const (
+ _T1 = 0x00 // 0000 0000
+ _Tx = 0x80 // 1000 0000
+ _T2 = 0xC0 // 1100 0000
+ _T3 = 0xE0 // 1110 0000
+ _T4 = 0xF0 // 1111 0000
+ _T5 = 0xF8 // 1111 1000
+
+ _Maskx = 0x3F // 0011 1111
+ _Mask2 = 0x1F // 0001 1111
+ _Mask3 = 0x0F // 0000 1111
+ _Mask4 = 0x07 // 0000 0111
+
+ _Rune1Max = 1<<7 - 1
+ _Rune2Max = 1<<11 - 1
+ _Rune3Max = 1<<16 - 1
+ _Rune4Max = 1<<21 - 1
+)
+
+func decodeRuneInternal(p []byte) (rune, size int, short bool) {
+ n := len(p)
+ if n < 1 {
+ return RuneError, 0, true
+ }
+ c0 := p[0]
+
+ // 1-byte, 7-bit sequence?
+ if c0 < _Tx {
+ return int(c0), 1, false
+ }
+
+ // unexpected continuation byte?
+ if c0 < _T2 {
+ return RuneError, 1, false
+ }
+
+ // need first continuation byte
+ if n < 2 {
+ return RuneError, 1, true
+ }
+ c1 := p[1]
+ if c1 < _Tx || _T2 <= c1 {
+ return RuneError, 1, false
+ }
+
+ // 2-byte, 11-bit sequence?
+ if c0 < _T3 {
+ rune = int(c0&_Mask2)<<6 | int(c1&_Maskx)
+ if rune <= _Rune1Max {
+ return RuneError, 1, false
+ }
+ return rune, 2, false
+ }
+
+ // need second continuation byte
+ if n < 3 {
+ return RuneError, 1, true
+ }
+ c2 := p[2]
+ if c2 < _Tx || _T2 <= c2 {
+ return RuneError, 1, false
+ }
+
+ // 3-byte, 16-bit sequence?
+ if c0 < _T4 {
+ rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx)
+ if rune <= _Rune2Max {
+ return RuneError, 1, false
+ }
+ return rune, 3, false
+ }
+
+ // need third continuation byte
+ if n < 4 {
+ return RuneError, 1, true
+ }
+ c3 := p[3]
+ if c3 < _Tx || _T2 <= c3 {
+ return RuneError, 1, false
+ }
+
+ // 4-byte, 21-bit sequence?
+ if c0 < _T5 {
+ rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+ if rune <= _Rune3Max {
+ return RuneError, 1, false
+ }
+ return rune, 4, false
+ }
+
+ // error
+ return RuneError, 1, false
+}
+
+func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
+ n := len(s)
+ if n < 1 {
+ return RuneError, 0, true
+ }
+ c0 := s[0]
+
+ // 1-byte, 7-bit sequence?
+ if c0 < _Tx {
+ return int(c0), 1, false
+ }
+
+ // unexpected continuation byte?
+ if c0 < _T2 {
+ return RuneError, 1, false
+ }
+
+ // need first continuation byte
+ if n < 2 {
+ return RuneError, 1, true
+ }
+ c1 := s[1]
+ if c1 < _Tx || _T2 <= c1 {
+ return RuneError, 1, false
+ }
+
+ // 2-byte, 11-bit sequence?
+ if c0 < _T3 {
+ rune = int(c0&_Mask2)<<6 | int(c1&_Maskx)
+ if rune <= _Rune1Max {
+ return RuneError, 1, false
+ }
+ return rune, 2, false
+ }
+
+ // need second continuation byte
+ if n < 3 {
+ return RuneError, 1, true
+ }
+ c2 := s[2]
+ if c2 < _Tx || _T2 <= c2 {
+ return RuneError, 1, false
+ }
+
+ // 3-byte, 16-bit sequence?
+ if c0 < _T4 {
+ rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx)
+ if rune <= _Rune2Max {
+ return RuneError, 1, false
+ }
+ return rune, 3, false
+ }
+
+ // need third continuation byte
+ if n < 4 {
+ return RuneError, 1, true
+ }
+ c3 := s[3]
+ if c3 < _Tx || _T2 <= c3 {
+ return RuneError, 1, false
+ }
+
+ // 4-byte, 21-bit sequence?
+ if c0 < _T5 {
+ rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
+ if rune <= _Rune3Max {
+ return RuneError, 1, false
+ }
+ return rune, 4, false
+ }
+
+ // error
+ return RuneError, 1, false
+}
+
+// FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.
+// An invalid encoding is considered a full Rune since it will convert as a width-1 error rune.
+func FullRune(p []byte) bool {
+ _, _, short := decodeRuneInternal(p)
+ return !short
+}
+
+// FullRuneInString is like FullRune but its input is a string.
+func FullRuneInString(s string) bool {
+ _, _, short := decodeRuneInStringInternal(s)
+ return !short
+}
+
+// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
+func DecodeRune(p []byte) (rune, size int) {
+ rune, size, _ = decodeRuneInternal(p)
+ return
+}
+
+// DecodeRuneInString is like DecodeRune but its input is a string.
+func DecodeRuneInString(s string) (rune, size int) {
+ rune, size, _ = decodeRuneInStringInternal(s)
+ return
+}
+
+// DecodeLastRune unpacks the last UTF-8 encoding in p
+// and returns the rune and its width in bytes.
+func DecodeLastRune(p []byte) (rune, size int) {
+ end := len(p)
+ if end == 0 {
+ return RuneError, 0
+ }
+ start := end - 1
+ rune = int(p[start])
+ if rune < RuneSelf {
+ return rune, 1
+ }
+ // guard against O(n^2) behavior when traversing
+ // backwards through strings with long sequences of
+ // invalid UTF-8.
+ lim := end - UTFMax
+ if lim < 0 {
+ lim = 0
+ }
+ for start--; start >= lim; start-- {
+ if RuneStart(p[start]) {
+ break
+ }
+ }
+ if start < 0 {
+ start = 0
+ }
+ rune, size = DecodeRune(p[start:end])
+ if start+size != end {
+ return RuneError, 1
+ }
+ return rune, size
+}
+
+// DecodeLastRuneInString is like DecodeLastRune but its input is a string.
+func DecodeLastRuneInString(s string) (rune, size int) {
+ end := len(s)
+ if end == 0 {
+ return RuneError, 0
+ }
+ start := end - 1
+ rune = int(s[start])
+ if rune < RuneSelf {
+ return rune, 1
+ }
+ // guard against O(n^2) behavior when traversing
+ // backwards through strings with long sequences of
+ // invalid UTF-8.
+ lim := end - UTFMax
+ if lim < 0 {
+ lim = 0
+ }
+ for start--; start >= lim; start-- {
+ if RuneStart(s[start]) {
+ break
+ }
+ }
+ if start < 0 {
+ start = 0
+ }
+ rune, size = DecodeRuneInString(s[start:end])
+ if start+size != end {
+ return RuneError, 1
+ }
+ return rune, size
+}
+
+// RuneLen returns the number of bytes required to encode the rune.
+func RuneLen(rune int) int {
+ switch {
+ case rune <= _Rune1Max:
+ return 1
+ case rune <= _Rune2Max:
+ return 2
+ case rune <= _Rune3Max:
+ return 3
+ case rune <= _Rune4Max:
+ return 4
+ }
+ return -1
+}
+
+// EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
+// It returns the number of bytes written.
+func EncodeRune(p []byte, rune int) int {
+ // Negative values are erroneous. Making it unsigned addresses the problem.
+ r := uint(rune)
+
+ if r <= _Rune1Max {
+ p[0] = byte(r)
+ return 1
+ }
+
+ if r <= _Rune2Max {
+ p[0] = _T2 | byte(r>>6)
+ p[1] = _Tx | byte(r)&_Maskx
+ return 2
+ }
+
+ if r > unicode.MaxRune {
+ r = RuneError
+ }
+
+ if r <= _Rune3Max {
+ p[0] = _T3 | byte(r>>12)
+ p[1] = _Tx | byte(r>>6)&_Maskx
+ p[2] = _Tx | byte(r)&_Maskx
+ return 3
+ }
+
+ p[0] = _T4 | byte(r>>18)
+ p[1] = _Tx | byte(r>>12)&_Maskx
+ p[2] = _Tx | byte(r>>6)&_Maskx
+ p[3] = _Tx | byte(r)&_Maskx
+ return 4
+}
+
+// RuneCount returns the number of runes in p. Erroneous and short
+// encodings are treated as single runes of width 1 byte.
+func RuneCount(p []byte) int {
+ i := 0
+ var n int
+ for n = 0; i < len(p); n++ {
+ if p[i] < RuneSelf {
+ i++
+ } else {
+ _, size := DecodeRune(p[i:])
+ i += size
+ }
+ }
+ return n
+}
+
+// RuneCountInString is like RuneCount but its input is a string.
+func RuneCountInString(s string) (n int) {
+ for _ = range s {
+ n++
+ }
+ return
+}
+
+// RuneStart reports whether the byte could be the first byte of
+// an encoded rune. Second and subsequent bytes always have the top
+// two bits set to 10.
+func RuneStart(b byte) bool { return b&0xC0 != 0x80 }
diff --git a/libgo/go/utf8/utf8_test.go b/libgo/go/utf8/utf8_test.go
new file mode 100644
index 000000000..7a1db93e5
--- /dev/null
+++ b/libgo/go/utf8/utf8_test.go
@@ -0,0 +1,315 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf8_test
+
+import (
+ "bytes"
+ "testing"
+ . "utf8"
+)
+
+type Utf8Map struct {
+ rune int
+ str string
+}
+
+var utf8map = []Utf8Map{
+ {0x0000, "\x00"},
+ {0x0001, "\x01"},
+ {0x007e, "\x7e"},
+ {0x007f, "\x7f"},
+ {0x0080, "\xc2\x80"},
+ {0x0081, "\xc2\x81"},
+ {0x00bf, "\xc2\xbf"},
+ {0x00c0, "\xc3\x80"},
+ {0x00c1, "\xc3\x81"},
+ {0x00c8, "\xc3\x88"},
+ {0x00d0, "\xc3\x90"},
+ {0x00e0, "\xc3\xa0"},
+ {0x00f0, "\xc3\xb0"},
+ {0x00f8, "\xc3\xb8"},
+ {0x00ff, "\xc3\xbf"},
+ {0x0100, "\xc4\x80"},
+ {0x07ff, "\xdf\xbf"},
+ {0x0800, "\xe0\xa0\x80"},
+ {0x0801, "\xe0\xa0\x81"},
+ {0xfffe, "\xef\xbf\xbe"},
+ {0xffff, "\xef\xbf\xbf"},
+ {0x10000, "\xf0\x90\x80\x80"},
+ {0x10001, "\xf0\x90\x80\x81"},
+ {0x10fffe, "\xf4\x8f\xbf\xbe"},
+ {0x10ffff, "\xf4\x8f\xbf\xbf"},
+ {0xFFFD, "\xef\xbf\xbd"},
+}
+
+var testStrings = []string{
+ "",
+ "abcd",
+ "☺☻☹",
+ "日a本b語ç日ð本Ê語þ日¥本¼語i日©",
+ "日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©",
+ "\x80\x80\x80\x80",
+}
+
+func TestFullRune(t *testing.T) {
+ for i := 0; i < len(utf8map); i++ {
+ m := utf8map[i]
+ b := []byte(m.str)
+ if !FullRune(b) {
+ t.Errorf("FullRune(%q) (%U) = false, want true", b, m.rune)
+ }
+ s := m.str
+ if !FullRuneInString(s) {
+ t.Errorf("FullRuneInString(%q) (%U) = false, want true", s, m.rune)
+ }
+ b1 := b[0 : len(b)-1]
+ if FullRune(b1) {
+ t.Errorf("FullRune(%q) = true, want false", b1)
+ }
+ s1 := string(b1)
+ if FullRuneInString(s1) {
+ t.Errorf("FullRune(%q) = true, want false", s1)
+ }
+ }
+}
+
+func TestEncodeRune(t *testing.T) {
+ for i := 0; i < len(utf8map); i++ {
+ m := utf8map[i]
+ b := []byte(m.str)
+ var buf [10]byte
+ n := EncodeRune(buf[0:], m.rune)
+ b1 := buf[0:n]
+ if !bytes.Equal(b, b1) {
+ t.Errorf("EncodeRune(%#04x) = %q want %q", m.rune, b1, b)
+ }
+ }
+}
+
+func TestDecodeRune(t *testing.T) {
+ for i := 0; i < len(utf8map); i++ {
+ m := utf8map[i]
+ b := []byte(m.str)
+ rune, size := DecodeRune(b)
+ if rune != m.rune || size != len(b) {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
+ }
+ s := m.str
+ rune, size = DecodeRuneInString(s)
+ if rune != m.rune || size != len(b) {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
+ }
+
+ // there's an extra byte that bytes left behind - make sure trailing byte works
+ rune, size = DecodeRune(b[0:cap(b)])
+ if rune != m.rune || size != len(b) {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
+ }
+ s = m.str + "\x00"
+ rune, size = DecodeRuneInString(s)
+ if rune != m.rune || size != len(b) {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
+ }
+
+ // make sure missing bytes fail
+ wantsize := 1
+ if wantsize >= len(b) {
+ wantsize = 0
+ }
+ rune, size = DecodeRune(b[0 : len(b)-1])
+ if rune != RuneError || size != wantsize {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b[0:len(b)-1], rune, size, RuneError, wantsize)
+ }
+ s = m.str[0 : len(m.str)-1]
+ rune, size = DecodeRuneInString(s)
+ if rune != RuneError || size != wantsize {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, wantsize)
+ }
+
+ // make sure bad sequences fail
+ if len(b) == 1 {
+ b[0] = 0x80
+ } else {
+ b[len(b)-1] = 0x7F
+ }
+ rune, size = DecodeRune(b)
+ if rune != RuneError || size != 1 {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, RuneError, 1)
+ }
+ s = string(b)
+ rune, size = DecodeRune(b)
+ if rune != RuneError || size != 1 {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, 1)
+ }
+
+ }
+}
+
+// Check that DecodeRune and DecodeLastRune correspond to
+// the equivalent range loop.
+func TestSequencing(t *testing.T) {
+ for _, ts := range testStrings {
+ for _, m := range utf8map {
+ for _, s := range []string{ts + m.str, m.str + ts, ts + m.str + ts} {
+ testSequence(t, s)
+ }
+ }
+ }
+}
+
+// Check that a range loop and a []int conversion visit the same runes.
+// Not really a test of this package, but the assumption is used here and
+// it's good to verify
+func TestIntConversion(t *testing.T) {
+ for _, ts := range testStrings {
+ runes := []int(ts)
+ if RuneCountInString(ts) != len(runes) {
+ t.Errorf("%q: expected %d runes; got %d", ts, len(runes), RuneCountInString(ts))
+ break
+ }
+ i := 0
+ for _, r := range ts {
+ if r != runes[i] {
+ t.Errorf("%q[%d]: expected %c (%U); got %c (%U)", ts, i, runes[i], runes[i], r, r)
+ }
+ i++
+ }
+ }
+}
+
+func testSequence(t *testing.T, s string) {
+ type info struct {
+ index int
+ rune int
+ }
+ index := make([]info, len(s))
+ b := []byte(s)
+ si := 0
+ j := 0
+ for i, r := range s {
+ if si != i {
+ t.Errorf("Sequence(%q) mismatched index %d, want %d", s, si, i)
+ return
+ }
+ index[j] = info{i, r}
+ j++
+ rune1, size1 := DecodeRune(b[i:])
+ if r != rune1 {
+ t.Errorf("DecodeRune(%q) = %#04x, want %#04x", s[i:], rune1, r)
+ return
+ }
+ rune2, size2 := DecodeRuneInString(s[i:])
+ if r != rune2 {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, want %#04x", s[i:], rune2, r)
+ return
+ }
+ if size1 != size2 {
+ t.Errorf("DecodeRune/DecodeRuneInString(%q) size mismatch %d/%d", s[i:], size1, size2)
+ return
+ }
+ si += size1
+ }
+ j--
+ for si = len(s); si > 0; {
+ rune1, size1 := DecodeLastRune(b[0:si])
+ rune2, size2 := DecodeLastRuneInString(s[0:si])
+ if size1 != size2 {
+ t.Errorf("DecodeLastRune/DecodeLastRuneInString(%q, %d) size mismatch %d/%d", s, si, size1, size2)
+ return
+ }
+ if rune1 != index[j].rune {
+ t.Errorf("DecodeLastRune(%q, %d) = %#04x, want %#04x", s, si, rune1, index[j].rune)
+ return
+ }
+ if rune2 != index[j].rune {
+ t.Errorf("DecodeLastRuneInString(%q, %d) = %#04x, want %#04x", s, si, rune2, index[j].rune)
+ return
+ }
+ si -= size1
+ if si != index[j].index {
+ t.Errorf("DecodeLastRune(%q) index mismatch at %d, want %d", s, si, index[j].index)
+ return
+ }
+ j--
+ }
+ if si != 0 {
+ t.Errorf("DecodeLastRune(%q) finished at %d, not 0", s, si)
+ }
+}
+
+// Check that negative runes encode as U+FFFD.
+func TestNegativeRune(t *testing.T) {
+ errorbuf := make([]byte, UTFMax)
+ errorbuf = errorbuf[0:EncodeRune(errorbuf, RuneError)]
+ buf := make([]byte, UTFMax)
+ buf = buf[0:EncodeRune(buf, -1)]
+ if !bytes.Equal(buf, errorbuf) {
+ t.Errorf("incorrect encoding [% x] for -1; expected [% x]", buf, errorbuf)
+ }
+}
+
+type RuneCountTest struct {
+ in string
+ out int
+}
+
+var runecounttests = []RuneCountTest{
+ {"abcd", 4},
+ {"☺☻☹", 3},
+ {"1,2,3,4", 7},
+ {"\xe2\x00", 2},
+}
+
+func TestRuneCount(t *testing.T) {
+ for i := 0; i < len(runecounttests); i++ {
+ tt := runecounttests[i]
+ if out := RuneCountInString(tt.in); out != tt.out {
+ t.Errorf("RuneCountInString(%q) = %d, want %d", tt.in, out, tt.out)
+ }
+ if out := RuneCount([]byte(tt.in)); out != tt.out {
+ t.Errorf("RuneCount(%q) = %d, want %d", tt.in, out, tt.out)
+ }
+ }
+}
+
+func BenchmarkRuneCountTenASCIIChars(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ RuneCountInString("0123456789")
+ }
+}
+
+func BenchmarkRuneCountTenJapaneseChars(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ RuneCountInString("日本語日本語日本語日")
+ }
+}
+
+func BenchmarkEncodeASCIIRune(b *testing.B) {
+ buf := make([]byte, UTFMax)
+ for i := 0; i < b.N; i++ {
+ EncodeRune(buf, 'a')
+ }
+}
+
+func BenchmarkEncodeJapaneseRune(b *testing.B) {
+ buf := make([]byte, UTFMax)
+ for i := 0; i < b.N; i++ {
+ EncodeRune(buf, '本')
+ }
+}
+
+func BenchmarkDecodeASCIIRune(b *testing.B) {
+ a := []byte{'a'}
+ for i := 0; i < b.N; i++ {
+ DecodeRune(a)
+ }
+}
+
+func BenchmarkDecodeJapaneseRune(b *testing.B) {
+ nihon := []byte("本")
+ for i := 0; i < b.N; i++ {
+ DecodeRune(nihon)
+ }
+}
diff --git a/libgo/go/websocket/client.go b/libgo/go/websocket/client.go
new file mode 100644
index 000000000..091345944
--- /dev/null
+++ b/libgo/go/websocket/client.go
@@ -0,0 +1,321 @@
+// 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 websocket
+
+import (
+ "bufio"
+ "bytes"
+ "container/vector"
+ "crypto/tls"
+ "fmt"
+ "http"
+ "io"
+ "net"
+ "os"
+ "rand"
+ "strings"
+)
+
+type ProtocolError struct {
+ os.ErrorString
+}
+
+var (
+ ErrBadScheme = os.ErrorString("bad scheme")
+ ErrBadStatus = &ProtocolError{"bad status"}
+ ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"}
+ ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"}
+ ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
+ ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
+ ErrChallengeResponse = &ProtocolError{"mismatch challange/response"}
+ secKeyRandomChars [0x30 - 0x21 + 0x7F - 0x3A]byte
+)
+
+type DialError struct {
+ URL string
+ Protocol string
+ Origin string
+ Error os.Error
+}
+
+func (e *DialError) String() string {
+ return "websocket.Dial " + e.URL + ": " + e.Error.String()
+}
+
+func init() {
+ i := 0
+ for ch := byte(0x21); ch < 0x30; ch++ {
+ secKeyRandomChars[i] = ch
+ i++
+ }
+ for ch := byte(0x3a); ch < 0x7F; ch++ {
+ secKeyRandomChars[i] = ch
+ i++
+ }
+}
+
+type handshaker func(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) os.Error
+
+// newClient creates a new Web Socket client connection.
+func newClient(resourceName, host, origin, location, protocol string, rwc io.ReadWriteCloser, handshake handshaker) (ws *Conn, err os.Error) {
+ br := bufio.NewReader(rwc)
+ bw := bufio.NewWriter(rwc)
+ err = handshake(resourceName, host, origin, location, protocol, br, bw)
+ if err != nil {
+ return
+ }
+ buf := bufio.NewReadWriter(br, bw)
+ ws = newConn(origin, location, protocol, buf, rwc)
+ return
+}
+
+/*
+Dial opens a new client connection to a Web Socket.
+
+A trivial example client:
+
+ package main
+
+ import (
+ "websocket"
+ "strings"
+ )
+
+ func main() {
+ ws, err := websocket.Dial("ws://localhost/ws", "", "http://localhost/");
+ if err != nil {
+ panic("Dial: " + err.String())
+ }
+ if _, err := ws.Write([]byte("hello, world!\n")); err != nil {
+ panic("Write: " + err.String())
+ }
+ var msg = make([]byte, 512);
+ if n, err := ws.Read(msg); err != nil {
+ panic("Read: " + err.String())
+ }
+ // use msg[0:n]
+ }
+*/
+func Dial(url, protocol, origin string) (ws *Conn, err os.Error) {
+ var client net.Conn
+
+ parsedUrl, err := http.ParseURL(url)
+ if err != nil {
+ goto Error
+ }
+
+ switch parsedUrl.Scheme {
+ case "ws":
+ client, err = net.Dial("tcp", "", parsedUrl.Host)
+
+ case "wss":
+ client, err = tls.Dial("tcp", "", parsedUrl.Host, nil)
+
+ default:
+ err = ErrBadScheme
+ }
+ if err != nil {
+ goto Error
+ }
+
+ ws, err = newClient(parsedUrl.RawPath, parsedUrl.Host, origin, url, protocol, client, handshake)
+ if err != nil {
+ goto Error
+ }
+ return
+
+Error:
+ return nil, &DialError{url, protocol, origin, err}
+}
+
+/*
+Generates handshake key as described in 4.1 Opening handshake step 16 to 22.
+cf. http://www.whatwg.org/specs/web-socket-protocol/
+*/
+func generateKeyNumber() (key string, number uint32) {
+ // 16. Let /spaces_n/ be a random integer from 1 to 12 inclusive.
+ spaces := rand.Intn(12) + 1
+
+ // 17. Let /max_n/ be the largest integer not greater than
+ // 4,294,967,295 divided by /spaces_n/
+ max := int(4294967295 / uint32(spaces))
+
+ // 18. Let /number_n/ be a random integer from 0 to /max_n/ inclusive.
+ number = uint32(rand.Intn(max + 1))
+
+ // 19. Let /product_n/ be the result of multiplying /number_n/ and
+ // /spaces_n/ together.
+ product := number * uint32(spaces)
+
+ // 20. Let /key_n/ be a string consisting of /product_n/, expressed
+ // in base ten using the numerals in the range U+0030 DIGIT ZERO (0)
+ // to U+0039 DIGIT NINE (9).
+ key = fmt.Sprintf("%d", product)
+
+ // 21. Insert between one and twelve random characters from the ranges
+ // U+0021 to U+002F and U+003A to U+007E into /key_n/ at random
+ // positions.
+ n := rand.Intn(12) + 1
+ for i := 0; i < n; i++ {
+ pos := rand.Intn(len(key)) + 1
+ ch := secKeyRandomChars[rand.Intn(len(secKeyRandomChars))]
+ key = key[0:pos] + string(ch) + key[pos:]
+ }
+
+ // 22. Insert /spaces_n/ U+0020 SPACE characters into /key_n/ at random
+ // positions other than the start or end of the string.
+ for i := 0; i < spaces; i++ {
+ pos := rand.Intn(len(key)-1) + 1
+ key = key[0:pos] + " " + key[pos:]
+ }
+
+ return
+}
+
+/*
+Generates handshake key_3 as described in 4.1 Opening handshake step 26.
+cf. http://www.whatwg.org/specs/web-socket-protocol/
+*/
+func generateKey3() (key []byte) {
+ // 26. Let /key3/ be a string consisting of eight random bytes (or
+ // equivalently, a random 64 bit integer encoded in big-endian order).
+ key = make([]byte, 8)
+ for i := 0; i < 8; i++ {
+ key[i] = byte(rand.Intn(256))
+ }
+ return
+}
+
+/*
+Web Socket protocol handshake based on
+http://www.whatwg.org/specs/web-socket-protocol/
+(draft of http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol)
+*/
+func handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
+ // 4.1. Opening handshake.
+ // Step 5. send a request line.
+ bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
+
+ // Step 6-14. push request headers in fields.
+ var fields vector.StringVector
+ fields.Push("Upgrade: WebSocket\r\n")
+ fields.Push("Connection: Upgrade\r\n")
+ fields.Push("Host: " + host + "\r\n")
+ fields.Push("Origin: " + origin + "\r\n")
+ if protocol != "" {
+ fields.Push("Sec-WebSocket-Protocol: " + protocol + "\r\n")
+ }
+ // TODO(ukai): Step 15. send cookie if any.
+
+ // Step 16-23. generate keys and push Sec-WebSocket-Key<n> in fields.
+ key1, number1 := generateKeyNumber()
+ key2, number2 := generateKeyNumber()
+ fields.Push("Sec-WebSocket-Key1: " + key1 + "\r\n")
+ fields.Push("Sec-WebSocket-Key2: " + key2 + "\r\n")
+
+ // Step 24. shuffle fields and send them out.
+ for i := 1; i < len(fields); i++ {
+ j := rand.Intn(i)
+ fields[i], fields[j] = fields[j], fields[i]
+ }
+ for i := 0; i < len(fields); i++ {
+ bw.WriteString(fields[i])
+ }
+ // Step 25. send CRLF.
+ bw.WriteString("\r\n")
+
+ // Step 26. genearte 8 bytes random key.
+ key3 := generateKey3()
+ // Step 27. send it out.
+ bw.Write(key3)
+ if err = bw.Flush(); err != nil {
+ return
+ }
+
+ // Step 28-29, 32-40. read response from server.
+ resp, err := http.ReadResponse(br, "GET")
+ if err != nil {
+ return err
+ }
+ // Step 30. check response code is 101.
+ if resp.StatusCode != 101 {
+ return ErrBadStatus
+ }
+
+ // Step 41. check websocket headers.
+ if resp.Header["Upgrade"] != "WebSocket" ||
+ strings.ToLower(resp.Header["Connection"]) != "upgrade" {
+ return ErrBadUpgrade
+ }
+
+ if resp.Header["Sec-Websocket-Origin"] != origin {
+ return ErrBadWebSocketOrigin
+ }
+
+ if resp.Header["Sec-Websocket-Location"] != location {
+ return ErrBadWebSocketLocation
+ }
+
+ if protocol != "" && resp.Header["Sec-Websocket-Protocol"] != protocol {
+ return ErrBadWebSocketProtocol
+ }
+
+ // Step 42-43. get expected data from challange data.
+ expected, err := getChallengeResponse(number1, number2, key3)
+ if err != nil {
+ return err
+ }
+
+ // Step 44. read 16 bytes from server.
+ reply := make([]byte, 16)
+ if _, err = io.ReadFull(br, reply); err != nil {
+ return err
+ }
+
+ // Step 45. check the reply equals to expected data.
+ if !bytes.Equal(expected, reply) {
+ return ErrChallengeResponse
+ }
+ // WebSocket connection is established.
+ return
+}
+
+/*
+Handhake described in (soon obsolete)
+draft-hixie-thewebsocket-protocol-75.
+*/
+func draft75handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
+ bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
+ bw.WriteString("Upgrade: WebSocket\r\n")
+ bw.WriteString("Connection: Upgrade\r\n")
+ bw.WriteString("Host: " + host + "\r\n")
+ bw.WriteString("Origin: " + origin + "\r\n")
+ if protocol != "" {
+ bw.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
+ }
+ bw.WriteString("\r\n")
+ bw.Flush()
+ resp, err := http.ReadResponse(br, "GET")
+ if err != nil {
+ return
+ }
+ if resp.Status != "101 Web Socket Protocol Handshake" {
+ return ErrBadStatus
+ }
+ if resp.Header["Upgrade"] != "WebSocket" ||
+ resp.Header["Connection"] != "Upgrade" {
+ return ErrBadUpgrade
+ }
+ if resp.Header["Websocket-Origin"] != origin {
+ return ErrBadWebSocketOrigin
+ }
+ if resp.Header["Websocket-Location"] != location {
+ return ErrBadWebSocketLocation
+ }
+ if protocol != "" && resp.Header["Websocket-Protocol"] != protocol {
+ return ErrBadWebSocketProtocol
+ }
+ return
+}
diff --git a/libgo/go/websocket/server.go b/libgo/go/websocket/server.go
new file mode 100644
index 000000000..dd797f24e
--- /dev/null
+++ b/libgo/go/websocket/server.go
@@ -0,0 +1,219 @@
+// 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 websocket
+
+import (
+ "http"
+ "io"
+ "strings"
+)
+
+/*
+Handler is an interface to a WebSocket.
+
+A trivial example server:
+
+ package main
+
+ import (
+ "http"
+ "io"
+ "websocket"
+ )
+
+ // Echo the data received on the Web Socket.
+ func EchoServer(ws *websocket.Conn) {
+ io.Copy(ws, ws);
+ }
+
+ func main() {
+ http.Handle("/echo", websocket.Handler(EchoServer));
+ err := http.ListenAndServe(":12345", nil);
+ if err != nil {
+ panic("ListenAndServe: " + err.String())
+ }
+ }
+*/
+type Handler func(*Conn)
+
+/*
+Gets key number from Sec-WebSocket-Key<n>: field as described
+in 5.2 Sending the server's opening handshake, 4.
+*/
+func getKeyNumber(s string) (r uint32) {
+ // 4. Let /key-number_n/ be the digits (characters in the range
+ // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9)) in /key_1/,
+ // interpreted as a base ten integer, ignoring all other characters
+ // in /key_n/.
+ r = 0
+ for i := 0; i < len(s); i++ {
+ if s[i] >= '0' && s[i] <= '9' {
+ r = r*10 + uint32(s[i]) - '0'
+ }
+ }
+ return
+}
+
+// ServeHTTP implements the http.Handler interface for a Web Socket
+func (f Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ rwc, buf, err := w.Hijack()
+ if err != nil {
+ panic("Hijack failed: " + err.String())
+ return
+ }
+ // The server should abort the WebSocket connection if it finds
+ // the client did not send a handshake that matches with protocol
+ // specification.
+ defer rwc.Close()
+
+ if req.Method != "GET" {
+ return
+ }
+ // HTTP version can be safely ignored.
+
+ if strings.ToLower(req.Header["Upgrade"]) != "websocket" ||
+ strings.ToLower(req.Header["Connection"]) != "upgrade" {
+ return
+ }
+
+ // TODO(ukai): check Host
+ origin, found := req.Header["Origin"]
+ if !found {
+ return
+ }
+
+ key1, found := req.Header["Sec-Websocket-Key1"]
+ if !found {
+ return
+ }
+ key2, found := req.Header["Sec-Websocket-Key2"]
+ if !found {
+ return
+ }
+ key3 := make([]byte, 8)
+ if _, err := io.ReadFull(buf, key3); err != nil {
+ return
+ }
+
+ var location string
+ if w.UsingTLS() {
+ location = "wss://" + req.Host + req.URL.RawPath
+ } else {
+ location = "ws://" + req.Host + req.URL.RawPath
+ }
+
+ // Step 4. get key number in Sec-WebSocket-Key<n> fields.
+ keyNumber1 := getKeyNumber(key1)
+ keyNumber2 := getKeyNumber(key2)
+
+ // Step 5. get number of spaces in Sec-WebSocket-Key<n> fields.
+ space1 := uint32(strings.Count(key1, " "))
+ space2 := uint32(strings.Count(key2, " "))
+ if space1 == 0 || space2 == 0 {
+ return
+ }
+
+ // Step 6. key number must be an integral multiple of spaces.
+ if keyNumber1%space1 != 0 || keyNumber2%space2 != 0 {
+ return
+ }
+
+ // Step 7. let part be key number divided by spaces.
+ part1 := keyNumber1 / space1
+ part2 := keyNumber2 / space2
+
+ // Step 8. let challenge to be concatination of part1, part2 and key3.
+ // Step 9. get MD5 fingerprint of challenge.
+ response, err := getChallengeResponse(part1, part2, key3)
+ if err != nil {
+ return
+ }
+
+ // Step 10. send response status line.
+ buf.WriteString("HTTP/1.1 101 WebSocket Protocol Handshake\r\n")
+ // Step 11. send response headers.
+ buf.WriteString("Upgrade: WebSocket\r\n")
+ buf.WriteString("Connection: Upgrade\r\n")
+ buf.WriteString("Sec-WebSocket-Location: " + location + "\r\n")
+ buf.WriteString("Sec-WebSocket-Origin: " + origin + "\r\n")
+ protocol, found := req.Header["Sec-Websocket-Protocol"]
+ if found {
+ buf.WriteString("Sec-WebSocket-Protocol: " + protocol + "\r\n")
+ }
+ // Step 12. send CRLF.
+ buf.WriteString("\r\n")
+ // Step 13. send response data.
+ buf.Write(response)
+ if err := buf.Flush(); err != nil {
+ return
+ }
+ ws := newConn(origin, location, protocol, buf, rwc)
+ f(ws)
+}
+
+
+/*
+Draft75Handler is an interface to a WebSocket based on the
+(soon obsolete) draft-hixie-thewebsocketprotocol-75.
+*/
+type Draft75Handler func(*Conn)
+
+// ServeHTTP implements the http.Handler interface for a Web Socket.
+func (f Draft75Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ if req.Method != "GET" || req.Proto != "HTTP/1.1" {
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "Unexpected request")
+ return
+ }
+ if req.Header["Upgrade"] != "WebSocket" {
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "missing Upgrade: WebSocket header")
+ return
+ }
+ if req.Header["Connection"] != "Upgrade" {
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "missing Connection: Upgrade header")
+ return
+ }
+ origin, found := req.Header["Origin"]
+ if !found {
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "missing Origin header")
+ return
+ }
+
+ rwc, buf, err := w.Hijack()
+ if err != nil {
+ panic("Hijack failed: " + err.String())
+ return
+ }
+ defer rwc.Close()
+
+ var location string
+ if w.UsingTLS() {
+ location = "wss://" + req.Host + req.URL.RawPath
+ } else {
+ location = "ws://" + req.Host + req.URL.RawPath
+ }
+
+ // TODO(ukai): verify origin,location,protocol.
+
+ buf.WriteString("HTTP/1.1 101 Web Socket Protocol Handshake\r\n")
+ buf.WriteString("Upgrade: WebSocket\r\n")
+ buf.WriteString("Connection: Upgrade\r\n")
+ buf.WriteString("WebSocket-Origin: " + origin + "\r\n")
+ buf.WriteString("WebSocket-Location: " + location + "\r\n")
+ protocol, found := req.Header["Websocket-Protocol"]
+ // canonical header key of WebSocket-Protocol.
+ if found {
+ buf.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
+ }
+ buf.WriteString("\r\n")
+ if err := buf.Flush(); err != nil {
+ return
+ }
+ ws := newConn(origin, location, protocol, buf, rwc)
+ f(ws)
+}
diff --git a/libgo/go/websocket/websocket.go b/libgo/go/websocket/websocket.go
new file mode 100644
index 000000000..d5996abe1
--- /dev/null
+++ b/libgo/go/websocket/websocket.go
@@ -0,0 +1,189 @@
+// 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.
+
+// The websocket package implements a client and server for the Web Socket protocol.
+// The protocol is defined at http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
+package websocket
+
+// TODO(ukai):
+// better logging.
+
+import (
+ "bufio"
+ "crypto/md5"
+ "encoding/binary"
+ "io"
+ "net"
+ "os"
+)
+
+// WebSocketAddr is an implementation of net.Addr for Web Sockets.
+type WebSocketAddr string
+
+// Network returns the network type for a Web Socket, "websocket".
+func (addr WebSocketAddr) Network() string { return "websocket" }
+
+// String returns the network address for a Web Socket.
+func (addr WebSocketAddr) String() string { return string(addr) }
+
+const (
+ stateFrameByte = iota
+ stateFrameLength
+ stateFrameData
+ stateFrameTextData
+)
+
+// Conn is a channel to communicate to a Web Socket.
+// It implements the net.Conn interface.
+type Conn struct {
+ // The origin URI for the Web Socket.
+ Origin string
+ // The location URI for the Web Socket.
+ Location string
+ // The subprotocol for the Web Socket.
+ Protocol string
+
+ buf *bufio.ReadWriter
+ rwc io.ReadWriteCloser
+
+ // It holds text data in previous Read() that failed with small buffer.
+ data []byte
+ reading bool
+}
+
+// newConn creates a new Web Socket.
+func newConn(origin, location, protocol string, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
+ if buf == nil {
+ br := bufio.NewReader(rwc)
+ bw := bufio.NewWriter(rwc)
+ buf = bufio.NewReadWriter(br, bw)
+ }
+ ws := &Conn{Origin: origin, Location: location, Protocol: protocol, buf: buf, rwc: rwc}
+ return ws
+}
+
+// Read implements the io.Reader interface for a Conn.
+func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
+Frame:
+ for !ws.reading && len(ws.data) == 0 {
+ // Beginning of frame, possibly.
+ b, err := ws.buf.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ if b&0x80 == 0x80 {
+ // Skip length frame.
+ length := 0
+ for {
+ c, err := ws.buf.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ length = length*128 + int(c&0x7f)
+ if c&0x80 == 0 {
+ break
+ }
+ }
+ for length > 0 {
+ _, err := ws.buf.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ }
+ continue Frame
+ }
+ // In text mode
+ if b != 0 {
+ // Skip this frame
+ for {
+ c, err := ws.buf.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ if c == '\xff' {
+ break
+ }
+ }
+ continue Frame
+ }
+ ws.reading = true
+ }
+ if len(ws.data) == 0 {
+ ws.data, err = ws.buf.ReadSlice('\xff')
+ if err == nil {
+ ws.reading = false
+ ws.data = ws.data[:len(ws.data)-1] // trim \xff
+ }
+ }
+ n = copy(msg, ws.data)
+ ws.data = ws.data[n:]
+ return n, err
+}
+
+// Write implements the io.Writer interface for a Conn.
+func (ws *Conn) Write(msg []byte) (n int, err os.Error) {
+ ws.buf.WriteByte(0)
+ ws.buf.Write(msg)
+ ws.buf.WriteByte(0xff)
+ err = ws.buf.Flush()
+ return len(msg), err
+}
+
+// Close implements the io.Closer interface for a Conn.
+func (ws *Conn) Close() os.Error { return ws.rwc.Close() }
+
+// LocalAddr returns the WebSocket Origin for the connection.
+func (ws *Conn) LocalAddr() net.Addr { return WebSocketAddr(ws.Origin) }
+
+// RemoteAddr returns the WebSocket locations for the connection.
+func (ws *Conn) RemoteAddr() net.Addr { return WebSocketAddr(ws.Location) }
+
+// SetTimeout sets the connection's network timeout in nanoseconds.
+func (ws *Conn) SetTimeout(nsec int64) os.Error {
+ if conn, ok := ws.rwc.(net.Conn); ok {
+ return conn.SetTimeout(nsec)
+ }
+ return os.EINVAL
+}
+
+// SetReadTimeout sets the connection's network read timeout in nanoseconds.
+func (ws *Conn) SetReadTimeout(nsec int64) os.Error {
+ if conn, ok := ws.rwc.(net.Conn); ok {
+ return conn.SetReadTimeout(nsec)
+ }
+ return os.EINVAL
+}
+
+// SetWritetTimeout sets the connection's network write timeout in nanoseconds.
+func (ws *Conn) SetWriteTimeout(nsec int64) os.Error {
+ if conn, ok := ws.rwc.(net.Conn); ok {
+ return conn.SetWriteTimeout(nsec)
+ }
+ return os.EINVAL
+}
+
+// getChallengeResponse computes the expected response from the
+// challenge as described in section 5.1 Opening Handshake steps 42 to
+// 43 of http://www.whatwg.org/specs/web-socket-protocol/
+func getChallengeResponse(number1, number2 uint32, key3 []byte) (expected []byte, err os.Error) {
+ // 41. Let /challenge/ be the concatenation of /number_1/, expressed
+ // a big-endian 32 bit integer, /number_2/, expressed in a big-
+ // endian 32 bit integer, and the eight bytes of /key_3/ in the
+ // order they were sent to the wire.
+ challenge := make([]byte, 16)
+ binary.BigEndian.PutUint32(challenge[0:], number1)
+ binary.BigEndian.PutUint32(challenge[4:], number2)
+ copy(challenge[8:], key3)
+
+ // 42. Let /expected/ be the MD5 fingerprint of /challenge/ as a big-
+ // endian 128 bit string.
+ h := md5.New()
+ if _, err = h.Write(challenge); err != nil {
+ return
+ }
+ expected = h.Sum()
+ return
+}
+
+var _ net.Conn = (*Conn)(nil) // compile-time check that *Conn implements net.Conn.
diff --git a/libgo/go/websocket/websocket_test.go b/libgo/go/websocket/websocket_test.go
new file mode 100644
index 000000000..cc4b9dc18
--- /dev/null
+++ b/libgo/go/websocket/websocket_test.go
@@ -0,0 +1,272 @@
+// 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 websocket
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "http"
+ "io"
+ "log"
+ "net"
+ "sync"
+ "testing"
+)
+
+var serverAddr string
+var once sync.Once
+
+func echoServer(ws *Conn) { io.Copy(ws, ws) }
+
+func startServer() {
+ l, e := net.Listen("tcp", "127.0.0.1:0") // any available address
+ if e != nil {
+ log.Exitf("net.Listen tcp :0 %v", e)
+ }
+ serverAddr = l.Addr().String()
+ log.Print("Test WebSocket server listening on ", serverAddr)
+ http.Handle("/echo", Handler(echoServer))
+ http.Handle("/echoDraft75", Draft75Handler(echoServer))
+ go http.Serve(l, nil)
+}
+
+// Test the getChallengeResponse function with values from section
+// 5.1 of the specification steps 18, 26, and 43 from
+// http://www.whatwg.org/specs/web-socket-protocol/
+func TestChallenge(t *testing.T) {
+ var part1 uint32 = 777007543
+ var part2 uint32 = 114997259
+ key3 := []byte{0x47, 0x30, 0x22, 0x2D, 0x5A, 0x3F, 0x47, 0x58}
+ expected := []byte("0st3Rl&q-2ZU^weu")
+
+ response, err := getChallengeResponse(part1, part2, key3)
+ if err != nil {
+ t.Errorf("getChallengeResponse: returned error %v", err)
+ return
+ }
+ if !bytes.Equal(expected, response) {
+ t.Errorf("getChallengeResponse: expected %q got %q", expected, response)
+ }
+}
+
+func TestEcho(t *testing.T) {
+ once.Do(startServer)
+
+ // websocket.Dial()
+ client, err := net.Dial("tcp", "", serverAddr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+ ws, err := newClient("/echo", "localhost", "http://localhost",
+ "ws://localhost/echo", "", client, handshake)
+ if err != nil {
+ t.Errorf("WebSocket handshake error: %v", err)
+ return
+ }
+
+ msg := []byte("hello, world\n")
+ if _, err := ws.Write(msg); err != nil {
+ t.Errorf("Write: %v", err)
+ }
+ var actual_msg = make([]byte, 512)
+ n, err := ws.Read(actual_msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ actual_msg = actual_msg[0:n]
+ if !bytes.Equal(msg, actual_msg) {
+ t.Errorf("Echo: expected %q got %q", msg, actual_msg)
+ }
+ ws.Close()
+}
+
+func TestEchoDraft75(t *testing.T) {
+ once.Do(startServer)
+
+ // websocket.Dial()
+ client, err := net.Dial("tcp", "", serverAddr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+ ws, err := newClient("/echoDraft75", "localhost", "http://localhost",
+ "ws://localhost/echoDraft75", "", client, draft75handshake)
+ if err != nil {
+ t.Errorf("WebSocket handshake: %v", err)
+ return
+ }
+
+ msg := []byte("hello, world\n")
+ if _, err := ws.Write(msg); err != nil {
+ t.Errorf("Write: error %v", err)
+ }
+ var actual_msg = make([]byte, 512)
+ n, err := ws.Read(actual_msg)
+ if err != nil {
+ t.Errorf("Read: error %v", err)
+ }
+ actual_msg = actual_msg[0:n]
+ if !bytes.Equal(msg, actual_msg) {
+ t.Errorf("Echo: expected %q got %q", msg, actual_msg)
+ }
+ ws.Close()
+}
+
+func TestWithQuery(t *testing.T) {
+ once.Do(startServer)
+
+ client, err := net.Dial("tcp", "", serverAddr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+
+ ws, err := newClient("/echo?q=v", "localhost", "http://localhost",
+ "ws://localhost/echo?q=v", "", client, handshake)
+ if err != nil {
+ t.Errorf("WebSocket handshake: %v", err)
+ return
+ }
+ ws.Close()
+}
+
+func TestWithProtocol(t *testing.T) {
+ once.Do(startServer)
+
+ client, err := net.Dial("tcp", "", serverAddr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+
+ ws, err := newClient("/echo", "localhost", "http://localhost",
+ "ws://localhost/echo", "test", client, handshake)
+ if err != nil {
+ t.Errorf("WebSocket handshake: %v", err)
+ return
+ }
+ ws.Close()
+}
+
+func TestHTTP(t *testing.T) {
+ once.Do(startServer)
+
+ // If the client did not send a handshake that matches the protocol
+ // specification, the server should abort the WebSocket connection.
+ _, _, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr))
+ if err == nil {
+ t.Error("Get: unexpected success")
+ return
+ }
+ urlerr, ok := err.(*http.URLError)
+ if !ok {
+ t.Errorf("Get: not URLError %#v", err)
+ return
+ }
+ if urlerr.Error != io.ErrUnexpectedEOF {
+ t.Errorf("Get: error %#v", err)
+ return
+ }
+}
+
+func TestHTTPDraft75(t *testing.T) {
+ once.Do(startServer)
+
+ r, _, err := http.Get(fmt.Sprintf("http://%s/echoDraft75", serverAddr))
+ if err != nil {
+ t.Errorf("Get: error %#v", err)
+ return
+ }
+ if r.StatusCode != http.StatusBadRequest {
+ t.Errorf("Get: got status %d", r.StatusCode)
+ }
+}
+
+func TestTrailingSpaces(t *testing.T) {
+ // http://code.google.com/p/go/issues/detail?id=955
+ // The last runs of this create keys with trailing spaces that should not be
+ // generated by the client.
+ once.Do(startServer)
+ for i := 0; i < 30; i++ {
+ // body
+ _, err := Dial(fmt.Sprintf("ws://%s/echo", serverAddr), "",
+ "http://localhost/")
+ if err != nil {
+ panic("Dial failed: " + err.String())
+ }
+ }
+}
+
+func TestSmallBuffer(t *testing.T) {
+ // http://code.google.com/p/go/issues/detail?id=1145
+ // Read should be able to handle reading a fragment of a frame.
+ once.Do(startServer)
+
+ // websocket.Dial()
+ client, err := net.Dial("tcp", "", serverAddr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+ ws, err := newClient("/echo", "localhost", "http://localhost",
+ "ws://localhost/echo", "", client, handshake)
+ if err != nil {
+ t.Errorf("WebSocket handshake error: %v", err)
+ return
+ }
+
+ msg := []byte("hello, world\n")
+ if _, err := ws.Write(msg); err != nil {
+ t.Errorf("Write: %v", err)
+ }
+ var small_msg = make([]byte, 8)
+ n, err := ws.Read(small_msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ if !bytes.Equal(msg[:len(small_msg)], small_msg) {
+ t.Errorf("Echo: expected %q got %q", msg[:len(small_msg)], small_msg)
+ }
+ var second_msg = make([]byte, len(msg))
+ n, err = ws.Read(second_msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ second_msg = second_msg[0:n]
+ if !bytes.Equal(msg[len(small_msg):], second_msg) {
+ t.Errorf("Echo: expected %q got %q", msg[len(small_msg):], second_msg)
+ }
+ ws.Close()
+
+}
+
+func testSkipLengthFrame(t *testing.T) {
+ b := []byte{'\x80', '\x01', 'x', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
+ buf := bytes.NewBuffer(b)
+ br := bufio.NewReader(buf)
+ bw := bufio.NewWriter(buf)
+ ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
+ msg := make([]byte, 5)
+ n, err := ws.Read(msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ if !bytes.Equal(b[4:8], msg[0:n]) {
+ t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
+ }
+}
+
+func testSkipNoUTF8Frame(t *testing.T) {
+ b := []byte{'\x01', 'n', '\xff', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
+ buf := bytes.NewBuffer(b)
+ br := bufio.NewReader(buf)
+ bw := bufio.NewWriter(buf)
+ ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
+ msg := make([]byte, 5)
+ n, err := ws.Read(msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ if !bytes.Equal(b[4:8], msg[0:n]) {
+ t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
+ }
+}
diff --git a/libgo/go/xml/embed_test.go b/libgo/go/xml/embed_test.go
new file mode 100644
index 000000000..abfe781ac
--- /dev/null
+++ b/libgo/go/xml/embed_test.go
@@ -0,0 +1,124 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import "testing"
+
+type C struct {
+ Name string
+ Open bool
+}
+
+type A struct {
+ XMLName Name "http://domain a"
+ C
+ B B
+ FieldA string
+}
+
+type B struct {
+ XMLName Name "b"
+ C
+ FieldB string
+}
+
+const _1a = `
+<?xml version="1.0" encoding="UTF-8"?>
+<a xmlns="http://domain">
+ <name>KmlFile</name>
+ <open>1</open>
+ <b>
+ <name>Absolute</name>
+ <open>0</open>
+ <fieldb>bar</fieldb>
+ </b>
+ <fielda>foo</fielda>
+</a>
+`
+
+// Tests that embedded structs are marshalled.
+func TestEmbedded1(t *testing.T) {
+ var a A
+ if e := Unmarshal(StringReader(_1a), &a); e != nil {
+ t.Fatalf("Unmarshal: %s", e)
+ }
+ if a.FieldA != "foo" {
+ t.Fatalf("Unmarshal: expected 'foo' but found '%s'", a.FieldA)
+ }
+ if a.Name != "KmlFile" {
+ t.Fatalf("Unmarshal: expected 'KmlFile' but found '%s'", a.Name)
+ }
+ if !a.Open {
+ t.Fatal("Unmarshal: expected 'true' but found otherwise")
+ }
+ if a.B.FieldB != "bar" {
+ t.Fatalf("Unmarshal: expected 'bar' but found '%s'", a.B.FieldB)
+ }
+ if a.B.Name != "Absolute" {
+ t.Fatalf("Unmarshal: expected 'Absolute' but found '%s'", a.B.Name)
+ }
+ if a.B.Open {
+ t.Fatal("Unmarshal: expected 'false' but found otherwise")
+ }
+}
+
+type A2 struct {
+ XMLName Name "http://domain a"
+ XY string
+ Xy string
+}
+
+const _2a = `
+<?xml version="1.0" encoding="UTF-8"?>
+<a xmlns="http://domain">
+ <xy>foo</xy>
+</a>
+`
+
+// Tests that conflicting field names get excluded.
+func TestEmbedded2(t *testing.T) {
+ var a A2
+ if e := Unmarshal(StringReader(_2a), &a); e != nil {
+ t.Fatalf("Unmarshal: %s", e)
+ }
+ if a.XY != "" {
+ t.Fatalf("Unmarshal: expected empty string but found '%s'", a.XY)
+ }
+ if a.Xy != "" {
+ t.Fatalf("Unmarshal: expected empty string but found '%s'", a.Xy)
+ }
+}
+
+type A3 struct {
+ XMLName Name "http://domain a"
+ xy string
+}
+
+// Tests that private fields are not set.
+func TestEmbedded3(t *testing.T) {
+ var a A3
+ if e := Unmarshal(StringReader(_2a), &a); e != nil {
+ t.Fatalf("Unmarshal: %s", e)
+ }
+ if a.xy != "" {
+ t.Fatalf("Unmarshal: expected empty string but found '%s'", a.xy)
+ }
+}
+
+type A4 struct {
+ XMLName Name "http://domain a"
+ Any string
+}
+
+// Tests that private fields are not set.
+func TestEmbedded4(t *testing.T) {
+ var a A4
+ if e := Unmarshal(StringReader(_2a), &a); e != nil {
+ t.Fatalf("Unmarshal: %s", e)
+ }
+ if a.Any != "foo" {
+ t.Fatalf("Unmarshal: expected 'foo' but found '%s'", a.Any)
+ }
+}
diff --git a/libgo/go/xml/read.go b/libgo/go/xml/read.go
new file mode 100644
index 000000000..9ae3bb8ee
--- /dev/null
+++ b/libgo/go/xml/read.go
@@ -0,0 +1,620 @@
+// 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 xml
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
+// an XML element is an order-dependent collection of anonymous
+// values, while a data structure is an order-independent collection
+// of named values.
+// See package json for a textual representation more suitable
+// to data structures.
+
+// Unmarshal parses an XML element from r and uses the
+// reflect library to fill in an arbitrary struct, slice, or string
+// pointed at by val. Well-formed data that does not fit
+// into val is discarded.
+//
+// For example, given these definitions:
+//
+// type Email struct {
+// Where string "attr"
+// Addr string
+// }
+//
+// type Result struct {
+// XMLName xml.Name "result"
+// Name string
+// Phone string
+// Email []Email
+// Groups []string "group>value"
+// }
+//
+// result := Result{Name: "name", Phone: "phone", Email: nil}
+//
+// unmarshalling the XML input
+//
+// <result>
+// <email where="home">
+// <addr>gre@example.com</addr>
+// </email>
+// <email where='work'>
+// <addr>gre@work.com</addr>
+// </email>
+// <name>Grace R. Emlin</name>
+// <group>
+// <value>Friends</value>
+// <value>Squash</value>
+// </group>
+// <address>123 Main Street</address>
+// </result>
+//
+// via Unmarshal(r, &result) is equivalent to assigning
+//
+// r = Result{xml.Name{"", "result"},
+// "Grace R. Emlin", // name
+// "phone", // no phone given
+// []Email{
+// Email{"home", "gre@example.com"},
+// Email{"work", "gre@work.com"},
+// },
+// []string{"Friends", "Squash"},
+// }
+//
+// Note that the field r.Phone has not been modified and
+// that the XML <address> element was discarded. Also, the field
+// Groups was assigned considering the element path provided in the
+// field tag.
+//
+// Because Unmarshal uses the reflect package, it can only
+// assign to upper case fields. Unmarshal uses a case-insensitive
+// comparison to match XML element names to struct field names.
+//
+// Unmarshal maps an XML element to a struct using the following rules:
+//
+// * If the struct has a field of type []byte or string with tag "innerxml",
+// Unmarshal accumulates the raw XML nested inside the element
+// in that field. The rest of the rules still apply.
+//
+// * If the struct has a field named XMLName of type xml.Name,
+// Unmarshal records the element name in that field.
+//
+// * If the XMLName field has an associated tag string of the form
+// "tag" or "namespace-URL tag", the XML element must have
+// the given tag (and, optionally, name space) or else Unmarshal
+// returns an error.
+//
+// * If the XML element has an attribute whose name matches a
+// struct field of type string with tag "attr", Unmarshal records
+// the attribute value in that field.
+//
+// * If the XML element contains character data, that data is
+// accumulated in the first struct field that has tag "chardata".
+// 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 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
+// given names, and will map the innermost elements to that struct field.
+// A struct field tag starting with ">" is equivalent to one starting
+// with the field name followed by ">".
+//
+// * If the XML element contains a sub-element whose name
+// matches a struct field whose tag is neither "attr" nor "chardata",
+// Unmarshal maps the sub-element to that struct field.
+// Otherwise, if the struct has a field named Any, unmarshal
+// 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.
+//
+// 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 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.
+//
+// Unmarshal maps an XML element to a pointer by setting the pointer
+// to a freshly allocated value and then mapping the element to that value.
+//
+func Unmarshal(r io.Reader, val interface{}) os.Error {
+ v, ok := reflect.NewValue(val).(*reflect.PtrValue)
+ if !ok {
+ return os.NewError("non-pointer passed to Unmarshal")
+ }
+ p := NewParser(r)
+ elem := v.Elem()
+ err := p.unmarshal(elem, nil)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// An UnmarshalError represents an error in the unmarshalling process.
+type UnmarshalError string
+
+func (e UnmarshalError) String() string { return string(e) }
+
+// A TagPathError represents an error in the unmarshalling process
+// caused by the use of field tags with conflicting paths.
+type TagPathError struct {
+ Struct reflect.Type
+ Field1, Tag1 string
+ Field2, Tag2 string
+}
+
+func (e *TagPathError) String() string {
+ return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2)
+}
+
+// The Parser's Unmarshal method is like xml.Unmarshal
+// except that it can be passed a pointer to the initial start element,
+// useful when a client reads some raw XML tokens itself
+// but also defers to Unmarshal for some elements.
+// Passing a nil start element indicates that Unmarshal should
+// read the token stream to find the start element.
+func (p *Parser) Unmarshal(val interface{}, start *StartElement) os.Error {
+ v, ok := reflect.NewValue(val).(*reflect.PtrValue)
+ if !ok {
+ return os.NewError("non-pointer passed to Unmarshal")
+ }
+ return p.unmarshal(v.Elem(), start)
+}
+
+// fieldName strips invalid characters from an XML name
+// to create a valid Go struct name. It also converts the
+// name to lower case letters.
+func fieldName(original string) string {
+
+ var i int
+ //remove leading underscores
+ for i = 0; i < len(original) && original[i] == '_'; i++ {
+ }
+
+ return strings.Map(
+ func(x int) int {
+ if x == '_' || unicode.IsDigit(x) || unicode.IsLetter(x) {
+ return unicode.ToLower(x)
+ }
+ return -1
+ },
+ original[i:])
+}
+
+// Unmarshal a single XML element into val.
+func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
+ // Find start element if we need it.
+ if start == nil {
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ if t, ok := tok.(StartElement); ok {
+ start = &t
+ break
+ }
+ }
+ }
+
+ if pv, ok := val.(*reflect.PtrValue); ok {
+ if pv.Get() == 0 {
+ zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem())
+ pv.PointTo(zv)
+ val = zv
+ } else {
+ val = pv.Elem()
+ }
+ }
+
+ var (
+ data []byte
+ saveData reflect.Value
+ comment []byte
+ saveComment reflect.Value
+ saveXML reflect.Value
+ saveXMLIndex int
+ saveXMLData []byte
+ sv *reflect.StructValue
+ styp *reflect.StructType
+ fieldPaths map[string]pathInfo
+ )
+
+ switch v := val.(type) {
+ default:
+ return os.ErrorString("unknown type " + v.Type().String())
+
+ case *reflect.SliceValue:
+ typ := v.Type().(*reflect.SliceType)
+ if typ.Elem().Kind() == reflect.Uint8 {
+ // []byte
+ saveData = v
+ break
+ }
+
+ // Slice of element values.
+ // Grow slice.
+ n := v.Len()
+ if n >= v.Cap() {
+ ncap := 2 * n
+ if ncap < 4 {
+ ncap = 4
+ }
+ new := reflect.MakeSlice(typ, n, ncap)
+ reflect.Copy(new, v)
+ v.Set(new)
+ }
+ v.SetLen(n + 1)
+
+ // Recur to read element into slice.
+ if err := p.unmarshal(v.Elem(n), start); err != nil {
+ v.SetLen(n)
+ return err
+ }
+ return nil
+
+ case *reflect.BoolValue, *reflect.FloatValue, *reflect.IntValue, *reflect.UintValue, *reflect.StringValue:
+ saveData = v
+
+ case *reflect.StructValue:
+ if _, ok := v.Interface().(Name); ok {
+ v.Set(reflect.NewValue(start.Name).(*reflect.StructValue))
+ break
+ }
+
+ sv = v
+ typ := sv.Type().(*reflect.StructType)
+ styp = typ
+ // Assign name.
+ if f, ok := typ.FieldByName("XMLName"); ok {
+ // Validate element name.
+ if f.Tag != "" {
+ tag := f.Tag
+ ns := ""
+ i := strings.LastIndex(tag, " ")
+ if i >= 0 {
+ ns, tag = tag[0:i], tag[i+1:]
+ }
+ if tag != start.Name.Local {
+ return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">")
+ }
+ if ns != "" && ns != start.Name.Space {
+ e := "expected element <" + tag + "> in name space " + ns + " but have "
+ if start.Name.Space == "" {
+ e += "no name space"
+ } else {
+ e += start.Name.Space
+ }
+ return UnmarshalError(e)
+ }
+ }
+
+ // Save
+ v := sv.FieldByIndex(f.Index)
+ if _, ok := v.Interface().(Name); !ok {
+ return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
+ }
+ v.(*reflect.StructValue).Set(reflect.NewValue(start.Name).(*reflect.StructValue))
+ }
+
+ // Assign attributes.
+ // Also, determine whether we need to save character data or comments.
+ for i, n := 0, typ.NumField(); i < n; i++ {
+ f := typ.Field(i)
+ switch f.Tag {
+ case "attr":
+ strv, ok := sv.FieldByIndex(f.Index).(*reflect.StringValue)
+ if !ok {
+ 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)
+ for _, a := range start.Attr {
+ if fieldName(a.Name.Local) == k {
+ val = a.Value
+ break
+ }
+ }
+ strv.Set(val)
+
+ case "comment":
+ if saveComment == nil {
+ saveComment = sv.FieldByIndex(f.Index)
+ }
+
+ case "chardata":
+ if saveData == nil {
+ saveData = sv.FieldByIndex(f.Index)
+ }
+
+ case "innerxml":
+ if saveXML == nil {
+ saveXML = sv.FieldByIndex(f.Index)
+ if p.saved == nil {
+ saveXMLIndex = 0
+ p.saved = new(bytes.Buffer)
+ } else {
+ saveXMLIndex = p.savedOffset()
+ }
+ }
+
+ default:
+ if strings.Contains(f.Tag, ">") {
+ if fieldPaths == nil {
+ fieldPaths = make(map[string]pathInfo)
+ }
+ path := strings.ToLower(f.Tag)
+ if strings.HasPrefix(f.Tag, ">") {
+ path = strings.ToLower(f.Name) + path
+ }
+ if strings.HasSuffix(f.Tag, ">") {
+ path = path[:len(path)-1]
+ }
+ err := addFieldPath(sv, fieldPaths, path, f.Index)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ }
+
+ // Find end element.
+ // Process sub-elements along the way.
+Loop:
+ for {
+ var savedOffset int
+ if saveXML != nil {
+ savedOffset = p.savedOffset()
+ }
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ // Sub-element.
+ // Look up by tag name.
+ if sv != nil {
+ k := fieldName(t.Name.Local)
+
+ if fieldPaths != nil {
+ if _, found := fieldPaths[k]; found {
+ if err := p.unmarshalPaths(sv, fieldPaths, k, &t); err != nil {
+ return err
+ }
+ continue Loop
+ }
+ }
+
+ match := func(s string) bool {
+ // check if the name matches ignoring case
+ if strings.ToLower(s) != k {
+ return false
+ }
+ // now check that it's public
+ c, _ := utf8.DecodeRuneInString(s)
+ return unicode.IsUpper(c)
+ }
+
+ f, found := styp.FieldByNameFunc(match)
+ if !found { // fall back to mop-up field named "Any"
+ f, found = styp.FieldByName("Any")
+ }
+ if found {
+ if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil {
+ return err
+ }
+ continue Loop
+ }
+ }
+ // Not saving sub-element but still have to skip over it.
+ if err := p.Skip(); err != nil {
+ return err
+ }
+
+ case EndElement:
+ if saveXML != nil {
+ saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
+ if saveXMLIndex == 0 {
+ p.saved = nil
+ }
+ }
+ break Loop
+
+ case CharData:
+ if saveData != nil {
+ data = append(data, t...)
+ }
+
+ case Comment:
+ if saveComment != nil {
+ comment = append(comment, t...)
+ }
+ }
+ }
+
+ var err os.Error
+ // Helper functions for integer and unsigned integer conversions
+ var itmp int64
+ getInt64 := func() bool {
+ itmp, err = strconv.Atoi64(string(data))
+ // TODO: should check sizes
+ return err == nil
+ }
+ var utmp uint64
+ getUint64 := func() bool {
+ utmp, err = strconv.Atoui64(string(data))
+ // TODO: check for overflow?
+ return err == nil
+ }
+ var ftmp float64
+ getFloat64 := func() bool {
+ ftmp, err = strconv.Atof64(string(data))
+ // TODO: check for overflow?
+ return err == nil
+ }
+
+ // Save accumulated data and comments
+ switch t := saveData.(type) {
+ case nil:
+ // Probably a comment, handled below
+ default:
+ return os.ErrorString("cannot happen: unknown type " + t.Type().String())
+ case *reflect.IntValue:
+ if !getInt64() {
+ return err
+ }
+ t.Set(itmp)
+ case *reflect.UintValue:
+ if !getUint64() {
+ return err
+ }
+ t.Set(utmp)
+ case *reflect.FloatValue:
+ if !getFloat64() {
+ return err
+ }
+ t.Set(ftmp)
+ case *reflect.BoolValue:
+ value, err := strconv.Atob(strings.TrimSpace(string(data)))
+ if err != nil {
+ return err
+ }
+ t.Set(value)
+ case *reflect.StringValue:
+ t.Set(string(data))
+ case *reflect.SliceValue:
+ t.Set(reflect.NewValue(data).(*reflect.SliceValue))
+ }
+
+ switch t := saveComment.(type) {
+ case *reflect.StringValue:
+ t.Set(string(comment))
+ case *reflect.SliceValue:
+ t.Set(reflect.NewValue(comment).(*reflect.SliceValue))
+ }
+
+ switch t := saveXML.(type) {
+ case *reflect.StringValue:
+ t.Set(string(saveXMLData))
+ case *reflect.SliceValue:
+ t.Set(reflect.NewValue(saveXMLData).(*reflect.SliceValue))
+ }
+
+ return nil
+}
+
+type pathInfo struct {
+ fieldIdx []int
+ complete bool
+}
+
+// addFieldPath takes an element path such as "a>b>c" and fills the
+// paths map with all paths leading to it ("a", "a>b", and "a>b>c").
+// It is okay for paths to share a common, shorter prefix but not ok
+// for one path to itself be a prefix of another.
+func addFieldPath(sv *reflect.StructValue, paths map[string]pathInfo, path string, fieldIdx []int) os.Error {
+ if info, found := paths[path]; found {
+ return tagError(sv, info.fieldIdx, fieldIdx)
+ }
+ paths[path] = pathInfo{fieldIdx, true}
+ for {
+ i := strings.LastIndex(path, ">")
+ if i < 0 {
+ break
+ }
+ path = path[:i]
+ if info, found := paths[path]; found {
+ if info.complete {
+ return tagError(sv, info.fieldIdx, fieldIdx)
+ }
+ } else {
+ paths[path] = pathInfo{fieldIdx, false}
+ }
+ }
+ return nil
+
+}
+
+func tagError(sv *reflect.StructValue, idx1 []int, idx2 []int) os.Error {
+ t := sv.Type().(*reflect.StructType)
+ f1 := t.FieldByIndex(idx1)
+ f2 := t.FieldByIndex(idx2)
+ return &TagPathError{t, f1.Name, f1.Tag, f2.Name, f2.Tag}
+}
+
+// unmarshalPaths walks down an XML structure looking for
+// wanted paths, and calls unmarshal on them.
+func (p *Parser) unmarshalPaths(sv *reflect.StructValue, paths map[string]pathInfo, path string, start *StartElement) os.Error {
+ if info, _ := paths[path]; info.complete {
+ return p.unmarshal(sv.FieldByIndex(info.fieldIdx), start)
+ }
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ k := path + ">" + fieldName(t.Name.Local)
+ if _, found := paths[k]; found {
+ if err := p.unmarshalPaths(sv, paths, k, &t); err != nil {
+ return err
+ }
+ continue
+ }
+ if err := p.Skip(); err != nil {
+ return err
+ }
+ case EndElement:
+ return nil
+ }
+ }
+ panic("unreachable")
+}
+
+// Have already read a start element.
+// Read tokens until we find the end element.
+// Token is taking care of making sure the
+// end element matches the start element we saw.
+func (p *Parser) Skip() os.Error {
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ if err := p.Skip(); err != nil {
+ return err
+ }
+ case EndElement:
+ return nil
+ }
+ }
+ panic("unreachable")
+}
diff --git a/libgo/go/xml/read_test.go b/libgo/go/xml/read_test.go
new file mode 100644
index 000000000..71ceddce4
--- /dev/null
+++ b/libgo/go/xml/read_test.go
@@ -0,0 +1,329 @@
+// 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 xml
+
+import (
+ "reflect"
+ "testing"
+)
+
+// Stripped down Atom feed data structures.
+
+func TestUnmarshalFeed(t *testing.T) {
+ var f Feed
+ if err := Unmarshal(StringReader(rssFeedString), &f); err != nil {
+ t.Fatalf("Unmarshal: %s", err)
+ }
+ if !reflect.DeepEqual(f, rssFeed) {
+ t.Fatalf("have %#v\nwant %#v", f, rssFeed)
+ }
+}
+
+// hget http://codereview.appspot.com/rss/mine/rsc
+const rssFeedString = `
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us"><title>Code Review - My issues</title><link href="http://codereview.appspot.com/" rel="alternate"></link><li-nk href="http://codereview.appspot.com/rss/mine/rsc" rel="self"></li-nk><id>http://codereview.appspot.com/</id><updated>2009-10-04T01:35:58+00:00</updated><author><name>rietveld&lt;&gt;</name></author><entry><title>rietveld: an attempt at pubsubhubbub
+</title><link hre-f="http://codereview.appspot.com/126085" rel="alternate"></link><updated>2009-10-04T01:35:58+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:134d9179c41f806be79b3a5f7877d19a</id><summary type="html">
+ An attempt at adding pubsubhubbub support to Rietveld.
+http://code.google.com/p/pubsubhubbub
+http://code.google.com/p/rietveld/issues/detail?id=155
+
+The server side of the protocol is trivial:
+ 1. add a &amp;lt;link rel=&amp;quot;hub&amp;quot; href=&amp;quot;hub-server&amp;quot;&amp;gt; tag to all
+ feeds that will be pubsubhubbubbed.
+ 2. every time one of those feeds changes, tell the hub
+ with a simple POST request.
+
+I have tested this by adding debug prints to a local hub
+server and checking that the server got the right publish
+requests.
+
+I can&amp;#39;t quite get the server to work, but I think the bug
+is not in my code. I think that the server expects to be
+able to grab the feed and see the feed&amp;#39;s actual URL in
+the link rel=&amp;quot;self&amp;quot;, but the default value for that drops
+the :port from the URL, and I cannot for the life of me
+figure out how to get the Atom generator deep inside
+django not to do that, or even where it is doing that,
+or even what code is running to generate the Atom feed.
+(I thought I knew but I added some assert False statements
+and it kept running!)
+
+Ignoring that particular problem, I would appreciate
+feedback on the right way to get the two values at
+the top of feeds.py marked NOTE(rsc).
+
+
+</summary></entry><entry><title>rietveld: correct tab handling
+</title><link href="http://codereview.appspot.com/124106" rel="alternate"></link><updated>2009-10-03T23:02:17+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:0a2a4f19bb815101f0ba2904aed7c35a</id><summary type="html">
+ This fixes the buggy tab rendering that can be seen at
+http://codereview.appspot.com/116075/diff/1/2
+
+The fundamental problem was that the tab code was
+not being told what column the text began in, so it
+didn&amp;#39;t know where to put the tab stops. Another problem
+was that some of the code assumed that string byte
+offsets were the same as column offsets, which is only
+true if there are no tabs.
+
+In the process of fixing this, I cleaned up the arguments
+to Fold and ExpandTabs and renamed them Break and
+_ExpandTabs so that I could be sure that I found all the
+call sites. I also wanted to verify that ExpandTabs was
+not being used from outside intra_region_diff.py.
+
+
+</summary></entry></feed> `
+
+type Feed struct {
+ XMLName Name "http://www.w3.org/2005/Atom feed"
+ Title string
+ Id string
+ Link []Link
+ Updated Time
+ Author Person
+ Entry []Entry
+}
+
+type Entry struct {
+ Title string
+ Id string
+ Link []Link
+ Updated Time
+ Author Person
+ Summary Text
+}
+
+type Link struct {
+ Rel string "attr"
+ Href string "attr"
+}
+
+type Person struct {
+ Name string
+ URI string
+ Email string
+ InnerXML string "innerxml"
+}
+
+type Text struct {
+ Type string "attr"
+ Body string "chardata"
+}
+
+type Time string
+
+var rssFeed = Feed{
+ XMLName: Name{"http://www.w3.org/2005/Atom", "feed"},
+ Title: "Code Review - My issues",
+ Link: []Link{
+ {Rel: "alternate", Href: "http://codereview.appspot.com/"},
+ {Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"},
+ },
+ Id: "http://codereview.appspot.com/",
+ Updated: "2009-10-04T01:35:58+00:00",
+ Author: Person{
+ Name: "rietveld<>",
+ InnerXML: "<name>rietveld&lt;&gt;</name>",
+ },
+ Entry: []Entry{
+ {
+ Title: "rietveld: an attempt at pubsubhubbub\n",
+ Link: []Link{
+ {Rel: "alternate", Href: "http://codereview.appspot.com/126085"},
+ },
+ Updated: "2009-10-04T01:35:58+00:00",
+ Author: Person{
+ Name: "email-address-removed",
+ InnerXML: "<name>email-address-removed</name>",
+ },
+ Id: "urn:md5:134d9179c41f806be79b3a5f7877d19a",
+ Summary: Text{
+ Type: "html",
+ Body: `
+ An attempt at adding pubsubhubbub support to Rietveld.
+http://code.google.com/p/pubsubhubbub
+http://code.google.com/p/rietveld/issues/detail?id=155
+
+The server side of the protocol is trivial:
+ 1. add a &lt;link rel=&quot;hub&quot; href=&quot;hub-server&quot;&gt; tag to all
+ feeds that will be pubsubhubbubbed.
+ 2. every time one of those feeds changes, tell the hub
+ with a simple POST request.
+
+I have tested this by adding debug prints to a local hub
+server and checking that the server got the right publish
+requests.
+
+I can&#39;t quite get the server to work, but I think the bug
+is not in my code. I think that the server expects to be
+able to grab the feed and see the feed&#39;s actual URL in
+the link rel=&quot;self&quot;, but the default value for that drops
+the :port from the URL, and I cannot for the life of me
+figure out how to get the Atom generator deep inside
+django not to do that, or even where it is doing that,
+or even what code is running to generate the Atom feed.
+(I thought I knew but I added some assert False statements
+and it kept running!)
+
+Ignoring that particular problem, I would appreciate
+feedback on the right way to get the two values at
+the top of feeds.py marked NOTE(rsc).
+
+
+`,
+ },
+ },
+ {
+ Title: "rietveld: correct tab handling\n",
+ Link: []Link{
+ {Rel: "alternate", Href: "http://codereview.appspot.com/124106"},
+ },
+ Updated: "2009-10-03T23:02:17+00:00",
+ Author: Person{
+ Name: "email-address-removed",
+ InnerXML: "<name>email-address-removed</name>",
+ },
+ Id: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a",
+ Summary: Text{
+ Type: "html",
+ Body: `
+ This fixes the buggy tab rendering that can be seen at
+http://codereview.appspot.com/116075/diff/1/2
+
+The fundamental problem was that the tab code was
+not being told what column the text began in, so it
+didn&#39;t know where to put the tab stops. Another problem
+was that some of the code assumed that string byte
+offsets were the same as column offsets, which is only
+true if there are no tabs.
+
+In the process of fixing this, I cleaned up the arguments
+to Fold and ExpandTabs and renamed them Break and
+_ExpandTabs so that I could be sure that I found all the
+call sites. I also wanted to verify that ExpandTabs was
+not being used from outside intra_region_diff.py.
+
+
+`,
+ },
+ },
+ },
+}
+
+type FieldNameTest struct {
+ in, out string
+}
+
+var FieldNameTests = []FieldNameTest{
+ {"Profile-Image", "profileimage"},
+ {"_score", "score"},
+}
+
+func TestFieldName(t *testing.T) {
+ for _, tt := range FieldNameTests {
+ a := fieldName(tt.in)
+ if a != tt.out {
+ t.Fatalf("have %#v\nwant %#v\n\n", a, tt.out)
+ }
+ }
+}
+
+const pathTestString = `
+<result>
+ <before>1</before>
+ <items>
+ <item1>
+ <value>A</value>
+ </item1>
+ <item2>
+ <value>B</value>
+ </item2>
+ <Item1>
+ <Value>C</Value>
+ <Value>D</Value>
+ </Item1>
+ </items>
+ <after>2</after>
+</result>
+`
+
+type PathTestItem struct {
+ Value string
+}
+
+type PathTestA struct {
+ Items []PathTestItem ">item1"
+ Before, After string
+}
+
+type PathTestB struct {
+ Other []PathTestItem "items>Item1"
+ Before, After string
+}
+
+type PathTestC struct {
+ Values1 []string "items>item1>value"
+ Values2 []string "items>item2>value"
+ Before, After string
+}
+
+type PathTestSet struct {
+ Item1 []PathTestItem
+}
+
+type PathTestD struct {
+ Other PathTestSet "items>"
+ Before, After string
+}
+
+var pathTests = []interface{}{
+ &PathTestA{Items: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"},
+ &PathTestB{Other: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"},
+ &PathTestC{Values1: []string{"A", "C", "D"}, Values2: []string{"B"}, Before: "1", After: "2"},
+ &PathTestD{Other: PathTestSet{Item1: []PathTestItem{{"A"}, {"D"}}}, Before: "1", After: "2"},
+}
+
+func TestUnmarshalPaths(t *testing.T) {
+ for _, pt := range pathTests {
+ p := reflect.MakeZero(reflect.NewValue(pt).Type()).(*reflect.PtrValue)
+ p.PointTo(reflect.MakeZero(p.Type().(*reflect.PtrType).Elem()))
+ v := p.Interface()
+ if err := Unmarshal(StringReader(pathTestString), v); err != nil {
+ t.Fatalf("Unmarshal: %s", err)
+ }
+ if !reflect.DeepEqual(v, pt) {
+ t.Fatalf("have %#v\nwant %#v", v, pt)
+ }
+ }
+}
+
+type BadPathTestA struct {
+ First string "items>item1"
+ Other string "items>item2"
+ Second string "items>"
+}
+
+type BadPathTestB struct {
+ Other string "items>item2>value"
+ First string "items>item1"
+ Second string "items>item1>value"
+}
+
+var badPathTests = []struct {
+ v, e interface{}
+}{
+ {&BadPathTestA{}, &TagPathError{reflect.Typeof(BadPathTestA{}), "First", "items>item1", "Second", "items>"}},
+ {&BadPathTestB{}, &TagPathError{reflect.Typeof(BadPathTestB{}), "First", "items>item1", "Second", "items>item1>value"}},
+}
+
+func TestUnmarshalBadPaths(t *testing.T) {
+ for _, tt := range badPathTests {
+ err := Unmarshal(StringReader(pathTestString), tt.v)
+ if !reflect.DeepEqual(err, tt.e) {
+ t.Fatalf("Unmarshal with %#v didn't fail properly: %#v", tt.v, err)
+ }
+ }
+}
diff --git a/libgo/go/xml/xml.go b/libgo/go/xml/xml.go
new file mode 100644
index 000000000..4d9c672d2
--- /dev/null
+++ b/libgo/go/xml/xml.go
@@ -0,0 +1,1617 @@
+// 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 xml implements a simple XML 1.0 parser that
+// understands XML name spaces.
+package xml
+
+// References:
+// Annotated XML spec: http://www.xml.com/axml/testaxml.htm
+// XML name spaces: http://www.w3.org/TR/REC-xml-names/
+
+// TODO(rsc):
+// Test error handling.
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// A SyntaxError represents a syntax error in the XML input stream.
+type SyntaxError struct {
+ Msg string
+ Line int
+}
+
+func (e *SyntaxError) String() string {
+ return "XML syntax error on line " + strconv.Itoa(e.Line) + ": " + e.Msg
+}
+
+// A Name represents an XML name (Local) annotated
+// with a name space identifier (Space).
+// In tokens returned by Parser.Token, the Space identifier
+// is given as a canonical URL, not the short prefix used
+// in the document being parsed.
+type Name struct {
+ Space, Local string
+}
+
+// An Attr represents an attribute in an XML element (Name=Value).
+type Attr struct {
+ Name Name
+ Value string
+}
+
+// A Token is an interface holding one of the token types:
+// StartElement, EndElement, CharData, Comment, ProcInst, or Directive.
+type Token interface{}
+
+// A StartElement represents an XML start element.
+type StartElement struct {
+ Name Name
+ Attr []Attr
+}
+
+func (e StartElement) Copy() StartElement {
+ attrs := make([]Attr, len(e.Attr))
+ copy(e.Attr, attrs)
+ e.Attr = attrs
+ return e
+}
+
+// An EndElement represents an XML end element.
+type EndElement struct {
+ Name Name
+}
+
+// A CharData represents XML character data (raw text),
+// in which XML escape sequences have been replaced by
+// the characters they represent.
+type CharData []byte
+
+func makeCopy(b []byte) []byte {
+ b1 := make([]byte, len(b))
+ copy(b1, b)
+ return b1
+}
+
+func (c CharData) Copy() CharData { return CharData(makeCopy(c)) }
+
+// A Comment represents an XML comment of the form <!--comment-->.
+// The bytes do not include the <!-- and --> comment markers.
+type Comment []byte
+
+func (c Comment) Copy() Comment { return Comment(makeCopy(c)) }
+
+// A ProcInst represents an XML processing instruction of the form <?target inst?>
+type ProcInst struct {
+ Target string
+ Inst []byte
+}
+
+func (p ProcInst) Copy() ProcInst {
+ p.Inst = makeCopy(p.Inst)
+ return p
+}
+
+// A Directive represents an XML directive of the form <!text>.
+// The bytes do not include the <! and > markers.
+type Directive []byte
+
+func (d Directive) Copy() Directive { return Directive(makeCopy(d)) }
+
+// CopyToken returns a copy of a Token.
+func CopyToken(t Token) Token {
+ switch v := t.(type) {
+ case CharData:
+ return v.Copy()
+ case Comment:
+ return v.Copy()
+ case Directive:
+ return v.Copy()
+ case ProcInst:
+ return v.Copy()
+ case StartElement:
+ return v.Copy()
+ }
+ return t
+}
+
+// A Parser represents an XML parser reading a particular input stream.
+// The parser assumes that its input is encoded in UTF-8.
+type Parser struct {
+ // Strict defaults to true, enforcing the requirements
+ // of the XML specification.
+ // If set to false, the parser allows input containing common
+ // mistakes:
+ // * If an element is missing an end tag, the parser invents
+ // end tags as necessary to keep the return values from Token
+ // properly balanced.
+ // * In attribute values and character data, unknown or malformed
+ // character entities (sequences beginning with &) are left alone.
+ //
+ // Setting:
+ //
+ // p.Strict = false;
+ // p.AutoClose = HTMLAutoClose;
+ // p.Entity = HTMLEntity
+ //
+ // creates a parser that can handle typical HTML.
+ Strict bool
+
+ // When Strict == false, AutoClose indicates a set of elements to
+ // consider closed immediately after they are opened, regardless
+ // of whether an end element is present.
+ AutoClose []string
+
+ // Entity can be used to map non-standard entity names to string replacements.
+ // The parser behaves as if these standard mappings are present in the map,
+ // regardless of the actual map content:
+ //
+ // "lt": "<",
+ // "gt": ">",
+ // "amp": "&",
+ // "apos": "'",
+ // "quot": `"`,
+ Entity map[string]string
+
+ r io.ReadByter
+ buf bytes.Buffer
+ saved *bytes.Buffer
+ stk *stack
+ free *stack
+ needClose bool
+ toClose Name
+ nextToken Token
+ nextByte int
+ ns map[string]string
+ err os.Error
+ line int
+ tmp [32]byte
+}
+
+// NewParser creates a new XML parser reading from r.
+func NewParser(r io.Reader) *Parser {
+ p := &Parser{
+ ns: make(map[string]string),
+ nextByte: -1,
+ line: 1,
+ Strict: true,
+ }
+
+ // Get efficient byte at a time reader.
+ // Assume that if reader has its own
+ // ReadByte, it's efficient enough.
+ // Otherwise, use bufio.
+ if rb, ok := r.(io.ReadByter); ok {
+ p.r = rb
+ } else {
+ p.r = bufio.NewReader(r)
+ }
+
+ return p
+}
+
+// Token returns the next XML token in the input stream.
+// At the end of the input stream, Token returns nil, os.EOF.
+//
+// Slices of bytes in the returned token data refer to the
+// parser's internal buffer and remain valid only until the next
+// call to Token. To acquire a copy of the bytes, call CopyToken
+// or the token's Copy method.
+//
+// Token expands self-closing elements such as <br/>
+// into separate start and end elements returned by successive calls.
+//
+// Token guarantees that the StartElement and EndElement
+// tokens it returns are properly nested and matched:
+// if Token encounters an unexpected end element,
+// it will return an error.
+//
+// Token implements XML name spaces as described by
+// http://www.w3.org/TR/REC-xml-names/. Each of the
+// Name structures contained in the Token has the Space
+// set to the URL identifying its name space when known.
+// If Token encounters an unrecognized name space prefix,
+// it uses the prefix as the Space rather than report an error.
+func (p *Parser) Token() (t Token, err os.Error) {
+ if p.nextToken != nil {
+ t = p.nextToken
+ p.nextToken = nil
+ } else if t, err = p.RawToken(); err != nil {
+ return
+ }
+
+ if !p.Strict {
+ if t1, ok := p.autoClose(t); ok {
+ p.nextToken = t
+ t = t1
+ }
+ }
+ switch t1 := t.(type) {
+ case StartElement:
+ // In XML name spaces, the translations listed in the
+ // attributes apply to the element name and
+ // to the other attribute names, so process
+ // the translations first.
+ for _, a := range t1.Attr {
+ if a.Name.Space == "xmlns" {
+ v, ok := p.ns[a.Name.Local]
+ p.pushNs(a.Name.Local, v, ok)
+ p.ns[a.Name.Local] = a.Value
+ }
+ if a.Name.Space == "" && a.Name.Local == "xmlns" {
+ // Default space for untagged names
+ v, ok := p.ns[""]
+ p.pushNs("", v, ok)
+ p.ns[""] = a.Value
+ }
+ }
+
+ p.translate(&t1.Name, true)
+ for i := range t1.Attr {
+ p.translate(&t1.Attr[i].Name, false)
+ }
+ p.pushElement(t1.Name)
+ t = t1
+
+ case EndElement:
+ p.translate(&t1.Name, true)
+ if !p.popElement(&t1) {
+ return nil, p.err
+ }
+ t = t1
+ }
+ return
+}
+
+// Apply name space translation to name n.
+// The default name space (for Space=="")
+// applies only to element names, not to attribute names.
+func (p *Parser) translate(n *Name, isElementName bool) {
+ switch {
+ case n.Space == "xmlns":
+ return
+ case n.Space == "" && !isElementName:
+ return
+ case n.Space == "" && n.Local == "xmlns":
+ return
+ }
+ if v, ok := p.ns[n.Space]; ok {
+ n.Space = v
+ }
+}
+
+// Parsing state - stack holds old name space translations
+// and the current set of open elements. The translations to pop when
+// ending a given tag are *below* it on the stack, which is
+// more work but forced on us by XML.
+type stack struct {
+ next *stack
+ kind int
+ name Name
+ ok bool
+}
+
+const (
+ stkStart = iota
+ stkNs
+)
+
+func (p *Parser) push(kind int) *stack {
+ s := p.free
+ if s != nil {
+ p.free = s.next
+ } else {
+ s = new(stack)
+ }
+ s.next = p.stk
+ s.kind = kind
+ p.stk = s
+ return s
+}
+
+func (p *Parser) pop() *stack {
+ s := p.stk
+ if s != nil {
+ p.stk = s.next
+ s.next = p.free
+ p.free = s
+ }
+ return s
+}
+
+// Record that we are starting an element with the given name.
+func (p *Parser) pushElement(name Name) {
+ s := p.push(stkStart)
+ s.name = name
+}
+
+// Record that we are changing the value of ns[local].
+// The old value is url, ok.
+func (p *Parser) pushNs(local string, url string, ok bool) {
+ s := p.push(stkNs)
+ s.name.Local = local
+ s.name.Space = url
+ s.ok = ok
+}
+
+// Creates a SyntaxError with the current line number.
+func (p *Parser) syntaxError(msg string) os.Error {
+ return &SyntaxError{Msg: msg, Line: p.line}
+}
+
+// Record that we are ending an element with the given name.
+// The name must match the record at the top of the stack,
+// which must be a pushElement record.
+// After popping the element, apply any undo records from
+// the stack to restore the name translations that existed
+// before we saw this element.
+func (p *Parser) popElement(t *EndElement) bool {
+ s := p.pop()
+ name := t.Name
+ switch {
+ case s == nil || s.kind != stkStart:
+ p.err = p.syntaxError("unexpected end element </" + name.Local + ">")
+ return false
+ case s.name.Local != name.Local:
+ if !p.Strict {
+ p.needClose = true
+ p.toClose = t.Name
+ t.Name = s.name
+ return true
+ }
+ p.err = p.syntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">")
+ return false
+ case s.name.Space != name.Space:
+ p.err = p.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space +
+ "closed by </" + name.Local + "> in space " + name.Space)
+ return false
+ }
+
+ // Pop stack until a Start is on the top, undoing the
+ // translations that were associated with the element we just closed.
+ for p.stk != nil && p.stk.kind != stkStart {
+ s := p.pop()
+ p.ns[s.name.Local] = s.name.Space, s.ok
+ }
+
+ return true
+}
+
+// If the top element on the stack is autoclosing and
+// t is not the end tag, invent the end tag.
+func (p *Parser) autoClose(t Token) (Token, bool) {
+ if p.stk == nil || p.stk.kind != stkStart {
+ return nil, false
+ }
+ name := strings.ToLower(p.stk.name.Local)
+ for _, s := range p.AutoClose {
+ if strings.ToLower(s) == name {
+ // This one should be auto closed if t doesn't close it.
+ et, ok := t.(EndElement)
+ if !ok || et.Name.Local != name {
+ return EndElement{p.stk.name}, true
+ }
+ break
+ }
+ }
+ return nil, false
+}
+
+
+// RawToken is like Token but does not verify that
+// start and end elements match and does not translate
+// name space prefixes to their corresponding URLs.
+func (p *Parser) RawToken() (Token, os.Error) {
+ if p.err != nil {
+ return nil, p.err
+ }
+ if p.needClose {
+ // The last element we read was self-closing and
+ // we returned just the StartElement half.
+ // Return the EndElement half now.
+ p.needClose = false
+ return EndElement{p.toClose}, nil
+ }
+
+ b, ok := p.getc()
+ if !ok {
+ return nil, p.err
+ }
+
+ if b != '<' {
+ // Text section.
+ p.ungetc(b)
+ data := p.text(-1, false)
+ if data == nil {
+ return nil, p.err
+ }
+ return CharData(data), nil
+ }
+
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ switch b {
+ case '/':
+ // </: End element
+ var name Name
+ if name, ok = p.nsname(); !ok {
+ if p.err == nil {
+ p.err = p.syntaxError("expected element name after </")
+ }
+ return nil, p.err
+ }
+ p.space()
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b != '>' {
+ p.err = p.syntaxError("invalid characters between </" + name.Local + " and >")
+ return nil, p.err
+ }
+ return EndElement{name}, nil
+
+ case '?':
+ // <?: Processing instruction.
+ // TODO(rsc): Should parse the <?xml declaration to make sure
+ // the version is 1.0 and the encoding is UTF-8.
+ var target string
+ if target, ok = p.name(); !ok {
+ if p.err == nil {
+ p.err = p.syntaxError("expected target name after <?")
+ }
+ return nil, p.err
+ }
+ p.space()
+ p.buf.Reset()
+ var b0 byte
+ for {
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ p.buf.WriteByte(b)
+ if b0 == '?' && b == '>' {
+ break
+ }
+ b0 = b
+ }
+ data := p.buf.Bytes()
+ data = data[0 : len(data)-2] // chop ?>
+ return ProcInst{target, data}, nil
+
+ case '!':
+ // <!: Maybe comment, maybe CDATA.
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ switch b {
+ case '-': // <!-
+ // Probably <!-- for a comment.
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b != '-' {
+ p.err = p.syntaxError("invalid sequence <!- not part of <!--")
+ return nil, p.err
+ }
+ // Look for terminator.
+ p.buf.Reset()
+ var b0, b1 byte
+ for {
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ p.buf.WriteByte(b)
+ if b0 == '-' && b1 == '-' && b == '>' {
+ break
+ }
+ b0, b1 = b1, b
+ }
+ data := p.buf.Bytes()
+ data = data[0 : len(data)-3] // chop -->
+ return Comment(data), nil
+
+ case '[': // <![
+ // Probably <![CDATA[.
+ for i := 0; i < 6; i++ {
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b != "CDATA["[i] {
+ p.err = p.syntaxError("invalid <![ sequence")
+ return nil, p.err
+ }
+ }
+ // Have <![CDATA[. Read text until ]]>.
+ data := p.text(-1, true)
+ if data == nil {
+ return nil, p.err
+ }
+ return CharData(data), nil
+ }
+
+ // Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc.
+ // We don't care, but accumulate for caller.
+ p.buf.Reset()
+ p.buf.WriteByte(b)
+ for {
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b == '>' {
+ break
+ }
+ p.buf.WriteByte(b)
+ }
+ return Directive(p.buf.Bytes()), nil
+ }
+
+ // Must be an open element like <a href="foo">
+ p.ungetc(b)
+
+ var (
+ name Name
+ empty bool
+ attr []Attr
+ )
+ if name, ok = p.nsname(); !ok {
+ if p.err == nil {
+ p.err = p.syntaxError("expected element name after <")
+ }
+ return nil, p.err
+ }
+
+ attr = make([]Attr, 0, 4)
+ for {
+ p.space()
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b == '/' {
+ empty = true
+ if b, ok = p.mustgetc(); !ok {
+ return nil, p.err
+ }
+ if b != '>' {
+ p.err = p.syntaxError("expected /> in element")
+ return nil, p.err
+ }
+ break
+ }
+ if b == '>' {
+ break
+ }
+ p.ungetc(b)
+
+ n := len(attr)
+ if n >= cap(attr) {
+ nattr := make([]Attr, n, 2*cap(attr))
+ copy(nattr, attr)
+ attr = nattr
+ }
+ attr = attr[0 : n+1]
+ a := &attr[n]
+ if a.Name, ok = p.nsname(); !ok {
+ if p.err == nil {
+ p.err = p.syntaxError("expected attribute name in element")
+ }
+ return nil, p.err
+ }
+ p.space()
+ if b, ok = p.mustgetc(); !ok {
+ 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
+ }
+ a.Value = string(data)
+ }
+
+ if empty {
+ p.needClose = true
+ p.toClose = name
+ }
+ return StartElement{name, attr}, nil
+}
+
+func (p *Parser) attrval() []byte {
+ b, ok := p.mustgetc()
+ if !ok {
+ return nil
+ }
+ // Handle quoted attribute values
+ if b == '"' || b == '\'' {
+ return p.text(int(b), false)
+ }
+ // Handle unquoted attribute values for strict parsers
+ if p.Strict {
+ p.err = p.syntaxError("unquoted or missing attribute value in element")
+ return nil
+ }
+ // Handle unquoted attribute values for unstrict parsers
+ p.ungetc(b)
+ p.buf.Reset()
+ for {
+ b, ok = p.mustgetc()
+ if !ok {
+ return nil
+ }
+ // http://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2
+ if 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' ||
+ '0' <= b && b <= '9' || b == '_' || b == ':' || b == '-' {
+ p.buf.WriteByte(b)
+ } else {
+ p.ungetc(b)
+ break
+ }
+ }
+ return p.buf.Bytes()
+}
+
+// Skip spaces if any
+func (p *Parser) space() {
+ for {
+ b, ok := p.getc()
+ if !ok {
+ return
+ }
+ switch b {
+ case ' ', '\r', '\n', '\t':
+ default:
+ p.ungetc(b)
+ return
+ }
+ }
+}
+
+// Read a single byte.
+// If there is no byte to read, return ok==false
+// and leave the error in p.err.
+// Maintain line number.
+func (p *Parser) getc() (b byte, ok bool) {
+ if p.err != nil {
+ return 0, false
+ }
+ if p.nextByte >= 0 {
+ b = byte(p.nextByte)
+ p.nextByte = -1
+ } else {
+ b, p.err = p.r.ReadByte()
+ if p.err != nil {
+ return 0, false
+ }
+ if p.saved != nil {
+ p.saved.WriteByte(b)
+ }
+ }
+ if b == '\n' {
+ p.line++
+ }
+ return b, true
+}
+
+// Return saved offset.
+// If we did ungetc (nextByte >= 0), have to back up one.
+func (p *Parser) savedOffset() int {
+ n := p.saved.Len()
+ if p.nextByte >= 0 {
+ n--
+ }
+ return n
+}
+
+// Must read a single byte.
+// If there is no byte to read,
+// set p.err to SyntaxError("unexpected EOF")
+// and return ok==false
+func (p *Parser) mustgetc() (b byte, ok bool) {
+ if b, ok = p.getc(); !ok {
+ if p.err == os.EOF {
+ p.err = p.syntaxError("unexpected EOF")
+ }
+ }
+ return
+}
+
+// Unread a single byte.
+func (p *Parser) ungetc(b byte) {
+ if b == '\n' {
+ p.line--
+ }
+ p.nextByte = int(b)
+}
+
+var entity = map[string]int{
+ "lt": '<',
+ "gt": '>',
+ "amp": '&',
+ "apos": '\'',
+ "quot": '"',
+}
+
+// Read plain text section (XML calls it character data).
+// If quote >= 0, we are in a quoted string and need to find the matching quote.
+// If cdata == true, we are in a <![CDATA[ section and need to find ]]>.
+// On failure return nil and leave the error in p.err.
+func (p *Parser) text(quote int, cdata bool) []byte {
+ var b0, b1 byte
+ var trunc int
+ p.buf.Reset()
+Input:
+ for {
+ b, ok := p.getc()
+ if !ok {
+ if cdata {
+ if p.err == os.EOF {
+ p.err = p.syntaxError("unexpected EOF in CDATA section")
+ }
+ return nil
+ }
+ break Input
+ }
+
+ // <![CDATA[ section ends with ]]>.
+ // It is an error for ]]> to appear in ordinary text.
+ if b0 == ']' && b1 == ']' && b == '>' {
+ if cdata {
+ trunc = 2
+ break Input
+ }
+ p.err = p.syntaxError("unescaped ]]> not in CDATA section")
+ return nil
+ }
+
+ // Stop reading text if we see a <.
+ if b == '<' && !cdata {
+ if quote >= 0 {
+ p.err = p.syntaxError("unescaped < inside quoted string")
+ return nil
+ }
+ p.ungetc('<')
+ break Input
+ }
+ if quote >= 0 && b == byte(quote) {
+ break Input
+ }
+ if b == '&' && !cdata {
+ // Read escaped character expression up to semicolon.
+ // XML in all its glory allows a document to define and use
+ // its own character names with <!ENTITY ...> directives.
+ // Parsers are required to recognize lt, gt, amp, apos, and quot
+ // even if they have not been declared. That's all we allow.
+ var i int
+ CharLoop:
+ for i = 0; i < len(p.tmp); i++ {
+ var ok bool
+ p.tmp[i], ok = p.getc()
+ if !ok {
+ if p.err == os.EOF {
+ p.err = p.syntaxError("unexpected EOF")
+ }
+ return nil
+ }
+ c := p.tmp[i]
+ if c == ';' {
+ break
+ }
+ if 'a' <= c && c <= 'z' ||
+ 'A' <= c && c <= 'Z' ||
+ '0' <= c && c <= '9' ||
+ c == '_' || c == '#' {
+ continue
+ }
+ p.ungetc(c)
+ break
+ }
+ s := string(p.tmp[0:i])
+ if i >= len(p.tmp) {
+ if !p.Strict {
+ b0, b1 = 0, 0
+ p.buf.WriteByte('&')
+ p.buf.Write(p.tmp[0:i])
+ continue Input
+ }
+ p.err = p.syntaxError("character entity expression &" + s + "... too long")
+ return nil
+ }
+ var haveText bool
+ var text string
+ if i >= 2 && s[0] == '#' {
+ var n uint64
+ var err os.Error
+ if i >= 3 && s[1] == 'x' {
+ n, err = strconv.Btoui64(s[2:], 16)
+ } else {
+ n, err = strconv.Btoui64(s[1:], 10)
+ }
+ if err == nil && n <= unicode.MaxRune {
+ text = string(n)
+ haveText = true
+ }
+ } else {
+ if r, ok := entity[s]; ok {
+ text = string(r)
+ haveText = true
+ } else if p.Entity != nil {
+ text, haveText = p.Entity[s]
+ }
+ }
+ if !haveText {
+ if !p.Strict {
+ b0, b1 = 0, 0
+ p.buf.WriteByte('&')
+ p.buf.Write(p.tmp[0:i])
+ continue Input
+ }
+ p.err = p.syntaxError("invalid character entity &" + s + ";")
+ return nil
+ }
+ p.buf.Write([]byte(text))
+ b0, b1 = 0, 0
+ continue Input
+ }
+ p.buf.WriteByte(b)
+ b0, b1 = b1, b
+ }
+ data := p.buf.Bytes()
+ data = data[0 : len(data)-trunc]
+
+ // Inspect each rune for being a disallowed character.
+ buf := data
+ for len(buf) > 0 {
+ r, size := utf8.DecodeRune(buf)
+ if r == utf8.RuneError && size == 1 {
+ p.err = p.syntaxError("invalid UTF-8")
+ return nil
+ }
+ buf = buf[size:]
+ if !isInCharacterRange(r) {
+ p.err = p.syntaxError(fmt.Sprintf("illegal character code %U", r))
+ return nil
+ }
+ }
+
+ // Must rewrite \r and \r\n into \n.
+ w := 0
+ for r := 0; r < len(data); r++ {
+ b := data[r]
+ if b == '\r' {
+ if r+1 < len(data) && data[r+1] == '\n' {
+ continue
+ }
+ b = '\n'
+ }
+ data[w] = b
+ w++
+ }
+ return data[0:w]
+}
+
+// Decide whether the given rune is in the XML Character Range, per
+// the Char production of http://www.xml.com/axml/testaxml.htm,
+// Section 2.2 Characters.
+func isInCharacterRange(rune int) (inrange bool) {
+ return rune == 0x09 ||
+ rune == 0x0A ||
+ rune == 0x0D ||
+ rune >= 0x20 && rune <= 0xDF77 ||
+ rune >= 0xE000 && rune <= 0xFFFD ||
+ rune >= 0x10000 && rune <= 0x10FFFF
+}
+
+// Get name space name: name with a : stuck in the middle.
+// The part before the : is the name space identifier.
+func (p *Parser) nsname() (name Name, ok bool) {
+ s, ok := p.name()
+ if !ok {
+ return
+ }
+ i := strings.Index(s, ":")
+ if i < 0 {
+ name.Local = s
+ } else {
+ name.Space = s[0:i]
+ name.Local = s[i+1:]
+ }
+ return name, true
+}
+
+// Get name: /first(first|second)*/
+// Do not set p.err if the name is missing (unless unexpected EOF is received):
+// let the caller provide better context.
+func (p *Parser) name() (s string, ok bool) {
+ var b byte
+ if b, ok = p.mustgetc(); !ok {
+ return
+ }
+
+ // As a first approximation, we gather the bytes [A-Za-z_:.-\x80-\xFF]*
+ if b < utf8.RuneSelf && !isNameByte(b) {
+ p.ungetc(b)
+ return "", false
+ }
+ p.buf.Reset()
+ p.buf.WriteByte(b)
+ for {
+ if b, ok = p.mustgetc(); !ok {
+ return
+ }
+ if b < utf8.RuneSelf && !isNameByte(b) {
+ p.ungetc(b)
+ break
+ }
+ p.buf.WriteByte(b)
+ }
+
+ // Then we check the characters.
+ s = p.buf.String()
+ for i, c := range s {
+ if !unicode.Is(first, c) && (i == 0 || !unicode.Is(second, c)) {
+ p.err = p.syntaxError("invalid XML name: " + s)
+ return "", false
+ }
+ }
+ return s, true
+}
+
+func isNameByte(c byte) bool {
+ return 'A' <= c && c <= 'Z' ||
+ 'a' <= c && c <= 'z' ||
+ '0' <= c && c <= '9' ||
+ c == '_' || c == ':' || c == '.' || c == '-'
+}
+
+// These tables were generated by cut and paste from Appendix B of
+// the XML spec at http://www.xml.com/axml/testaxml.htm
+// and then reformatting. First corresponds to (Letter | '_' | ':')
+// and second corresponds to NameChar.
+
+var first = []unicode.Range{
+ {0x003A, 0x003A, 1},
+ {0x0041, 0x005A, 1},
+ {0x005F, 0x005F, 1},
+ {0x0061, 0x007A, 1},
+ {0x00C0, 0x00D6, 1},
+ {0x00D8, 0x00F6, 1},
+ {0x00F8, 0x00FF, 1},
+ {0x0100, 0x0131, 1},
+ {0x0134, 0x013E, 1},
+ {0x0141, 0x0148, 1},
+ {0x014A, 0x017E, 1},
+ {0x0180, 0x01C3, 1},
+ {0x01CD, 0x01F0, 1},
+ {0x01F4, 0x01F5, 1},
+ {0x01FA, 0x0217, 1},
+ {0x0250, 0x02A8, 1},
+ {0x02BB, 0x02C1, 1},
+ {0x0386, 0x0386, 1},
+ {0x0388, 0x038A, 1},
+ {0x038C, 0x038C, 1},
+ {0x038E, 0x03A1, 1},
+ {0x03A3, 0x03CE, 1},
+ {0x03D0, 0x03D6, 1},
+ {0x03DA, 0x03E0, 2},
+ {0x03E2, 0x03F3, 1},
+ {0x0401, 0x040C, 1},
+ {0x040E, 0x044F, 1},
+ {0x0451, 0x045C, 1},
+ {0x045E, 0x0481, 1},
+ {0x0490, 0x04C4, 1},
+ {0x04C7, 0x04C8, 1},
+ {0x04CB, 0x04CC, 1},
+ {0x04D0, 0x04EB, 1},
+ {0x04EE, 0x04F5, 1},
+ {0x04F8, 0x04F9, 1},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x0559, 1},
+ {0x0561, 0x0586, 1},
+ {0x05D0, 0x05EA, 1},
+ {0x05F0, 0x05F2, 1},
+ {0x0621, 0x063A, 1},
+ {0x0641, 0x064A, 1},
+ {0x0671, 0x06B7, 1},
+ {0x06BA, 0x06BE, 1},
+ {0x06C0, 0x06CE, 1},
+ {0x06D0, 0x06D3, 1},
+ {0x06D5, 0x06D5, 1},
+ {0x06E5, 0x06E6, 1},
+ {0x0905, 0x0939, 1},
+ {0x093D, 0x093D, 1},
+ {0x0958, 0x0961, 1},
+ {0x0985, 0x098C, 1},
+ {0x098F, 0x0990, 1},
+ {0x0993, 0x09A8, 1},
+ {0x09AA, 0x09B0, 1},
+ {0x09B2, 0x09B2, 1},
+ {0x09B6, 0x09B9, 1},
+ {0x09DC, 0x09DD, 1},
+ {0x09DF, 0x09E1, 1},
+ {0x09F0, 0x09F1, 1},
+ {0x0A05, 0x0A0A, 1},
+ {0x0A0F, 0x0A10, 1},
+ {0x0A13, 0x0A28, 1},
+ {0x0A2A, 0x0A30, 1},
+ {0x0A32, 0x0A33, 1},
+ {0x0A35, 0x0A36, 1},
+ {0x0A38, 0x0A39, 1},
+ {0x0A59, 0x0A5C, 1},
+ {0x0A5E, 0x0A5E, 1},
+ {0x0A72, 0x0A74, 1},
+ {0x0A85, 0x0A8B, 1},
+ {0x0A8D, 0x0A8D, 1},
+ {0x0A8F, 0x0A91, 1},
+ {0x0A93, 0x0AA8, 1},
+ {0x0AAA, 0x0AB0, 1},
+ {0x0AB2, 0x0AB3, 1},
+ {0x0AB5, 0x0AB9, 1},
+ {0x0ABD, 0x0AE0, 0x23},
+ {0x0B05, 0x0B0C, 1},
+ {0x0B0F, 0x0B10, 1},
+ {0x0B13, 0x0B28, 1},
+ {0x0B2A, 0x0B30, 1},
+ {0x0B32, 0x0B33, 1},
+ {0x0B36, 0x0B39, 1},
+ {0x0B3D, 0x0B3D, 1},
+ {0x0B5C, 0x0B5D, 1},
+ {0x0B5F, 0x0B61, 1},
+ {0x0B85, 0x0B8A, 1},
+ {0x0B8E, 0x0B90, 1},
+ {0x0B92, 0x0B95, 1},
+ {0x0B99, 0x0B9A, 1},
+ {0x0B9C, 0x0B9C, 1},
+ {0x0B9E, 0x0B9F, 1},
+ {0x0BA3, 0x0BA4, 1},
+ {0x0BA8, 0x0BAA, 1},
+ {0x0BAE, 0x0BB5, 1},
+ {0x0BB7, 0x0BB9, 1},
+ {0x0C05, 0x0C0C, 1},
+ {0x0C0E, 0x0C10, 1},
+ {0x0C12, 0x0C28, 1},
+ {0x0C2A, 0x0C33, 1},
+ {0x0C35, 0x0C39, 1},
+ {0x0C60, 0x0C61, 1},
+ {0x0C85, 0x0C8C, 1},
+ {0x0C8E, 0x0C90, 1},
+ {0x0C92, 0x0CA8, 1},
+ {0x0CAA, 0x0CB3, 1},
+ {0x0CB5, 0x0CB9, 1},
+ {0x0CDE, 0x0CDE, 1},
+ {0x0CE0, 0x0CE1, 1},
+ {0x0D05, 0x0D0C, 1},
+ {0x0D0E, 0x0D10, 1},
+ {0x0D12, 0x0D28, 1},
+ {0x0D2A, 0x0D39, 1},
+ {0x0D60, 0x0D61, 1},
+ {0x0E01, 0x0E2E, 1},
+ {0x0E30, 0x0E30, 1},
+ {0x0E32, 0x0E33, 1},
+ {0x0E40, 0x0E45, 1},
+ {0x0E81, 0x0E82, 1},
+ {0x0E84, 0x0E84, 1},
+ {0x0E87, 0x0E88, 1},
+ {0x0E8A, 0x0E8D, 3},
+ {0x0E94, 0x0E97, 1},
+ {0x0E99, 0x0E9F, 1},
+ {0x0EA1, 0x0EA3, 1},
+ {0x0EA5, 0x0EA7, 2},
+ {0x0EAA, 0x0EAB, 1},
+ {0x0EAD, 0x0EAE, 1},
+ {0x0EB0, 0x0EB0, 1},
+ {0x0EB2, 0x0EB3, 1},
+ {0x0EBD, 0x0EBD, 1},
+ {0x0EC0, 0x0EC4, 1},
+ {0x0F40, 0x0F47, 1},
+ {0x0F49, 0x0F69, 1},
+ {0x10A0, 0x10C5, 1},
+ {0x10D0, 0x10F6, 1},
+ {0x1100, 0x1100, 1},
+ {0x1102, 0x1103, 1},
+ {0x1105, 0x1107, 1},
+ {0x1109, 0x1109, 1},
+ {0x110B, 0x110C, 1},
+ {0x110E, 0x1112, 1},
+ {0x113C, 0x1140, 2},
+ {0x114C, 0x1150, 2},
+ {0x1154, 0x1155, 1},
+ {0x1159, 0x1159, 1},
+ {0x115F, 0x1161, 1},
+ {0x1163, 0x1169, 2},
+ {0x116D, 0x116E, 1},
+ {0x1172, 0x1173, 1},
+ {0x1175, 0x119E, 0x119E - 0x1175},
+ {0x11A8, 0x11AB, 0x11AB - 0x11A8},
+ {0x11AE, 0x11AF, 1},
+ {0x11B7, 0x11B8, 1},
+ {0x11BA, 0x11BA, 1},
+ {0x11BC, 0x11C2, 1},
+ {0x11EB, 0x11F0, 0x11F0 - 0x11EB},
+ {0x11F9, 0x11F9, 1},
+ {0x1E00, 0x1E9B, 1},
+ {0x1EA0, 0x1EF9, 1},
+ {0x1F00, 0x1F15, 1},
+ {0x1F18, 0x1F1D, 1},
+ {0x1F20, 0x1F45, 1},
+ {0x1F48, 0x1F4D, 1},
+ {0x1F50, 0x1F57, 1},
+ {0x1F59, 0x1F5B, 0x1F5B - 0x1F59},
+ {0x1F5D, 0x1F5D, 1},
+ {0x1F5F, 0x1F7D, 1},
+ {0x1F80, 0x1FB4, 1},
+ {0x1FB6, 0x1FBC, 1},
+ {0x1FBE, 0x1FBE, 1},
+ {0x1FC2, 0x1FC4, 1},
+ {0x1FC6, 0x1FCC, 1},
+ {0x1FD0, 0x1FD3, 1},
+ {0x1FD6, 0x1FDB, 1},
+ {0x1FE0, 0x1FEC, 1},
+ {0x1FF2, 0x1FF4, 1},
+ {0x1FF6, 0x1FFC, 1},
+ {0x2126, 0x2126, 1},
+ {0x212A, 0x212B, 1},
+ {0x212E, 0x212E, 1},
+ {0x2180, 0x2182, 1},
+ {0x3007, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3041, 0x3094, 1},
+ {0x30A1, 0x30FA, 1},
+ {0x3105, 0x312C, 1},
+ {0x4E00, 0x9FA5, 1},
+ {0xAC00, 0xD7A3, 1},
+}
+
+var second = []unicode.Range{
+ {0x002D, 0x002E, 1},
+ {0x0030, 0x0039, 1},
+ {0x00B7, 0x00B7, 1},
+ {0x02D0, 0x02D1, 1},
+ {0x0300, 0x0345, 1},
+ {0x0360, 0x0361, 1},
+ {0x0387, 0x0387, 1},
+ {0x0483, 0x0486, 1},
+ {0x0591, 0x05A1, 1},
+ {0x05A3, 0x05B9, 1},
+ {0x05BB, 0x05BD, 1},
+ {0x05BF, 0x05BF, 1},
+ {0x05C1, 0x05C2, 1},
+ {0x05C4, 0x0640, 0x0640 - 0x05C4},
+ {0x064B, 0x0652, 1},
+ {0x0660, 0x0669, 1},
+ {0x0670, 0x0670, 1},
+ {0x06D6, 0x06DC, 1},
+ {0x06DD, 0x06DF, 1},
+ {0x06E0, 0x06E4, 1},
+ {0x06E7, 0x06E8, 1},
+ {0x06EA, 0x06ED, 1},
+ {0x06F0, 0x06F9, 1},
+ {0x0901, 0x0903, 1},
+ {0x093C, 0x093C, 1},
+ {0x093E, 0x094C, 1},
+ {0x094D, 0x094D, 1},
+ {0x0951, 0x0954, 1},
+ {0x0962, 0x0963, 1},
+ {0x0966, 0x096F, 1},
+ {0x0981, 0x0983, 1},
+ {0x09BC, 0x09BC, 1},
+ {0x09BE, 0x09BF, 1},
+ {0x09C0, 0x09C4, 1},
+ {0x09C7, 0x09C8, 1},
+ {0x09CB, 0x09CD, 1},
+ {0x09D7, 0x09D7, 1},
+ {0x09E2, 0x09E3, 1},
+ {0x09E6, 0x09EF, 1},
+ {0x0A02, 0x0A3C, 0x3A},
+ {0x0A3E, 0x0A3F, 1},
+ {0x0A40, 0x0A42, 1},
+ {0x0A47, 0x0A48, 1},
+ {0x0A4B, 0x0A4D, 1},
+ {0x0A66, 0x0A6F, 1},
+ {0x0A70, 0x0A71, 1},
+ {0x0A81, 0x0A83, 1},
+ {0x0ABC, 0x0ABC, 1},
+ {0x0ABE, 0x0AC5, 1},
+ {0x0AC7, 0x0AC9, 1},
+ {0x0ACB, 0x0ACD, 1},
+ {0x0AE6, 0x0AEF, 1},
+ {0x0B01, 0x0B03, 1},
+ {0x0B3C, 0x0B3C, 1},
+ {0x0B3E, 0x0B43, 1},
+ {0x0B47, 0x0B48, 1},
+ {0x0B4B, 0x0B4D, 1},
+ {0x0B56, 0x0B57, 1},
+ {0x0B66, 0x0B6F, 1},
+ {0x0B82, 0x0B83, 1},
+ {0x0BBE, 0x0BC2, 1},
+ {0x0BC6, 0x0BC8, 1},
+ {0x0BCA, 0x0BCD, 1},
+ {0x0BD7, 0x0BD7, 1},
+ {0x0BE7, 0x0BEF, 1},
+ {0x0C01, 0x0C03, 1},
+ {0x0C3E, 0x0C44, 1},
+ {0x0C46, 0x0C48, 1},
+ {0x0C4A, 0x0C4D, 1},
+ {0x0C55, 0x0C56, 1},
+ {0x0C66, 0x0C6F, 1},
+ {0x0C82, 0x0C83, 1},
+ {0x0CBE, 0x0CC4, 1},
+ {0x0CC6, 0x0CC8, 1},
+ {0x0CCA, 0x0CCD, 1},
+ {0x0CD5, 0x0CD6, 1},
+ {0x0CE6, 0x0CEF, 1},
+ {0x0D02, 0x0D03, 1},
+ {0x0D3E, 0x0D43, 1},
+ {0x0D46, 0x0D48, 1},
+ {0x0D4A, 0x0D4D, 1},
+ {0x0D57, 0x0D57, 1},
+ {0x0D66, 0x0D6F, 1},
+ {0x0E31, 0x0E31, 1},
+ {0x0E34, 0x0E3A, 1},
+ {0x0E46, 0x0E46, 1},
+ {0x0E47, 0x0E4E, 1},
+ {0x0E50, 0x0E59, 1},
+ {0x0EB1, 0x0EB1, 1},
+ {0x0EB4, 0x0EB9, 1},
+ {0x0EBB, 0x0EBC, 1},
+ {0x0EC6, 0x0EC6, 1},
+ {0x0EC8, 0x0ECD, 1},
+ {0x0ED0, 0x0ED9, 1},
+ {0x0F18, 0x0F19, 1},
+ {0x0F20, 0x0F29, 1},
+ {0x0F35, 0x0F39, 2},
+ {0x0F3E, 0x0F3F, 1},
+ {0x0F71, 0x0F84, 1},
+ {0x0F86, 0x0F8B, 1},
+ {0x0F90, 0x0F95, 1},
+ {0x0F97, 0x0F97, 1},
+ {0x0F99, 0x0FAD, 1},
+ {0x0FB1, 0x0FB7, 1},
+ {0x0FB9, 0x0FB9, 1},
+ {0x20D0, 0x20DC, 1},
+ {0x20E1, 0x3005, 0x3005 - 0x20E1},
+ {0x302A, 0x302F, 1},
+ {0x3031, 0x3035, 1},
+ {0x3099, 0x309A, 1},
+ {0x309D, 0x309E, 1},
+ {0x30FC, 0x30FE, 1},
+}
+
+// HTMLEntity is an entity map containing translations for the
+// standard HTML entity characters.
+var HTMLEntity = htmlEntity
+
+var htmlEntity = map[string]string{
+ /*
+ hget http://www.w3.org/TR/html4/sgml/entities.html |
+ ssam '
+ ,y /\&gt;/ x/\&lt;(.|\n)+/ s/\n/ /g
+ ,x v/^\&lt;!ENTITY/d
+ ,s/\&lt;!ENTITY ([^ ]+) .*U\+([0-9A-F][0-9A-F][0-9A-F][0-9A-F]) .+/ "\1": "\\u\2",/g
+ '
+ */
+ "nbsp": "\u00A0",
+ "iexcl": "\u00A1",
+ "cent": "\u00A2",
+ "pound": "\u00A3",
+ "curren": "\u00A4",
+ "yen": "\u00A5",
+ "brvbar": "\u00A6",
+ "sect": "\u00A7",
+ "uml": "\u00A8",
+ "copy": "\u00A9",
+ "ordf": "\u00AA",
+ "laquo": "\u00AB",
+ "not": "\u00AC",
+ "shy": "\u00AD",
+ "reg": "\u00AE",
+ "macr": "\u00AF",
+ "deg": "\u00B0",
+ "plusmn": "\u00B1",
+ "sup2": "\u00B2",
+ "sup3": "\u00B3",
+ "acute": "\u00B4",
+ "micro": "\u00B5",
+ "para": "\u00B6",
+ "middot": "\u00B7",
+ "cedil": "\u00B8",
+ "sup1": "\u00B9",
+ "ordm": "\u00BA",
+ "raquo": "\u00BB",
+ "frac14": "\u00BC",
+ "frac12": "\u00BD",
+ "frac34": "\u00BE",
+ "iquest": "\u00BF",
+ "Agrave": "\u00C0",
+ "Aacute": "\u00C1",
+ "Acirc": "\u00C2",
+ "Atilde": "\u00C3",
+ "Auml": "\u00C4",
+ "Aring": "\u00C5",
+ "AElig": "\u00C6",
+ "Ccedil": "\u00C7",
+ "Egrave": "\u00C8",
+ "Eacute": "\u00C9",
+ "Ecirc": "\u00CA",
+ "Euml": "\u00CB",
+ "Igrave": "\u00CC",
+ "Iacute": "\u00CD",
+ "Icirc": "\u00CE",
+ "Iuml": "\u00CF",
+ "ETH": "\u00D0",
+ "Ntilde": "\u00D1",
+ "Ograve": "\u00D2",
+ "Oacute": "\u00D3",
+ "Ocirc": "\u00D4",
+ "Otilde": "\u00D5",
+ "Ouml": "\u00D6",
+ "times": "\u00D7",
+ "Oslash": "\u00D8",
+ "Ugrave": "\u00D9",
+ "Uacute": "\u00DA",
+ "Ucirc": "\u00DB",
+ "Uuml": "\u00DC",
+ "Yacute": "\u00DD",
+ "THORN": "\u00DE",
+ "szlig": "\u00DF",
+ "agrave": "\u00E0",
+ "aacute": "\u00E1",
+ "acirc": "\u00E2",
+ "atilde": "\u00E3",
+ "auml": "\u00E4",
+ "aring": "\u00E5",
+ "aelig": "\u00E6",
+ "ccedil": "\u00E7",
+ "egrave": "\u00E8",
+ "eacute": "\u00E9",
+ "ecirc": "\u00EA",
+ "euml": "\u00EB",
+ "igrave": "\u00EC",
+ "iacute": "\u00ED",
+ "icirc": "\u00EE",
+ "iuml": "\u00EF",
+ "eth": "\u00F0",
+ "ntilde": "\u00F1",
+ "ograve": "\u00F2",
+ "oacute": "\u00F3",
+ "ocirc": "\u00F4",
+ "otilde": "\u00F5",
+ "ouml": "\u00F6",
+ "divide": "\u00F7",
+ "oslash": "\u00F8",
+ "ugrave": "\u00F9",
+ "uacute": "\u00FA",
+ "ucirc": "\u00FB",
+ "uuml": "\u00FC",
+ "yacute": "\u00FD",
+ "thorn": "\u00FE",
+ "yuml": "\u00FF",
+ "fnof": "\u0192",
+ "Alpha": "\u0391",
+ "Beta": "\u0392",
+ "Gamma": "\u0393",
+ "Delta": "\u0394",
+ "Epsilon": "\u0395",
+ "Zeta": "\u0396",
+ "Eta": "\u0397",
+ "Theta": "\u0398",
+ "Iota": "\u0399",
+ "Kappa": "\u039A",
+ "Lambda": "\u039B",
+ "Mu": "\u039C",
+ "Nu": "\u039D",
+ "Xi": "\u039E",
+ "Omicron": "\u039F",
+ "Pi": "\u03A0",
+ "Rho": "\u03A1",
+ "Sigma": "\u03A3",
+ "Tau": "\u03A4",
+ "Upsilon": "\u03A5",
+ "Phi": "\u03A6",
+ "Chi": "\u03A7",
+ "Psi": "\u03A8",
+ "Omega": "\u03A9",
+ "alpha": "\u03B1",
+ "beta": "\u03B2",
+ "gamma": "\u03B3",
+ "delta": "\u03B4",
+ "epsilon": "\u03B5",
+ "zeta": "\u03B6",
+ "eta": "\u03B7",
+ "theta": "\u03B8",
+ "iota": "\u03B9",
+ "kappa": "\u03BA",
+ "lambda": "\u03BB",
+ "mu": "\u03BC",
+ "nu": "\u03BD",
+ "xi": "\u03BE",
+ "omicron": "\u03BF",
+ "pi": "\u03C0",
+ "rho": "\u03C1",
+ "sigmaf": "\u03C2",
+ "sigma": "\u03C3",
+ "tau": "\u03C4",
+ "upsilon": "\u03C5",
+ "phi": "\u03C6",
+ "chi": "\u03C7",
+ "psi": "\u03C8",
+ "omega": "\u03C9",
+ "thetasym": "\u03D1",
+ "upsih": "\u03D2",
+ "piv": "\u03D6",
+ "bull": "\u2022",
+ "hellip": "\u2026",
+ "prime": "\u2032",
+ "Prime": "\u2033",
+ "oline": "\u203E",
+ "frasl": "\u2044",
+ "weierp": "\u2118",
+ "image": "\u2111",
+ "real": "\u211C",
+ "trade": "\u2122",
+ "alefsym": "\u2135",
+ "larr": "\u2190",
+ "uarr": "\u2191",
+ "rarr": "\u2192",
+ "darr": "\u2193",
+ "harr": "\u2194",
+ "crarr": "\u21B5",
+ "lArr": "\u21D0",
+ "uArr": "\u21D1",
+ "rArr": "\u21D2",
+ "dArr": "\u21D3",
+ "hArr": "\u21D4",
+ "forall": "\u2200",
+ "part": "\u2202",
+ "exist": "\u2203",
+ "empty": "\u2205",
+ "nabla": "\u2207",
+ "isin": "\u2208",
+ "notin": "\u2209",
+ "ni": "\u220B",
+ "prod": "\u220F",
+ "sum": "\u2211",
+ "minus": "\u2212",
+ "lowast": "\u2217",
+ "radic": "\u221A",
+ "prop": "\u221D",
+ "infin": "\u221E",
+ "ang": "\u2220",
+ "and": "\u2227",
+ "or": "\u2228",
+ "cap": "\u2229",
+ "cup": "\u222A",
+ "int": "\u222B",
+ "there4": "\u2234",
+ "sim": "\u223C",
+ "cong": "\u2245",
+ "asymp": "\u2248",
+ "ne": "\u2260",
+ "equiv": "\u2261",
+ "le": "\u2264",
+ "ge": "\u2265",
+ "sub": "\u2282",
+ "sup": "\u2283",
+ "nsub": "\u2284",
+ "sube": "\u2286",
+ "supe": "\u2287",
+ "oplus": "\u2295",
+ "otimes": "\u2297",
+ "perp": "\u22A5",
+ "sdot": "\u22C5",
+ "lceil": "\u2308",
+ "rceil": "\u2309",
+ "lfloor": "\u230A",
+ "rfloor": "\u230B",
+ "lang": "\u2329",
+ "rang": "\u232A",
+ "loz": "\u25CA",
+ "spades": "\u2660",
+ "clubs": "\u2663",
+ "hearts": "\u2665",
+ "diams": "\u2666",
+ "quot": "\u0022",
+ "amp": "\u0026",
+ "lt": "\u003C",
+ "gt": "\u003E",
+ "OElig": "\u0152",
+ "oelig": "\u0153",
+ "Scaron": "\u0160",
+ "scaron": "\u0161",
+ "Yuml": "\u0178",
+ "circ": "\u02C6",
+ "tilde": "\u02DC",
+ "ensp": "\u2002",
+ "emsp": "\u2003",
+ "thinsp": "\u2009",
+ "zwnj": "\u200C",
+ "zwj": "\u200D",
+ "lrm": "\u200E",
+ "rlm": "\u200F",
+ "ndash": "\u2013",
+ "mdash": "\u2014",
+ "lsquo": "\u2018",
+ "rsquo": "\u2019",
+ "sbquo": "\u201A",
+ "ldquo": "\u201C",
+ "rdquo": "\u201D",
+ "bdquo": "\u201E",
+ "dagger": "\u2020",
+ "Dagger": "\u2021",
+ "permil": "\u2030",
+ "lsaquo": "\u2039",
+ "rsaquo": "\u203A",
+ "euro": "\u20AC",
+}
+
+// HTMLAutoClose is the set of HTML elements that
+// should be considered to close automatically.
+var HTMLAutoClose = htmlAutoClose
+
+var htmlAutoClose = []string{
+ /*
+ hget http://www.w3.org/TR/html4/loose.dtd |
+ 9 sed -n 's/<!ELEMENT (.*) - O EMPTY.+/ "\1",/p' | tr A-Z a-z
+ */
+ "basefont",
+ "br",
+ "area",
+ "link",
+ "img",
+ "param",
+ "hr",
+ "input",
+ "col ",
+ "frame",
+ "isindex",
+ "base",
+ "meta",
+}
+
+var (
+ esc_quot = []byte("&#34;") // shorter than "&quot;"
+ esc_apos = []byte("&#39;") // shorter than "&apos;"
+ esc_amp = []byte("&amp;")
+ esc_lt = []byte("&lt;")
+ esc_gt = []byte("&gt;")
+)
+
+// Escape writes to w the properly escaped XML equivalent
+// of the plain text data s.
+func Escape(w io.Writer, s []byte) {
+ var esc []byte
+ last := 0
+ for i, c := range s {
+ switch c {
+ case '"':
+ esc = esc_quot
+ case '\'':
+ esc = esc_apos
+ case '&':
+ esc = esc_amp
+ case '<':
+ esc = esc_lt
+ case '>':
+ esc = esc_gt
+ default:
+ continue
+ }
+ w.Write(s[last:i])
+ w.Write(esc)
+ last = i + 1
+ }
+ w.Write(s[last:])
+}
diff --git a/libgo/go/xml/xml_test.go b/libgo/go/xml/xml_test.go
new file mode 100644
index 000000000..317ecabd9
--- /dev/null
+++ b/libgo/go/xml/xml_test.go
@@ -0,0 +1,439 @@
+// 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 xml
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "reflect"
+ "testing"
+)
+
+const testInput = `
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<body xmlns:foo="ns1" xmlns="ns2" xmlns:tag="ns3" ` +
+ "\r\n\t" + ` >
+ <hello lang="en">World &lt;&gt;&apos;&quot; &#x767d;&#40300;翔</hello>
+ <goodbye />
+ <outer foo:attr="value" xmlns:tag="ns4">
+ <inner/>
+ </outer>
+ <tag:name>
+ <![CDATA[Some text here.]]>
+ </tag:name>
+</body><!-- missing final newline -->`
+
+var rawTokens = []Token{
+ CharData([]byte("\n")),
+ ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
+ CharData([]byte("\n")),
+ Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
+ ),
+ CharData([]byte("\n")),
+ StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
+ CharData([]byte("World <>'\" 白鵬翔")),
+ EndElement{Name{"", "hello"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"", "goodbye"}, nil},
+ EndElement{Name{"", "goodbye"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"", "inner"}, nil},
+ EndElement{Name{"", "inner"}},
+ CharData([]byte("\n ")),
+ EndElement{Name{"", "outer"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"tag", "name"}, nil},
+ CharData([]byte("\n ")),
+ CharData([]byte("Some text here.")),
+ CharData([]byte("\n ")),
+ EndElement{Name{"tag", "name"}},
+ CharData([]byte("\n")),
+ EndElement{Name{"", "body"}},
+ Comment([]byte(" missing final newline ")),
+}
+
+var cookedTokens = []Token{
+ CharData([]byte("\n")),
+ ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
+ CharData([]byte("\n")),
+ Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
+ ),
+ CharData([]byte("\n")),
+ StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
+ CharData([]byte("World <>'\" 白鵬翔")),
+ EndElement{Name{"ns2", "hello"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"ns2", "goodbye"}, nil},
+ EndElement{Name{"ns2", "goodbye"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"ns2", "inner"}, nil},
+ EndElement{Name{"ns2", "inner"}},
+ CharData([]byte("\n ")),
+ EndElement{Name{"ns2", "outer"}},
+ CharData([]byte("\n ")),
+ StartElement{Name{"ns3", "name"}, nil},
+ CharData([]byte("\n ")),
+ CharData([]byte("Some text here.")),
+ CharData([]byte("\n ")),
+ EndElement{Name{"ns3", "name"}},
+ CharData([]byte("\n")),
+ EndElement{Name{"ns2", "body"}},
+ Comment([]byte(" missing final newline ")),
+}
+
+var xmlInput = []string{
+ // unexpected EOF cases
+ "<",
+ "<t",
+ "<t ",
+ "<t/",
+ "<!",
+ "<!-",
+ "<!--",
+ "<!--c-",
+ "<!--c--",
+ "<!d",
+ "<t></",
+ "<t></t",
+ "<?",
+ "<?p",
+ "<t a",
+ "<t a=",
+ "<t a='",
+ "<t a=''",
+ "<t/><![",
+ "<t/><![C",
+ "<t/><![CDATA[d",
+ "<t/><![CDATA[d]",
+ "<t/><![CDATA[d]]",
+
+ // other Syntax errors
+ "<>",
+ "<t/a",
+ "<0 />",
+ "<?0 >",
+ // "<!0 >", // let the Token() caller handle
+ "</0>",
+ "<t 0=''>",
+ "<t a='&'>",
+ "<t a='<'>",
+ "<t>&nbspc;</t>",
+ "<t a>",
+ "<t a=>",
+ "<t a=v>",
+ // "<![CDATA[d]]>", // let the Token() caller handle
+ "<t></e>",
+ "<t></>",
+ "<t></t!",
+ "<t>cdata]]></t>",
+}
+
+type stringReader struct {
+ s string
+ off int
+}
+
+func (r *stringReader) Read(b []byte) (n int, err os.Error) {
+ if r.off >= len(r.s) {
+ return 0, os.EOF
+ }
+ for r.off < len(r.s) && n < len(b) {
+ b[n] = r.s[r.off]
+ n++
+ r.off++
+ }
+ return
+}
+
+func (r *stringReader) ReadByte() (b byte, err os.Error) {
+ if r.off >= len(r.s) {
+ return 0, os.EOF
+ }
+ b = r.s[r.off]
+ r.off++
+ return
+}
+
+func StringReader(s string) io.Reader { return &stringReader{s, 0} }
+
+func TestRawToken(t *testing.T) {
+ p := NewParser(StringReader(testInput))
+
+ for i, want := range rawTokens {
+ have, err := p.RawToken()
+ if err != nil {
+ t.Fatalf("token %d: unexpected error: %s", i, err)
+ }
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("token %d = %#v want %#v", i, have, want)
+ }
+ }
+}
+
+func TestToken(t *testing.T) {
+ p := NewParser(StringReader(testInput))
+
+ for i, want := range cookedTokens {
+ have, err := p.Token()
+ if err != nil {
+ t.Fatalf("token %d: unexpected error: %s", i, err)
+ }
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("token %d = %#v want %#v", i, have, want)
+ }
+ }
+}
+
+func TestSyntax(t *testing.T) {
+ for i := range xmlInput {
+ p := NewParser(StringReader(xmlInput[i]))
+ var err os.Error
+ for _, err = p.Token(); err == nil; _, err = p.Token() {
+ }
+ if _, ok := err.(*SyntaxError); !ok {
+ t.Fatalf(`xmlInput "%s": expected SyntaxError not received`, xmlInput[i])
+ }
+ }
+}
+
+type allScalars struct {
+ True1 bool
+ True2 bool
+ False1 bool
+ False2 bool
+ Int int
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint int
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ Uintptr uintptr
+ Float32 float32
+ Float64 float64
+ String string
+}
+
+var all = allScalars{
+ True1: true,
+ True2: true,
+ False1: false,
+ False2: false,
+ Int: 1,
+ Int8: -2,
+ Int16: 3,
+ Int32: -4,
+ Int64: 5,
+ Uint: 6,
+ Uint8: 7,
+ Uint16: 8,
+ Uint32: 9,
+ Uint64: 10,
+ Uintptr: 11,
+ Float32: 13.0,
+ Float64: 14.0,
+ String: "15",
+}
+
+const testScalarsInput = `<allscalars>
+ <true1>true</true1>
+ <true2>1</true2>
+ <false1>false</false1>
+ <false2>0</false2>
+ <int>1</int>
+ <int8>-2</int8>
+ <int16>3</int16>
+ <int32>-4</int32>
+ <int64>5</int64>
+ <uint>6</uint>
+ <uint8>7</uint8>
+ <uint16>8</uint16>
+ <uint32>9</uint32>
+ <uint64>10</uint64>
+ <uintptr>11</uintptr>
+ <float>12.0</float>
+ <float32>13.0</float32>
+ <float64>14.0</float64>
+ <string>15</string>
+</allscalars>`
+
+func TestAllScalars(t *testing.T) {
+ var a allScalars
+ buf := bytes.NewBufferString(testScalarsInput)
+ err := Unmarshal(buf, &a)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(a, all) {
+ t.Errorf("expected %+v got %+v", all, a)
+ }
+}
+
+type item struct {
+ Field_a string
+}
+
+func TestIssue569(t *testing.T) {
+ data := `<item><field_a>abcd</field_a></item>`
+ var i item
+ buf := bytes.NewBufferString(data)
+ err := Unmarshal(buf, &i)
+
+ if err != nil || i.Field_a != "abcd" {
+ t.Fatal("Expecting abcd")
+ }
+}
+
+func TestUnquotedAttrs(t *testing.T) {
+ data := "<tag attr=azAZ09:-_\t>"
+ p := NewParser(StringReader(data))
+ p.Strict = false
+ token, err := p.Token()
+ if _, ok := err.(*SyntaxError); ok {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if token.(StartElement).Name.Local != "tag" {
+ t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
+ }
+ attr := token.(StartElement).Attr[0]
+ if attr.Value != "azAZ09:-_" {
+ t.Errorf("Unexpected attribute value: %v", attr.Value)
+ }
+ if attr.Name.Local != "attr" {
+ t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
+ }
+}
+
+func TestCopyTokenCharData(t *testing.T) {
+ data := []byte("same data")
+ var tok1 Token = CharData(data)
+ tok2 := CopyToken(tok1)
+ if !reflect.DeepEqual(tok1, tok2) {
+ t.Error("CopyToken(CharData) != CharData")
+ }
+ data[1] = 'o'
+ if reflect.DeepEqual(tok1, tok2) {
+ t.Error("CopyToken(CharData) uses same buffer.")
+ }
+}
+
+func TestCopyTokenStartElement(t *testing.T) {
+ elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}
+ var tok1 Token = elt
+ tok2 := CopyToken(tok1)
+ if !reflect.DeepEqual(tok1, tok2) {
+ t.Error("CopyToken(StartElement) != StartElement")
+ }
+ elt.Attr[0] = Attr{Name{"", "lang"}, "de"}
+ if reflect.DeepEqual(tok1, tok2) {
+ t.Error("CopyToken(CharData) uses same buffer.")
+ }
+}
+
+func TestSyntaxErrorLineNum(t *testing.T) {
+ testInput := "<P>Foo<P>\n\n<P>Bar</>\n"
+ p := NewParser(StringReader(testInput))
+ var err os.Error
+ for _, err = p.Token(); err == nil; _, err = p.Token() {
+ }
+ synerr, ok := err.(*SyntaxError)
+ if !ok {
+ t.Error("Expected SyntaxError.")
+ }
+ if synerr.Line != 3 {
+ t.Error("SyntaxError didn't have correct line number.")
+ }
+}
+
+func TestTrailingRawToken(t *testing.T) {
+ input := `<FOO></FOO> `
+ p := NewParser(StringReader(input))
+ var err os.Error
+ for _, err = p.RawToken(); err == nil; _, err = p.RawToken() {
+ }
+ if err != os.EOF {
+ t.Fatalf("p.RawToken() = _, %v, want _, os.EOF", err)
+ }
+}
+
+func TestTrailingToken(t *testing.T) {
+ input := `<FOO></FOO> `
+ p := NewParser(StringReader(input))
+ var err os.Error
+ for _, err = p.Token(); err == nil; _, err = p.Token() {
+ }
+ if err != os.EOF {
+ t.Fatalf("p.Token() = _, %v, want _, os.EOF", err)
+ }
+}
+
+func TestEntityInsideCDATA(t *testing.T) {
+ input := `<test><![CDATA[ &val=foo ]]></test>`
+ p := NewParser(StringReader(input))
+ var err os.Error
+ for _, err = p.Token(); err == nil; _, err = p.Token() {
+ }
+ if err != os.EOF {
+ t.Fatalf("p.Token() = _, %v, want _, os.EOF", err)
+ }
+}
+
+
+// The last three tests (respectively one for characters in attribute
+// names and two for character entities) pass not because of code
+// changed for issue 1259, but instead pass with the given messages
+// from other parts of xml.Parser. I provide these to note the
+// current behavior of situations where one might think that character
+// range checking would detect the error, but it does not in fact.
+
+var characterTests = []struct {
+ in string
+ err string
+}{
+ {"\x12<doc/>", "illegal character code U+0012"},
+ {"<?xml version=\"1.0\"?>\x0b<doc/>", "illegal character code U+000B"},
+ {"\xef\xbf\xbe<doc/>", "illegal character code U+FFFE"},
+ {"<?xml version=\"1.0\"?><doc>\r\n<hiya/>\x07<toots/></doc>", "illegal character code U+0007"},
+ {"<?xml version=\"1.0\"?><doc \x12='value'>what's up</doc>", "expected attribute name in element"},
+ {"<doc>&\x01;</doc>", "invalid character entity &;"},
+ {"<doc>&\xef\xbf\xbe;</doc>", "invalid character entity &;"},
+}
+
+
+func TestDisallowedCharacters(t *testing.T) {
+
+ for i, tt := range characterTests {
+ p := NewParser(StringReader(tt.in))
+ var err os.Error
+
+ for err == nil {
+ _, err = p.Token()
+ }
+ synerr, ok := err.(*SyntaxError)
+ if !ok {
+ t.Fatalf("input %d p.Token() = _, %v, want _, *SyntaxError", i, err)
+ }
+ if synerr.Msg != tt.err {
+ t.Fatalf("input %d synerr.Msg wrong: want '%s', got '%s'", i, tt.err, synerr.Msg)
+ }
+ }
+}
diff --git a/libgo/merge.sh b/libgo/merge.sh
new file mode 100644
index 000000000..17dc57340
--- /dev/null
+++ b/libgo/merge.sh
@@ -0,0 +1,173 @@
+#!/bin/sh
+
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This script merges changes from the master copy of the Go library
+# into the libgo library. This does the easy stuff; the hard stuff is
+# left to the user.
+
+# The file MERGE should hold the Mercurial revision number of the last
+# revision which was merged into these sources. Given that, and given
+# the current sources, we can run the usual diff3 algorithm to merge
+# all changes into our sources.
+
+set -e
+
+TMPDIR=${TMPDIR:-/tmp}
+
+OLDDIR=${TMPDIR}/libgo-merge-old
+NEWDIR=${TMPDIR}/libgo-merge-new
+
+if ! test -f MERGE; then
+ echo 1>&2 "merge.sh: must be run in libgo source directory"
+ exit 1
+fi
+
+if test $# -ne 1; then
+ echo 1>&2 "merge.sh: Usage: merge.sh mercurial-repository"
+ exit 1
+fi
+
+repository=$1
+
+merge_rev=`sed 1q MERGE`
+
+rm -rf ${OLDDIR}
+hg clone -r ${merge_rev} ${repository} ${OLDDIR}
+
+rm -rf ${NEWDIR}
+hg clone ${repository} ${NEWDIR}
+
+new_rev=`cd ${NEWDIR} && hg log | sed 1q | sed -e 's/.*://'`
+
+merge() {
+ name=$1
+ old=$2
+ new=$3
+ libgo=$4
+ if ! test -f ${new}; then
+ # The file does not exist in the new version.
+ if ! test -f ${old}; then
+ echo 1>&2 "merge.sh internal error no files $old $new"
+ exit 1
+ fi
+ if ! test -f ${libgo}; then
+ # File removed in new version and libgo.
+ :;
+ else
+ echo "merge.sh: ${name}: REMOVED"
+ rm -f ${libgo}
+ hg rm ${libgo}
+ fi
+ elif test -f ${old}; then
+ # The file exists in the old version.
+ if ! test -f ${libgo}; then
+ echo "merge.sh: $name: skipping: exists in old and new hg, but not in libgo"
+ continue
+ fi
+ if cmp -s ${old} ${libgo}; then
+ # The libgo file is unchanged from the old version.
+ if cmp -s ${new} ${libgo}; then
+ # File is unchanged from old to new version.
+ continue
+ fi
+ # Update file in libgo.
+ echo "merge.sh: $name: updating"
+ cp ${new} ${libgo}
+ else
+ # The libgo file has local changes.
+ set +e
+ diff3 -m -E ${libgo} ${old} ${new} > ${libgo}.tmp
+ status=$?
+ set -e
+ case $status in
+ 0)
+ echo "merge.sh: $name: updating"
+ mv ${libgo}.tmp ${libgo}
+ ;;
+ 1)
+ echo "merge.sh: $name: CONFLICTS"
+ mv ${libgo}.tmp ${libgo}
+ hg resolve -u ${libgo}
+ ;;
+ *)
+ echo 1>&2 "merge.sh: $name: diff3 failure"
+ exit 1
+ ;;
+ esac
+ fi
+ else
+ # The file does not exist in the old version.
+ if test -f ${libgo}; then
+ if ! cmp -s ${new} ${libgo}; then
+ echo 1>&2 "merge.sh: $name: IN NEW AND LIBGO BUT NOT OLD"
+ fi
+ else
+ echo "merge.sh: $name: NEW"
+ dir=`dirname ${libgo}`
+ if ! test -d ${dir}; then
+ mkdir -p ${dir}
+ fi
+ cp ${new} ${libgo}
+ hg add ${libgo}
+ fi
+ fi
+}
+
+(cd ${NEWDIR}/src/pkg && find . -name '*.go' -print) | while read f; do
+ if test `dirname $f` = "./syscall"; then
+ continue
+ fi
+ oldfile=${OLDDIR}/src/pkg/$f
+ newfile=${NEWDIR}/src/pkg/$f
+ libgofile=go/$f
+ merge $f ${oldfile} ${newfile} ${libgofile}
+done
+
+(cd ${NEWDIR}/src/pkg && find . -name testdata -print) | while read d; do
+ oldtd=${OLDDIR}/src/pkg/$d
+ newtd=${NEWDIR}/src/pkg/$d
+ libgotd=go/$d
+ if ! test -d ${oldtd}; then
+ continue
+ fi
+ (cd ${oldtd} && hg status -A .) | while read f; do
+ if test "`basename $f`" = ".hgignore"; then
+ continue
+ fi
+ f=`echo $f | sed -e 's/^..//'`
+ name=$d/$f
+ oldfile=${oldtd}/$f
+ newfile=${newtd}/$f
+ libgofile=${libgotd}/$f
+ merge ${name} ${oldfile} ${newfile} ${libgofile}
+ done
+done
+
+runtime="goc2c.c mcache.c mcentral.c mfinal.c mfixalloc.c mgc0.c mheap.c mheapmap32.c mheapmap64.c msize.c malloc.h mheapmap32.h mheapmap64.h malloc.goc mprof.goc"
+for f in $runtime; do
+ oldfile=${OLDDIR}/src/pkg/runtime/$f
+ newfile=${NEWDIR}/src/pkg/runtime/$f
+ libgofile=runtime/$f
+ merge $f ${oldfile} ${newfile} ${libgofile}
+done
+
+(cd ${OLDDIR}/src/pkg && find . -name '*.go' -print) | while read f; do
+ oldfile=${OLDDIR}/src/pkg/$f
+ newfile=${NEWDIR}/src/pkg/$f
+ libgofile=go/$f
+ if test -f ${newfile}; then
+ continue
+ fi
+ if ! test -f ${libgofile}; then
+ continue
+ fi
+ echo "merge.sh: ${libgofile}: REMOVED"
+ rm -f ${libgofile}
+ hg rm ${libgofile}
+done
+
+(echo ${new_rev}; sed -ne '2,$p' MERGE) > MERGE.tmp
+mv MERGE.tmp MERGE
diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh
new file mode 100755
index 000000000..e29febfa6
--- /dev/null
+++ b/libgo/mksysinfo.sh
@@ -0,0 +1,419 @@
+#!/bin/sh
+
+# 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.
+
+# Create sysinfo.go.
+
+# This shell script creates the sysinfo.go file which holds types and
+# constants extracted from the system header files. This relies on a
+# hook in gcc: the -fdump-go-spec option will generate debugging
+# information in Go syntax.
+
+# We currently #include all the files at once, which works, but leads
+# to exposing some names which ideally should not be exposed, as they
+# match grep patterns. E.g., WCHAR_MIN gets exposed because it starts
+# with W, like the wait flags.
+
+CC=${CC:-gcc}
+OUT=tmp-sysinfo.go
+
+set -e
+
+rm -f sysinfo.c
+cat > sysinfo.c <<EOF
+#include "config.h"
+
+#define _GNU_SOURCE
+#define _LARGEFILE_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+#if defined(__sun__) && defined(__svr4__)
+/* Needed by Solaris header files. */
+#define _XOPEN_SOURCE 600
+#define __EXTENSIONS__
+#endif
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#if defined(HAVE_SYSCALL_H)
+#include <syscall.h>
+#endif
+#if defined(HAVE_SYS_SYSCALL_H)
+#include <sys/syscall.h>
+#endif
+#if defined(HAVE_SYS_EPOLL_H)
+#include <sys/epoll.h>
+#endif
+#if defined(HAVE_SYS_PTRACE_H)
+#include <sys/ptrace.h>
+#endif
+#include <sys/resource.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#if defined(HAVE_SYS_USER_H)
+#include <sys/user.h>
+#endif
+#if defined(HAVE_SYS_UTSNAME_H)
+#include <sys/utsname.h>
+#endif
+#include <unistd.h>
+EOF
+
+${CC} -fdump-go-spec=gen-sysinfo.go -std=gnu99 -S -o sysinfo.s sysinfo.c
+
+echo 'package syscall' > ${OUT}
+
+# Get all the consts and types, skipping ones which could not be
+# represented in Go and ones which we need to rewrite. We also skip
+# function declarations, as we don't need them here. All the symbols
+# will all have a leading underscore.
+grep -v '^// ' gen-sysinfo.go | \
+ grep -v '^func' | \
+ grep -v '^type _timeval ' | \
+ grep -v '^type _timespec ' | \
+ grep -v '^type _timestruc_t ' | \
+ grep -v '^type _epoll_' | \
+ grep -v 'in6_addr' | \
+ grep -v 'sockaddr_in6' | \
+ sed -e 's/\([^a-zA-Z0-9_]\)_timeval\([^a-zA-Z0-9_]\)/\1Timeval\2/g' \
+ -e 's/\([^a-zA-Z0-9_]\)_timespec\([^a-zA-Z0-9_]\)/\1Timespec\2/g' \
+ -e 's/\([^a-zA-Z0-9_]\)_timestruc_t\([^a-zA-Z0-9_]\)/\1Timestruc\2/g' \
+ >> ${OUT}
+
+# The errno constants.
+grep '^const _E' gen-sysinfo.go | \
+ sed -e 's/^\(const \)_\(E[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# The O_xxx flags.
+grep '^const _\(O\|F\|FD\)_' gen-sysinfo.go | \
+ sed -e 's/^\(const \)_\([^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+if ! grep '^const O_ASYNC' ${OUT} >/dev/null 2>&1; then
+ echo "const O_ASYNC = 0" >> ${OUT}
+fi
+if ! grep '^const O_CLOEXEC' ${OUT} >/dev/null 2>&1; then
+ echo "const O_CLOEXEC = 0" >> ${OUT}
+fi
+
+# The signal numbers.
+grep '^const _SIG[^_]' gen-sysinfo.go | \
+ grep -v '^const _SIGEV_' | \
+ sed -e 's/^\(const \)_\(SIG[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# The syscall numbers. We force the names to upper case.
+grep '^const _SYS_' gen-sysinfo.go | \
+ sed -e 's/const _\(SYS_[^= ]*\).*$/\1/' | \
+ while read sys; do
+ sup=`echo $sys | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
+ echo "const $sup = _$sys" >> ${OUT}
+ done
+
+# Stat constants.
+grep '^const _S_' gen-sysinfo.go | \
+ sed -e 's/^\(const \)_\(S_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# Process status constants.
+grep '^const _W' gen-sysinfo.go |
+ sed -e 's/^\(const \)_\(W[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+# WSTOPPED was introduced in glibc 2.3.4.
+if ! grep '^const _WSTOPPED = ' gen-sysinfo.go >/dev/null 2>&1; then
+ if grep '^const _WUNTRACED = ' gen-sysinfo.go > /dev/null 2>&1; then
+ echo 'const WSTOPPED = _WUNTRACED' >> ${OUT}
+ else
+ echo 'const WSTOPPED = 2' >> ${OUT}
+ fi
+fi
+if grep '^const ___WALL = ' gen-sysinfo.go >/dev/null 2>&1 \
+ && ! grep '^const _WALL = ' gen-sysinfo.go >/dev/null 2>&1; then
+ echo 'const WALL = ___WALL' >> ${OUT}
+fi
+
+# Networking constants.
+grep '^const _\(AF\|SOCK\|SOL\|SO\|IPPROTO\|TCP\|IP\|IPV6\)_' gen-sysinfo.go |
+ sed -e 's/^\(const \)_\([^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+grep '^const _SOMAXCONN' gen-sysinfo.go |
+ sed -e 's/^\(const \)_\(SOMAXCONN[^= ]*\)\(.*\)$/\1\2 = _\2/' \
+ >> ${OUT}
+grep '^const _SHUT_' gen-sysinfo.go |
+ sed -e 's/^\(const \)_\(SHUT[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# The net package requires a definition for IPV6ONLY.
+if ! grep '^const IPV6_V6ONLY ' ${OUT} >/dev/null 2>&1; then
+ echo "const IPV6_V6ONLY = 0" >> ${OUT}
+fi
+
+# pathconf constants.
+grep '^const __PC' gen-sysinfo.go |
+ sed -e 's/^\(const \)__\(PC[^= ]*\)\(.*\)$/\1\2 = __\2/' >> ${OUT}
+
+# The epoll constants were picked up by the errno constants, but we
+# need to be sure the EPOLLRDHUP is defined.
+if ! grep '^const EPOLLRDHUP' ${OUT} >/dev/null 2>&1; then
+ echo "const EPOLLRDHUP = 0x2000" >> ${OUT}
+fi
+
+# Ptrace constants. We don't expose all the PTRACE flags, just the
+# PTRACE_O_xxx and PTRACE_EVENT_xxx ones.
+grep '^const _PTRACE_O' gen-sysinfo.go |
+ sed -e 's/^\(const \)_\(PTRACE_O[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+grep '^const _PTRACE_EVENT' gen-sysinfo.go |
+ sed -e 's/^\(const \)_\(PTRACE_EVENT[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+# We need PTRACE_SETOPTIONS and PTRACE_GETEVENTMSG, but they are not
+# defined in older versions of glibc.
+if ! grep '^const _PTRACE_SETOPTIONS' ${OUT} > /dev/null 2>&1; then
+ echo "const _PTRACE_SETOPTIONS = 0x4200" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACESYSGOOD' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_O_TRACESYSGOOD = 0x1" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACEFORK' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_O_TRACEFORK = 0x2" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACEVFORK' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_O_TRACEVFORK = 0x4" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACECLONE' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_O_TRACECLONE = 0x8" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACEEXEC' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_O_TRACEEXEC = 0x10" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACEVFORKDONE' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_O_TRACEVFORKDONE = 0x20" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_TRACEEXIT' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_O_TRACEEXIT = 0x40" >> ${OUT}
+fi
+if ! grep '^const PTRACE_O_MASK' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_O_MASK = 0x7f" >> ${OUT}
+fi
+if ! grep '^const _PTRACE_GETEVENTMSG' ${OUT} > /dev/null 2>&1; then
+ echo "const _PTRACE_GETEVENTMSG = 0x4201" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_FORK' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_EVENT_FORK = 1" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_VFORK' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_EVENT_VFORK = 2" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_CLONE' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_EVENT_CLONE = 3" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_EXEC' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_EVENT_EXEC = 4" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_VFORK_DONE' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_EVENT_VFORK_DONE = 5" >> ${OUT}
+fi
+if ! grep '^const PTRACE_EVENT_EXIT' ${OUT} > /dev/null 2>&1; then
+ echo "const PTRACE_EVENT_EXIT = 6" >> ${OUT}
+fi
+if ! grep '^const _PTRACE_TRACEME' ${OUT} > /dev/null 2>&1; then
+ echo "const _PTRACE_TRACEME = 0" >> ${OUT}
+fi
+
+# The registers returned by PTRACE_GETREGS. This is probably
+# GNU/Linux specific; it should do no harm if there is no
+# _user_regs_struct.
+regs=`grep '^type _user_regs_struct struct' gen-sysinfo.go || true`
+if test "$regs" != ""; then
+ regs=`echo $regs | sed -e 's/type _user_regs_struct struct //' -e 's/[{}]//g'`
+ regs=`echo $regs | sed -e s'/^ *//'`
+ nregs=
+ while test -n "$regs"; do
+ field=`echo $regs | sed -e 's/^\([^;]*\);.*$/\1/'`
+ regs=`echo $regs | sed -e 's/^[^;]*; *\(.*\)$/\1/'`
+ # Capitalize the first character of the field.
+ f=`echo $field | sed -e 's/^\(.\).*$/\1/'`
+ r=`echo $field | sed -e 's/^.\(.*\)$/\1/'`
+ f=`echo $f | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
+ field="$f$r"
+ nregs="$nregs $field;"
+ done
+ echo "type PtraceRegs struct {$nregs }" >> ${OUT}
+fi
+
+# Some basic types.
+echo 'type Size_t _size_t' >> ${OUT}
+echo "type Ssize_t _ssize_t" >> ${OUT}
+if grep '^const _HAVE_OFF64_T = ' gen-sysinfo.go > /dev/null 2>&1; then
+ echo "type Offset_t _off64_t" >> ${OUT}
+else
+ echo "type Offset_t _off_t" >> ${OUT}
+fi
+echo "type Mode_t _mode_t" >> ${OUT}
+echo "type Pid_t _pid_t" >> ${OUT}
+echo "type Uid_t _uid_t" >> ${OUT}
+echo "type Gid_t _gid_t" >> ${OUT}
+echo "type Socklen_t _socklen_t" >> ${OUT}
+
+# The long type, needed because that is the type that ptrace returns.
+sizeof_long=`grep '^const ___SIZEOF_LONG__ = ' gen-sysinfo.go | sed -e 's/.*= //'`
+if test "$sizeof_long" = "4"; then
+ echo "type _C_long int32" >> ${OUT}
+elif test "$sizeof_long" = "8"; then
+ echo "type _C_long int64" >> ${OUT}
+else
+ echo 1>&2 "mksysinfo.sh: could not determine size of long (got $sizeof_long)"
+ exit 1
+fi
+
+# Solaris 2 needs _u?pad128_t, but its default definition in terms of long
+# double is commented by -fdump-go-spec.
+if grep "^// type _pad128_t" gen-sysinfo.go > /dev/null 2>&1; then
+ echo "type _pad128_t struct { _l [4]int32; }" >> ${OUT}
+fi
+if grep "^// type _upad128_t" gen-sysinfo.go > /dev/null 2>&1; then
+ echo "type _upad128_t struct { _l [4]uint32; }" >> ${OUT}
+fi
+
+# The time structures need special handling: we need to name the
+# types, so that we can cast integers to the right types when
+# assigning to the structures.
+timeval=`grep '^type _timeval ' gen-sysinfo.go`
+timeval_sec=`echo $timeval | sed -n -e 's/^.*tv_sec \([^ ]*\);.*$/\1/p'`
+timeval_usec=`echo $timeval | sed -n -e 's/^.*tv_usec \([^ ]*\);.*$/\1/p'`
+echo "type Timeval_sec_t $timeval_sec" >> ${OUT}
+echo "type Timeval_usec_t $timeval_usec" >> ${OUT}
+echo $timeval | \
+ sed -e 's/type _timeval /type Timeval /' \
+ -e 's/tv_sec *[a-zA-Z0-9_]*/Sec Timeval_sec_t/' \
+ -e 's/tv_usec *[a-zA-Z0-9_]*/Usec Timeval_usec_t/' >> ${OUT}
+timespec=`grep '^type _timespec ' gen-sysinfo.go`
+timespec_sec=`echo $timespec | sed -n -e 's/^.*tv_sec \([^ ]*\);.*$/\1/p'`
+timespec_nsec=`echo $timespec | sed -n -e 's/^.*tv_nsec \([^ ]*\);.*$/\1/p'`
+echo "type Timespec_sec_t $timespec_sec" >> ${OUT}
+echo "type Timespec_nsec_t $timespec_nsec" >> ${OUT}
+echo $timespec | \
+ sed -e 's/^type _timespec /type Timespec /' \
+ -e 's/tv_sec *[a-zA-Z0-9_]*/Sec Timespec_sec_t/' \
+ -e 's/tv_nsec *[a-zA-Z0-9_]*/Nsec Timespec_nsec_t/' >> ${OUT}
+
+timestruc=`grep '^type _timestruc_t ' gen-sysinfo.go || true`
+if test "$timestruc" != ""; then
+ timestruc_sec=`echo $timestruc | sed -n -e 's/^.*tv_sec \([^ ]*\);.*$/\1/p'`
+ timestruc_nsec=`echo $timestruc | sed -n -e 's/^.*tv_nsec \([^ ]*\);.*$/\1/p'`
+ echo "type Timestruc_sec_t $timestruc_sec" >> ${OUT}
+ echo "type Timestruc_nsec_t $timestruc_nsec" >> ${OUT}
+ echo $timestruc | \
+ sed -e 's/^type _timestruc_t /type Timestruc /' \
+ -e 's/tv_sec *[a-zA-Z0-9_]*/Sec Timestruc_sec_t/' \
+ -e 's/tv_nsec *[a-zA-Z0-9_]*/Nsec Timestruc_nsec_t/' >> ${OUT}
+fi
+
+# The stat type.
+# Prefer largefile variant if available.
+stat=`grep '^type _stat64 ' gen-sysinfo.go || true`
+if test "$stat" != ""; then
+ grep '^type _stat64 ' gen-sysinfo.go
+else
+ grep '^type _stat ' gen-sysinfo.go
+fi | sed -e 's/type _stat\(64\)\?/type Stat_t/' \
+ -e 's/st_dev/Dev/' \
+ -e 's/st_ino/Ino/g' \
+ -e 's/st_nlink/Nlink/' \
+ -e 's/st_mode/Mode/' \
+ -e 's/st_uid/Uid/' \
+ -e 's/st_gid/Gid/' \
+ -e 's/st_rdev/Rdev/' \
+ -e 's/st_size/Size/' \
+ -e 's/st_blksize/Blksize/' \
+ -e 's/st_blocks/Blocks/' \
+ -e 's/st_atim/Atime/' \
+ -e 's/st_mtim/Mtime/' \
+ -e 's/st_ctim/Ctime/' \
+ -e 's/\([^a-zA-Z0-9_]\)_timeval\([^a-zA-Z0-9_]\)/\1Timeval\2/g' \
+ -e 's/\([^a-zA-Z0-9_]\)_timespec\([^a-zA-Z0-9_]\)/\1Timespec\2/g' \
+ -e 's/\([^a-zA-Z0-9_]\)_timestruc_t\([^a-zA-Z0-9_]\)/\1Timestruc\2/g' \
+ >> ${OUT}
+
+# The directory searching types.
+# Prefer largefile variant if available.
+dirent=`grep '^type _dirent64 ' gen-sysinfo.go || true`
+if test "$dirent" != ""; then
+ grep '^type _dirent64 ' gen-sysinfo.go
+else
+ grep '^type _dirent ' gen-sysinfo.go
+fi | sed -e 's/type _dirent\(64\)\?/type Dirent/' \
+ -e 's/d_name \[0+1\]/d_name [0+256]/' \
+ -e 's/d_name/Name/' \
+ -e 's/]int8/]byte/' \
+ -e 's/d_ino/Ino/' \
+ -e 's/d_off/Off/' \
+ -e 's/d_reclen/Reclen/' \
+ -e 's/d_type/Type/' \
+ >> ${OUT}
+echo "type DIR _DIR" >> ${OUT}
+
+# The rusage struct.
+rusage=`grep '^type _rusage struct' gen-sysinfo.go`
+if test "$rusage" != ""; then
+ rusage=`echo $rusage | sed -e 's/type _rusage struct //' -e 's/[{}]//g'`
+ rusage=`echo $rusage | sed -e 's/^ *//'`
+ nrusage=
+ while test -n "$rusage"; do
+ field=`echo $rusage | sed -e 's/^\([^;]*\);.*$/\1/'`
+ rusage=`echo $rusage | sed -e 's/^[^;]*; *\(.*\)$/\1/'`
+ # Drop the leading ru_, capitalize the next character.
+ field=`echo $field | sed -e 's/^ru_//'`
+ f=`echo $field | sed -e 's/^\(.\).*$/\1/'`
+ r=`echo $field | sed -e 's/^.\(.*\)$/\1/'`
+ f=`echo $f | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
+ # Fix _timeval _timespec, and _timestruc_t.
+ r=`echo $r | sed -e s'/ _timeval$/ Timeval/'`
+ r=`echo $r | sed -e s'/ _timespec$/ Timespec/'`
+ r=`echo $r | sed -e s'/ _timestruc_t$/ Timestruc/'`
+ field="$f$r"
+ nrusage="$nrusage $field;"
+ done
+ echo "type Rusage struct {$nrusage }" >> ${OUT}
+fi
+
+# The utsname struct.
+grep '^type _utsname ' gen-sysinfo.go | \
+ sed -e 's/_utsname/Utsname/' \
+ -e 's/sysname/Sysname/' \
+ -e 's/nodename/Nodename/' \
+ -e 's/release/Release/' \
+ -e 's/version/Version/' \
+ -e 's/machine/Machine/' \
+ -e 's/domainname/Domainname/' \
+ >> ${OUT}
+
+# The iovec struct.
+iovec=`grep '^type _iovec ' gen-sysinfo.go`
+iovec_len=`echo $iovec | sed -n -e 's/^.*iov_len \([^ ]*\);.*$/\1/p'`
+echo "type Iovec_len_t $iovec_len" >> ${OUT}
+echo $iovec | \
+ sed -e 's/_iovec/Iovec/' \
+ -e 's/iov_base/Base/' \
+ -e 's/iov_len *[a-zA-Z0-9_]*/Len Iovec_len_t/' \
+ >> ${OUT}
+
+# The msghdr struct.
+msghdr=`grep '^type _msghdr ' gen-sysinfo.go`
+msghdr_controllen=`echo $msghdr | sed -n -e 's/^.*msg_controllen \([^ ]*\);.*$/\1/p'`
+echo "type Msghdr_controllen_t $msghdr_controllen" >> ${OUT}
+echo $msghdr | \
+ sed -e 's/_msghdr/Msghdr/' \
+ -e 's/msg_name/Name/' \
+ -e 's/msg_namelen/Namelen/' \
+ -e 's/msg_iov/Iov/' \
+ -e 's/msg_iovlen/Iovlen/' \
+ -e 's/_iovec/Iovec/' \
+ -e 's/msg_control/Control/' \
+ -e 's/msg_controllen *[a-zA-Z0-9_]*/Controllen Msghdr_controllen_t/' \
+ -e 's/msg_flags/Flags/' \
+ >> ${OUT}
+
+exit $?
diff --git a/libgo/runtime/array.h b/libgo/runtime/array.h
new file mode 100644
index 000000000..f6d0261df
--- /dev/null
+++ b/libgo/runtime/array.h
@@ -0,0 +1,28 @@
+/* array.h -- the open array type for Go.
+
+ 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. */
+
+#ifndef LIBGO_ARRAY_H
+#define LIBGO_ARRAY_H
+
+/* An open array is an instance of this structure. */
+
+struct __go_open_array
+{
+ /* The elements of the array. In use in the compiler this is a
+ pointer to the element type. */
+ void* __values;
+ /* The number of elements in the array. Note that this is "int",
+ not "size_t". The language definition says that "int" is large
+ enough to hold the size of any allocated object. Using "int"
+ saves 8 bytes per slice header on a 64-bit system with 32-bit
+ ints. */
+ int __count;
+ /* The capacity of the array--the number of elements that can fit in
+ the __VALUES field. */
+ int __capacity;
+};
+
+#endif /* !defined(LIBGO_ARRAY_H) */
diff --git a/libgo/runtime/chan.goc b/libgo/runtime/chan.goc
new file mode 100644
index 000000000..da0bbfccb
--- /dev/null
+++ b/libgo/runtime/chan.goc
@@ -0,0 +1,39 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+#include "config.h"
+#include "channel.h"
+
+typedef _Bool bool;
+typedef unsigned char byte;
+typedef struct __go_channel chan;
+
+/* Do a nonblocking channel receive. */
+
+func chanrecv2(c *chan, val *byte) (pres bool) {
+ if (c->element_size > 8) {
+ return __go_receive_nonblocking_big(c, val);
+ } else {
+ struct __go_receive_nonblocking_small rs;
+ union {
+ char b[8];
+ uint64_t v;
+ } u;
+
+ rs = __go_receive_nonblocking_small (c);
+ if (!rs.__success) {
+ __builtin_memset(val, 0, c->element_size);
+ return 0;
+ }
+ u.v = rs.__val;
+#ifndef WORDS_BIGENDIAN
+ __builtin_memcpy(val, u.b, c->element_size);
+#else
+ __builtin_memcpy(val, u.b + 8 - c->element_size,
+ c->element_size);
+#endif
+ return 1;
+ }
+}
diff --git a/libgo/runtime/channel.h b/libgo/runtime/channel.h
new file mode 100644
index 000000000..b0d13477a
--- /dev/null
+++ b/libgo/runtime/channel.h
@@ -0,0 +1,147 @@
+/* channel.h -- the channel type for Go.
+
+ 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. */
+
+#include <stdint.h>
+#include <pthread.h>
+
+/* This structure is used when a select is waiting for a synchronous
+ channel. */
+
+struct __go_channel_select
+{
+ /* A pointer to the next select waiting for this channel. */
+ struct __go_channel_select *next;
+ /* A pointer to the channel which this select will use. This starts
+ out as NULL and is set to the first channel which synchs up with
+ this one. This variable to which this points may only be
+ accessed when __go_select_data_mutex is held. */
+ struct __go_channel **selected;
+ /* A pointer to a variable which must be set to true if the
+ goroutine which sets *SELECTED wants to read from the channel,
+ false if it wants to write to it. */
+ _Bool *is_read;
+};
+
+/* A channel is a pointer to this structure. */
+
+struct __go_channel
+{
+ /* A mutex to control access to the channel. */
+ pthread_mutex_t lock;
+ /* A condition variable. This is signalled when data is added to
+ the channel and when data is removed from the channel. */
+ pthread_cond_t cond;
+ /* The size of elements on this channel. */
+ size_t element_size;
+ /* Number of operations on closed channel. */
+ unsigned short closed_op_count;
+ /* True if a goroutine is waiting to send on a synchronous
+ channel. */
+ _Bool waiting_to_send;
+ /* True if a goroutine is waiting to receive on a synchronous
+ channel. */
+ _Bool waiting_to_receive;
+ /* True if this channel was selected for send in a select statement.
+ This looks out all other sends. */
+ _Bool selected_for_send;
+ /* True if this channel was selected for receive in a select
+ statement. This locks out all other receives. */
+ _Bool selected_for_receive;
+ /* True if this channel has been closed. */
+ _Bool is_closed;
+ /* True if at least one null value has been read from a closed
+ channel. */
+ _Bool saw_close;
+ /* The list of select statements waiting to send on a synchronous
+ channel. */
+ struct __go_channel_select *select_send_queue;
+ /* The list of select statements waiting to receive on a synchronous
+ channel. */
+ struct __go_channel_select *select_receive_queue;
+ /* If a select statement is waiting for this channel, it sets these
+ pointers. When something happens on the channel, the channel
+ locks the mutex, signals the condition, and unlocks the
+ mutex. */
+ pthread_mutex_t *select_mutex;
+ pthread_cond_t *select_cond;
+ /* The number of entries in the circular buffer. */
+ unsigned int num_entries;
+ /* Where to store the next value. */
+ unsigned int next_store;
+ /* Where to fetch the next value. If next_fetch == next_store, the
+ buffer is empty. If next_store + 1 == next_fetch, the buffer is
+ full. */
+ unsigned int next_fetch;
+ /* The circular buffer. */
+ uint64_t data[];
+};
+
+/* The mutex used to control access to the value pointed to by the
+ __go_channel_select selected field. No additional mutexes may be
+ acquired while this mutex is held. */
+extern pthread_mutex_t __go_select_data_mutex;
+
+/* Maximum permitted number of operations on a closed channel. */
+#define MAX_CLOSED_OPERATIONS (0x100)
+
+extern struct __go_channel *__go_new_channel (size_t, size_t);
+
+extern _Bool __go_synch_with_select (struct __go_channel *, _Bool);
+
+extern void __go_broadcast_to_select (struct __go_channel *);
+
+extern _Bool __go_send_acquire (struct __go_channel *, _Bool);
+
+#define SEND_NONBLOCKING_ACQUIRE_SPACE 0
+#define SEND_NONBLOCKING_ACQUIRE_NOSPACE 1
+#define SEND_NONBLOCKING_ACQUIRE_CLOSED 2
+
+extern int __go_send_nonblocking_acquire (struct __go_channel *);
+
+extern void __go_send_release (struct __go_channel *);
+
+extern void __go_send_small (struct __go_channel *, uint64_t, _Bool);
+
+extern _Bool __go_send_nonblocking_small (struct __go_channel *, uint64_t);
+
+extern void __go_send_big (struct __go_channel *, const void *, _Bool);
+
+extern _Bool __go_send_nonblocking_big (struct __go_channel *, const void *);
+
+extern _Bool __go_receive_acquire (struct __go_channel *, _Bool);
+
+#define RECEIVE_NONBLOCKING_ACQUIRE_DATA 0
+#define RECEIVE_NONBLOCKING_ACQUIRE_NODATA 1
+#define RECEIVE_NONBLOCKING_ACQUIRE_CLOSED 2
+
+extern int __go_receive_nonblocking_acquire (struct __go_channel *);
+
+extern uint64_t __go_receive_small (struct __go_channel *, _Bool);
+
+extern void __go_receive_release (struct __go_channel *);
+
+struct __go_receive_nonblocking_small
+{
+ uint64_t __val;
+ _Bool __success;
+};
+
+extern struct __go_receive_nonblocking_small
+__go_receive_nonblocking_small (struct __go_channel *);
+
+extern void __go_receive_big (struct __go_channel *, void *, _Bool);
+
+extern _Bool __go_receive_nonblocking_big (struct __go_channel *, void *);
+
+extern void __go_unlock_and_notify_selects (struct __go_channel *);
+
+extern _Bool __go_builtin_closed (struct __go_channel *);
+
+extern void __go_builtin_close (struct __go_channel *);
+
+extern size_t __go_chan_len (struct __go_channel *);
+
+extern size_t __go_chan_cap (struct __go_channel *);
diff --git a/libgo/runtime/defs.h b/libgo/runtime/defs.h
new file mode 100644
index 000000000..67ad212b8
--- /dev/null
+++ b/libgo/runtime/defs.h
@@ -0,0 +1,12 @@
+/* defs.h -- runtime definitions for Go.
+
+ 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. */
+
+/* The gc library uses this file for system defines, and generates it
+ automatically using the godefs program. The logical thing to put
+ here for gccgo would be #include statements for system header
+ files. We can't do that, though, because runtime.h #define's the
+ standard types. So we #include the system headers from runtime.h
+ instead. */
diff --git a/libgo/runtime/go-alloc.h b/libgo/runtime/go-alloc.h
new file mode 100644
index 000000000..c880a043e
--- /dev/null
+++ b/libgo/runtime/go-alloc.h
@@ -0,0 +1,11 @@
+/* go-alloc.h -- allocate memory for Go.
+
+ 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. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+extern void *__go_alloc (unsigned int __attribute__ ((mode (pointer))));
+extern void __go_free (void *);
diff --git a/libgo/runtime/go-append.c b/libgo/runtime/go-append.c
new file mode 100644
index 000000000..91493b1b7
--- /dev/null
+++ b/libgo/runtime/go-append.c
@@ -0,0 +1,67 @@
+/* go-append.c -- the go builtin append function.
+
+ 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 "go-type.h"
+#include "go-panic.h"
+#include "array.h"
+#include "runtime.h"
+#include "malloc.h"
+
+/* We should be OK if we don't split the stack here, since the only
+ libc functions we call are memcpy and memmove. If we don't do
+ this, we will always split the stack, because of memcpy and
+ memmove. */
+extern struct __go_open_array
+__go_append (struct __go_open_array, void *, size_t, size_t)
+ __attribute__ ((no_split_stack));
+
+struct __go_open_array
+__go_append (struct __go_open_array a, void *bvalues, size_t bcount,
+ size_t element_size)
+{
+ size_t ucount;
+ int count;
+
+ if (bvalues == NULL || bcount == 0)
+ return a;
+
+ ucount = (size_t) a.__count + bcount;
+ count = (int) ucount;
+ if ((size_t) count != ucount || count <= a.__count)
+ __go_panic_msg ("append: slice overflow");
+
+ if (count > a.__capacity)
+ {
+ int m;
+ void *n;
+
+ m = a.__capacity;
+ if (m == 0)
+ m = (int) bcount;
+ else
+ {
+ do
+ {
+ if (a.__count < 1024)
+ m += m;
+ else
+ m += m / 4;
+ }
+ while (m < count);
+ }
+
+ n = __go_alloc (m * element_size);
+ __builtin_memcpy (n, a.__values, a.__count * element_size);
+
+ a.__values = n;
+ a.__capacity = m;
+ }
+
+ __builtin_memmove ((char *) a.__values + a.__count * element_size,
+ bvalues, bcount * element_size);
+ a.__count = count;
+ return a;
+}
diff --git a/libgo/runtime/go-assert-interface.c b/libgo/runtime/go-assert-interface.c
new file mode 100644
index 000000000..57a092d59
--- /dev/null
+++ b/libgo/runtime/go-assert-interface.c
@@ -0,0 +1,49 @@
+/* go-assert-interface.c -- interface type assertion for Go.
+
+ 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 "go-alloc.h"
+#include "go-assert.h"
+#include "go-panic.h"
+#include "interface.h"
+
+/* This is called by the compiler to implement a type assertion from
+ one interface type to another. This returns the value that should
+ go in the first field of the result tuple. The result may be an
+ empty or a non-empty interface. */
+
+const void *
+__go_assert_interface (const struct __go_type_descriptor *lhs_descriptor,
+ const struct __go_type_descriptor *rhs_descriptor)
+{
+ const struct __go_interface_type *lhs_interface;
+
+ if (rhs_descriptor == NULL)
+ {
+ struct __go_empty_interface panic_arg;
+
+ /* A type assertion is not permitted with a nil interface. */
+
+ newTypeAssertionError (NULL,
+ NULL,
+ lhs_descriptor,
+ NULL,
+ NULL,
+ lhs_descriptor->__reflection,
+ NULL,
+ &panic_arg);
+ __go_panic (panic_arg);
+ }
+
+ /* A type assertion to an empty interface just returns the object
+ descriptor. */
+
+ __go_assert (lhs_descriptor->__code == GO_INTERFACE);
+ lhs_interface = (const struct __go_interface_type *) lhs_descriptor;
+ if (lhs_interface->__methods.__count == 0)
+ return rhs_descriptor;
+
+ return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0);
+}
diff --git a/libgo/runtime/go-assert.c b/libgo/runtime/go-assert.c
new file mode 100644
index 000000000..48aa0725c
--- /dev/null
+++ b/libgo/runtime/go-assert.c
@@ -0,0 +1,18 @@
+/* go-assert.c -- libgo specific assertions
+
+ 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 <stdio.h>
+#include <stdlib.h>
+
+#include "go-assert.h"
+
+void
+__go_assert_fail (const char *file, unsigned int lineno)
+{
+ /* FIXME: Eventually we should dump a stack trace here. */
+ fprintf (stderr, "%s:%u: libgo assertion failure\n", file, lineno);
+ abort ();
+}
diff --git a/libgo/runtime/go-assert.h b/libgo/runtime/go-assert.h
new file mode 100644
index 000000000..636559597
--- /dev/null
+++ b/libgo/runtime/go-assert.h
@@ -0,0 +1,18 @@
+/* go-assert.h -- libgo specific assertions
+
+ 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. */
+
+#ifndef LIBGO_GO_ASSERT_H
+#define LIBGO_GO_ASSERT_H
+
+/* We use a Go specific assert function so that functions which call
+ assert aren't required to always split the stack. */
+
+extern void __go_assert_fail (const char *file, unsigned int lineno)
+ __attribute__ ((noreturn));
+
+#define __go_assert(e) ((e) ? (void) 0 : __go_assert_fail (__FILE__, __LINE__))
+
+#endif /* !defined(LIBGO_GO_ASSERT_H) */
diff --git a/libgo/runtime/go-breakpoint.c b/libgo/runtime/go-breakpoint.c
new file mode 100644
index 000000000..bb6eddc36
--- /dev/null
+++ b/libgo/runtime/go-breakpoint.c
@@ -0,0 +1,15 @@
+/* go-breakpoint.c -- the runtime.Breakpoint function.
+
+ 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. */
+
+#include <sched.h>
+
+void Breakpoint (void) asm ("libgo_runtime.runtime.Breakpoint");
+
+void
+Breakpoint (void)
+{
+ __builtin_trap ();
+}
diff --git a/libgo/runtime/go-byte-array-to-string.c b/libgo/runtime/go-byte-array-to-string.c
new file mode 100644
index 000000000..531730654
--- /dev/null
+++ b/libgo/runtime/go-byte-array-to-string.c
@@ -0,0 +1,24 @@
+/* go-byte-array-to-string.c -- convert an array of bytes to a string in Go.
+
+ 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. */
+
+#include "go-string.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_string
+__go_byte_array_to_string (const void* p, size_t len)
+{
+ const unsigned char *bytes;
+ unsigned char *retdata;
+ struct __go_string ret;
+
+ bytes = (const unsigned char *) p;
+ retdata = runtime_mallocgc (len, RefNoPointers, 1, 0);
+ __builtin_memcpy (retdata, bytes, len);
+ ret.__data = retdata;
+ ret.__length = len;
+ return ret;
+}
diff --git a/libgo/runtime/go-caller.c b/libgo/runtime/go-caller.c
new file mode 100644
index 000000000..b18759f2f
--- /dev/null
+++ b/libgo/runtime/go-caller.c
@@ -0,0 +1,51 @@
+/* go-caller.c -- runtime.Caller and runtime.FuncForPC for Go.
+
+ 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. */
+
+/* Implement runtime.Caller. */
+
+#include <stdint.h>
+
+#include "go-string.h"
+
+/* The values returned by runtime.Caller. */
+
+struct caller_ret
+{
+ uintptr_t pc;
+ struct __go_string file;
+ int line;
+ _Bool ok;
+};
+
+/* Implement runtime.Caller. */
+
+struct caller_ret Caller (int n) asm ("libgo_runtime.runtime.Caller");
+
+struct caller_ret
+Caller (int n __attribute__ ((unused)))
+{
+ struct caller_ret ret;
+
+ /* A proper implementation needs to dig through the debugging
+ information. */
+ ret.pc = (uint64_t) (uintptr_t) __builtin_return_address (0);
+ ret.file.__data = NULL;
+ ret.file.__length = 0;
+ ret.line = 0;
+ ret.ok = 0;
+
+ return ret;
+}
+
+/* Implement runtime.FuncForPC. */
+
+void *FuncForPC (uintptr_t) asm ("libgo_runtime.runtime.FuncForPC");
+
+void *
+FuncForPC(uintptr_t pc __attribute__ ((unused)))
+{
+ return NULL;
+}
diff --git a/libgo/runtime/go-can-convert-interface.c b/libgo/runtime/go-can-convert-interface.c
new file mode 100644
index 000000000..83217ab95
--- /dev/null
+++ b/libgo/runtime/go-can-convert-interface.c
@@ -0,0 +1,76 @@
+/* go-can-convert-interface.c -- can we convert to an interface?
+
+ 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. */
+
+#include "go-assert.h"
+#include "go-type.h"
+#include "interface.h"
+
+/* Return whether we can convert from the type in FROM_DESCRIPTOR to
+ the interface in TO_DESCRIPTOR. This is used for type
+ switches. */
+
+_Bool
+__go_can_convert_to_interface (
+ const struct __go_type_descriptor *to_descriptor,
+ const struct __go_type_descriptor *from_descriptor)
+{
+ const struct __go_interface_type *to_interface;
+ int to_method_count;
+ const struct __go_interface_method *to_method;
+ const struct __go_uncommon_type *from_uncommon;
+ int from_method_count;
+ const struct __go_method *from_method;
+ int i;
+
+ /* In a type switch FROM_DESCRIPTOR can be NULL. */
+ if (from_descriptor == NULL)
+ return 0;
+
+ __go_assert (to_descriptor->__code == GO_INTERFACE);
+ to_interface = (const struct __go_interface_type *) to_descriptor;
+ to_method_count = to_interface->__methods.__count;
+ to_method = ((const struct __go_interface_method *)
+ to_interface->__methods.__values);
+
+ from_uncommon = from_descriptor->__uncommon;
+ if (from_uncommon == NULL)
+ {
+ from_method_count = 0;
+ from_method = NULL;
+ }
+ else
+ {
+ from_method_count = from_uncommon->__methods.__count;
+ from_method = ((const struct __go_method *)
+ from_uncommon->__methods.__values);
+ }
+
+ for (i = 0; i < to_method_count; ++i)
+ {
+ while (from_method_count > 0
+ && (!__go_ptr_strings_equal (from_method->__name,
+ to_method->__name)
+ || !__go_ptr_strings_equal (from_method->__pkg_path,
+ to_method->__pkg_path)))
+ {
+ ++from_method;
+ --from_method_count;
+ }
+
+ if (from_method_count == 0)
+ return 0;
+
+ if (!__go_type_descriptors_equal (from_method->__mtype,
+ to_method->__type))
+ return 0;
+
+ ++to_method;
+ ++from_method;
+ --from_method_count;
+ }
+
+ return 1;
+}
diff --git a/libgo/runtime/go-cgo.c b/libgo/runtime/go-cgo.c
new file mode 100644
index 000000000..94917bca0
--- /dev/null
+++ b/libgo/runtime/go-cgo.c
@@ -0,0 +1,42 @@
+/* go-cgo.c -- SWIG support routines for libgo.
+
+ 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 "go-alloc.h"
+#include "interface.h"
+#include "go-panic.h"
+#include "go-string.h"
+
+/* These are routines used by SWIG. The gc runtime library provides
+ the same routines under the same name, though in that case the code
+ is required to import runtime/cgo. */
+
+void *
+_cgo_allocate (size_t n)
+{
+ return __go_alloc (n);
+}
+
+extern const struct __go_type_descriptor string_type_descriptor
+ asm ("__go_tdn_string");
+
+void
+_cgo_panic (const char *p)
+{
+ int len;
+ unsigned char *data;
+ struct __go_string *ps;
+ struct __go_empty_interface e;
+
+ len = __builtin_strlen (p);
+ data = __go_alloc (len);
+ __builtin_memcpy (data, p, len);
+ ps = __go_alloc (sizeof *ps);
+ ps->__data = data;
+ ps->__length = len;
+ e.__type_descriptor = &string_type_descriptor;
+ e.__object = ps;
+ __go_panic (e);
+}
diff --git a/libgo/runtime/go-chan-cap.c b/libgo/runtime/go-chan-cap.c
new file mode 100644
index 000000000..df603bf10
--- /dev/null
+++ b/libgo/runtime/go-chan-cap.c
@@ -0,0 +1,41 @@
+/* go-chan-cap.c -- the cap function applied to a channel.
+
+ 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. */
+
+#include <stddef.h>
+
+#include "go-assert.h"
+#include "channel.h"
+
+/* Return the cap function applied to a channel--the size of the
+ buffer. This could be done inline but I'm doing it as a function
+ for now to make it easy to change the channel structure. */
+
+size_t
+__go_chan_cap (struct __go_channel *channel)
+{
+ int i;
+ size_t ret;
+
+ if (channel == NULL)
+ return 0;
+
+ i = pthread_mutex_lock (&channel->lock);
+ __go_assert (i == 0);
+
+ if (channel->num_entries == 0)
+ ret = 0;
+ else
+ {
+ /* One slot is always unused. We added 1 when we created the
+ channel. */
+ ret = channel->num_entries - 1;
+ }
+
+ i = pthread_mutex_unlock (&channel->lock);
+ __go_assert (i == 0);
+
+ return ret;
+}
diff --git a/libgo/runtime/go-chan-len.c b/libgo/runtime/go-chan-len.c
new file mode 100644
index 000000000..5aebae141
--- /dev/null
+++ b/libgo/runtime/go-chan-len.c
@@ -0,0 +1,41 @@
+/* go-chan-len.c -- the len function applied to a channel.
+
+ 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. */
+
+#include <stddef.h>
+
+#include "go-assert.h"
+#include "channel.h"
+
+/* Return the len function applied to a channel--the number of
+ elements in the buffer. This could be done inline but I'm doing it
+ as a function for now to make it easy to change the channel
+ structure. */
+
+size_t
+__go_chan_len (struct __go_channel *channel)
+{
+ int i;
+ size_t ret;
+
+ if (channel == NULL)
+ return 0;
+
+ i = pthread_mutex_lock (&channel->lock);
+ __go_assert (i == 0);
+
+ if (channel->num_entries == 0)
+ ret = 0;
+ else if (channel->next_fetch == channel->next_store)
+ ret = 0;
+ else
+ ret = ((channel->next_store + channel->num_entries - channel->next_fetch)
+ % channel->num_entries);
+
+ i = pthread_mutex_unlock (&channel->lock);
+ __go_assert (i == 0);
+
+ return ret;
+}
diff --git a/libgo/runtime/go-check-interface.c b/libgo/runtime/go-check-interface.c
new file mode 100644
index 000000000..d2258a854
--- /dev/null
+++ b/libgo/runtime/go-check-interface.c
@@ -0,0 +1,46 @@
+/* go-check-interface.c -- check an interface type for a conversion
+
+ 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 "go-panic.h"
+#include "interface.h"
+
+/* Check that an interface type matches for a conversion to a
+ non-interface type. This panics if the types are bad. The actual
+ extraction of the object is inlined. */
+
+void
+__go_check_interface_type (
+ const struct __go_type_descriptor *lhs_descriptor,
+ const struct __go_type_descriptor *rhs_descriptor,
+ const struct __go_type_descriptor *rhs_inter_descriptor)
+{
+ if (rhs_descriptor == NULL)
+ {
+ struct __go_empty_interface panic_arg;
+
+ newTypeAssertionError(NULL, NULL, lhs_descriptor, NULL, NULL,
+ lhs_descriptor->__reflection, NULL, &panic_arg);
+ __go_panic(panic_arg);
+ }
+
+ if (lhs_descriptor != rhs_descriptor
+ && !__go_type_descriptors_equal (lhs_descriptor, rhs_descriptor)
+ && (lhs_descriptor->__code != GO_UNSAFE_POINTER
+ || !__go_is_pointer_type (rhs_descriptor))
+ && (rhs_descriptor->__code != GO_UNSAFE_POINTER
+ || !__go_is_pointer_type (lhs_descriptor)))
+ {
+ struct __go_empty_interface panic_arg;
+
+ newTypeAssertionError(rhs_inter_descriptor, rhs_descriptor,
+ lhs_descriptor,
+ rhs_inter_descriptor->__reflection,
+ rhs_descriptor->__reflection,
+ lhs_descriptor->__reflection,
+ NULL, &panic_arg);
+ __go_panic(panic_arg);
+ }
+}
diff --git a/libgo/runtime/go-close.c b/libgo/runtime/go-close.c
new file mode 100644
index 000000000..ced742985
--- /dev/null
+++ b/libgo/runtime/go-close.c
@@ -0,0 +1,33 @@
+/* go-close.c -- the builtin close function.
+
+ 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. */
+
+#include "go-assert.h"
+#include "channel.h"
+
+/* Close a channel. After a channel is closed, sends are no longer
+ permitted. Receives always return zero. */
+
+void
+__go_builtin_close (struct __go_channel *channel)
+{
+ int i;
+
+ i = pthread_mutex_lock (&channel->lock);
+ __go_assert (i == 0);
+
+ while (channel->selected_for_send)
+ {
+ i = pthread_cond_wait (&channel->cond, &channel->lock);
+ __go_assert (i == 0);
+ }
+
+ channel->is_closed = 1;
+
+ i = pthread_cond_broadcast (&channel->cond);
+ __go_assert (i == 0);
+
+ __go_unlock_and_notify_selects (channel);
+}
diff --git a/libgo/runtime/go-closed.c b/libgo/runtime/go-closed.c
new file mode 100644
index 000000000..bfa9cd6f9
--- /dev/null
+++ b/libgo/runtime/go-closed.c
@@ -0,0 +1,34 @@
+/* go-closed.c -- the builtin closed function.
+
+ 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. */
+
+#include "go-assert.h"
+#include "channel.h"
+
+/* Return whether a channel is closed. We only return true after at
+ least one nil value has been read from the channel. */
+
+_Bool
+__go_builtin_closed (struct __go_channel *channel)
+{
+ int i;
+ _Bool ret;
+
+ i = pthread_mutex_lock (&channel->lock);
+ __go_assert (i == 0);
+
+ while (channel->selected_for_receive)
+ {
+ i = pthread_cond_wait (&channel->cond, &channel->lock);
+ __go_assert (i == 0);
+ }
+
+ ret = channel->saw_close;
+
+ i = pthread_mutex_unlock (&channel->lock);
+ __go_assert (i == 0);
+
+ return ret;
+}
diff --git a/libgo/runtime/go-construct-map.c b/libgo/runtime/go-construct-map.c
new file mode 100644
index 000000000..15497eadb
--- /dev/null
+++ b/libgo/runtime/go-construct-map.c
@@ -0,0 +1,32 @@
+/* go-construct-map.c -- construct a map from an initializer.
+
+ 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. */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "map.h"
+
+struct __go_map *
+__go_construct_map (const struct __go_map_descriptor *descriptor,
+ size_t count, size_t entry_size, size_t val_offset,
+ size_t val_size, const void *ventries)
+{
+ struct __go_map *ret;
+ const unsigned char *entries;
+ size_t i;
+
+ ret = __go_new_map (descriptor, count);
+
+ entries = (const unsigned char *) ventries;
+ for (i = 0; i < count; ++i)
+ {
+ void *val = __go_map_index (ret, entries, 1);
+ __builtin_memcpy (val, entries + val_offset, val_size);
+ entries += entry_size;
+ }
+
+ return ret;
+}
diff --git a/libgo/runtime/go-convert-interface.c b/libgo/runtime/go-convert-interface.c
new file mode 100644
index 000000000..259456cda
--- /dev/null
+++ b/libgo/runtime/go-convert-interface.c
@@ -0,0 +1,138 @@
+/* go-convert-interface.c -- convert interfaces for Go.
+
+ 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. */
+
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "go-panic.h"
+#include "interface.h"
+
+/* This is called when converting one interface type into another
+ interface type. LHS_DESCRIPTOR is the type descriptor of the
+ resulting interface. RHS_DESCRIPTOR is the type descriptor of the
+ object being converted. This builds and returns a new interface
+ method table. If any method in the LHS_DESCRIPTOR interface is not
+ implemented by the object, the conversion fails. If the conversion
+ fails, then if MAY_FAIL is true this returns NULL; otherwise, it
+ panics. */
+
+void *
+__go_convert_interface_2 (const struct __go_type_descriptor *lhs_descriptor,
+ const struct __go_type_descriptor *rhs_descriptor,
+ _Bool may_fail)
+{
+ const struct __go_interface_type *lhs_interface;
+ int lhs_method_count;
+ const struct __go_interface_method* lhs_methods;
+ const void **methods;
+ const struct __go_uncommon_type *rhs_uncommon;
+ int rhs_method_count;
+ const struct __go_method *p_rhs_method;
+ int i;
+
+ if (rhs_descriptor == NULL)
+ {
+ /* A nil value always converts to nil. */
+ return NULL;
+ }
+
+ __go_assert (lhs_descriptor->__code == GO_INTERFACE);
+ lhs_interface = (const struct __go_interface_type *) lhs_descriptor;
+ lhs_method_count = lhs_interface->__methods.__count;
+ lhs_methods = ((const struct __go_interface_method *)
+ lhs_interface->__methods.__values);
+
+ /* This should not be called for an empty interface. */
+ __go_assert (lhs_method_count > 0);
+
+ rhs_uncommon = rhs_descriptor->__uncommon;
+ if (rhs_uncommon == NULL || rhs_uncommon->__methods.__count == 0)
+ {
+ struct __go_empty_interface panic_arg;
+
+ if (may_fail)
+ return NULL;
+
+ newTypeAssertionError (NULL,
+ rhs_descriptor,
+ lhs_descriptor,
+ NULL,
+ rhs_descriptor->__reflection,
+ lhs_descriptor->__reflection,
+ lhs_methods[0].__name,
+ &panic_arg);
+ __go_panic (panic_arg);
+ }
+
+ rhs_method_count = rhs_uncommon->__methods.__count;
+ p_rhs_method = ((const struct __go_method *)
+ rhs_uncommon->__methods.__values);
+
+ methods = NULL;
+
+ for (i = 0; i < lhs_method_count; ++i)
+ {
+ const struct __go_interface_method *p_lhs_method;
+
+ p_lhs_method = &lhs_methods[i];
+
+ while (rhs_method_count > 0
+ && (!__go_ptr_strings_equal (p_lhs_method->__name,
+ p_rhs_method->__name)
+ || !__go_ptr_strings_equal (p_lhs_method->__pkg_path,
+ p_rhs_method->__pkg_path)))
+ {
+ ++p_rhs_method;
+ --rhs_method_count;
+ }
+
+ if (rhs_method_count == 0
+ || !__go_type_descriptors_equal (p_lhs_method->__type,
+ p_rhs_method->__mtype))
+ {
+ struct __go_empty_interface panic_arg;
+
+ if (methods != NULL)
+ __go_free (methods);
+
+ if (may_fail)
+ return NULL;
+
+ newTypeAssertionError (NULL,
+ rhs_descriptor,
+ lhs_descriptor,
+ NULL,
+ rhs_descriptor->__reflection,
+ lhs_descriptor->__reflection,
+ p_lhs_method->__name,
+ &panic_arg);
+ __go_panic (panic_arg);
+ }
+
+ if (methods == NULL)
+ {
+ methods = (const void **) __go_alloc ((lhs_method_count + 1)
+ * sizeof (void *));
+
+ /* The first field in the method table is always the type of
+ the object. */
+ methods[0] = rhs_descriptor;
+ }
+
+ methods[i + 1] = p_rhs_method->__function;
+ }
+
+ return methods;
+}
+
+/* This is called by the compiler to convert a value from one
+ interface type to another. */
+
+void *
+__go_convert_interface (const struct __go_type_descriptor *lhs_descriptor,
+ const struct __go_type_descriptor *rhs_descriptor)
+{
+ return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0);
+}
diff --git a/libgo/runtime/go-copy.c b/libgo/runtime/go-copy.c
new file mode 100644
index 000000000..998aeb927
--- /dev/null
+++ b/libgo/runtime/go-copy.c
@@ -0,0 +1,21 @@
+/* go-append.c -- the go builtin copy function.
+
+ 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 <stddef.h>
+
+/* We should be OK if we don't split the stack here, since we are just
+ calling memmove which shouldn't need much stack. If we don't do
+ this we will always split the stack, because of memmove. */
+
+extern void
+__go_copy (void *, void *, size_t)
+ __attribute__ ((no_split_stack));
+
+void
+__go_copy (void *a, void *b, size_t len)
+{
+ __builtin_memmove (a, b, len);
+}
diff --git a/libgo/runtime/go-defer.c b/libgo/runtime/go-defer.c
new file mode 100644
index 000000000..6425f0586
--- /dev/null
+++ b/libgo/runtime/go-defer.c
@@ -0,0 +1,69 @@
+/* go-defer.c -- manage the defer stack.
+
+ 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. */
+
+#include <stddef.h>
+
+#include "go-alloc.h"
+#include "go-panic.h"
+#include "go-defer.h"
+
+/* This function is called each time we need to defer a call. */
+
+void
+__go_defer (void *frame, void (*pfn) (void *), void *arg)
+{
+ struct __go_defer_stack *n;
+
+ if (__go_panic_defer == NULL)
+ __go_panic_defer = ((struct __go_panic_defer_struct *)
+ __go_alloc (sizeof (struct __go_panic_defer_struct)));
+
+ n = (struct __go_defer_stack *) __go_alloc (sizeof (struct __go_defer_stack));
+ n->__next = __go_panic_defer->__defer;
+ n->__frame = frame;
+ n->__panic = __go_panic_defer->__panic;
+ n->__pfn = pfn;
+ n->__arg = arg;
+ n->__retaddr = NULL;
+ __go_panic_defer->__defer = n;
+}
+
+/* This function is called when we want to undefer the stack. */
+
+void
+__go_undefer (void *frame)
+{
+ if (__go_panic_defer == NULL)
+ return;
+ while (__go_panic_defer->__defer != NULL
+ && __go_panic_defer->__defer->__frame == frame)
+ {
+ struct __go_defer_stack *d;
+ void (*pfn) (void *);
+
+ d = __go_panic_defer->__defer;
+ pfn = d->__pfn;
+ d->__pfn = NULL;
+
+ if (pfn != NULL)
+ (*pfn) (d->__arg);
+
+ __go_panic_defer->__defer = d->__next;
+ __go_free (d);
+ }
+}
+
+/* This function is called to record the address to which the deferred
+ function returns. This may in turn be checked by __go_can_recover.
+ The frontend relies on this function returning false. */
+
+_Bool
+__go_set_defer_retaddr (void *retaddr)
+{
+ if (__go_panic_defer != NULL && __go_panic_defer->__defer != NULL)
+ __go_panic_defer->__defer->__retaddr = retaddr;
+ return 0;
+}
diff --git a/libgo/runtime/go-defer.h b/libgo/runtime/go-defer.h
new file mode 100644
index 000000000..f8924f3b6
--- /dev/null
+++ b/libgo/runtime/go-defer.h
@@ -0,0 +1,36 @@
+/* go-defer.h -- the defer stack.
+
+ 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. */
+
+struct __go_panic_stack;
+
+/* The defer stack is a list of these structures. */
+
+struct __go_defer_stack
+{
+ /* The next entry in the stack. */
+ struct __go_defer_stack *__next;
+
+ /* The frame pointer for the function which called this defer
+ statement. */
+ void *__frame;
+
+ /* The value of the panic stack when this function is deferred.
+ This function can not recover this value from the panic stack.
+ This can happen if a deferred function uses its own defer
+ statement. */
+ struct __go_panic_stack *__panic;
+
+ /* The function to call. */
+ void (*__pfn) (void *);
+
+ /* The argument to pass to the function. */
+ void *__arg;
+
+ /* The return address that a recover thunk matches against. This is
+ set by __go_set_defer_retaddr which is called by the thunks
+ created by defer statements. */
+ const void *__retaddr;
+};
diff --git a/libgo/runtime/go-deferred-recover.c b/libgo/runtime/go-deferred-recover.c
new file mode 100644
index 000000000..2d9ca1442
--- /dev/null
+++ b/libgo/runtime/go-deferred-recover.c
@@ -0,0 +1,92 @@
+/* go-deferred-recover.c -- support for a deferred recover function.
+
+ 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 <stddef.h>
+
+#include "go-panic.h"
+#include "go-defer.h"
+
+/* This is called when a call to recover is deferred. That is,
+ something like
+ defer recover()
+
+ We need to handle this specially. In 6g/8g, the recover function
+ looks up the stack frame. In particular, that means that a
+ deferred recover will not recover a panic thrown in the same
+ function that defers the recover. It will only recover a panic
+ thrown in a function that defers the deferred call to recover.
+
+ In other words:
+
+ func f1() {
+ defer recover() // does not stop panic
+ panic(0)
+ }
+
+ func f2() {
+ defer func() {
+ defer recover() // stops panic(0)
+ }()
+ panic(0)
+ }
+
+ func f3() {
+ defer func() {
+ defer recover() // does not stop panic
+ panic(0)
+ }()
+ panic(1)
+ }
+
+ func f4() {
+ defer func() {
+ defer func() {
+ defer recover() // stops panic(0)
+ }()
+ panic(0)
+ }()
+ panic(1)
+ }
+
+ The interesting case here is f3. As can be seen from f2, the
+ deferred recover could pick up panic(1). However, this does not
+ happen because it is blocked by the panic(0).
+
+ When a function calls recover, then when we invoke it we pass a
+ hidden parameter indicating whether it should recover something.
+ This parameter is set based on whether the function is being
+ invoked directly from defer. The parameter winds up determining
+ whether __go_recover or __go_deferred_recover is called at all.
+
+ In the case of a deferred recover, the hidden parameter which
+ controls the call is actually the one set up for the function which
+ runs the defer recover() statement. That is the right thing in all
+ the cases above except for f3. In f3 the function is permitted to
+ call recover, but the deferred recover call is not. We address
+ that here by checking for that specific case before calling
+ recover. If this function was deferred when there is already a
+ panic on the panic stack, then we can only recover that panic, not
+ any other.
+
+ Note that we can get away with using a special function here
+ because you are not permitted to take the address of a predeclared
+ function like recover. */
+
+struct __go_empty_interface
+__go_deferred_recover ()
+{
+ if (__go_panic_defer == NULL
+ || __go_panic_defer->__defer == NULL
+ || __go_panic_defer->__defer->__panic != __go_panic_defer->__panic)
+ {
+ struct __go_empty_interface ret;
+
+ ret.__type_descriptor = NULL;
+ ret.__object = NULL;
+ return ret;
+ }
+ return __go_recover();
+}
diff --git a/libgo/runtime/go-eface-compare.c b/libgo/runtime/go-eface-compare.c
new file mode 100644
index 000000000..c90177e20
--- /dev/null
+++ b/libgo/runtime/go-eface-compare.c
@@ -0,0 +1,32 @@
+/* go-eface-compare.c -- compare two empty values.
+
+ 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 "interface.h"
+
+/* Compare two interface values. Return 0 for equal, not zero for not
+ equal (return value is like strcmp). */
+
+int
+__go_empty_interface_compare (struct __go_empty_interface left,
+ struct __go_empty_interface right)
+{
+ const struct __go_type_descriptor *left_descriptor;
+
+ left_descriptor = left.__type_descriptor;
+ if (left_descriptor == NULL && right.__type_descriptor == NULL)
+ return 0;
+ if (left_descriptor == NULL || right.__type_descriptor == NULL)
+ return 1;
+ if (!__go_type_descriptors_equal (left_descriptor,
+ right.__type_descriptor))
+ return 1;
+ if (__go_is_pointer_type (left_descriptor))
+ return left.__object == right.__object ? 0 : 1;
+ if (!left_descriptor->__equalfn (left.__object, right.__object,
+ left_descriptor->__size))
+ return 1;
+ return 0;
+}
diff --git a/libgo/runtime/go-eface-val-compare.c b/libgo/runtime/go-eface-val-compare.c
new file mode 100644
index 000000000..319ede243
--- /dev/null
+++ b/libgo/runtime/go-eface-val-compare.c
@@ -0,0 +1,32 @@
+/* go-eface-val-compare.c -- compare an empty interface with a value.
+
+ 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 "go-type.h"
+#include "interface.h"
+
+/* Compare an empty interface with a value. Return 0 for equal, not
+ zero for not equal (return value is like strcmp). */
+
+int
+__go_empty_interface_value_compare (
+ struct __go_empty_interface left,
+ const struct __go_type_descriptor *right_descriptor,
+ const void *val)
+{
+ const struct __go_type_descriptor *left_descriptor;
+
+ left_descriptor = left.__type_descriptor;
+ if (left_descriptor == NULL)
+ return 1;
+ if (!__go_type_descriptors_equal (left_descriptor, right_descriptor))
+ return 1;
+ if (__go_is_pointer_type (left_descriptor))
+ return left.__object == val ? 0 : 1;
+ if (!left_descriptor->__equalfn (left.__object, val,
+ left_descriptor->__size))
+ return 1;
+ return 0;
+}
diff --git a/libgo/runtime/go-getgoroot.c b/libgo/runtime/go-getgoroot.c
new file mode 100644
index 000000000..e74fee886
--- /dev/null
+++ b/libgo/runtime/go-getgoroot.c
@@ -0,0 +1,26 @@
+/* go-getgoroot.c -- getgoroot function for runtime package.
+
+ 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 <stdlib.h>
+
+#include "go-string.h"
+
+struct __go_string getgoroot (void) asm ("libgo_runtime.runtime.getgoroot");
+
+struct __go_string
+getgoroot ()
+{
+ const char *p;
+ struct __go_string ret;
+
+ p = getenv ("GOROOT");
+ ret.__data = (const unsigned char *) p;
+ if (ret.__data == NULL)
+ ret.__length = 0;
+ else
+ ret.__length = __builtin_strlen (p);
+ return ret;
+}
diff --git a/libgo/runtime/go-go.c b/libgo/runtime/go-go.c
new file mode 100644
index 000000000..3d8e9e629
--- /dev/null
+++ b/libgo/runtime/go-go.c
@@ -0,0 +1,656 @@
+/* go-go.c -- the go function.
+
+ 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. */
+
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include "config.h"
+#include "go-assert.h"
+#include "go-panic.h"
+#include "go-alloc.h"
+#include "runtime.h"
+#include "malloc.h"
+
+#ifdef USING_SPLIT_STACK
+/* FIXME: This is not declared anywhere. */
+extern void *__splitstack_find (void *, void *, size_t *, void **, void **,
+ void **);
+#endif
+
+/* We stop the threads by sending them the signal GO_SIG_STOP and we
+ start them by sending them the signal GO_SIG_START. */
+
+#define GO_SIG_START (SIGRTMIN + 1)
+#define GO_SIG_STOP (SIGRTMIN + 2)
+
+#ifndef SA_RESTART
+ #define SA_RESTART 0
+#endif
+
+/* A doubly linked list of the threads we have started. */
+
+struct __go_thread_id
+{
+ /* Links. */
+ struct __go_thread_id *prev;
+ struct __go_thread_id *next;
+ /* True if the thread ID has not yet been filled in. */
+ _Bool tentative;
+ /* Thread ID. */
+ pthread_t id;
+ /* Thread's M structure. */
+ struct M *m;
+ /* If the thread ID has not been filled in, the function we are
+ running. */
+ void (*pfn) (void *);
+ /* If the thread ID has not been filled in, the argument to the
+ function. */
+ void *arg;
+};
+
+static struct __go_thread_id *__go_all_thread_ids;
+
+/* A lock to control access to ALL_THREAD_IDS. */
+
+static pthread_mutex_t __go_thread_ids_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* A semaphore used to wait until all the threads have stopped. */
+
+static sem_t __go_thread_ready_sem;
+
+/* A signal set used to wait until garbage collection is complete. */
+
+static sigset_t __go_thread_wait_sigset;
+
+/* Remove the current thread from the list of threads. */
+
+static void
+remove_current_thread (void)
+{
+ struct __go_thread_id *list_entry;
+ MCache *mcache;
+ int i;
+
+ list_entry = m->list_entry;
+ mcache = m->mcache;
+
+ i = pthread_mutex_lock (&__go_thread_ids_lock);
+ __go_assert (i == 0);
+
+ if (list_entry->prev != NULL)
+ list_entry->prev->next = list_entry->next;
+ else
+ __go_all_thread_ids = list_entry->next;
+ if (list_entry->next != NULL)
+ list_entry->next->prev = list_entry->prev;
+
+ /* This will look runtime_mheap as needed. */
+ runtime_MCache_ReleaseAll (mcache);
+
+ /* This should never deadlock--there shouldn't be any code that
+ holds the runtime_mheap lock when locking __go_thread_ids_lock.
+ We don't want to do this after releasing __go_thread_ids_lock
+ because it will mean that the garbage collector might run, and
+ the garbage collector does not try to lock runtime_mheap in all
+ cases since it knows it is running single-threaded. */
+ runtime_lock (&runtime_mheap);
+ mstats.heap_alloc += mcache->local_alloc;
+ mstats.heap_objects += mcache->local_objects;
+ __builtin_memset (mcache, 0, sizeof (struct MCache));
+ runtime_FixAlloc_Free (&runtime_mheap.cachealloc, mcache);
+ runtime_unlock (&runtime_mheap);
+
+ /* As soon as we release this look, a GC could run. Since this
+ thread is no longer on the list, the GC will not find our M
+ structure, so it could get freed at any time. That means that
+ any code from here to thread exit must not assume that m is
+ valid. */
+ m = NULL;
+
+ i = pthread_mutex_unlock (&__go_thread_ids_lock);
+ __go_assert (i == 0);
+
+ free (list_entry);
+}
+
+/* Start the thread. */
+
+static void *
+start_go_thread (void *thread_arg)
+{
+ struct M *newm = (struct M *) thread_arg;
+ void (*pfn) (void *);
+ void *arg;
+ struct __go_thread_id *list_entry;
+ int i;
+
+#ifdef __rtems__
+ __wrap_rtems_task_variable_add ((void **) &m);
+ __wrap_rtems_task_variable_add ((void **) &__go_panic_defer);
+#endif
+
+ m = newm;
+
+ list_entry = newm->list_entry;
+
+ pfn = list_entry->pfn;
+ arg = list_entry->arg;
+
+#ifndef USING_SPLIT_STACK
+ /* If we don't support split stack, record the current stack as the
+ top of the stack. There shouldn't be anything relevant to the
+ garbage collector above this point. */
+ m->gc_sp = (void *) &arg;
+#endif
+
+ /* Finish up the entry on the thread list. */
+
+ i = pthread_mutex_lock (&__go_thread_ids_lock);
+ __go_assert (i == 0);
+
+ list_entry->id = pthread_self ();
+ list_entry->pfn = NULL;
+ list_entry->arg = NULL;
+ list_entry->tentative = 0;
+
+ i = pthread_mutex_unlock (&__go_thread_ids_lock);
+ __go_assert (i == 0);
+
+ (*pfn) (arg);
+
+ remove_current_thread ();
+
+ return NULL;
+}
+
+/* The runtime.Goexit function. */
+
+void Goexit (void) asm ("libgo_runtime.runtime.Goexit");
+
+void
+Goexit (void)
+{
+ remove_current_thread ();
+ pthread_exit (NULL);
+ abort ();
+}
+
+/* Implement the go statement. */
+
+void
+__go_go (void (*pfn) (void*), void *arg)
+{
+ int i;
+ pthread_attr_t attr;
+ struct M *newm;
+ struct __go_thread_id *list_entry;
+ pthread_t tid;
+
+ i = pthread_attr_init (&attr);
+ __go_assert (i == 0);
+ i = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+ __go_assert (i == 0);
+
+#ifdef LINKER_SUPPORTS_SPLIT_STACK
+ /* The linker knows how to handle calls between code which uses
+ -fsplit-stack and code which does not. That means that we can
+ run with a smaller stack and rely on the -fsplit-stack support to
+ save us. The GNU/Linux glibc library won't let us have a very
+ small stack, but we make it as small as we can. */
+#ifndef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN 8192
+#endif
+ i = pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
+ __go_assert (i == 0);
+#endif
+
+ newm = __go_alloc (sizeof (M));
+
+ list_entry = malloc (sizeof (struct __go_thread_id));
+ list_entry->prev = NULL;
+ list_entry->next = NULL;
+ list_entry->tentative = 1;
+ list_entry->m = newm;
+ list_entry->pfn = pfn;
+ list_entry->arg = arg;
+
+ newm->list_entry = list_entry;
+
+ newm->mcache = runtime_allocmcache ();
+
+ /* Add the thread to the list of all threads, marked as tentative
+ since it is not yet ready to go. */
+ i = pthread_mutex_lock (&__go_thread_ids_lock);
+ __go_assert (i == 0);
+
+ if (__go_all_thread_ids != NULL)
+ __go_all_thread_ids->prev = list_entry;
+ list_entry->next = __go_all_thread_ids;
+ __go_all_thread_ids = list_entry;
+
+ i = pthread_mutex_unlock (&__go_thread_ids_lock);
+ __go_assert (i == 0);
+
+ /* Start the thread. */
+ i = pthread_create (&tid, &attr, start_go_thread, newm);
+ __go_assert (i == 0);
+
+ i = pthread_attr_destroy (&attr);
+ __go_assert (i == 0);
+}
+
+/* This is the signal handler for GO_SIG_START. The garbage collector
+ will send this signal to a thread when it wants the thread to
+ start. We don't have to actually do anything here, but we need a
+ signal handler since ignoring the signal will mean that the
+ sigsuspend will never see it. */
+
+static void
+gc_start_handler (int sig __attribute__ ((unused)))
+{
+}
+
+/* Tell the garbage collector that we are ready, and wait for the
+ garbage collector to tell us that it is done. This may be called
+ by a signal handler, so it is restricted to using functions which
+ are async cancel safe. */
+
+static void
+stop_for_gc (void)
+{
+ int i;
+
+ /* Tell the garbage collector about our stack. */
+#ifdef USING_SPLIT_STACK
+ m->gc_sp = __splitstack_find (NULL, NULL, &m->gc_len,
+ &m->gc_next_segment, &m->gc_next_sp,
+ &m->gc_initial_sp);
+#else
+ {
+ uintptr_t top = (uintptr_t) m->gc_sp;
+ uintptr_t bottom = (uintptr_t) &top;
+ if (top < bottom)
+ {
+ m->gc_next_sp = m->gc_sp;
+ m->gc_len = bottom - top;
+ }
+ else
+ {
+ m->gc_next_sp = (void *) bottom;
+ m->gc_len = top - bottom;
+ }
+ }
+#endif
+
+ /* FIXME: Perhaps we should just move __go_panic_defer into M. */
+ m->gc_panic_defer = __go_panic_defer;
+
+ /* Tell the garbage collector that we are ready by posting to the
+ semaphore. */
+ i = sem_post (&__go_thread_ready_sem);
+ __go_assert (i == 0);
+
+ /* Wait for the garbage collector to tell us to continue. */
+ sigsuspend (&__go_thread_wait_sigset);
+}
+
+/* This is the signal handler for GO_SIG_STOP. The garbage collector
+ will send this signal to a thread when it wants the thread to
+ stop. */
+
+static void
+gc_stop_handler (int sig __attribute__ ((unused)))
+{
+ struct M *pm = m;
+
+ if (__sync_bool_compare_and_swap (&pm->holds_finlock, 1, 1))
+ {
+ /* We can't interrupt the thread while it holds the finalizer
+ lock. Otherwise we can get into a deadlock when mark calls
+ runtime_walkfintab. */
+ __sync_bool_compare_and_swap (&pm->gcing_for_finlock, 0, 1);
+ return;
+ }
+
+ if (__sync_bool_compare_and_swap (&pm->mallocing, 1, 1))
+ {
+ /* m->mallocing was already non-zero. We can't interrupt the
+ thread while it is running an malloc. Instead, tell it to
+ call back to us when done. */
+ __sync_bool_compare_and_swap (&pm->gcing, 0, 1);
+ return;
+ }
+
+ if (__sync_bool_compare_and_swap (&pm->nomemprof, 1, 1))
+ {
+ /* Similarly, we can't interrupt the thread while it is building
+ profiling information. Otherwise we can get into a deadlock
+ when sweepspan calls MProf_Free. */
+ __sync_bool_compare_and_swap (&pm->gcing_for_prof, 0, 1);
+ return;
+ }
+
+ stop_for_gc ();
+}
+
+/* This is called by malloc when it gets a signal during the malloc
+ call itself. */
+
+int
+__go_run_goroutine_gc (int r)
+{
+ /* Force callee-saved registers to be saved on the stack. This is
+ not needed if we are invoked from the signal handler, but it is
+ needed if we are called directly, since otherwise we might miss
+ something that a function somewhere up the call stack is holding
+ in a register. */
+ __builtin_unwind_init ();
+
+ stop_for_gc ();
+
+ /* This avoids tail recursion, to make sure that the saved registers
+ are on the stack. */
+ return r;
+}
+
+/* Stop all the other threads for garbage collection. */
+
+void
+runtime_stoptheworld (void)
+{
+ int i;
+ pthread_t me;
+ int c;
+ struct __go_thread_id *p;
+
+ i = pthread_mutex_lock (&__go_thread_ids_lock);
+ __go_assert (i == 0);
+
+ me = pthread_self ();
+ c = 0;
+ p = __go_all_thread_ids;
+ while (p != NULL)
+ {
+ if (p->tentative || pthread_equal (me, p->id))
+ p = p->next;
+ else
+ {
+ i = pthread_kill (p->id, GO_SIG_STOP);
+ if (i == 0)
+ {
+ ++c;
+ p = p->next;
+ }
+ else if (i == ESRCH)
+ {
+ struct __go_thread_id *next;
+
+ /* This thread died somehow. Remove it from the
+ list. */
+ next = p->next;
+ if (p->prev != NULL)
+ p->prev->next = next;
+ else
+ __go_all_thread_ids = next;
+ if (next != NULL)
+ next->prev = p->prev;
+ free (p);
+ p = next;
+ }
+ else
+ abort ();
+ }
+ }
+
+ /* Wait for each thread to receive the signal and post to the
+ semaphore. If a thread receives the signal but contrives to die
+ before it posts to the semaphore, then we will hang forever
+ here. */
+
+ while (c > 0)
+ {
+ i = sem_wait (&__go_thread_ready_sem);
+ if (i < 0 && errno == EINTR)
+ continue;
+ __go_assert (i == 0);
+ --c;
+ }
+
+ /* The gc_panic_defer field should now be set for all M's except the
+ one in this thread. Set this one now. */
+ m->gc_panic_defer = __go_panic_defer;
+
+ /* Leave with __go_thread_ids_lock held. */
+}
+
+/* Scan all the stacks for garbage collection. This should be called
+ with __go_thread_ids_lock held. */
+
+void
+__go_scanstacks (void (*scan) (byte *, int64))
+{
+ pthread_t me;
+ struct __go_thread_id *p;
+
+ /* Make sure all the registers for this thread are on the stack. */
+ __builtin_unwind_init ();
+
+ me = pthread_self ();
+ for (p = __go_all_thread_ids; p != NULL; p = p->next)
+ {
+ if (p->tentative)
+ {
+ /* The goroutine function and argument can be allocated on
+ the heap, so we have to scan them for a thread that has
+ not yet started. */
+ scan ((void *) &p->pfn, sizeof (void *));
+ scan ((void *) &p->arg, sizeof (void *));
+ scan ((void *) &p->m, sizeof (void *));
+ continue;
+ }
+
+#ifdef USING_SPLIT_STACK
+
+ void *sp;
+ size_t len;
+ void *next_segment;
+ void *next_sp;
+ void *initial_sp;
+
+ if (pthread_equal (me, p->id))
+ {
+ next_segment = NULL;
+ next_sp = NULL;
+ initial_sp = NULL;
+ sp = __splitstack_find (NULL, NULL, &len, &next_segment,
+ &next_sp, &initial_sp);
+ }
+ else
+ {
+ sp = p->m->gc_sp;
+ len = p->m->gc_len;
+ next_segment = p->m->gc_next_segment;
+ next_sp = p->m->gc_next_sp;
+ initial_sp = p->m->gc_initial_sp;
+ }
+
+ while (sp != NULL)
+ {
+ scan (sp, len);
+ sp = __splitstack_find (next_segment, next_sp, &len,
+ &next_segment, &next_sp, &initial_sp);
+ }
+
+#else /* !defined(USING_SPLIT_STACK) */
+
+ if (pthread_equal (me, p->id))
+ {
+ uintptr_t top = (uintptr_t) m->gc_sp;
+ uintptr_t bottom = (uintptr_t) &top;
+ if (top < bottom)
+ scan (m->gc_sp, bottom - top);
+ else
+ scan ((void *) bottom, top - bottom);
+ }
+ else
+ {
+ scan (p->m->gc_next_sp, p->m->gc_len);
+ }
+
+#endif /* !defined(USING_SPLIT_STACK) */
+
+ /* Also scan the M structure while we're at it. */
+
+ scan ((void *) &p->m, sizeof (void *));
+ }
+}
+
+/* Release all the memory caches. This is called with
+ __go_thread_ids_lock held. */
+
+void
+__go_stealcache (void)
+{
+ struct __go_thread_id *p;
+
+ for (p = __go_all_thread_ids; p != NULL; p = p->next)
+ runtime_MCache_ReleaseAll (p->m->mcache);
+}
+
+/* Gather memory cache statistics. This is called with
+ __go_thread_ids_lock held. */
+
+void
+__go_cachestats (void)
+{
+ struct __go_thread_id *p;
+
+ for (p = __go_all_thread_ids; p != NULL; p = p->next)
+ {
+ MCache *c;
+
+ c = p->m->mcache;
+ mstats.heap_alloc += c->local_alloc;
+ c->local_alloc = 0;
+ mstats.heap_objects += c->local_objects;
+ c->local_objects = 0;
+ }
+}
+
+/* Start the other threads after garbage collection. */
+
+void
+runtime_starttheworld (void)
+{
+ int i;
+ pthread_t me;
+ struct __go_thread_id *p;
+
+ /* Here __go_thread_ids_lock should be held. */
+
+ me = pthread_self ();
+ p = __go_all_thread_ids;
+ while (p != NULL)
+ {
+ if (p->tentative || pthread_equal (me, p->id))
+ p = p->next;
+ else
+ {
+ i = pthread_kill (p->id, GO_SIG_START);
+ if (i == 0)
+ p = p->next;
+ else
+ abort ();
+ }
+ }
+
+ i = pthread_mutex_unlock (&__go_thread_ids_lock);
+ __go_assert (i == 0);
+}
+
+/* Initialize the interaction between goroutines and the garbage
+ collector. */
+
+void
+__go_gc_goroutine_init (void *sp __attribute__ ((unused)))
+{
+ struct __go_thread_id *list_entry;
+ int i;
+ sigset_t sset;
+ struct sigaction act;
+
+ /* Add the initial thread to the list of all threads. */
+
+ list_entry = malloc (sizeof (struct __go_thread_id));
+ list_entry->prev = NULL;
+ list_entry->next = NULL;
+ list_entry->tentative = 0;
+ list_entry->id = pthread_self ();
+ list_entry->m = m;
+ list_entry->pfn = NULL;
+ list_entry->arg = NULL;
+ __go_all_thread_ids = list_entry;
+
+ /* Initialize the semaphore which signals when threads are ready for
+ GC. */
+
+ i = sem_init (&__go_thread_ready_sem, 0, 0);
+ __go_assert (i == 0);
+
+ /* Fetch the current signal mask. */
+
+ i = sigemptyset (&sset);
+ __go_assert (i == 0);
+ i = sigprocmask (SIG_BLOCK, NULL, &sset);
+ __go_assert (i == 0);
+
+ /* Make sure that GO_SIG_START is not blocked and GO_SIG_STOP is
+ blocked, and save that set for use with later calls to sigsuspend
+ while waiting for GC to complete. */
+
+ i = sigdelset (&sset, GO_SIG_START);
+ __go_assert (i == 0);
+ i = sigaddset (&sset, GO_SIG_STOP);
+ __go_assert (i == 0);
+ __go_thread_wait_sigset = sset;
+
+ /* Block SIG_SET_START and unblock SIG_SET_STOP, and use that for
+ the process signal mask. */
+
+ i = sigaddset (&sset, GO_SIG_START);
+ __go_assert (i == 0);
+ i = sigdelset (&sset, GO_SIG_STOP);
+ __go_assert (i == 0);
+ i = sigprocmask (SIG_SETMASK, &sset, NULL);
+ __go_assert (i == 0);
+
+ /* Install the signal handlers. */
+ memset (&act, 0, sizeof act);
+ i = sigemptyset (&act.sa_mask);
+ __go_assert (i == 0);
+
+ act.sa_handler = gc_start_handler;
+ act.sa_flags = SA_RESTART;
+ i = sigaction (GO_SIG_START, &act, NULL);
+ __go_assert (i == 0);
+
+ /* We could consider using an alternate signal stack for this. The
+ function does not use much stack space, so it may be OK. */
+ act.sa_handler = gc_stop_handler;
+ i = sigaction (GO_SIG_STOP, &act, NULL);
+ __go_assert (i == 0);
+
+#ifndef USING_SPLIT_STACK
+ /* If we don't support split stack, record the current stack as the
+ top of the stack. */
+ m->gc_sp = sp;
+#endif
+}
diff --git a/libgo/runtime/go-gomaxprocs.c b/libgo/runtime/go-gomaxprocs.c
new file mode 100644
index 000000000..04dc448b8
--- /dev/null
+++ b/libgo/runtime/go-gomaxprocs.c
@@ -0,0 +1,15 @@
+/* go-gomaxprocs.c -- runtime.GOMAXPROCS.
+
+ Copyright 2009 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file. */
+
+/* This is the runtime.GOMAXPROCS function. This currently does
+ nothing, since each goroutine runs in a separate thread anyhow. */
+
+void GOMAXPROCS (int) asm ("libgo_runtime.runtime.GOMAXPROCS");
+
+void
+GOMAXPROCS (int n __attribute__ ((unused)))
+{
+}
diff --git a/libgo/runtime/go-int-array-to-string.c b/libgo/runtime/go-int-array-to-string.c
new file mode 100644
index 000000000..46a33dafc
--- /dev/null
+++ b/libgo/runtime/go-int-array-to-string.c
@@ -0,0 +1,85 @@
+/* go-int-array-to-string.c -- convert an array of ints to a string in Go.
+
+ 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. */
+
+#include "go-assert.h"
+#include "go-string.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_string
+__go_int_array_to_string (const void* p, size_t len)
+{
+ const int *ints;
+ size_t slen;
+ size_t i;
+ unsigned char *retdata;
+ struct __go_string ret;
+ unsigned char *s;
+
+ ints = (const int *) p;
+
+ slen = 0;
+ for (i = 0; i < len; ++i)
+ {
+ int v;
+
+ v = ints[i];
+
+ if (v > 0x10ffff)
+ v = 0xfffd;
+
+ if (v <= 0x7f)
+ slen += 1;
+ else if (v <= 0x7ff)
+ slen += 2;
+ else if (v <= 0xffff)
+ slen += 3;
+ else
+ slen += 4;
+ }
+
+ retdata = runtime_mallocgc (slen, RefNoPointers, 1, 0);
+ ret.__data = retdata;
+ ret.__length = slen;
+
+ s = retdata;
+ for (i = 0; i < len; ++i)
+ {
+ int v;
+
+ v = ints[i];
+
+ /* If V is out of range for UTF-8, substitute the replacement
+ character. */
+ if (v > 0x10ffff)
+ v = 0xfffd;
+
+ if (v <= 0x7f)
+ *s++ = v;
+ else if (v <= 0x7ff)
+ {
+ *s++ = 0xc0 | ((v >> 6) & 0x1f);
+ *s++ = 0x80 | (v & 0x3f);
+ }
+ else if (v <= 0xffff)
+ {
+ *s++ = 0xe0 | ((v >> 12) & 0xf);
+ *s++ = 0x80 | ((v >> 6) & 0x3f);
+ *s++ = 0x80 | (v & 0x3f);
+ }
+ else
+ {
+ *s++ = 0xf0 | ((v >> 18) & 0x7);
+ *s++ = 0x80 | ((v >> 12) & 0x3f);
+ *s++ = 0x80 | ((v >> 6) & 0x3f);
+ *s++ = 0x80 | (v & 0x3f);
+ }
+ }
+
+ __go_assert ((size_t) (s - retdata) == slen);
+
+ return ret;
+}
diff --git a/libgo/runtime/go-int-to-string.c b/libgo/runtime/go-int-to-string.c
new file mode 100644
index 000000000..24d729cf8
--- /dev/null
+++ b/libgo/runtime/go-int-to-string.c
@@ -0,0 +1,60 @@
+/* go-int-to-string.c -- convert an integer to a string in Go.
+
+ 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. */
+
+#include "go-string.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_string
+__go_int_to_string (int v)
+{
+ char buf[4];
+ int len;
+ unsigned char *retdata;
+ struct __go_string ret;
+
+ if (v <= 0x7f)
+ {
+ buf[0] = v;
+ len = 1;
+ }
+ else if (v <= 0x7ff)
+ {
+ buf[0] = 0xc0 + (v >> 6);
+ buf[1] = 0x80 + (v & 0x3f);
+ len = 2;
+ }
+ else
+ {
+ /* If the value is out of range for UTF-8, turn it into the
+ "replacement character". */
+ if (v > 0x10ffff)
+ v = 0xfffd;
+
+ if (v <= 0xffff)
+ {
+ buf[0] = 0xe0 + (v >> 12);
+ buf[1] = 0x80 + ((v >> 6) & 0x3f);
+ buf[2] = 0x80 + (v & 0x3f);
+ len = 3;
+ }
+ else
+ {
+ buf[0] = 0xf0 + (v >> 18);
+ buf[1] = 0x80 + ((v >> 12) & 0x3f);
+ buf[2] = 0x80 + ((v >> 6) & 0x3f);
+ buf[3] = 0x80 + (v & 0x3f);
+ len = 4;
+ }
+ }
+
+ retdata = runtime_mallocgc (len, RefNoPointers, 1, 0);
+ __builtin_memcpy (retdata, buf, len);
+ ret.__data = retdata;
+ ret.__length = len;
+
+ return ret;
+}
diff --git a/libgo/runtime/go-interface-compare.c b/libgo/runtime/go-interface-compare.c
new file mode 100644
index 000000000..11c75e812
--- /dev/null
+++ b/libgo/runtime/go-interface-compare.c
@@ -0,0 +1,31 @@
+/* go-interface-compare.c -- compare two interface values.
+
+ 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. */
+
+#include "interface.h"
+
+/* Compare two interface values. Return 0 for equal, not zero for not
+ equal (return value is like strcmp). */
+
+int
+__go_interface_compare (struct __go_interface left,
+ struct __go_interface right)
+{
+ const struct __go_type_descriptor *left_descriptor;
+
+ if (left.__methods == NULL && right.__methods == NULL)
+ return 0;
+ if (left.__methods == NULL || right.__methods == NULL)
+ return 1;
+ left_descriptor = left.__methods[0];
+ if (!__go_type_descriptors_equal (left_descriptor, right.__methods[0]))
+ return 1;
+ if (__go_is_pointer_type (left_descriptor))
+ return left.__object == right.__object ? 0 : 1;
+ if (!left_descriptor->__equalfn (left.__object, right.__object,
+ left_descriptor->__size))
+ return 1;
+ return 0;
+}
diff --git a/libgo/runtime/go-interface-eface-compare.c b/libgo/runtime/go-interface-eface-compare.c
new file mode 100644
index 000000000..9de8424ac
--- /dev/null
+++ b/libgo/runtime/go-interface-eface-compare.c
@@ -0,0 +1,32 @@
+/* go-interface-eface-compare.c -- compare non-empty and empty interface.
+
+ 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 "interface.h"
+
+/* Compare a non-empty interface value with an empty interface value.
+ Return 0 for equal, not zero for not equal (return value is like
+ strcmp). */
+
+int
+__go_interface_empty_compare (struct __go_interface left,
+ struct __go_empty_interface right)
+{
+ const struct __go_type_descriptor *left_descriptor;
+
+ if (left.__methods == NULL && right.__type_descriptor == NULL)
+ return 0;
+ if (left.__methods == NULL || right.__type_descriptor == NULL)
+ return 1;
+ left_descriptor = left.__methods[0];
+ if (!__go_type_descriptors_equal (left_descriptor, right.__type_descriptor))
+ return 1;
+ if (__go_is_pointer_type (left_descriptor))
+ return left.__object == right.__object ? 0 : 1;
+ if (!left_descriptor->__equalfn (left.__object, right.__object,
+ left_descriptor->__size))
+ return 1;
+ return 0;
+}
diff --git a/libgo/runtime/go-interface-val-compare.c b/libgo/runtime/go-interface-val-compare.c
new file mode 100644
index 000000000..15898924a
--- /dev/null
+++ b/libgo/runtime/go-interface-val-compare.c
@@ -0,0 +1,32 @@
+/* go-interface-val-compare.c -- compare an interface to a value.
+
+ 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. */
+
+#include "go-type.h"
+#include "interface.h"
+
+/* Compare two interface values. Return 0 for equal, not zero for not
+ equal (return value is like strcmp). */
+
+int
+__go_interface_value_compare (
+ struct __go_interface left,
+ const struct __go_type_descriptor *right_descriptor,
+ const void *val)
+{
+ const struct __go_type_descriptor *left_descriptor;
+
+ if (left.__methods == NULL)
+ return 1;
+ left_descriptor = left.__methods[0];
+ if (!__go_type_descriptors_equal (left_descriptor, right_descriptor))
+ return 1;
+ if (__go_is_pointer_type (left_descriptor))
+ return left.__object == val ? 0 : 1;
+ if (!left_descriptor->__equalfn (left.__object, val,
+ left_descriptor->__size))
+ return 1;
+ return 0;
+}
diff --git a/libgo/runtime/go-lock-os-thread.c b/libgo/runtime/go-lock-os-thread.c
new file mode 100644
index 000000000..204f11dce
--- /dev/null
+++ b/libgo/runtime/go-lock-os-thread.c
@@ -0,0 +1,24 @@
+/* go-lock-os-thread.c -- the LockOSThread and UnlockOSThread functions.
+
+ 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. */
+
+/* The runtime.LockOSThread and runtime.UnlockOSThread functions are
+ meaningless in the current implementation, since for us a goroutine
+ always stays on a single OS thread. */
+
+extern void LockOSThread (void) __asm__ ("libgo_runtime.runtime.LockOSThread");
+
+void
+LockOSThread (void)
+{
+}
+
+extern void UnlockOSThread (void)
+ __asm__ ("libgo_runtime.runtime.UnlockOSThread");
+
+void
+UnlockOSThread (void)
+{
+}
diff --git a/libgo/runtime/go-main.c b/libgo/runtime/go-main.c
new file mode 100644
index 000000000..a6dbf347f
--- /dev/null
+++ b/libgo/runtime/go-main.c
@@ -0,0 +1,89 @@
+/* go-main.c -- the main function for a Go program.
+
+ 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. */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef HAVE_FPU_CONTROL_H
+#include <fpu_control.h>
+#endif
+
+#include "go-alloc.h"
+#include "array.h"
+#include "go-signal.h"
+#include "go-string.h"
+
+#include "runtime.h"
+#include "malloc.h"
+
+#undef int
+#undef char
+#undef unsigned
+
+/* The main function for a Go program. This records the command line
+ parameters, calls the real main function, and returns a zero status
+ if the real main function returns. */
+
+extern char **environ;
+
+extern struct __go_open_array Args asm ("libgo_os.os.Args");
+
+extern struct __go_open_array Envs asm ("libgo_os.os.Envs");
+
+/* These functions are created for the main package. */
+extern void __go_init_main (void);
+extern void real_main (void) asm ("main.main");
+
+/* The main function. */
+
+int
+main (int argc, char **argv)
+{
+ int i;
+ struct __go_string *values;
+
+ runtime_mallocinit ();
+ __go_gc_goroutine_init (&argc);
+
+ Args.__count = argc;
+ Args.__capacity = argc;
+ values = __go_alloc (argc * sizeof (struct __go_string));
+ for (i = 0; i < argc; ++i)
+ {
+ values[i].__data = (unsigned char *) argv[i];
+ values[i].__length = __builtin_strlen (argv[i]);
+ }
+ Args.__values = values;
+
+ for (i = 0; environ[i] != NULL; ++i)
+ ;
+ Envs.__count = i;
+ Envs.__capacity = i;
+ values = __go_alloc (i * sizeof (struct __go_string));
+ for (i = 0; environ[i] != NULL; ++i)
+ {
+ values[i].__data = (unsigned char *) environ[i];
+ values[i].__length = __builtin_strlen (environ[i]);
+ }
+ Envs.__values = values;
+
+ __initsig ();
+
+#if defined(HAVE_SRANDOM)
+ srandom ((unsigned int) time (NULL));
+#else
+ srand ((unsigned int) time (NULL));
+#endif
+ __go_init_main ();
+
+ __go_enable_gc ();
+
+ real_main ();
+
+ return 0;
+}
diff --git a/libgo/runtime/go-map-delete.c b/libgo/runtime/go-map-delete.c
new file mode 100644
index 000000000..ec851e531
--- /dev/null
+++ b/libgo/runtime/go-map-delete.c
@@ -0,0 +1,52 @@
+/* go-map-delete.c -- delete an entry from a map.
+
+ 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. */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "map.h"
+
+/* Delete the entry matching KEY from MAP. */
+
+void
+__go_map_delete (struct __go_map *map, const void *key)
+{
+ const struct __go_map_descriptor *descriptor;
+ const struct __go_type_descriptor *key_descriptor;
+ size_t key_offset;
+ _Bool (*equalfn) (const void*, const void*, size_t);
+ size_t key_hash;
+ size_t key_size;
+ size_t bucket_index;
+ void **pentry;
+
+ descriptor = map->__descriptor;
+
+ key_descriptor = descriptor->__map_descriptor->__key_type;
+ key_offset = descriptor->__key_offset;
+ key_size = key_descriptor->__size;
+ __go_assert (key_size != 0 && key_size != -1UL);
+ equalfn = key_descriptor->__equalfn;
+
+ key_hash = key_descriptor->__hashfn (key, key_size);
+ bucket_index = key_hash % map->__bucket_count;
+
+ pentry = map->__buckets + bucket_index;
+ while (*pentry != NULL)
+ {
+ char *entry = (char *) *pentry;
+ if (equalfn (key, entry + key_offset, key_size))
+ {
+ *pentry = *(void **) entry;
+ __go_free (entry);
+ map->__element_count -= 1;
+ break;
+ }
+ pentry = (void **) entry;
+ }
+}
diff --git a/libgo/runtime/go-map-index.c b/libgo/runtime/go-map-index.c
new file mode 100644
index 000000000..1561c97a6
--- /dev/null
+++ b/libgo/runtime/go-map-index.c
@@ -0,0 +1,127 @@
+/* go-map-index.c -- find or insert an entry in a map.
+
+ 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. */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "map.h"
+
+/* Rehash MAP to a larger size. */
+
+static void
+__go_map_rehash (struct __go_map *map)
+{
+ const struct __go_map_descriptor *descriptor;
+ const struct __go_type_descriptor *key_descriptor;
+ size_t key_offset;
+ size_t key_size;
+ size_t (*hashfn) (const void *, size_t);
+ size_t old_bucket_count;
+ void **old_buckets;
+ size_t new_bucket_count;
+ void **new_buckets;
+ size_t i;
+
+ descriptor = map->__descriptor;
+
+ key_descriptor = descriptor->__map_descriptor->__key_type;
+ key_offset = descriptor->__key_offset;
+ key_size = key_descriptor->__size;
+ hashfn = key_descriptor->__hashfn;
+
+ old_bucket_count = map->__bucket_count;
+ old_buckets = map->__buckets;
+
+ new_bucket_count = __go_map_next_prime (old_bucket_count * 2);
+ new_buckets = (void **) __go_alloc (new_bucket_count * sizeof (void *));
+ __builtin_memset (new_buckets, 0, new_bucket_count * sizeof (void *));
+
+ for (i = 0; i < old_bucket_count; ++i)
+ {
+ char* entry;
+ char* next;
+
+ for (entry = old_buckets[i]; entry != NULL; entry = next)
+ {
+ size_t key_hash;
+ size_t new_bucket_index;
+
+ /* We could speed up rehashing at the cost of memory space
+ by caching the hash code. */
+ key_hash = hashfn (entry + key_offset, key_size);
+ new_bucket_index = key_hash % new_bucket_count;
+
+ next = *(char **) entry;
+ *(char **) entry = new_buckets[new_bucket_index];
+ new_buckets[new_bucket_index] = entry;
+ }
+ }
+
+ __go_free (old_buckets);
+
+ map->__bucket_count = new_bucket_count;
+ map->__buckets = new_buckets;
+}
+
+/* Find KEY in MAP, return a pointer to the value. If KEY is not
+ present, then if INSERT is false, return NULL, and if INSERT is
+ true, insert a new value and zero-initialize it before returning a
+ pointer to it. */
+
+void *
+__go_map_index (struct __go_map *map, const void *key, _Bool insert)
+{
+ const struct __go_map_descriptor *descriptor;
+ const struct __go_type_descriptor *key_descriptor;
+ size_t key_offset;
+ _Bool (*equalfn) (const void*, const void*, size_t);
+ size_t key_hash;
+ size_t key_size;
+ size_t bucket_index;
+ char *entry;
+
+ descriptor = map->__descriptor;
+
+ key_descriptor = descriptor->__map_descriptor->__key_type;
+ key_offset = descriptor->__key_offset;
+ key_size = key_descriptor->__size;
+ __go_assert (key_size != 0 && key_size != -1UL);
+ equalfn = key_descriptor->__equalfn;
+
+ key_hash = key_descriptor->__hashfn (key, key_size);
+ bucket_index = key_hash % map->__bucket_count;
+
+ entry = (char *) map->__buckets[bucket_index];
+ while (entry != NULL)
+ {
+ if (equalfn (key, entry + key_offset, key_size))
+ return entry + descriptor->__val_offset;
+ entry = *(char **) entry;
+ }
+
+ if (!insert)
+ return NULL;
+
+ if (map->__element_count >= map->__bucket_count)
+ {
+ __go_map_rehash (map);
+ bucket_index = key_hash % map->__bucket_count;
+ }
+
+ entry = (char *) __go_alloc (descriptor->__entry_size);
+ __builtin_memset (entry, 0, descriptor->__entry_size);
+
+ __builtin_memcpy (entry + key_offset, key, key_size);
+
+ *(char **) entry = map->__buckets[bucket_index];
+ map->__buckets[bucket_index] = entry;
+
+ map->__element_count += 1;
+
+ return entry + descriptor->__val_offset;
+}
diff --git a/libgo/runtime/go-map-len.c b/libgo/runtime/go-map-len.c
new file mode 100644
index 000000000..75b747339
--- /dev/null
+++ b/libgo/runtime/go-map-len.c
@@ -0,0 +1,21 @@
+/* go-map-len.c -- return the length of a map.
+
+ 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. */
+
+#include <stddef.h>
+
+#include "map.h"
+
+/* Return the length of a map. This could be done inline, of course,
+ but I'm doing it as a function for now to make it easy to chang the
+ map structure. */
+
+size_t
+__go_map_len (struct __go_map *map)
+{
+ if (map == NULL)
+ return 0;
+ return map->__element_count;
+}
diff --git a/libgo/runtime/go-map-range.c b/libgo/runtime/go-map-range.c
new file mode 100644
index 000000000..364cda9b6
--- /dev/null
+++ b/libgo/runtime/go-map-range.c
@@ -0,0 +1,102 @@
+/* go-map-range.c -- implement a range clause over a map.
+
+ Copyright 2009, 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 "go-assert.h"
+#include "map.h"
+
+/* Initialize a range over a map. */
+
+void
+__go_mapiterinit (const struct __go_map *h, struct __go_hash_iter *it)
+{
+ it->entry = NULL;
+ if (h != NULL)
+ {
+ it->map = h;
+ it->next_entry = NULL;
+ it->bucket = 0;
+ --it->bucket;
+ __go_mapiternext(it);
+ }
+}
+
+/* Move to the next iteration, updating *HITER. */
+
+void
+__go_mapiternext (struct __go_hash_iter *it)
+{
+ const void *entry;
+
+ entry = it->next_entry;
+ if (entry == NULL)
+ {
+ const struct __go_map *map;
+ size_t bucket;
+
+ map = it->map;
+ bucket = it->bucket;
+ while (1)
+ {
+ ++bucket;
+ if (bucket >= map->__bucket_count)
+ {
+ /* Map iteration is complete. */
+ it->entry = NULL;
+ return;
+ }
+ entry = map->__buckets[bucket];
+ if (entry != NULL)
+ break;
+ }
+ it->bucket = bucket;
+ }
+ it->entry = entry;
+ it->next_entry = *(const void * const *) entry;
+}
+
+/* Get the key of the current iteration. */
+
+void
+__go_mapiter1 (struct __go_hash_iter *it, unsigned char *key)
+{
+ const struct __go_map *map;
+ const struct __go_map_descriptor *descriptor;
+ const struct __go_type_descriptor *key_descriptor;
+ const char *p;
+
+ map = it->map;
+ descriptor = map->__descriptor;
+ key_descriptor = descriptor->__map_descriptor->__key_type;
+ p = it->entry;
+ __go_assert (p != NULL);
+ __builtin_memcpy (key, p + descriptor->__key_offset, key_descriptor->__size);
+}
+
+/* Get the key and value of the current iteration. */
+
+void
+__go_mapiter2 (struct __go_hash_iter *it, unsigned char *key,
+ unsigned char *val)
+{
+ const struct __go_map *map;
+ const struct __go_map_descriptor *descriptor;
+ const struct __go_map_type *map_descriptor;
+ const struct __go_type_descriptor *key_descriptor;
+ const struct __go_type_descriptor *val_descriptor;
+ const char *p;
+
+ map = it->map;
+ descriptor = map->__descriptor;
+ map_descriptor = descriptor->__map_descriptor;
+ key_descriptor = map_descriptor->__key_type;
+ val_descriptor = map_descriptor->__val_type;
+ p = it->entry;
+ __go_assert (p != NULL);
+ __builtin_memcpy (key, p + descriptor->__key_offset,
+ key_descriptor->__size);
+ __builtin_memcpy (val, p + descriptor->__val_offset,
+ val_descriptor->__size);
+}
diff --git a/libgo/runtime/go-nanotime.c b/libgo/runtime/go-nanotime.c
new file mode 100644
index 000000000..8cd423010
--- /dev/null
+++ b/libgo/runtime/go-nanotime.c
@@ -0,0 +1,22 @@
+// 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.
+
+// Return time in nanoseconds. This is only used for computing runtime.
+
+#include <sys/time.h>
+
+#include "go-assert.h"
+#include "runtime.h"
+
+int64
+runtime_nanotime (void)
+{
+ int i;
+ struct timeval tv;
+
+ i = gettimeofday (&tv, NULL);
+ __go_assert (i == 0);
+
+ return (int64) tv.tv_sec * 1000000000 + (int64) tv.tv_usec * 1000;
+}
diff --git a/libgo/runtime/go-new-channel.c b/libgo/runtime/go-new-channel.c
new file mode 100644
index 000000000..d57f52c6c
--- /dev/null
+++ b/libgo/runtime/go-new-channel.c
@@ -0,0 +1,57 @@
+/* go-new-channel.c -- allocate a new channel.
+
+ 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. */
+
+#include <stddef.h>
+
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "go-panic.h"
+#include "channel.h"
+
+struct __go_channel*
+__go_new_channel (size_t element_size, size_t entries)
+{
+ struct __go_channel* ret;
+ size_t alloc_size;
+ int i;
+
+ if ((size_t) (int) entries != entries || entries > (size_t) -1 / element_size)
+ __go_panic_msg ("chan size out of range");
+
+ alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t);
+
+ /* We use a circular buffer which means that when next_fetch ==
+ next_store we don't know whether the buffer is empty or full. So
+ we allocate an extra space, and always leave a space open.
+ FIXME. */
+ if (entries != 0)
+ ++entries;
+
+ ret = (struct __go_channel*) __go_alloc (sizeof (struct __go_channel)
+ + ((entries == 0 ? 1 : entries)
+ * alloc_size
+ * sizeof (uint64_t)));
+ i = pthread_mutex_init (&ret->lock, NULL);
+ __go_assert (i == 0);
+ i = pthread_cond_init (&ret->cond, NULL);
+ __go_assert (i == 0);
+ ret->element_size = element_size;
+ ret->closed_op_count = 0;
+ ret->waiting_to_send = 0;
+ ret->waiting_to_receive = 0;
+ ret->selected_for_send = 0;
+ ret->selected_for_receive = 0;
+ ret->is_closed = 0;
+ ret->saw_close = 0;
+ ret->select_send_queue = NULL;
+ ret->select_receive_queue = NULL;
+ ret->select_mutex = NULL;
+ ret->select_cond = NULL;
+ ret->num_entries = entries;
+ ret->next_store = 0;
+ ret->next_fetch = 0;
+ return ret;
+}
diff --git a/libgo/runtime/go-new-map.c b/libgo/runtime/go-new-map.c
new file mode 100644
index 000000000..519f38f78
--- /dev/null
+++ b/libgo/runtime/go-new-map.c
@@ -0,0 +1,125 @@
+/* go-new-map.c -- allocate a new map.
+
+ 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. */
+
+#include "go-alloc.h"
+#include "go-panic.h"
+#include "map.h"
+
+/* List of prime numbers, copied from libstdc++/src/hashtable.c. */
+
+static const unsigned long prime_list[] = /* 256 + 1 or 256 + 48 + 1 */
+{
+ 2ul, 3ul, 5ul, 7ul, 11ul, 13ul, 17ul, 19ul, 23ul, 29ul, 31ul,
+ 37ul, 41ul, 43ul, 47ul, 53ul, 59ul, 61ul, 67ul, 71ul, 73ul, 79ul,
+ 83ul, 89ul, 97ul, 103ul, 109ul, 113ul, 127ul, 137ul, 139ul, 149ul,
+ 157ul, 167ul, 179ul, 193ul, 199ul, 211ul, 227ul, 241ul, 257ul,
+ 277ul, 293ul, 313ul, 337ul, 359ul, 383ul, 409ul, 439ul, 467ul,
+ 503ul, 541ul, 577ul, 619ul, 661ul, 709ul, 761ul, 823ul, 887ul,
+ 953ul, 1031ul, 1109ul, 1193ul, 1289ul, 1381ul, 1493ul, 1613ul,
+ 1741ul, 1879ul, 2029ul, 2179ul, 2357ul, 2549ul, 2753ul, 2971ul,
+ 3209ul, 3469ul, 3739ul, 4027ul, 4349ul, 4703ul, 5087ul, 5503ul,
+ 5953ul, 6427ul, 6949ul, 7517ul, 8123ul, 8783ul, 9497ul, 10273ul,
+ 11113ul, 12011ul, 12983ul, 14033ul, 15173ul, 16411ul, 17749ul,
+ 19183ul, 20753ul, 22447ul, 24281ul, 26267ul, 28411ul, 30727ul,
+ 33223ul, 35933ul, 38873ul, 42043ul, 45481ul, 49201ul, 53201ul,
+ 57557ul, 62233ul, 67307ul, 72817ul, 78779ul, 85229ul, 92203ul,
+ 99733ul, 107897ul, 116731ul, 126271ul, 136607ul, 147793ul,
+ 159871ul, 172933ul, 187091ul, 202409ul, 218971ul, 236897ul,
+ 256279ul, 277261ul, 299951ul, 324503ul, 351061ul, 379787ul,
+ 410857ul, 444487ul, 480881ul, 520241ul, 562841ul, 608903ul,
+ 658753ul, 712697ul, 771049ul, 834181ul, 902483ul, 976369ul,
+ 1056323ul, 1142821ul, 1236397ul, 1337629ul, 1447153ul, 1565659ul,
+ 1693859ul, 1832561ul, 1982627ul, 2144977ul, 2320627ul, 2510653ul,
+ 2716249ul, 2938679ul, 3179303ul, 3439651ul, 3721303ul, 4026031ul,
+ 4355707ul, 4712381ul, 5098259ul, 5515729ul, 5967347ul, 6456007ul,
+ 6984629ul, 7556579ul, 8175383ul, 8844859ul, 9569143ul, 10352717ul,
+ 11200489ul, 12117689ul, 13109983ul, 14183539ul, 15345007ul,
+ 16601593ul, 17961079ul, 19431899ul, 21023161ul, 22744717ul,
+ 24607243ul, 26622317ul, 28802401ul, 31160981ul, 33712729ul,
+ 36473443ul, 39460231ul, 42691603ul, 46187573ul, 49969847ul,
+ 54061849ul, 58488943ul, 63278561ul, 68460391ul, 74066549ul,
+ 80131819ul, 86693767ul, 93793069ul, 101473717ul, 109783337ul,
+ 118773397ul, 128499677ul, 139022417ul, 150406843ul, 162723577ul,
+ 176048909ul, 190465427ul, 206062531ul, 222936881ul, 241193053ul,
+ 260944219ul, 282312799ul, 305431229ul, 330442829ul, 357502601ul,
+ 386778277ul, 418451333ul, 452718089ul, 489790921ul, 529899637ul,
+ 573292817ul, 620239453ul, 671030513ul, 725980837ul, 785430967ul,
+ 849749479ul, 919334987ul, 994618837ul, 1076067617ul, 1164186217ul,
+ 1259520799ul, 1362662261ul, 1474249943ul, 1594975441ul, 1725587117ul,
+ 1866894511ul, 2019773507ul, 2185171673ul, 2364114217ul, 2557710269ul,
+ 2767159799ul, 2993761039ul, 3238918481ul, 3504151727ul, 3791104843ul,
+ 4101556399ul, 4294967291ul,
+#if __SIZEOF_LONG__ >= 8
+ 6442450933ul, 8589934583ul, 12884901857ul, 17179869143ul,
+ 25769803693ul, 34359738337ul, 51539607367ul, 68719476731ul,
+ 103079215087ul, 137438953447ul, 206158430123ul, 274877906899ul,
+ 412316860387ul, 549755813881ul, 824633720731ul, 1099511627689ul,
+ 1649267441579ul, 2199023255531ul, 3298534883309ul, 4398046511093ul,
+ 6597069766607ul, 8796093022151ul, 13194139533241ul, 17592186044399ul,
+ 26388279066581ul, 35184372088777ul, 52776558133177ul, 70368744177643ul,
+ 105553116266399ul, 140737488355213ul, 211106232532861ul, 281474976710597ul,
+ 562949953421231ul, 1125899906842597ul, 2251799813685119ul,
+ 4503599627370449ul, 9007199254740881ul, 18014398509481951ul,
+ 36028797018963913ul, 72057594037927931ul, 144115188075855859ul,
+ 288230376151711717ul, 576460752303423433ul,
+ 1152921504606846883ul, 2305843009213693951ul,
+ 4611686018427387847ul, 9223372036854775783ul,
+ 18446744073709551557ul
+#endif
+};
+
+/* Return the next number from PRIME_LIST >= N. */
+
+unsigned long
+__go_map_next_prime (unsigned long n)
+{
+ size_t low;
+ size_t high;
+
+ low = 0;
+ high = sizeof prime_list / sizeof prime_list[0];
+ while (low < high)
+ {
+ size_t mid;
+
+ mid = (low + high) / 2;
+
+ /* Here LOW <= MID < HIGH. */
+
+ if (prime_list[mid] < n)
+ high = mid;
+ else if (prime_list[mid] > n)
+ low = mid + 1;
+ else
+ return n;
+ }
+ if (low >= sizeof prime_list / sizeof prime_list[0])
+ return n;
+ return prime_list[low];
+}
+
+/* Allocate a new map. */
+
+struct __go_map *
+__go_new_map (const struct __go_map_descriptor *descriptor, size_t entries)
+{
+ struct __go_map *ret;
+
+ if ((size_t) (int) entries != entries)
+ __go_panic_msg ("map size out of range");
+
+ if (entries == 0)
+ entries = 5;
+ else
+ entries = __go_map_next_prime (entries);
+ ret = (struct __go_map *) __go_alloc (sizeof (struct __go_map));
+ ret->__descriptor = descriptor;
+ ret->__element_count = 0;
+ ret->__bucket_count = entries;
+ ret->__buckets = (void **) __go_alloc (entries * sizeof (void *));
+ __builtin_memset (ret->__buckets, 0, entries * sizeof (void *));
+ return ret;
+}
diff --git a/libgo/runtime/go-new.c b/libgo/runtime/go-new.c
new file mode 100644
index 000000000..a592174e5
--- /dev/null
+++ b/libgo/runtime/go-new.c
@@ -0,0 +1,21 @@
+/* go-new.c -- the generic go new() function.
+
+ 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. */
+
+#include "go-alloc.h"
+#include "runtime.h"
+#include "malloc.h"
+
+void *
+__go_new (size_t size)
+{
+ return runtime_mallocgc (size, 0, 1, 1);
+}
+
+void *
+__go_new_nopointers (size_t size)
+{
+ return runtime_mallocgc (size, RefNoPointers, 1, 1);
+}
diff --git a/libgo/runtime/go-note.c b/libgo/runtime/go-note.c
new file mode 100644
index 000000000..3b750f30e
--- /dev/null
+++ b/libgo/runtime/go-note.c
@@ -0,0 +1,74 @@
+/* go-note.c -- implement notesleep, notewakeup and noteclear.
+
+ 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 note is a one-time notification. noteclear clears the note.
+ notesleep waits for a call to notewakeup. notewakeup wakes up
+ every thread waiting on the note. */
+
+#include "go-assert.h"
+#include "runtime.h"
+
+/* We use a single global lock and condition variable. It would be
+ better to use a futex on Linux. */
+
+static pthread_mutex_t note_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t note_cond = PTHREAD_COND_INITIALIZER;
+
+/* noteclear is called before any calls to notesleep or
+ notewakeup. */
+
+void
+noteclear (Note* n)
+{
+ int32 i;
+
+ i = pthread_mutex_lock (&note_lock);
+ __go_assert (i == 0);
+
+ n->woken = 0;
+
+ i = pthread_mutex_unlock (&note_lock);
+ __go_assert (i == 0);
+}
+
+/* Wait until notewakeup is called. */
+
+void
+notesleep (Note* n)
+{
+ int32 i;
+
+ i = pthread_mutex_lock (&note_lock);
+ __go_assert (i == 0);
+
+ while (!n->woken)
+ {
+ i = pthread_cond_wait (&note_cond, &note_lock);
+ __go_assert (i == 0);
+ }
+
+ i = pthread_mutex_unlock (&note_lock);
+ __go_assert (i == 0);
+}
+
+/* Wake up every thread sleeping on the note. */
+
+void
+notewakeup (Note *n)
+{
+ int32 i;
+
+ i = pthread_mutex_lock (&note_lock);
+ __go_assert (i == 0);
+
+ n->woken = 1;
+
+ i = pthread_cond_broadcast (&note_cond);
+ __go_assert (i == 0);
+
+ i = pthread_mutex_unlock (&note_lock);
+ __go_assert (i == 0);
+}
diff --git a/libgo/runtime/go-panic-defer.c b/libgo/runtime/go-panic-defer.c
new file mode 100644
index 000000000..64773bb5e
--- /dev/null
+++ b/libgo/runtime/go-panic-defer.c
@@ -0,0 +1,13 @@
+/* go-panic-stack.c -- The panic/defer stack.
+
+ 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 "go-panic.h"
+
+#ifdef __rtems__
+#define __thread
+#endif
+
+__thread struct __go_panic_defer_struct *__go_panic_defer;
diff --git a/libgo/runtime/go-panic.c b/libgo/runtime/go-panic.c
new file mode 100644
index 000000000..48d644162
--- /dev/null
+++ b/libgo/runtime/go-panic.c
@@ -0,0 +1,121 @@
+/* go-panic.c -- support for the go panic function.
+
+ 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. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "runtime.h"
+#include "malloc.h"
+#include "go-alloc.h"
+#include "go-defer.h"
+#include "go-panic.h"
+#include "go-string.h"
+#include "interface.h"
+
+/* Print the panic stack. This is used when there is no recover. */
+
+static void
+__printpanics (struct __go_panic_stack *p)
+{
+ if (p->__next != NULL)
+ {
+ __printpanics (p->__next);
+ printf ("\t");
+ }
+ printf ("panic: ");
+ printany (p->__arg);
+ if (p->__was_recovered)
+ printf (" [recovered]");
+ putchar ('\n');
+}
+
+/* This implements __go_panic which is used for the panic
+ function. */
+
+void
+__go_panic (struct __go_empty_interface arg)
+{
+ struct __go_panic_stack *n;
+
+ if (__go_panic_defer == NULL)
+ __go_panic_defer = ((struct __go_panic_defer_struct *)
+ __go_alloc (sizeof (struct __go_panic_defer_struct)));
+
+ n = (struct __go_panic_stack *) __go_alloc (sizeof (struct __go_panic_stack));
+ n->__arg = arg;
+ n->__next = __go_panic_defer->__panic;
+ __go_panic_defer->__panic = n;
+
+ /* Run all the defer functions. */
+
+ while (1)
+ {
+ struct __go_defer_stack *d;
+ void (*pfn) (void *);
+
+ d = __go_panic_defer->__defer;
+ if (d == NULL)
+ break;
+
+ pfn = d->__pfn;
+ d->__pfn = NULL;
+
+ if (pfn != NULL)
+ {
+ (*pfn) (d->__arg);
+
+ if (n->__was_recovered)
+ {
+ /* Some defer function called recover. That means that
+ we should stop running this panic. */
+
+ __go_panic_defer->__panic = n->__next;
+ __go_free (n);
+
+ /* Now unwind the stack by throwing an exception. The
+ compiler has arranged to create exception handlers in
+ each function which uses a defer statement. These
+ exception handlers will check whether the entry on
+ the top of the defer stack is from the current
+ function. If it is, we have unwound the stack far
+ enough. */
+ __go_unwind_stack ();
+
+ /* __go_unwind_stack should not return. */
+ abort ();
+ }
+ }
+
+ __go_panic_defer->__defer = d->__next;
+ __go_free (d);
+ }
+
+ /* The panic was not recovered. */
+
+ __printpanics (__go_panic_defer->__panic);
+
+ /* FIXME: We should dump a call stack here. */
+ abort ();
+}
+
+/* This is used by the runtime library. */
+
+void
+__go_panic_msg (const char* msg)
+{
+ size_t len;
+ unsigned char *sdata;
+ struct __go_string s;
+ struct __go_empty_interface arg;
+
+ len = __builtin_strlen (msg);
+ sdata = runtime_mallocgc (len, RefNoPointers, 0, 0);
+ __builtin_memcpy (sdata, msg, len);
+ s.__data = sdata;
+ s.__length = len;
+ newErrorString(s, &arg);
+ __go_panic (arg);
+}
diff --git a/libgo/runtime/go-panic.h b/libgo/runtime/go-panic.h
new file mode 100644
index 000000000..2836c4681
--- /dev/null
+++ b/libgo/runtime/go-panic.h
@@ -0,0 +1,94 @@
+/* go-panic.h -- declare the go panic functions.
+
+ 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. */
+
+#ifndef LIBGO_GO_PANIC_H
+#define LIBGO_GO_PANIC_H
+
+#include "interface.h"
+
+struct __go_string;
+struct __go_type_descriptor;
+struct __go_defer_stack;
+
+/* The stack of panic calls. */
+
+struct __go_panic_stack
+{
+ /* The next entry in the stack. */
+ struct __go_panic_stack *__next;
+
+ /* The value associated with this panic. */
+ struct __go_empty_interface __arg;
+
+ /* Whether this panic has been recovered. */
+ _Bool __was_recovered;
+
+ /* Whether this panic was pushed on the stack because of an
+ exception thrown in some other language. */
+ _Bool __is_foreign;
+};
+
+/* The panic and defer stacks, grouped together into a single thread
+ local variable for convenience for systems without TLS. */
+
+struct __go_panic_defer_struct
+{
+ /* The list of defers to execute. */
+ struct __go_defer_stack *__defer;
+
+ /* The list of currently active panics. There will be more than one
+ if a deferred function calls panic. */
+ struct __go_panic_stack *__panic;
+
+ /* The current exception being thrown when unwinding after a call to
+ panic . This is really struct _UnwindException *. */
+ void *__exception;
+
+ /* Whether the current exception is from some other language. */
+ _Bool __is_foreign;
+};
+
+#ifdef __rtems__
+#define __thread
+#endif
+
+extern __thread struct __go_panic_defer_struct *__go_panic_defer;
+
+#ifdef __rtems__
+#undef __thread
+#endif
+
+extern void __go_panic (struct __go_empty_interface)
+ __attribute__ ((noreturn));
+
+extern void __go_panic_msg (const char* msg)
+ __attribute__ ((noreturn));
+
+extern void __go_print_string (struct __go_string);
+
+extern struct __go_empty_interface __go_recover (void);
+
+extern void __go_unwind_stack (void);
+
+/* Functions defined in libgo/go/runtime/error.go. */
+
+extern void newTypeAssertionError(const struct __go_type_descriptor *pt1,
+ const struct __go_type_descriptor *pt2,
+ const struct __go_type_descriptor *pt3,
+ const struct __go_string *ps1,
+ const struct __go_string *ps2,
+ const struct __go_string *ps3,
+ const struct __go_string *pmeth,
+ struct __go_empty_interface *ret)
+ __asm__ ("libgo_runtime.runtime.NewTypeAssertionError");
+
+extern void newErrorString(struct __go_string, struct __go_empty_interface *)
+ __asm__ ("libgo_runtime.runtime.NewErrorString");
+
+extern void printany(struct __go_empty_interface)
+ __asm__ ("libgo_runtime.runtime.Printany");
+
+#endif /* !defined(LIBGO_GO_PANIC_H) */
diff --git a/libgo/runtime/go-print.c b/libgo/runtime/go-print.c
new file mode 100644
index 000000000..095909de2
--- /dev/null
+++ b/libgo/runtime/go-print.c
@@ -0,0 +1,93 @@
+/* go-print.c -- support for the go print statement.
+
+ 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. */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "array.h"
+#include "go-panic.h"
+#include "go-string.h"
+#include "interface.h"
+
+/* This implements the various little functions which are called by
+ the predeclared functions print/println/panic/panicln. */
+
+void
+__go_print_space ()
+{
+ putchar (' ');
+}
+
+void
+__go_print_nl ()
+{
+ putchar ('\n');
+}
+
+void
+__go_print_string (struct __go_string val)
+{
+ printf ("%.*s", (int) val.__length, (const char *) val.__data);
+}
+
+void
+__go_print_uint64 (uint64_t val)
+{
+ printf ("%llu", (unsigned long long) val);
+}
+
+void
+__go_print_int64 (int64_t val)
+{
+ printf ("%lld", (long long) val);
+}
+
+void
+__go_print_double (double val)
+{
+ printf ("%.24g", val);
+}
+
+void
+__go_print_complex (__complex double val)
+{
+ printf ("(%.24g%s%.24gi)",
+ __builtin_creal (val),
+ (__builtin_cimag (val) >= 0 || __builtin_isnan (__builtin_cimag(val))
+ ? "+"
+ : ""),
+ __builtin_cimag (val));
+}
+
+void
+__go_print_bool (_Bool val)
+{
+ fputs (val ? "true" : "false", stdout);
+}
+
+void
+__go_print_pointer (void *val)
+{
+ printf ("%p", val);
+}
+
+void
+__go_print_empty_interface (struct __go_empty_interface e)
+{
+ printf ("(%p,%p)", e.__type_descriptor, e.__object);
+}
+
+void
+__go_print_interface (struct __go_interface i)
+{
+ printf ("(%p,%p)", i.__methods, i.__object);
+}
+
+void
+__go_print_slice (struct __go_open_array val)
+{
+ printf ("[%d/%d]%p", val.__count, val.__capacity, val.__values);
+}
diff --git a/libgo/runtime/go-rec-big.c b/libgo/runtime/go-rec-big.c
new file mode 100644
index 000000000..23d65296a
--- /dev/null
+++ b/libgo/runtime/go-rec-big.c
@@ -0,0 +1,34 @@
+/* go-rec-big.c -- receive something larger than 64 bits on a channel.
+
+ 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. */
+
+#include <stdint.h>
+
+#include "go-panic.h"
+#include "channel.h"
+
+void
+__go_receive_big (struct __go_channel *channel, void *val, _Bool for_select)
+{
+ size_t alloc_size;
+ size_t offset;
+
+ if (channel == NULL)
+ __go_panic_msg ("receive from nil channel");
+
+ alloc_size = ((channel->element_size + sizeof (uint64_t) - 1)
+ / sizeof (uint64_t));
+
+ if (!__go_receive_acquire (channel, for_select))
+ {
+ __builtin_memset (val, 0, channel->element_size);
+ return;
+ }
+
+ offset = channel->next_fetch * alloc_size;
+ __builtin_memcpy (val, &channel->data[offset], channel->element_size);
+
+ __go_receive_release (channel);
+}
diff --git a/libgo/runtime/go-rec-nb-big.c b/libgo/runtime/go-rec-nb-big.c
new file mode 100644
index 000000000..53ffe48ab
--- /dev/null
+++ b/libgo/runtime/go-rec-nb-big.c
@@ -0,0 +1,39 @@
+/* go-rec-nb-big.c -- nonblocking receive of something big on a channel.
+
+ 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. */
+
+#include <stdint.h>
+
+#include "channel.h"
+
+_Bool
+__go_receive_nonblocking_big (struct __go_channel* channel, void *val)
+{
+ size_t alloc_size;
+ size_t offset;
+
+ alloc_size = ((channel->element_size + sizeof (uint64_t) - 1)
+ / sizeof (uint64_t));
+
+ int data = __go_receive_nonblocking_acquire (channel);
+ if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA)
+ {
+ __builtin_memset (val, 0, channel->element_size);
+ if (data == RECEIVE_NONBLOCKING_ACQUIRE_NODATA)
+ return 0;
+ else
+ {
+ /* Channel is closed. */
+ return 1;
+ }
+ }
+
+ offset = channel->next_fetch * alloc_size;
+ __builtin_memcpy (val, &channel->data[offset], channel->element_size);
+
+ __go_receive_release (channel);
+
+ return 1;
+}
diff --git a/libgo/runtime/go-rec-nb-small.c b/libgo/runtime/go-rec-nb-small.c
new file mode 100644
index 000000000..9983d3464
--- /dev/null
+++ b/libgo/runtime/go-rec-nb-small.c
@@ -0,0 +1,127 @@
+/* go-rec-nb-small.c -- nonblocking receive of something smal on a channel.
+
+ 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. */
+
+#include <stdint.h>
+
+#include "go-assert.h"
+#include "go-panic.h"
+#include "channel.h"
+
+/* Prepare to receive something on a nonblocking channel. */
+
+int
+__go_receive_nonblocking_acquire (struct __go_channel *channel)
+{
+ int i;
+ _Bool has_data;
+
+ i = pthread_mutex_lock (&channel->lock);
+ __go_assert (i == 0);
+
+ while (channel->selected_for_receive)
+ {
+ i = pthread_cond_wait (&channel->cond, &channel->lock);
+ __go_assert (i == 0);
+ }
+
+ if (channel->is_closed
+ && (channel->num_entries == 0
+ ? channel->next_store == 0
+ : channel->next_fetch == channel->next_store))
+ {
+ if (channel->saw_close)
+ {
+ ++channel->closed_op_count;
+ if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
+ {
+ i = pthread_mutex_unlock (&channel->lock);
+ __go_assert (i == 0);
+ __go_panic_msg ("too many operations on closed channel");
+ }
+ }
+ channel->saw_close = 1;
+ __go_unlock_and_notify_selects (channel);
+ return RECEIVE_NONBLOCKING_ACQUIRE_CLOSED;
+ }
+
+ if (channel->num_entries > 0)
+ has_data = channel->next_fetch != channel->next_store;
+ else
+ {
+ if (channel->waiting_to_receive)
+ {
+ /* Some other goroutine is already waiting for data on this
+ channel, so we can't pick it up. */
+ has_data = 0;
+ }
+ else if (channel->next_store > 0)
+ {
+ /* There is data on the channel. */
+ has_data = 1;
+ }
+ else if (__go_synch_with_select (channel, 0))
+ {
+ /* We synched up with a select sending data, so there will
+ be data for us shortly. Tell the select to go, and then
+ wait for the data. */
+ __go_broadcast_to_select (channel);
+
+ while (channel->next_store == 0)
+ {
+ i = pthread_cond_wait (&channel->cond, &channel->lock);
+ __go_assert (i == 0);
+ }
+
+ has_data = 1;
+ }
+ else
+ {
+ /* Otherwise there is no data. */
+ has_data = 0;
+ }
+
+ if (has_data)
+ {
+ channel->waiting_to_receive = 1;
+ __go_assert (channel->next_store == 1);
+ }
+ }
+
+ if (!has_data)
+ {
+ i = pthread_mutex_unlock (&channel->lock);
+ __go_assert (i == 0);
+ return RECEIVE_NONBLOCKING_ACQUIRE_NODATA;
+ }
+
+ return RECEIVE_NONBLOCKING_ACQUIRE_DATA;
+}
+
+/* Receive something 64 bits or smaller on a nonblocking channel. */
+
+struct __go_receive_nonblocking_small
+__go_receive_nonblocking_small (struct __go_channel *channel)
+{
+ struct __go_receive_nonblocking_small ret;
+
+ __go_assert (channel->element_size <= sizeof (uint64_t));
+
+ int data = __go_receive_nonblocking_acquire (channel);
+ if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA)
+ {
+ ret.__val = 0;
+ ret.__success = data == RECEIVE_NONBLOCKING_ACQUIRE_CLOSED;
+ return ret;
+ }
+
+ ret.__val = channel->data[channel->next_fetch];
+
+ __go_receive_release (channel);
+
+ ret.__success = 1;
+
+ return ret;
+}
diff --git a/libgo/runtime/go-rec-small.c b/libgo/runtime/go-rec-small.c
new file mode 100644
index 000000000..765e8d310
--- /dev/null
+++ b/libgo/runtime/go-rec-small.c
@@ -0,0 +1,289 @@
+/* go-rec-small.c -- receive something smaller than 64 bits on a channel.
+
+ 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. */
+
+#include <stdint.h>
+
+#include "go-assert.h"
+#include "go-panic.h"
+#include "channel.h"
+
+/* This mutex controls access to the selected field of struct
+ __go_channel_select. While this mutex is held, no other mutexes
+ may be acquired. */
+
+pthread_mutex_t __go_select_data_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Try to synchronize with a select waiting on a sychronized channel.
+ This is used by a send or receive. The channel is locked. This
+ returns true if it was able to synch. */
+
+_Bool
+__go_synch_with_select (struct __go_channel *channel, _Bool is_send)
+{
+ struct __go_channel_select *p;
+ int i;
+
+ __go_assert (channel->num_entries == 0);
+
+ i = pthread_mutex_lock (&__go_select_data_mutex);
+ __go_assert (i == 0);
+
+ for (p = (is_send
+ ? channel->select_receive_queue
+ : channel->select_send_queue);
+ p != NULL;
+ p = p->next)
+ {
+ if (*p->selected == NULL)
+ {
+ *p->selected = channel;
+ *p->is_read = !is_send;
+ if (is_send)
+ channel->selected_for_receive = 1;
+ else
+ channel->selected_for_send = 1;
+ break;
+ }
+ }
+
+ i = pthread_mutex_unlock (&__go_select_data_mutex);
+ __go_assert (i == 0);
+
+ /* The caller is responsible for signalling the select condition
+ variable so that the other select knows that something has
+ changed. We can't signal it here because we can't acquire the
+ select mutex while we hold a channel lock. */
+
+ return p != NULL;
+}
+
+/* If we synch with a select, then we need to signal the select that
+ something has changed. This requires grabbing the select mutex,
+ which can only be done when the channel is unlocked. This routine
+ does the signalling. It is called with the channel locked. It
+ unlocks the channel, broadcasts the signal and relocks the
+ channel. */
+
+void
+__go_broadcast_to_select (struct __go_channel *channel)
+{
+ pthread_mutex_t *select_mutex;
+ pthread_cond_t *select_cond;
+ int i;
+
+ select_mutex = channel->select_mutex;
+ select_cond = channel->select_cond;
+
+ i = pthread_mutex_unlock (&channel->lock);
+ __go_assert (i == 0);
+
+ __go_assert (select_mutex != NULL && select_cond != NULL);
+
+ i = pthread_mutex_lock (select_mutex);
+ __go_assert (i == 0);
+
+ i = pthread_cond_broadcast (select_cond);
+ __go_assert (i == 0);
+
+ i = pthread_mutex_unlock (select_mutex);
+ __go_assert (i == 0);
+
+ i = pthread_mutex_lock (&channel->lock);
+ __go_assert (i == 0);
+}
+
+/* Prepare to receive something on a channel. Return true if the
+ channel is acquired, false if it is closed. */
+
+_Bool
+__go_receive_acquire (struct __go_channel *channel, _Bool for_select)
+{
+ int i;
+ _Bool my_wait_lock;
+ _Bool synched_with_select;
+
+ my_wait_lock = 0;
+ synched_with_select = 0;
+
+ i = pthread_mutex_lock (&channel->lock);
+ __go_assert (i == 0);
+
+ while (1)
+ {
+ _Bool need_broadcast;
+
+ need_broadcast = 0;
+
+ /* Check whether the channel is closed. */
+ if (channel->is_closed
+ && (channel->num_entries == 0
+ ? channel->next_store == 0
+ : channel->next_fetch == channel->next_store))
+ {
+ if (channel->saw_close)
+ {
+ ++channel->closed_op_count;
+ if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
+ __go_panic_msg ("too many operations on closed channel");
+ }
+ channel->saw_close = 1;
+ channel->selected_for_receive = 0;
+ __go_unlock_and_notify_selects (channel);
+ return 0;
+ }
+
+ /* If somebody else has the channel locked for receiving, we
+ have to wait. If FOR_SELECT is true, then we are the one
+ with the lock. */
+ if (!channel->selected_for_receive || for_select)
+ {
+ if (channel->num_entries == 0)
+ {
+ /* If somebody else is waiting to receive, we have to
+ wait. */
+ if (!channel->waiting_to_receive || my_wait_lock)
+ {
+ _Bool was_marked;
+
+ /* Lock the channel so that we get to receive
+ next. */
+ was_marked = channel->waiting_to_receive;
+ channel->waiting_to_receive = 1;
+ my_wait_lock = 1;
+
+ /* See if there is a value to receive. */
+ if (channel->next_store > 0)
+ return 1;
+
+ /* If we haven't already done so, try to synch with
+ a select waiting to send on this channel. If we
+ have already synched with a select, we are just
+ looping until the select eventually causes
+ something to be sent. */
+ if (!synched_with_select && !for_select)
+ {
+ if (__go_synch_with_select (channel, 0))
+ {
+ synched_with_select = 1;
+ need_broadcast = 1;
+ }
+ }
+
+ /* If we marked the channel as waiting, we need to
+ signal, because something changed. It needs to
+ be a broadcast since there might be other
+ receivers waiting. */
+ if (!was_marked)
+ {
+ i = pthread_cond_broadcast (&channel->cond);
+ __go_assert (i == 0);
+ }
+ }
+ }
+ else
+ {
+ /* If there is a value on the channel, we are OK. */
+ if (channel->next_fetch != channel->next_store)
+ return 1;
+ }
+ }
+
+ /* If we just synched with a select, then we need to signal the
+ select condition variable. We can only do that if we unlock
+ the channel. So we need to unlock, signal, lock, and go
+ around the loop again without waiting. */
+ if (need_broadcast)
+ {
+ __go_broadcast_to_select (channel);
+ continue;
+ }
+
+ /* Wait for something to change, then loop around and try
+ again. */
+
+ i = pthread_cond_wait (&channel->cond, &channel->lock);
+ __go_assert (i == 0);
+ }
+}
+
+/* Finished receiving something on a channel. */
+
+void
+__go_receive_release (struct __go_channel *channel)
+{
+ int i;
+
+ if (channel->num_entries != 0)
+ channel->next_fetch = (channel->next_fetch + 1) % channel->num_entries;
+ else
+ {
+ /* For a synchronous receiver, we tell the sender that we picked
+ up the value by setting the next_store field back to 0.
+ Using the mutexes should implement a memory barrier. */
+ __go_assert (channel->next_store == 1);
+ channel->next_store = 0;
+
+ channel->waiting_to_receive = 0;
+ }
+
+ channel->selected_for_receive = 0;
+
+ /* This is a broadcast to make sure that a synchronous sender sees
+ it. */
+ i = pthread_cond_broadcast (&channel->cond);
+ __go_assert (i == 0);
+
+ __go_unlock_and_notify_selects (channel);
+}
+
+/* Unlock a channel and notify any waiting selects that something
+ happened. */
+
+void
+__go_unlock_and_notify_selects (struct __go_channel *channel)
+{
+ pthread_mutex_t* select_mutex;
+ pthread_cond_t* select_cond;
+ int i;
+
+ select_mutex = channel->select_mutex;
+ select_cond = channel->select_cond;
+
+ i = pthread_mutex_unlock (&channel->lock);
+ __go_assert (i == 0);
+
+ if (select_mutex != NULL)
+ {
+ i = pthread_mutex_lock (select_mutex);
+ __go_assert (i == 0);
+ i = pthread_cond_broadcast (select_cond);
+ __go_assert (i == 0);
+ i = pthread_mutex_unlock (select_mutex);
+ __go_assert (i == 0);
+ }
+}
+
+/* Receive something 64 bits or smaller on a channel. */
+
+uint64_t
+__go_receive_small (struct __go_channel *channel, _Bool for_select)
+{
+ uint64_t ret;
+
+ if (channel == NULL)
+ __go_panic_msg ("receive from nil channel");
+
+ __go_assert (channel->element_size <= sizeof (uint64_t));
+
+ if (!__go_receive_acquire (channel, for_select))
+ return 0;
+
+ ret = channel->data[channel->next_fetch];
+
+ __go_receive_release (channel);
+
+ return ret;
+}
diff --git a/libgo/runtime/go-recover.c b/libgo/runtime/go-recover.c
new file mode 100644
index 000000000..4de122e3b
--- /dev/null
+++ b/libgo/runtime/go-recover.c
@@ -0,0 +1,69 @@
+/* go-recover.c -- support for the go recover function.
+
+ 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 "interface.h"
+#include "go-panic.h"
+#include "go-defer.h"
+
+/* This is called by a thunk to see if the real function should be
+ permitted to recover a panic value. Recovering a value is
+ permitted if the thunk was called directly by defer. RETADDR is
+ the return address of the function which is calling
+ __go_can_recover--this is, the thunk. */
+
+_Bool
+__go_can_recover (const void* retaddr)
+{
+ struct __go_defer_stack *d;
+ const char* ret;
+ const char* dret;
+
+ if (__go_panic_defer == NULL)
+ return 0;
+ d = __go_panic_defer->__defer;
+ if (d == NULL)
+ return 0;
+
+ /* The panic which this function would recover is the one on the top
+ of the panic stack. We do not want to recover it if that panic
+ was on the top of the panic stack when this function was
+ deferred. */
+ if (d->__panic == __go_panic_defer->__panic)
+ return 0;
+
+ /* D->__RETADDR is the address of a label immediately following the
+ call to the thunk. We can recover a panic if that is the same as
+ the return address of the thunk. We permit a bit of slack in
+ case there is any code between the function return and the label,
+ such as an instruction to adjust the stack pointer. */
+
+ ret = (const char *) retaddr;
+ dret = (const char *) d->__retaddr;
+ return ret <= dret && ret + 16 >= dret;
+}
+
+/* This is only called when it is valid for the caller to recover the
+ value on top of the panic stack, if there is one. */
+
+struct __go_empty_interface
+__go_recover ()
+{
+ struct __go_panic_stack *p;
+
+ if (__go_panic_defer == NULL
+ || __go_panic_defer->__panic == NULL
+ || __go_panic_defer->__panic->__was_recovered)
+ {
+ struct __go_empty_interface ret;
+
+ ret.__type_descriptor = NULL;
+ ret.__object = NULL;
+ return ret;
+ }
+ p = __go_panic_defer->__panic;
+ p->__was_recovered = 1;
+ return p->__arg;
+}
diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c
new file mode 100644
index 000000000..6ae749f9a
--- /dev/null
+++ b/libgo/runtime/go-reflect-call.c
@@ -0,0 +1,375 @@
+/* go-reflect-call.c -- call reflection support for Go.
+
+ 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. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ffi.h"
+
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "go-type.h"
+#include "runtime.h"
+
+/* Forward declaration. */
+
+static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *);
+
+/* Return an ffi_type for a Go array type. The libffi library does
+ not have any builtin support for passing arrays as values. We work
+ around this by pretending that the array is a struct. */
+
+static ffi_type *
+go_array_to_ffi (const struct __go_array_type *descriptor)
+{
+ ffi_type *ret;
+ uintptr_t len;
+ ffi_type *element;
+ uintptr_t i;
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ __builtin_memset (ret, 0, sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ len = descriptor->__len;
+ ret->elements = (ffi_type **) __go_alloc ((len + 1) * sizeof (ffi_type *));
+ element = go_type_to_ffi (descriptor->__element_type);
+ for (i = 0; i < len; ++i)
+ ret->elements[i] = element;
+ ret->elements[len] = NULL;
+ return ret;
+}
+
+/* Return an ffi_type for a Go slice type. This describes the
+ __go_open_array type defines in array.h. */
+
+static ffi_type *
+go_slice_to_ffi (
+ const struct __go_slice_type *descriptor __attribute__ ((unused)))
+{
+ ffi_type *ret;
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ __builtin_memset (ret, 0, sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ ret->elements = (ffi_type **) __go_alloc (4 * sizeof (ffi_type *));
+ ret->elements[0] = &ffi_type_pointer;
+ ret->elements[1] = &ffi_type_sint;
+ ret->elements[2] = &ffi_type_sint;
+ ret->elements[3] = NULL;
+ return ret;
+}
+
+/* Return an ffi_type for a Go struct type. */
+
+static ffi_type *
+go_struct_to_ffi (const struct __go_struct_type *descriptor)
+{
+ ffi_type *ret;
+ int field_count;
+ const struct __go_struct_field *fields;
+ int i;
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ __builtin_memset (ret, 0, sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ field_count = descriptor->__fields.__count;
+ fields = (const struct __go_struct_field *) descriptor->__fields.__values;
+ ret->elements = (ffi_type **) __go_alloc ((field_count + 1)
+ * sizeof (ffi_type *));
+ for (i = 0; i < field_count; ++i)
+ ret->elements[i] = go_type_to_ffi (fields[i].__type);
+ ret->elements[field_count] = NULL;
+ return ret;
+}
+
+/* Return an ffi_type for a Go string type. This describes the
+ __go_string struct. */
+
+static ffi_type *
+go_string_to_ffi (void)
+{
+ ffi_type *ret;
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+ ret->elements[0] = &ffi_type_pointer;
+ ret->elements[1] = &ffi_type_sint;
+ ret->elements[2] = NULL;
+ return ret;
+}
+
+/* Return an ffi_type for a Go interface type. This describes the
+ __go_interface and __go_empty_interface structs. */
+
+static ffi_type *
+go_interface_to_ffi (void)
+{
+ ffi_type *ret;
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+ ret->elements[0] = &ffi_type_pointer;
+ ret->elements[1] = &ffi_type_pointer;
+ ret->elements[2] = NULL;
+ return ret;
+}
+
+/* Return an ffi_type for a Go complex type. */
+
+static ffi_type *
+go_complex_to_ffi (ffi_type *float_type)
+{
+ ffi_type *ret;
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+ ret->elements[0] = float_type;
+ ret->elements[1] = float_type;
+ ret->elements[2] = NULL;
+ return ret;
+}
+
+/* Return an ffi_type for a type described by a
+ __go_type_descriptor. */
+
+static ffi_type *
+go_type_to_ffi (const struct __go_type_descriptor *descriptor)
+{
+ switch (descriptor->__code)
+ {
+ case GO_BOOL:
+ if (sizeof (_Bool) == 1)
+ return &ffi_type_uint8;
+ else if (sizeof (_Bool) == sizeof (int))
+ return &ffi_type_uint;
+ abort ();
+ case GO_FLOAT32:
+ if (sizeof (float) == 4)
+ return &ffi_type_float;
+ abort ();
+ case GO_FLOAT64:
+ if (sizeof (double) == 8)
+ return &ffi_type_double;
+ abort ();
+ case GO_COMPLEX64:
+ if (sizeof (float) == 4)
+ return go_complex_to_ffi (&ffi_type_float);
+ abort ();
+ case GO_COMPLEX128:
+ if (sizeof (double) == 8)
+ return go_complex_to_ffi (&ffi_type_double);
+ abort ();
+ case GO_INT16:
+ return &ffi_type_sint16;
+ case GO_INT32:
+ return &ffi_type_sint32;
+ case GO_INT64:
+ return &ffi_type_sint64;
+ case GO_INT8:
+ return &ffi_type_sint8;
+ case GO_INT:
+ return &ffi_type_sint;
+ case GO_UINT16:
+ return &ffi_type_uint16;
+ case GO_UINT32:
+ return &ffi_type_uint32;
+ case GO_UINT64:
+ return &ffi_type_uint64;
+ case GO_UINT8:
+ return &ffi_type_uint8;
+ case GO_UINT:
+ return &ffi_type_uint;
+ case GO_UINTPTR:
+ if (sizeof (void *) == 2)
+ return &ffi_type_uint16;
+ else if (sizeof (void *) == 4)
+ return &ffi_type_uint32;
+ else if (sizeof (void *) == 8)
+ return &ffi_type_uint64;
+ abort ();
+ case GO_ARRAY:
+ return go_array_to_ffi ((const struct __go_array_type *) descriptor);
+ case GO_SLICE:
+ return go_slice_to_ffi ((const struct __go_slice_type *) descriptor);
+ case GO_STRUCT:
+ return go_struct_to_ffi ((const struct __go_struct_type *) descriptor);
+ case GO_STRING:
+ return go_string_to_ffi ();
+ case GO_INTERFACE:
+ return go_interface_to_ffi ();
+ case GO_CHAN:
+ case GO_FUNC:
+ case GO_MAP:
+ case GO_PTR:
+ case GO_UNSAFE_POINTER:
+ /* These types are always pointers, and for FFI purposes nothing
+ else matters. */
+ return &ffi_type_pointer;
+ default:
+ abort ();
+ }
+}
+
+/* Return the return type for a function, given the number of out
+ parameters and their types. */
+
+static ffi_type *
+go_func_return_ffi (const struct __go_func_type *func)
+{
+ int count;
+ const struct __go_type_descriptor **types;
+ ffi_type *ret;
+ int i;
+
+ count = func->__out.__count;
+ if (count == 0)
+ return &ffi_type_void;
+
+ types = (const struct __go_type_descriptor **) func->__out.__values;
+
+ if (count == 1)
+ return go_type_to_ffi (types[0]);
+
+ ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+ __builtin_memset (ret, 0, sizeof (ffi_type));
+ ret->type = FFI_TYPE_STRUCT;
+ ret->elements = (ffi_type **) __go_alloc ((count + 1) * sizeof (ffi_type *));
+ for (i = 0; i < count; ++i)
+ ret->elements[i] = go_type_to_ffi (types[i]);
+ ret->elements[count] = NULL;
+ return ret;
+}
+
+/* Build an ffi_cif structure for a function described by a
+ __go_func_type structure. */
+
+static void
+go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
+ ffi_cif *cif)
+{
+ int num_params;
+ const struct __go_type_descriptor **in_types;
+ size_t num_args;
+ ffi_type **args;
+ int off;
+ int i;
+ ffi_type *rettype;
+ ffi_status status;
+
+ num_params = func->__in.__count;
+ in_types = ((const struct __go_type_descriptor **)
+ func->__in.__values);
+
+ num_args = num_params + (is_interface ? 1 : 0);
+ args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *));
+ if (is_interface)
+ args[0] = &ffi_type_pointer;
+ off = is_interface ? 1 : 0;
+ for (i = 0; i < num_params; ++i)
+ args[i + off] = go_type_to_ffi (in_types[i]);
+
+ rettype = go_func_return_ffi (func);
+
+ status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args);
+ __go_assert (status == FFI_OK);
+}
+
+/* Get the total size required for the result parameters of a
+ function. */
+
+static size_t
+go_results_size (const struct __go_func_type *func)
+{
+ int count;
+ const struct __go_type_descriptor **types;
+ size_t off;
+ size_t maxalign;
+ int i;
+
+ count = func->__out.__count;
+ if (count == 0)
+ return 0;
+
+ types = (const struct __go_type_descriptor **) func->__out.__values;
+
+ off = 0;
+ maxalign = 0;
+ for (i = 0; i < count; ++i)
+ {
+ size_t align;
+
+ align = types[i]->__field_align;
+ if (align > maxalign)
+ maxalign = align;
+ off = (off + align - 1) & ~ (align - 1);
+ off += types[i]->__size;
+ }
+
+ off = (off + maxalign - 1) & ~ (maxalign - 1);
+
+ return off;
+}
+
+/* Copy the results of calling a function via FFI from CALL_RESULT
+ into the addresses in RESULTS. */
+
+static void
+go_set_results (const struct __go_func_type *func, unsigned char *call_result,
+ void **results)
+{
+ int count;
+ const struct __go_type_descriptor **types;
+ size_t off;
+ int i;
+
+ count = func->__out.__count;
+ if (count == 0)
+ return;
+
+ types = (const struct __go_type_descriptor **) func->__out.__values;
+
+ off = 0;
+ for (i = 0; i < count; ++i)
+ {
+ size_t align;
+ size_t size;
+
+ align = types[i]->__field_align;
+ size = types[i]->__size;
+ off = (off + align - 1) & ~ (align - 1);
+ __builtin_memcpy (results[i], call_result + off, size);
+ off += size;
+ }
+}
+
+/* Call a function. The type of the function is FUNC_TYPE, and the
+ address is FUNC_ADDR. PARAMS is an array of parameter addresses.
+ RESULTS is an array of result addresses. */
+
+void
+reflect_call (const struct __go_func_type *func_type, const void *func_addr,
+ _Bool is_interface, void **params, void **results)
+{
+ ffi_cif cif;
+ unsigned char *call_result;
+
+ __go_assert (func_type->__common.__code == GO_FUNC);
+ go_func_to_cif (func_type, is_interface, &cif);
+
+ call_result = (unsigned char *) malloc (go_results_size (func_type));
+
+ ffi_call (&cif, func_addr, call_result, params);
+
+ /* Some day we may need to free result values if RESULTS is
+ NULL. */
+ if (results != NULL)
+ go_set_results (func_type, call_result, results);
+
+ free (call_result);
+}
diff --git a/libgo/runtime/go-reflect-chan.c b/libgo/runtime/go-reflect-chan.c
new file mode 100644
index 000000000..412cfeedf
--- /dev/null
+++ b/libgo/runtime/go-reflect-chan.c
@@ -0,0 +1,148 @@
+/* go-reflect-chan.c -- channel reflection support for Go.
+
+ 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. */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "config.h"
+#include "go-type.h"
+#include "channel.h"
+
+/* This file implements support for reflection on channels. These
+ functions are called from reflect/value.go. */
+
+extern unsigned char *makechan (const struct __go_type_descriptor *, uint32_t)
+ asm ("libgo_reflect.reflect.makechan");
+
+unsigned char *
+makechan (const struct __go_type_descriptor *typ, uint32_t size)
+{
+ return (unsigned char *) __go_new_channel (typ->__size, size);
+}
+
+extern void chansend (unsigned char *, unsigned char *, _Bool *)
+ asm ("libgo_reflect.reflect.chansend");
+
+void
+chansend (unsigned char *ch, unsigned char *val, _Bool *pres)
+{
+ struct __go_channel *channel = (struct __go_channel *) ch;
+
+ if (channel->element_size <= sizeof (uint64_t))
+ {
+ union
+ {
+ char b[sizeof (uint64_t)];
+ uint64_t v;
+ } u;
+
+ __builtin_memset (u.b, 0, sizeof (uint64_t));
+#ifndef WORDS_BIGENDIAN
+ __builtin_memcpy (u.b, val, channel->element_size);
+#else
+ __builtin_memcpy (u.b + sizeof (uint64_t) - channel->element_size, val,
+ channel->element_size);
+#endif
+ if (pres == NULL)
+ __go_send_small (channel, u.v, 0);
+ else
+ *pres = __go_send_nonblocking_small (channel, u.v);
+ }
+ else
+ {
+ if (pres == NULL)
+ __go_send_big (channel, val, 0);
+ else
+ *pres = __go_send_nonblocking_big (channel, val);
+ }
+}
+
+extern void chanrecv (unsigned char *, unsigned char *, _Bool *)
+ asm ("libgo_reflect.reflect.chanrecv");
+
+void
+chanrecv (unsigned char *ch, unsigned char *val, _Bool *pres)
+{
+ struct __go_channel *channel = (struct __go_channel *) ch;
+
+ if (channel->element_size <= sizeof (uint64_t))
+ {
+ union
+ {
+ char b[sizeof (uint64_t)];
+ uint64_t v;
+ } u;
+
+ if (pres == NULL)
+ u.v = __go_receive_small (channel, 0);
+ else
+ {
+ struct __go_receive_nonblocking_small s;
+
+ s = __go_receive_nonblocking_small (channel);
+ *pres = s.__success;
+ if (!s.__success)
+ return;
+ u.v = s.__val;
+ }
+
+#ifndef WORDS_BIGENDIAN
+ __builtin_memcpy (val, u.b, channel->element_size);
+#else
+ __builtin_memcpy (val, u.b + sizeof (uint64_t) - channel->element_size,
+ channel->element_size);
+#endif
+ }
+ else
+ {
+ if (pres == NULL)
+ __go_receive_big (channel, val, 0);
+ else
+ *pres = __go_receive_nonblocking_big (channel, val);
+ }
+}
+
+extern _Bool chanclosed (unsigned char *)
+ asm ("libgo_reflect.reflect.chanclosed");
+
+_Bool
+chanclosed (unsigned char *ch)
+{
+ struct __go_channel *channel = (struct __go_channel *) ch;
+
+ return __go_builtin_closed (channel);
+}
+
+extern void chanclose (unsigned char *)
+ asm ("libgo_reflect.reflect.chanclose");
+
+void
+chanclose (unsigned char *ch)
+{
+ struct __go_channel *channel = (struct __go_channel *) ch;
+
+ __go_builtin_close (channel);
+}
+
+extern int32_t chanlen (unsigned char *) asm ("libgo_reflect.reflect.chanlen");
+
+int32_t
+chanlen (unsigned char *ch)
+{
+ struct __go_channel *channel = (struct __go_channel *) ch;
+
+ return (int32_t) __go_chan_len (channel);
+}
+
+extern int32_t chancap (unsigned char *) asm ("libgo_reflect.reflect.chancap");
+
+int32_t
+chancap (unsigned char *ch)
+{
+ struct __go_channel *channel = (struct __go_channel *) ch;
+
+ return (int32_t) __go_chan_cap (channel);
+}
diff --git a/libgo/runtime/go-reflect-map.c b/libgo/runtime/go-reflect-map.c
new file mode 100644
index 000000000..67960dee4
--- /dev/null
+++ b/libgo/runtime/go-reflect-map.c
@@ -0,0 +1,139 @@
+/* go-reflect-map.c -- map reflection support for Go.
+
+ Copyright 2009, 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 <stdlib.h>
+#include <stdint.h>
+
+#include "go-alloc.h"
+#include "go-type.h"
+#include "map.h"
+
+/* This file implements support for reflection on maps. These
+ functions are called from reflect/value.go. */
+
+extern _Bool mapaccess (unsigned char *, unsigned char *, unsigned char *)
+ asm ("libgo_reflect.reflect.mapaccess");
+
+_Bool
+mapaccess (unsigned char *m, unsigned char *key, unsigned char *val)
+{
+ struct __go_map *map = (struct __go_map *) m;
+ void *p;
+ const struct __go_type_descriptor *val_descriptor;
+
+ p = __go_map_index (map, key, 0);
+ if (p == NULL)
+ return 0;
+ else
+ {
+ val_descriptor = map->__descriptor->__map_descriptor->__val_type;
+ __builtin_memcpy (val, p, val_descriptor->__size);
+ return 1;
+ }
+}
+
+extern void mapassign (unsigned char *, unsigned char *, unsigned char *)
+ asm ("libgo_reflect.reflect.mapassign");
+
+void
+mapassign (unsigned char *m, unsigned char *key, unsigned char *val)
+{
+ struct __go_map *map = (struct __go_map *) m;
+
+ if (val == NULL)
+ __go_map_delete (map, key);
+ else
+ {
+ void *p;
+ const struct __go_type_descriptor *val_descriptor;
+
+ p = __go_map_index (map, key, 1);
+ val_descriptor = map->__descriptor->__map_descriptor->__val_type;
+ __builtin_memcpy (p, val, val_descriptor->__size);
+ }
+}
+
+extern int32_t maplen (unsigned char *)
+ asm ("libgo_reflect.reflect.maplen");
+
+int32_t
+maplen (unsigned char *m __attribute__ ((unused)))
+{
+ struct __go_map *map = (struct __go_map *) m;
+ return (int32_t) map->__element_count;
+}
+
+extern unsigned char *mapiterinit (unsigned char *)
+ asm ("libgo_reflect.reflect.mapiterinit");
+
+unsigned char *
+mapiterinit (unsigned char *m)
+{
+ struct __go_hash_iter *it;
+
+ it = __go_alloc (sizeof (struct __go_hash_iter));
+ __go_mapiterinit ((struct __go_map *) m, it);
+ return (unsigned char *) it;
+}
+
+extern void mapiternext (unsigned char *)
+ asm ("libgo_reflect.reflect.mapiternext");
+
+void
+mapiternext (unsigned char *it)
+{
+ __go_mapiternext ((struct __go_hash_iter *) it);
+}
+
+extern _Bool mapiterkey (unsigned char *, unsigned char *)
+ asm ("libgo_reflect.reflect.mapiterkey");
+
+_Bool
+mapiterkey (unsigned char *ita, unsigned char *key)
+{
+ struct __go_hash_iter *it = (struct __go_hash_iter *) ita;
+
+ if (it->entry == NULL)
+ return 0;
+ else
+ {
+ __go_mapiter1 (it, key);
+ return 1;
+ }
+}
+
+/* Make a new map. We have to build our own map descriptor. */
+
+extern unsigned char *makemap (const struct __go_map_type *)
+ asm ("libgo_reflect.reflect.makemap");
+
+unsigned char *
+makemap (const struct __go_map_type *t)
+{
+ struct __go_map_descriptor *md;
+ unsigned int o;
+ const struct __go_type_descriptor *kt;
+ const struct __go_type_descriptor *vt;
+
+ /* FIXME: Reference count. */
+ md = (struct __go_map_descriptor *) __go_alloc (sizeof (*md));
+ md->__map_descriptor = t;
+ o = sizeof (void *);
+ kt = t->__key_type;
+ o = (o + kt->__field_align - 1) & ~ (kt->__field_align - 1);
+ md->__key_offset = o;
+ o += kt->__size;
+ vt = t->__val_type;
+ o = (o + vt->__field_align - 1) & ~ (vt->__field_align - 1);
+ md->__val_offset = o;
+ o += vt->__size;
+ o = (o + sizeof (void *) - 1) & ~ (sizeof (void *) - 1);
+ o = (o + kt->__field_align - 1) & ~ (kt->__field_align - 1);
+ o = (o + vt->__field_align - 1) & ~ (vt->__field_align - 1);
+ md->__entry_size = o;
+
+ return (unsigned char *) __go_new_map (md, 0);
+}
diff --git a/libgo/runtime/go-reflect.c b/libgo/runtime/go-reflect.c
new file mode 100644
index 000000000..9485c0979
--- /dev/null
+++ b/libgo/runtime/go-reflect.c
@@ -0,0 +1,186 @@
+/* go-reflect.c -- implement unsafe.Reflect and unsafe.Typeof for Go.
+
+ 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. */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "interface.h"
+#include "go-alloc.h"
+#include "go-panic.h"
+#include "go-string.h"
+#include "go-type.h"
+
+/* For field alignment. */
+
+struct field_align
+{
+ char c;
+ struct __go_type_descriptor *p;
+};
+
+/* The type descriptors in the runtime package. */
+
+extern const struct __go_type_descriptor ptr_bool_descriptor
+ asm ("__go_td_pN30_libgo_runtime.runtime.BoolType");
+extern const struct __go_type_descriptor ptr_float_descriptor
+ asm ("__go_td_pN31_libgo_runtime.runtime.FloatType");
+extern const struct __go_type_descriptor ptr_complex_descriptor
+ asm ("__go_td_pN33_libgo_runtime.runtime.ComplexType");
+extern const struct __go_type_descriptor ptr_int_descriptor
+ asm ("__go_td_pN29_libgo_runtime.runtime.IntType");
+extern const struct __go_type_descriptor ptr_uint_descriptor
+ asm ("__go_td_pN30_libgo_runtime.runtime.UintType");
+extern const struct __go_type_descriptor ptr_string_descriptor
+ asm ("__go_td_pN32_libgo_runtime.runtime.StringType");
+extern const struct __go_type_descriptor ptr_unsafe_pointer_decriptor
+ asm ("__go_td_pN39_libgo_runtime.runtime.UnsafePointerType");
+extern const struct __go_type_descriptor ptr_array_descriptor
+ asm ("__go_td_pN31_libgo_runtime.runtime.ArrayType");
+extern const struct __go_type_descriptor ptr_slice_descriptor
+ asm ("__go_td_pN31_libgo_runtime.runtime.SliceType");
+extern const struct __go_type_descriptor ptr_chan_descriptor
+ asm ("__go_td_pN30_libgo_runtime.runtime.ChanType");
+extern const struct __go_type_descriptor ptr_func_descriptor
+ asm ("__go_td_pN30_libgo_runtime.runtime.FuncType");
+extern const struct __go_type_descriptor ptr_interface_descriptor
+ asm ("__go_td_pN35_libgo_runtime.runtime.InterfaceType");
+extern const struct __go_type_descriptor ptr_map_descriptor
+ asm ("__go_td_pN29_libgo_runtime.runtime.MapType");
+extern const struct __go_type_descriptor ptr_ptr_descriptor
+ asm ("__go_td_pN29_libgo_runtime.runtime.PtrType");
+extern const struct __go_type_descriptor ptr_struct_descriptor
+ asm ("__go_td_pN32_libgo_runtime.runtime.StructType");
+
+const struct __go_type_descriptor *
+get_descriptor (int code)
+{
+ switch (code)
+ {
+ case GO_BOOL:
+ return &ptr_bool_descriptor;
+ case GO_FLOAT32:
+ case GO_FLOAT64:
+ return &ptr_float_descriptor;
+ case GO_COMPLEX64:
+ case GO_COMPLEX128:
+ return &ptr_complex_descriptor;
+ case GO_INT16:
+ case GO_INT32:
+ case GO_INT64:
+ case GO_INT8:
+ case GO_INT:
+ return &ptr_int_descriptor;
+ case GO_UINT16:
+ case GO_UINT32:
+ case GO_UINT64:
+ case GO_UINT8:
+ case GO_UINTPTR:
+ case GO_UINT:
+ return &ptr_uint_descriptor;
+ case GO_STRING:
+ return &ptr_string_descriptor;
+ case GO_UNSAFE_POINTER:
+ return &ptr_unsafe_pointer_decriptor;
+ case GO_ARRAY:
+ return &ptr_array_descriptor;
+ case GO_SLICE:
+ return &ptr_slice_descriptor;
+ case GO_CHAN:
+ return &ptr_chan_descriptor;
+ case GO_FUNC:
+ return &ptr_func_descriptor;
+ case GO_INTERFACE:
+ return &ptr_interface_descriptor;
+ case GO_MAP:
+ return &ptr_map_descriptor;
+ case GO_PTR:
+ return &ptr_ptr_descriptor;
+ case GO_STRUCT:
+ return &ptr_struct_descriptor;
+ default:
+ abort ();
+ }
+}
+
+/* Implement unsafe.Reflect. */
+
+struct reflect_ret
+{
+ struct __go_empty_interface rettype;
+ void *addr;
+};
+
+struct reflect_ret Reflect (struct __go_empty_interface)
+ asm ("libgo_unsafe.unsafe.Reflect");
+
+struct reflect_ret
+Reflect (struct __go_empty_interface e)
+{
+ struct reflect_ret ret;
+
+ if (e.__type_descriptor == NULL)
+ {
+ ret.rettype.__type_descriptor = NULL;
+ ret.rettype.__object = NULL;
+ ret.addr = NULL;
+ }
+ else
+ {
+ size_t size;
+
+ ret.rettype.__type_descriptor =
+ get_descriptor (e.__type_descriptor->__code);
+
+ /* This memcpy is really just an assignment of a const pointer
+ to a non-const pointer. FIXME: We should canonicalize this
+ pointer, so that for a given type we always return the same
+ pointer. */
+ __builtin_memcpy (&ret.rettype.__object, &e.__type_descriptor,
+ sizeof (void *));
+
+ /* Make a copy of the value. */
+ size = e.__type_descriptor->__size;
+ if (size <= sizeof (uint64_t))
+ ret.addr = __go_alloc (sizeof (uint64_t));
+ else
+ ret.addr = __go_alloc (size);
+ if (__go_is_pointer_type (e.__type_descriptor))
+ *(void **) ret.addr = e.__object;
+ else
+ __builtin_memcpy (ret.addr, e.__object, size);
+ }
+
+ return ret;
+}
+
+/* Implement unsafe.Typeof. */
+
+struct __go_empty_interface Typeof (struct __go_empty_interface)
+ asm ("libgo_unsafe.unsafe.Typeof");
+
+struct __go_empty_interface
+Typeof (const struct __go_empty_interface e)
+{
+ struct __go_empty_interface ret;
+
+ if (e.__type_descriptor == NULL)
+ {
+ ret.__type_descriptor = NULL;
+ ret.__object = NULL;
+ }
+ else
+ {
+ ret.__type_descriptor = get_descriptor (e.__type_descriptor->__code);
+
+ /* This memcpy is really just an assignment of a const pointer
+ to a non-const pointer. FIXME: We should canonicalize this
+ pointer, so that for a given type we always return the same
+ pointer. */
+ __builtin_memcpy (&ret.__object, &e.__type_descriptor, sizeof (void *));
+ }
+
+ return ret;
+}
diff --git a/libgo/runtime/go-rune.c b/libgo/runtime/go-rune.c
new file mode 100644
index 000000000..7e31eb8d6
--- /dev/null
+++ b/libgo/runtime/go-rune.c
@@ -0,0 +1,77 @@
+/* go-rune.c -- rune functions for Go.
+
+ Copyright 2009, 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 <stddef.h>
+
+#include "go-string.h"
+
+/* Get a character from the UTF-8 string STR, of length LEN. Store
+ the Unicode character, if any, in *RUNE. Return the number of
+ characters used from STR. */
+
+int
+__go_get_rune (const unsigned char *str, size_t len, int *rune)
+{
+ int c, c1, c2, c3;
+
+ /* Default to the "replacement character". */
+ *rune = 0xfffd;
+
+ if (len <= 0)
+ return 1;
+
+ c = *str;
+ if (c <= 0x7f)
+ {
+ *rune = c;
+ return 1;
+ }
+
+ if (len <= 1)
+ return 1;
+
+ c1 = str[1];
+ if ((c & 0xe0) == 0xc0
+ && (c1 & 0xc0) == 0x80)
+ {
+ *rune = (((c & 0x1f) << 6)
+ + (c1 & 0x3f));
+ return 2;
+ }
+
+ if (len <= 2)
+ return 1;
+
+ c2 = str[2];
+ if ((c & 0xf0) == 0xe0
+ && (c1 & 0xc0) == 0x80
+ && (c2 & 0xc0) == 0x80)
+ {
+ *rune = (((c & 0xf) << 12)
+ + ((c1 & 0x3f) << 6)
+ + (c2 & 0x3f));
+ return 3;
+ }
+
+ if (len <= 3)
+ return 1;
+
+ c3 = str[3];
+ if ((c & 0xf8) == 0xf0
+ && (c1 & 0xc0) == 0x80
+ && (c2 & 0xc0) == 0x80
+ && (c3 & 0xc0) == 0x80)
+ {
+ *rune = (((c & 0x7) << 18)
+ + ((c1 & 0x3f) << 12)
+ + ((c2 & 0x3f) << 6)
+ + (c3 & 0x3f));
+ return 4;
+ }
+
+ /* Invalid encoding. Return 1 so that we advance. */
+ return 1;
+}
diff --git a/libgo/runtime/go-runtime-error.c b/libgo/runtime/go-runtime-error.c
new file mode 100644
index 000000000..ceba2d673
--- /dev/null
+++ b/libgo/runtime/go-runtime-error.c
@@ -0,0 +1,84 @@
+/* go-runtime-error.c -- Go runtime error.
+
+ 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 "go-panic.h"
+
+/* The compiler generates calls to this function. This enum values
+ are known to the compiler and used by compiled code. Any change
+ here must be reflected in the compiler. */
+
+enum
+{
+ /* Slice index out of bounds: negative or larger than the length of
+ the slice. */
+ SLICE_INDEX_OUT_OF_BOUNDS = 0,
+
+ /* Array index out of bounds. */
+ ARRAY_INDEX_OUT_OF_BOUNDS = 1,
+
+ /* String index out of bounds. */
+ STRING_INDEX_OUT_OF_BOUNDS = 2,
+
+ /* Slice slice out of bounds: negative or larger than the length of
+ the slice or high bound less than low bound. */
+ SLICE_SLICE_OUT_OF_BOUNDS = 3,
+
+ /* Array slice out of bounds. */
+ ARRAY_SLICE_OUT_OF_BOUNDS = 4,
+
+ /* String slice out of bounds. */
+ STRING_SLICE_OUT_OF_BOUNDS = 5,
+
+ /* Dereference of nil pointer. This is used when there is a
+ dereference of a pointer to a very large struct or array, to
+ ensure that a gigantic array is not used a proxy to access random
+ memory locations. */
+ NIL_DEREFERENCE = 6,
+
+ /* Slice length or capacity out of bounds in make: negative or
+ overflow or length greater than capacity. */
+ MAKE_SLICE_OUT_OF_BOUNDS = 7,
+
+ /* Map capacity out of bounds in make: negative or overflow. */
+ MAKE_MAP_OUT_OF_BOUNDS = 8,
+
+ /* Channel capacity out of bounds in make: negative or overflow. */
+ MAKE_CHAN_OUT_OF_BOUNDS = 9
+};
+
+extern void __go_runtime_error () __attribute__ ((noreturn));
+
+void
+__go_runtime_error (int i)
+{
+ switch (i)
+ {
+ case SLICE_INDEX_OUT_OF_BOUNDS:
+ case ARRAY_INDEX_OUT_OF_BOUNDS:
+ case STRING_INDEX_OUT_OF_BOUNDS:
+ __go_panic_msg ("index out of range");
+
+ case SLICE_SLICE_OUT_OF_BOUNDS:
+ case ARRAY_SLICE_OUT_OF_BOUNDS:
+ case STRING_SLICE_OUT_OF_BOUNDS:
+ __go_panic_msg ("slice bounds out of range");
+
+ case NIL_DEREFERENCE:
+ __go_panic_msg ("nil pointer dereference");
+
+ case MAKE_SLICE_OUT_OF_BOUNDS:
+ __go_panic_msg ("make slice len or cap out of range");
+
+ case MAKE_MAP_OUT_OF_BOUNDS:
+ __go_panic_msg ("make map len out of range");
+
+ case MAKE_CHAN_OUT_OF_BOUNDS:
+ __go_panic_msg ("make chan len out of range");
+
+ default:
+ __go_panic_msg ("unknown runtime error");
+ }
+}
diff --git a/libgo/runtime/go-sched.c b/libgo/runtime/go-sched.c
new file mode 100644
index 000000000..2e36d31a5
--- /dev/null
+++ b/libgo/runtime/go-sched.c
@@ -0,0 +1,15 @@
+/* go-sched.c -- the runtime.Gosched function.
+
+ 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. */
+
+#include <sched.h>
+
+void Gosched (void) asm ("libgo_runtime.runtime.Gosched");
+
+void
+Gosched (void)
+{
+ sched_yield ();
+}
diff --git a/libgo/runtime/go-select.c b/libgo/runtime/go-select.c
new file mode 100644
index 000000000..9d9f728f2
--- /dev/null
+++ b/libgo/runtime/go-select.c
@@ -0,0 +1,758 @@
+/* go-select.c -- implement select.
+
+ 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. */
+
+#include <pthread.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "go-assert.h"
+#include "channel.h"
+
+/* __go_select builds an array of these structures. */
+
+struct select_channel
+{
+ /* The channel being selected. */
+ struct __go_channel* channel;
+ /* If this channel is selected, the value to return. */
+ size_t retval;
+ /* If this channel is a duplicate of one which appears earlier in
+ the array, this is the array index of the earlier channel. This
+ is -1UL if this is not a dup. */
+ size_t dup_index;
+ /* An entry to put on the send or receive queue. */
+ struct __go_channel_select queue_entry;
+ /* True if selected for send. */
+ _Bool is_send;
+ /* True if channel is ready--it has data to receive or space to
+ send. */
+ _Bool is_ready;
+};
+
+/* This mutex controls access to __go_select_cond. This mutex may not
+ be acquired if any channel locks are held. */
+
+static pthread_mutex_t __go_select_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* When we have to wait for channels, we tell them to trigger this
+ condition variable when they send or receive something. */
+
+static pthread_cond_t __go_select_cond = PTHREAD_COND_INITIALIZER;
+
+/* Sort the channels by address. This avoids deadlock when multiple
+ selects are running on overlapping sets of channels. */
+
+static int
+channel_sort (const void *p1, const void *p2)
+{
+ const struct select_channel *c1 = (const struct select_channel *) p1;
+ const struct select_channel *c2 = (const struct select_channel *) p2;
+
+ if ((uintptr_t) c1->channel < (uintptr_t) c2->channel)
+ return -1;
+ else if ((uintptr_t) c1->channel > (uintptr_t) c2->channel)
+ return 1;
+ else
+ return 0;
+}
+
+/* Return whether there is an entry on QUEUE which can be used for a
+ synchronous send or receive. */
+
+static _Bool
+is_queue_ready (struct __go_channel_select *queue)
+{
+ int x;
+
+ if (queue == NULL)
+ return 0;
+
+ x = pthread_mutex_lock (&__go_select_data_mutex);
+ __go_assert (x == 0);
+
+ while (queue != NULL)
+ {
+ if (*queue->selected == NULL)
+ break;
+ queue = queue->next;
+ }
+
+ x = pthread_mutex_unlock (&__go_select_data_mutex);
+ __go_assert (x == 0);
+
+ return queue != NULL;
+}
+
+/* Return whether CHAN is ready. If IS_SEND is true check whether it
+ has space to send, otherwise check whether it has a value to
+ receive. */
+
+static _Bool
+is_channel_ready (struct __go_channel* channel, _Bool is_send)
+{
+ if (is_send)
+ {
+ if (channel->selected_for_send)
+ return 0;
+ if (channel->is_closed)
+ return 1;
+ if (channel->num_entries > 0)
+ {
+ /* An asynchronous channel is ready for sending if there is
+ room in the buffer. */
+ return ((channel->next_store + 1) % channel->num_entries
+ != channel->next_fetch);
+ }
+ else
+ {
+ if (channel->waiting_to_send)
+ {
+ /* Some other goroutine is waiting to send on this
+ channel, so we can't. */
+ return 0;
+ }
+ if (channel->waiting_to_receive)
+ {
+ /* Some other goroutine is waiting to receive a value,
+ so we can send one. */
+ return 1;
+ }
+ if (is_queue_ready (channel->select_receive_queue))
+ {
+ /* There is a select statement waiting to synchronize
+ with this one. */
+ return 1;
+ }
+ return 0;
+ }
+ }
+ else
+ {
+ if (channel->selected_for_receive)
+ return 0;
+ if (channel->is_closed)
+ return 1;
+ if (channel->num_entries > 0)
+ {
+ /* An asynchronous channel is ready for receiving if there
+ is a value in the buffer. */
+ return channel->next_fetch != channel->next_store;
+ }
+ else
+ {
+ if (channel->waiting_to_receive)
+ {
+ /* Some other goroutine is waiting to receive from this
+ channel, so it is not ready for us to receive. */
+ return 0;
+ }
+ if (channel->next_store > 0)
+ {
+ /* There is data on the channel. */
+ return 1;
+ }
+ if (is_queue_ready (channel->select_send_queue))
+ {
+ /* There is a select statement waiting to synchronize
+ with this one. */
+ return 1;
+ }
+ return 0;
+ }
+ }
+}
+
+/* Mark a channel as selected. The channel is locked. IS_SELECTED is
+ true if the channel was selected for us by another goroutine. We
+ set *NEEDS_BROADCAST if we need to broadcast on the select
+ condition variable. Return true if we got it. */
+
+static _Bool
+mark_channel_selected (struct __go_channel *channel, _Bool is_send,
+ _Bool is_selected, _Bool *needs_broadcast)
+{
+ if (channel->num_entries == 0)
+ {
+ /* This is a synchronous channel. If there is no goroutine
+ currently waiting, but there is another select waiting, then
+ we need to tell that select to use this channel. That may
+ fail--there may be no other goroutines currently waiting--as
+ a third goroutine may already have claimed the select. */
+ if (!is_selected
+ && !channel->is_closed
+ && (is_send
+ ? !channel->waiting_to_receive
+ : channel->next_store == 0))
+ {
+ int x;
+ struct __go_channel_select *queue;
+
+ x = pthread_mutex_lock (&__go_select_data_mutex);
+ __go_assert (x == 0);
+
+ queue = (is_send
+ ? channel->select_receive_queue
+ : channel->select_send_queue);
+ __go_assert (queue != NULL);
+
+ while (queue != NULL)
+ {
+ if (*queue->selected == NULL)
+ {
+ *queue->selected = channel;
+ *queue->is_read = !is_send;
+ break;
+ }
+ queue = queue->next;
+ }
+
+ x = pthread_mutex_unlock (&__go_select_data_mutex);
+ __go_assert (x == 0);
+
+ if (queue == NULL)
+ return 0;
+
+ if (is_send)
+ channel->selected_for_receive = 1;
+ else
+ channel->selected_for_send = 1;
+
+ /* We are going to have to tell the other select that there
+ is something to do. */
+ *needs_broadcast = 1;
+ }
+ }
+
+ if (is_send)
+ channel->selected_for_send = 1;
+ else
+ channel->selected_for_receive = 1;
+
+ return 1;
+}
+
+/* Mark a channel to indicate that a select is waiting. The channel
+ is locked. */
+
+static void
+mark_select_waiting (struct select_channel *sc,
+ struct __go_channel **selected_pointer,
+ _Bool *selected_for_read_pointer)
+{
+ struct __go_channel *channel = sc->channel;
+ _Bool is_send = sc->is_send;
+
+ if (channel->num_entries == 0)
+ {
+ struct __go_channel_select **pp;
+
+ pp = (is_send
+ ? &channel->select_send_queue
+ : &channel->select_receive_queue);
+
+ /* Add an entry to the queue of selects on this channel. */
+ sc->queue_entry.next = *pp;
+ sc->queue_entry.selected = selected_pointer;
+ sc->queue_entry.is_read = selected_for_read_pointer;
+
+ *pp = &sc->queue_entry;
+ }
+
+ channel->select_mutex = &__go_select_mutex;
+ channel->select_cond = &__go_select_cond;
+
+ /* We never actually clear the select_mutex and select_cond fields.
+ In order to clear them safely, we would need to have some way of
+ knowing when no select is waiting for the channel. Thus we
+ introduce a bit of inefficiency for every channel that select
+ needs to wait for. This is harmless other than the performance
+ cost. */
+}
+
+/* Remove the entry for this select waiting on this channel. The
+ channel is locked. We check both queues, because the channel may
+ be selected for both reading and writing. */
+
+static void
+clear_select_waiting (struct select_channel *sc,
+ struct __go_channel **selected_pointer)
+{
+ struct __go_channel *channel = sc->channel;
+
+ if (channel->num_entries == 0)
+ {
+ _Bool found;
+ struct __go_channel_select **pp;
+
+ found = 0;
+
+ for (pp = &channel->select_send_queue; *pp != NULL; pp = &(*pp)->next)
+ {
+ if ((*pp)->selected == selected_pointer)
+ {
+ *pp = (*pp)->next;
+ found = 1;
+ break;
+ }
+ }
+
+ for (pp = &channel->select_receive_queue; *pp != NULL; pp = &(*pp)->next)
+ {
+ if ((*pp)->selected == selected_pointer)
+ {
+ *pp = (*pp)->next;
+ found = 1;
+ break;
+ }
+ }
+
+ __go_assert (found);
+ }
+}
+
+/* Look through the list of channels to see which ones are ready.
+ Lock each channels, and set the is_ready flag. Return the number
+ of ready channels. */
+
+static size_t
+lock_channels_find_ready (struct select_channel *channels, size_t count)
+{
+ size_t ready_count;
+ size_t i;
+
+ ready_count = 0;
+ for (i = 0; i < count; ++i)
+ {
+ struct __go_channel *channel = channels[i].channel;
+ _Bool is_send = channels[i].is_send;
+ size_t dup_index = channels[i].dup_index;
+ int x;
+
+ if (channel == NULL)
+ continue;
+
+ if (dup_index != (size_t) -1UL)
+ {
+ if (channels[dup_index].is_ready)
+ {
+ channels[i].is_ready = 1;
+ ++ready_count;
+ }
+ continue;
+ }
+
+ x = pthread_mutex_lock (&channel->lock);
+ __go_assert (x == 0);
+
+ if (is_channel_ready (channel, is_send))
+ {
+ channels[i].is_ready = 1;
+ ++ready_count;
+ }
+ }
+
+ return ready_count;
+}
+
+/* The channel we are going to select has been forced by some other
+ goroutine. SELECTED_CHANNEL is the channel we will use,
+ SELECTED_FOR_READ is whether the other goroutine wants to read from
+ the channel. Note that the channel could be specified multiple
+ times in this select, so we must mark each appropriate entry for
+ this channel as ready. Every other channel is marked as not ready.
+ All the channels are locked before this routine is called. This
+ returns the number of ready channels. */
+
+size_t
+force_selected_channel_ready (struct select_channel *channels, size_t count,
+ struct __go_channel *selected_channel,
+ _Bool selected_for_read)
+{
+ size_t ready_count;
+ size_t i;
+
+ ready_count = 0;
+ for (i = 0; i < count; ++i)
+ {
+ struct __go_channel *channel = channels[i].channel;
+ _Bool is_send = channels[i].is_send;
+
+ if (channel == NULL)
+ continue;
+
+ if (channel != selected_channel
+ || (is_send ? !selected_for_read : selected_for_read))
+ channels[i].is_ready = 0;
+ else
+ {
+ channels[i].is_ready = 1;
+ ++ready_count;
+ }
+ }
+ __go_assert (ready_count > 0);
+ return ready_count;
+}
+
+/* Unlock all the channels. */
+
+static void
+unlock_channels (struct select_channel *channels, size_t count)
+{
+ size_t i;
+ int x;
+
+ for (i = 0; i < count; ++i)
+ {
+ struct __go_channel *channel = channels[i].channel;
+
+ if (channel == NULL)
+ continue;
+
+ if (channels[i].dup_index != (size_t) -1UL)
+ continue;
+
+ x = pthread_mutex_unlock (&channel->lock);
+ __go_assert (x == 0);
+ }
+}
+
+/* At least one channel is ready. Randomly pick a channel to return.
+ Unlock all the channels. IS_SELECTED is true if the channel was
+ picked for us by some other goroutine. If SELECTED_POINTER is not
+ NULL, remove it from the queue for all the channels. Return the
+ retval field of the selected channel. This will return 0 if we
+ can't use the selected channel, because it relied on synchronizing
+ with some other select, and that select already synchronized with a
+ different channel. */
+
+static size_t
+unlock_channels_and_select (struct select_channel *channels,
+ size_t count, size_t ready_count,
+ _Bool is_selected,
+ struct __go_channel **selected_pointer)
+{
+ size_t selected;
+ size_t ret;
+ _Bool needs_broadcast;
+ size_t i;
+ int x;
+
+ /* Pick which channel we are going to return. */
+#if defined(HAVE_RANDOM)
+ selected = (size_t) random () % ready_count;
+#else
+ selected = (size_t) rand () % ready_count;
+#endif
+ ret = 0;
+ needs_broadcast = 0;
+
+ /* Look at the channels in reverse order so that we don't unlock a
+ duplicated channel until we have seen all its dups. */
+ for (i = 0; i < count; ++i)
+ {
+ size_t j = count - i - 1;
+ struct __go_channel *channel = channels[j].channel;
+ _Bool is_send = channels[j].is_send;
+
+ if (channel == NULL)
+ continue;
+
+ if (channels[j].is_ready)
+ {
+ if (selected == 0)
+ {
+ if (mark_channel_selected (channel, is_send, is_selected,
+ &needs_broadcast))
+ ret = channels[j].retval;
+ }
+
+ --selected;
+ }
+
+ if (channels[j].dup_index == (size_t) -1UL)
+ {
+ if (selected_pointer != NULL)
+ clear_select_waiting (&channels[j], selected_pointer);
+
+ x = pthread_mutex_unlock (&channel->lock);
+ __go_assert (x == 0);
+ }
+ }
+
+ /* The NEEDS_BROADCAST variable is set if we are synchronizing with
+ some other select statement. We can't do the actual broadcast
+ until we have unlocked all the channels. */
+
+ if (needs_broadcast)
+ {
+ x = pthread_mutex_lock (&__go_select_mutex);
+ __go_assert (x == 0);
+
+ x = pthread_cond_broadcast (&__go_select_cond);
+ __go_assert (x == 0);
+
+ x = pthread_mutex_unlock (&__go_select_mutex);
+ __go_assert (x == 0);
+ }
+
+ return ret;
+}
+
+/* Mark all channels to show that we are waiting for them. This is
+ called with the select mutex held, but none of the channels are
+ locked. This returns true if some channel was found to be
+ ready. */
+
+static _Bool
+mark_all_channels_waiting (struct select_channel* channels, size_t count,
+ struct __go_channel **selected_pointer,
+ _Bool *selected_for_read_pointer)
+{
+ _Bool ret;
+ int x;
+ size_t i;
+
+ ret = 0;
+ for (i = 0; i < count; ++i)
+ {
+ struct __go_channel *channel = channels[i].channel;
+ _Bool is_send = channels[i].is_send;
+
+ if (channel == NULL)
+ continue;
+
+ if (channels[i].dup_index != (size_t) -1UL)
+ {
+ size_t j;
+
+ /* A channel may be selected for both read and write. */
+ if (channels[channels[i].dup_index].is_send != is_send)
+ {
+ for (j = channels[i].dup_index + 1; j < i; ++j)
+ {
+ if (channels[j].channel == channel
+ && channels[j].is_send == is_send)
+ break;
+ }
+ if (j < i)
+ continue;
+ }
+ }
+
+ x = pthread_mutex_lock (&channel->lock);
+ __go_assert (x == 0);
+
+ /* To avoid a race condition, we have to check again whether the
+ channel is ready. It may have become ready since we did the
+ first set of checks but before we acquired the select mutex.
+ If we don't check here, we could sleep forever on the select
+ condition variable. */
+ if (is_channel_ready (channel, is_send))
+ ret = 1;
+
+ /* If SELECTED_POINTER is NULL, then we have already marked the
+ channel as waiting. */
+ if (selected_pointer != NULL)
+ mark_select_waiting (&channels[i], selected_pointer,
+ selected_for_read_pointer);
+
+ x = pthread_mutex_unlock (&channel->lock);
+ __go_assert (x == 0);
+ }
+
+ return ret;
+}
+
+/* Implement select. This is called by the compiler-generated code
+ with pairs of arguments: a pointer to a channel, and an int which
+ is non-zero for send, zero for receive. */
+
+size_t
+__go_select (size_t count, _Bool has_default,
+ struct __go_channel **channel_args, _Bool *is_send_args)
+{
+ struct select_channel stack_buffer[16];
+ struct select_channel *allocated_buffer;
+ struct select_channel *channels;
+ size_t i;
+ int x;
+ struct __go_channel *selected_channel;
+ _Bool selected_for_read;
+ _Bool is_queued;
+
+ if (count < sizeof stack_buffer / sizeof stack_buffer[0])
+ {
+ channels = &stack_buffer[0];
+ allocated_buffer = NULL;
+ }
+ else
+ {
+ allocated_buffer = ((struct select_channel *)
+ malloc (count * sizeof (struct select_channel)));
+ channels = allocated_buffer;
+ }
+
+ for (i = 0; i < count; ++i)
+ {
+ struct __go_channel *channel_arg = channel_args[i];
+ _Bool is_send = is_send_args[i];
+
+ channels[i].channel = (struct __go_channel*) channel_arg;
+ channels[i].retval = i + 1;
+ channels[i].dup_index = (size_t) -1UL;
+ channels[i].queue_entry.next = NULL;
+ channels[i].queue_entry.selected = NULL;
+ channels[i].is_send = is_send;
+ channels[i].is_ready = 0;
+ }
+
+ qsort (channels, count, sizeof (struct select_channel), channel_sort);
+
+ for (i = 0; i < count; ++i)
+ {
+ size_t j;
+
+ for (j = 0; j < i; ++j)
+ {
+ if (channels[j].channel == channels[i].channel)
+ {
+ channels[i].dup_index = j;
+ break;
+ }
+ }
+ }
+
+ /* SELECT_CHANNEL is used to select synchronized channels. If no
+ channels are ready, we store a pointer to this variable on the
+ select queue for each synchronized channel. Because the variable
+ may be set by channel operations running in other goroutines,
+ SELECT_CHANNEL may only be accessed when all the channels are
+ locked and/or when the select_data_mutex is locked. */
+ selected_channel = NULL;
+
+ /* SELECTED_FOR_READ is set to true if SELECTED_CHANNEL was set by a
+ goroutine which wants to read from the channel. The access
+ restrictions for this are like those for SELECTED_CHANNEL. */
+ selected_for_read = 0;
+
+ /* IS_QUEUED is true if we have queued up this select on the queues
+ for any associated synchronous channels. We only do this if no
+ channels are ready the first time around the loop. */
+ is_queued = 0;
+
+ while (1)
+ {
+ int ready_count;
+ _Bool is_selected;
+
+ /* Lock all channels, identify which ones are ready. */
+ ready_count = lock_channels_find_ready (channels, count);
+
+ /* All the channels are locked, so we can look at
+ SELECTED_CHANNEL. If it is not NULL, then our choice has
+ been forced by some other goroutine. This can only happen
+ after the first time through the loop. */
+ is_selected = selected_channel != NULL;
+ if (is_selected)
+ ready_count = force_selected_channel_ready (channels, count,
+ selected_channel,
+ selected_for_read);
+
+ if (ready_count > 0)
+ {
+ size_t ret;
+
+ ret = unlock_channels_and_select (channels, count, ready_count,
+ is_selected,
+ (is_queued
+ ? &selected_channel
+ : NULL));
+
+ /* If RET is zero, it means that the channel we picked
+ turned out not to be ready, because some other select
+ grabbed it during our traversal. Loop around and try
+ again. */
+ if (ret == 0)
+ {
+ is_queued = 0;
+ /* We are no longer on any channel queues, so it is safe
+ to touch SELECTED_CHANNEL here. It must be NULL,
+ because otherwise that would somebody has promised to
+ synch up with us and then failed to do so. */
+ __go_assert (selected_channel == NULL);
+ continue;
+ }
+
+ if (allocated_buffer != NULL)
+ free (allocated_buffer);
+
+ return ret;
+ }
+
+ /* No channels were ready. */
+
+ unlock_channels (channels, count);
+
+ if (has_default)
+ {
+ /* Use the default clause. */
+ if (allocated_buffer != NULL)
+ free (allocated_buffer);
+ return 0;
+ }
+
+ /* This is a blocking select. Grab the select lock, tell all
+ the channels to notify us when something happens, and wait
+ for something to happen. */
+
+ x = pthread_mutex_lock (&__go_select_mutex);
+ __go_assert (x == 0);
+
+ /* Check whether CHANNEL_SELECTED was set while the channels
+ were unlocked. If it was set, then we can simply loop around
+ again. We need to check this while the select mutex is held.
+ It is possible that something will set CHANNEL_SELECTED while
+ we mark the channels as waiting. If this happens, that
+ goroutine is required to signal the select condition
+ variable, which means acquiring the select mutex. Since we
+ have the select mutex locked ourselves, we can not miss that
+ signal. */
+
+ x = pthread_mutex_lock (&__go_select_data_mutex);
+ __go_assert (x == 0);
+
+ is_selected = selected_channel != NULL;
+
+ x = pthread_mutex_unlock (&__go_select_data_mutex);
+ __go_assert (x == 0);
+
+ if (!is_selected)
+ {
+ /* Mark the channels as waiting, and check whether they have
+ become ready. */
+ if (!mark_all_channels_waiting (channels, count,
+ (is_queued
+ ? NULL
+ : &selected_channel),
+ (is_queued
+ ? NULL
+ : &selected_for_read)))
+ {
+ x = pthread_cond_wait (&__go_select_cond, &__go_select_mutex);
+ __go_assert (x == 0);
+ }
+
+ is_queued = 1;
+ }
+
+ x = pthread_mutex_unlock (&__go_select_mutex);
+ __go_assert (x == 0);
+ }
+}
diff --git a/libgo/runtime/go-semacquire.c b/libgo/runtime/go-semacquire.c
new file mode 100644
index 000000000..24c6a7388
--- /dev/null
+++ b/libgo/runtime/go-semacquire.c
@@ -0,0 +1,151 @@
+/* go-semacquire.c -- implement runtime.Semacquire and runtime.Semrelease.
+
+ 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. */
+
+#include <stdint.h>
+
+#include <pthread.h>
+
+#include "go-assert.h"
+#include "runtime.h"
+
+/* We use a single global lock and condition variable. This is
+ painful, since it will cause unnecessary contention, but is hard to
+ avoid in a portable manner. On Linux we can use futexes, but they
+ are unfortunately not exposed by libc and are thus also hard to use
+ portably. */
+
+static pthread_mutex_t sem_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t sem_cond = PTHREAD_COND_INITIALIZER;
+
+/* If the value in *ADDR is positive, and we are able to atomically
+ decrement it, return true. Otherwise do nothing and return
+ false. */
+
+static _Bool
+acquire (uint32 *addr)
+{
+ while (1)
+ {
+ uint32 val;
+
+ val = *addr;
+ if (val == 0)
+ return 0;
+ if (__sync_bool_compare_and_swap (addr, val, val - 1))
+ return 1;
+ }
+}
+
+/* Implement runtime.Semacquire. ADDR points to a semaphore count.
+ We have acquired the semaphore when we have decremented the count
+ and it remains nonnegative. */
+
+void
+semacquire (uint32 *addr)
+{
+ while (1)
+ {
+ int i;
+
+ /* If the current count is positive, and we are able to atomically
+ decrement it, then we have acquired the semaphore. */
+ if (acquire (addr))
+ return;
+
+ /* Lock the mutex. */
+ i = pthread_mutex_lock (&sem_lock);
+ __go_assert (i == 0);
+
+ /* Check the count again with the mutex locked. */
+ if (acquire (addr))
+ {
+ i = pthread_mutex_unlock (&sem_lock);
+ __go_assert (i == 0);
+ return;
+ }
+
+ /* The count is zero. Even if a call to runtime.Semrelease
+ increments it to become positive, that call will try to
+ acquire the mutex and block, so we are sure to see the signal
+ of the condition variable. */
+ i = pthread_cond_wait (&sem_cond, &sem_lock);
+ __go_assert (i == 0);
+
+ /* Unlock the mutex and try again. */
+ i = pthread_mutex_unlock (&sem_lock);
+ __go_assert (i == 0);
+ }
+}
+
+/* Implement runtime.Semrelease. ADDR points to a semaphore count. We
+ must atomically increment the count. If the count becomes
+ positive, we signal the condition variable to wake up another
+ process. */
+
+void
+semrelease (uint32 *addr)
+{
+ int32_t val;
+
+ val = __sync_fetch_and_add (addr, 1);
+
+ /* VAL is the old value. It should never be negative. If it is
+ negative, that implies that Semacquire somehow decremented a zero
+ value, or that the count has overflowed. */
+ __go_assert (val >= 0);
+
+ /* If the old value was zero, then we have now released a count, and
+ we signal the condition variable. If the old value was positive,
+ then nobody can be waiting. We have to use
+ pthread_cond_broadcast, not pthread_cond_signal, because
+ otherwise there would be a race condition when the count is
+ incremented twice before any locker manages to decrement it. */
+ if (val == 0)
+ {
+ int i;
+
+ i = pthread_mutex_lock (&sem_lock);
+ __go_assert (i == 0);
+
+ i = pthread_cond_broadcast (&sem_cond);
+ __go_assert (i == 0);
+
+ i = pthread_mutex_unlock (&sem_lock);
+ __go_assert (i == 0);
+ }
+}
+
+
+#ifndef HAVE_SYNC_FETCH_AND_ADD_4
+
+/* For targets which don't have the required sync support. Really
+ this should be provided by gcc itself. FIXME. */
+
+static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER;
+
+uint32
+__sync_fetch_and_add_4(uint32*, uint32)
+ __attribute__((visibility("hidden")));
+
+uint32
+__sync_fetch_and_add_4(uint32* ptr, uint32 add)
+{
+ int i;
+ uint32 ret;
+
+ i = pthread_mutex_lock(&sync_lock);
+ __go_assert(i == 0);
+
+ ret = *ptr;
+ *ptr += add;
+
+ i = pthread_mutex_unlock(&sync_lock);
+ __go_assert(i == 0);
+
+ return ret;
+}
+
+#endif
diff --git a/libgo/runtime/go-send-big.c b/libgo/runtime/go-send-big.c
new file mode 100644
index 000000000..f58ffb6c8
--- /dev/null
+++ b/libgo/runtime/go-send-big.c
@@ -0,0 +1,31 @@
+/* go-send-big.c -- send something bigger than uint64_t on a channel.
+
+ 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. */
+
+#include <stdint.h>
+
+#include "go-panic.h"
+#include "channel.h"
+
+void
+__go_send_big (struct __go_channel* channel, const void *val, _Bool for_select)
+{
+ size_t alloc_size;
+ size_t offset;
+
+ if (channel == NULL)
+ __go_panic_msg ("send to nil channel");
+
+ alloc_size = ((channel->element_size + sizeof (uint64_t) - 1)
+ / sizeof (uint64_t));
+
+ if (!__go_send_acquire (channel, for_select))
+ return;
+
+ offset = channel->next_store * alloc_size;
+ __builtin_memcpy (&channel->data[offset], val, channel->element_size);
+
+ __go_send_release (channel);
+}
diff --git a/libgo/runtime/go-send-nb-big.c b/libgo/runtime/go-send-nb-big.c
new file mode 100644
index 000000000..288ce7f44
--- /dev/null
+++ b/libgo/runtime/go-send-nb-big.c
@@ -0,0 +1,30 @@
+/* go-send-nb-big.c -- nonblocking send of something big on a channel.
+
+ 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. */
+
+#include <stdint.h>
+
+#include "channel.h"
+
+_Bool
+__go_send_nonblocking_big (struct __go_channel* channel, const void *val)
+{
+ size_t alloc_size;
+ size_t offset;
+
+ alloc_size = ((channel->element_size + sizeof (uint64_t) - 1)
+ / sizeof (uint64_t));
+
+ int data = __go_send_nonblocking_acquire (channel);
+ if (data != SEND_NONBLOCKING_ACQUIRE_SPACE)
+ return data == SEND_NONBLOCKING_ACQUIRE_CLOSED;
+
+ offset = channel->next_store * alloc_size;
+ __builtin_memcpy (&channel->data[offset], val, channel->element_size);
+
+ __go_send_release (channel);
+
+ return 1;
+}
diff --git a/libgo/runtime/go-send-nb-small.c b/libgo/runtime/go-send-nb-small.c
new file mode 100644
index 000000000..f23ae0164
--- /dev/null
+++ b/libgo/runtime/go-send-nb-small.c
@@ -0,0 +1,112 @@
+/* go-send-nb-small.c -- nonblocking send of something small on a channel.
+
+ 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. */
+
+#include <stdint.h>
+
+#include "go-assert.h"
+#include "go-panic.h"
+#include "channel.h"
+
+/* Prepare to send something on a nonblocking channel. */
+
+int
+__go_send_nonblocking_acquire (struct __go_channel *channel)
+{
+ int i;
+ _Bool has_space;
+
+ i = pthread_mutex_lock (&channel->lock);
+ __go_assert (i == 0);
+
+ while (channel->selected_for_send)
+ {
+ i = pthread_cond_wait (&channel->cond, &channel->lock);
+ __go_assert (i == 0);
+ }
+
+ if (channel->is_closed)
+ {
+ ++channel->closed_op_count;
+ if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
+ {
+ i = pthread_mutex_unlock (&channel->lock);
+ __go_assert (i == 0);
+ __go_panic_msg ("too many operations on closed channel");
+ }
+ i = pthread_mutex_unlock (&channel->lock);
+ __go_assert (i == 0);
+ return SEND_NONBLOCKING_ACQUIRE_CLOSED;
+ }
+
+ if (channel->num_entries > 0)
+ has_space = ((channel->next_store + 1) % channel->num_entries
+ != channel->next_fetch);
+ else
+ {
+ /* This is a synchronous channel. If somebody is current
+ sending, then we can't send. Otherwise, see if somebody is
+ waiting to receive, or see if we can synch with a select. */
+ if (channel->waiting_to_send)
+ {
+ /* Some other goroutine is currently sending on this
+ channel, which means that we can't. */
+ has_space = 0;
+ }
+ else if (channel->waiting_to_receive)
+ {
+ /* Some other goroutine is waiting to receive a value, so we
+ can send directly to them. */
+ has_space = 1;
+ }
+ else if (__go_synch_with_select (channel, 1))
+ {
+ /* We found a select waiting to receive data, so we can send
+ to that. */
+ __go_broadcast_to_select (channel);
+ has_space = 1;
+ }
+ else
+ {
+ /* Otherwise, we can't send, because nobody is waiting to
+ receive. */
+ has_space = 0;
+ }
+
+ if (has_space)
+ {
+ channel->waiting_to_send = 1;
+ __go_assert (channel->next_store == 0);
+ }
+ }
+
+ if (!has_space)
+ {
+ i = pthread_mutex_unlock (&channel->lock);
+ __go_assert (i == 0);
+
+ return SEND_NONBLOCKING_ACQUIRE_NOSPACE;
+ }
+
+ return SEND_NONBLOCKING_ACQUIRE_SPACE;
+}
+
+/* Send something 64 bits or smaller on a channel. */
+
+_Bool
+__go_send_nonblocking_small (struct __go_channel *channel, uint64_t val)
+{
+ __go_assert (channel->element_size <= sizeof (uint64_t));
+
+ int data = __go_send_nonblocking_acquire (channel);
+ if (data != SEND_NONBLOCKING_ACQUIRE_SPACE)
+ return data == SEND_NONBLOCKING_ACQUIRE_CLOSED;
+
+ channel->data[channel->next_store] = val;
+
+ __go_send_release (channel);
+
+ return 1;
+}
diff --git a/libgo/runtime/go-send-small.c b/libgo/runtime/go-send-small.c
new file mode 100644
index 000000000..506c90e64
--- /dev/null
+++ b/libgo/runtime/go-send-small.c
@@ -0,0 +1,165 @@
+/* go-send-small.c -- send something 64 bits or smaller on a channel.
+
+ 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. */
+
+#include <stdint.h>
+
+#include "go-assert.h"
+#include "go-panic.h"
+#include "channel.h"
+
+/* Prepare to send something on a channel. Return true if the channel
+ is acquired, false, if it is closed. FOR_SELECT is true if this
+ call is being made after a select statement returned with this
+ channel selected. */
+
+_Bool
+__go_send_acquire (struct __go_channel *channel, _Bool for_select)
+{
+ int i;
+
+ i = pthread_mutex_lock (&channel->lock);
+ __go_assert (i == 0);
+
+ while (1)
+ {
+ /* Check whether the channel is closed. */
+ if (channel->is_closed)
+ {
+ ++channel->closed_op_count;
+ if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
+ {
+ i = pthread_mutex_unlock (&channel->lock);
+ __go_assert (i == 0);
+ __go_panic_msg ("too many operations on closed channel");
+ }
+ channel->selected_for_send = 0;
+ __go_unlock_and_notify_selects (channel);
+ return 0;
+ }
+
+ /* If somebody else has the channel locked for sending, we have
+ to wait. If FOR_SELECT is true, then we are the one with the
+ lock. */
+ if (!channel->selected_for_send || for_select)
+ {
+ if (channel->num_entries == 0)
+ {
+ /* This is a synchronous channel. If nobody else is
+ waiting to send, we grab the channel and tell the
+ caller to send the data. We will then wait for a
+ receiver. */
+ if (!channel->waiting_to_send)
+ {
+ __go_assert (channel->next_store == 0);
+ return 1;
+ }
+ }
+ else
+ {
+ /* If there is room on the channel, we are OK. */
+ if ((channel->next_store + 1) % channel->num_entries
+ != channel->next_fetch)
+ return 1;
+ }
+ }
+
+ /* Wait for something to change, then loop around and try
+ again. */
+
+ i = pthread_cond_wait (&channel->cond, &channel->lock);
+ __go_assert (i == 0);
+ }
+}
+
+/* Finished sending something on a channel. */
+
+void
+__go_send_release (struct __go_channel *channel)
+{
+ int i;
+
+ if (channel->num_entries != 0)
+ {
+ /* This is a buffered channel. Bump the store count and signal
+ the condition variable. */
+ channel->next_store = (channel->next_store + 1) % channel->num_entries;
+
+ i = pthread_cond_signal (&channel->cond);
+ __go_assert (i == 0);
+ }
+ else
+ {
+ _Bool synched_with_select;
+
+ /* This is a synchronous channel. Indicate that we have a value
+ waiting. */
+ channel->next_store = 1;
+ channel->waiting_to_send = 1;
+
+ /* Tell everybody else to do something. This has to be a
+ broadcast because we might have both senders and receivers
+ waiting on the condition, but senders won't send another
+ signal. */
+ i = pthread_cond_broadcast (&channel->cond);
+ __go_assert (i == 0);
+
+ /* Wait until the value is received. */
+ synched_with_select = 0;
+ while (1)
+ {
+ if (channel->next_store == 0)
+ break;
+
+ /* If nobody is currently waiting to receive, try to synch
+ up with a select. */
+ if (!channel->waiting_to_receive && !synched_with_select)
+ {
+ if (__go_synch_with_select (channel, 1))
+ {
+ synched_with_select = 1;
+ __go_broadcast_to_select (channel);
+ continue;
+ }
+ }
+
+ i = pthread_cond_wait (&channel->cond, &channel->lock);
+ __go_assert (i == 0);
+ }
+
+ channel->waiting_to_send = 0;
+
+ /* Using the mutexes should implement a memory barrier. */
+
+ /* We have to signal again since we cleared the waiting_to_send
+ field. This has to be a broadcast because both senders and
+ receivers might be waiting, but only senders will be able to
+ act. */
+ i = pthread_cond_broadcast (&channel->cond);
+ __go_assert (i == 0);
+ }
+
+ channel->selected_for_send = 0;
+
+ __go_unlock_and_notify_selects (channel);
+}
+
+/* Send something 64 bits or smaller on a channel. */
+
+void
+__go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select)
+{
+ if (channel == NULL)
+ __go_panic_msg ("send to nil channel");
+
+ __go_assert (channel->element_size <= sizeof (uint64_t));
+
+ if (!__go_send_acquire (channel, for_select))
+ return;
+
+ channel->data[channel->next_store] = val;
+
+ __go_send_release (channel);
+}
diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c
new file mode 100644
index 000000000..3838ab988
--- /dev/null
+++ b/libgo/runtime/go-signal.c
@@ -0,0 +1,200 @@
+/* go-signal.c -- signal handling for Go.
+
+ 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. */
+
+#include <signal.h>
+#include <stdlib.h>
+
+#include "go-assert.h"
+#include "go-panic.h"
+#include "go-signal.h"
+
+#include "runtime.h"
+
+#undef int
+
+#ifndef SA_ONSTACK
+#define SA_ONSTACK 0
+#endif
+
+/* What to do for a signal. */
+
+struct sigtab
+{
+ /* Signal number. */
+ int sig;
+ /* Nonzero if the signal should be ignored. */
+ _Bool ignore;
+};
+
+/* What to do for signals. */
+
+static struct sigtab signals[] =
+{
+ { SIGHUP, 0 },
+ { SIGINT, 0 },
+ { SIGALRM, 1 },
+ { SIGTERM, 0 },
+#ifdef SIGBUS
+ { SIGBUS, 0 },
+#endif
+#ifdef SIGFPE
+ { SIGFPE, 0 },
+#endif
+#ifdef SIGUSR1
+ { SIGUSR1, 1 },
+#endif
+#ifdef SIGSEGV
+ { SIGSEGV, 0 },
+#endif
+#ifdef SIGUSR2
+ { SIGUSR2, 1 },
+#endif
+#ifdef SIGPIPE
+ { SIGPIPE, 1 },
+#endif
+#ifdef SIGCHLD
+ { SIGCHLD, 1 },
+#endif
+#ifdef SIGTSTP
+ { SIGTSTP, 1 },
+#endif
+#ifdef SIGTTIN
+ { SIGTTIN, 1 },
+#endif
+#ifdef SIGTTOU
+ { SIGTTOU, 1 },
+#endif
+#ifdef SIGURG
+ { SIGURG, 1 },
+#endif
+#ifdef SIGXCPU
+ { SIGXCPU, 1 },
+#endif
+#ifdef SIGXFSZ
+ { SIGXFSZ, 1 },
+#endif
+#ifdef SIGVTARLM
+ { SIGVTALRM, 1 },
+#endif
+#ifdef SIGPROF
+ { SIGPROF, 1 },
+#endif
+#ifdef SIGWINCH
+ { SIGWINCH, 1 },
+#endif
+#ifdef SIGIO
+ { SIGIO, 1 },
+#endif
+#ifdef SIGPWR
+ { SIGPWR, 1 },
+#endif
+ { -1, 0 }
+};
+
+/* The Go signal handler. */
+
+static void
+sighandler (int sig)
+{
+ const char *msg;
+ int i;
+
+ /* FIXME: Should check siginfo for more information when
+ available. */
+ msg = NULL;
+ switch (sig)
+ {
+#ifdef SIGBUS
+ case SIGBUS:
+ msg = "invalid memory address or nil pointer dereference";
+ break;
+#endif
+
+#ifdef SIGFPE
+ case SIGFPE:
+ msg = "integer divide by zero or floating point error";
+ break;
+#endif
+
+#ifdef SIGSEGV
+ case SIGSEGV:
+ msg = "invalid memory address or nil pointer dereference";
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ if (msg != NULL)
+ {
+ sigset_t clear;
+
+ if (__sync_bool_compare_and_swap (&m->mallocing, 1, 1))
+ {
+ fprintf (stderr, "caught signal while mallocing: %s\n", msg);
+ __go_assert (0);
+ }
+
+ /* The signal handler blocked signals; unblock them. */
+ i = sigfillset (&clear);
+ __go_assert (i == 0);
+ i = sigprocmask (SIG_UNBLOCK, &clear, NULL);
+ __go_assert (i == 0);
+
+ __go_panic_msg (msg);
+ }
+
+ if (__go_sigsend (sig))
+ return;
+ for (i = 0; signals[i].sig != -1; ++i)
+ {
+ if (signals[i].sig == sig)
+ {
+ struct sigaction sa;
+
+ if (signals[i].ignore)
+ return;
+
+ memset (&sa, 0, sizeof sa);
+
+ sa.sa_handler = SIG_DFL;
+
+ i = sigemptyset (&sa.sa_mask);
+ __go_assert (i == 0);
+
+ if (sigaction (sig, &sa, NULL) != 0)
+ abort ();
+
+ raise (sig);
+ exit (2);
+ }
+ }
+ abort ();
+}
+
+/* Initialize signal handling for Go. This is called when the program
+ starts. */
+
+void
+__initsig ()
+{
+ struct sigaction sa;
+ int i;
+
+ siginit ();
+
+ memset (&sa, 0, sizeof sa);
+
+ sa.sa_handler = sighandler;
+
+ i = sigfillset (&sa.sa_mask);
+ __go_assert (i == 0);
+
+ for (i = 0; signals[i].sig != -1; ++i)
+ if (sigaction (signals[i].sig, &sa, NULL) != 0)
+ __go_assert (0);
+}
diff --git a/libgo/runtime/go-signal.h b/libgo/runtime/go-signal.h
new file mode 100644
index 000000000..a30173a34
--- /dev/null
+++ b/libgo/runtime/go-signal.h
@@ -0,0 +1,7 @@
+/* go-signal.h -- signal handling for Go.
+
+ 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. */
+
+extern void __initsig (void);
diff --git a/libgo/runtime/go-strcmp.c b/libgo/runtime/go-strcmp.c
new file mode 100644
index 000000000..8e6cb1834
--- /dev/null
+++ b/libgo/runtime/go-strcmp.c
@@ -0,0 +1,27 @@
+/* go-strcmp.c -- the go string comparison function.
+
+ 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. */
+
+#include "go-string.h"
+
+int
+__go_strcmp(struct __go_string s1, struct __go_string s2)
+{
+ int i;
+
+ i = __builtin_memcmp(s1.__data, s2.__data,
+ (s1.__length < s2.__length
+ ? s1.__length
+ : s2.__length));
+ if (i != 0)
+ return i;
+
+ if (s1.__length < s2.__length)
+ return -1;
+ else if (s1.__length > s2.__length)
+ return 1;
+ else
+ return 0;
+}
diff --git a/libgo/runtime/go-string-to-byte-array.c b/libgo/runtime/go-string-to-byte-array.c
new file mode 100644
index 000000000..3b646c81a
--- /dev/null
+++ b/libgo/runtime/go-string-to-byte-array.c
@@ -0,0 +1,24 @@
+/* go-string-to-byte-array.c -- convert a string to an array of bytes in Go.
+
+ 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 "go-string.h"
+#include "array.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_open_array
+__go_string_to_byte_array (struct __go_string str)
+{
+ unsigned char *data;
+ struct __go_open_array ret;
+
+ data = (unsigned char *) runtime_mallocgc (str.__length, RefNoPointers, 1, 0);
+ __builtin_memcpy (data, str.__data, str.__length);
+ ret.__values = (void *) data;
+ ret.__count = str.__length;
+ ret.__capacity = str.__length;
+ return ret;
+}
diff --git a/libgo/runtime/go-string-to-int-array.c b/libgo/runtime/go-string-to-int-array.c
new file mode 100644
index 000000000..8d7f94f93
--- /dev/null
+++ b/libgo/runtime/go-string-to-int-array.c
@@ -0,0 +1,50 @@
+/* go-string-to-int-array.c -- convert a string to an array of ints in Go.
+
+ 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 "go-alloc.h"
+#include "go-string.h"
+#include "array.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_open_array
+__go_string_to_int_array (struct __go_string str)
+{
+ size_t c;
+ const unsigned char *p;
+ const unsigned char *pend;
+ uint32_t *data;
+ uint32_t *pd;
+ struct __go_open_array ret;
+
+ c = 0;
+ p = str.__data;
+ pend = p + str.__length;
+ while (p < pend)
+ {
+ int rune;
+
+ ++c;
+ p += __go_get_rune (p, pend - p, &rune);
+ }
+
+ data = (uint32_t *) runtime_mallocgc (c * sizeof (uint32_t), RefNoPointers,
+ 1, 0);
+ p = str.__data;
+ pd = data;
+ while (p < pend)
+ {
+ int rune;
+
+ p += __go_get_rune (p, pend - p, &rune);
+ *pd++ = rune;
+ }
+
+ ret.__values = (void *) data;
+ ret.__count = c;
+ ret.__capacity = c;
+ return ret;
+}
diff --git a/libgo/runtime/go-string.h b/libgo/runtime/go-string.h
new file mode 100644
index 000000000..2c8e1acd3
--- /dev/null
+++ b/libgo/runtime/go-string.h
@@ -0,0 +1,42 @@
+/* go-string.h -- the string type for Go.
+
+ 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. */
+
+#ifndef LIBGO_GO_STRING_H
+#define LIBGO_GO_STRING_H
+
+#include <stddef.h>
+
+/* A string is an instance of this structure. */
+
+struct __go_string
+{
+ /* The bytes. */
+ const unsigned char *__data;
+ /* The length. */
+ int __length;
+};
+
+static inline _Bool
+__go_strings_equal (struct __go_string s1, struct __go_string s2)
+{
+ return (s1.__length == s2.__length
+ && __builtin_memcmp (s1.__data, s2.__data, s1.__length) == 0);
+}
+
+static inline _Bool
+__go_ptr_strings_equal (const struct __go_string *ps1,
+ const struct __go_string *ps2)
+{
+ if (ps1 == NULL)
+ return ps2 == NULL;
+ if (ps2 == NULL)
+ return 0;
+ return __go_strings_equal (*ps1, *ps2);
+}
+
+extern int __go_get_rune (const unsigned char *, size_t, int *);
+
+#endif /* !defined(LIBGO_GO_STRING_H) */
diff --git a/libgo/runtime/go-strplus.c b/libgo/runtime/go-strplus.c
new file mode 100644
index 000000000..c0cd356ca
--- /dev/null
+++ b/libgo/runtime/go-strplus.c
@@ -0,0 +1,30 @@
+/* go-strplus.c -- the go string append function.
+
+ 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. */
+
+#include "go-string.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_string
+__go_string_plus (struct __go_string s1, struct __go_string s2)
+{
+ int len;
+ unsigned char *retdata;
+ struct __go_string ret;
+
+ if (s1.__length == 0)
+ return s2;
+ else if (s2.__length == 0)
+ return s1;
+
+ len = s1.__length + s2.__length;
+ retdata = runtime_mallocgc (len, RefNoPointers, 1, 0);
+ __builtin_memcpy (retdata, s1.__data, s1.__length);
+ __builtin_memcpy (retdata + s1.__length, s2.__data, s2.__length);
+ ret.__data = retdata;
+ ret.__length = len;
+ return ret;
+}
diff --git a/libgo/runtime/go-strslice.c b/libgo/runtime/go-strslice.c
new file mode 100644
index 000000000..94ecee92e
--- /dev/null
+++ b/libgo/runtime/go-strslice.c
@@ -0,0 +1,26 @@
+/* go-strslice.c -- the go string slice function.
+
+ 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. */
+
+#include "go-string.h"
+#include "go-panic.h"
+#include "runtime.h"
+#include "malloc.h"
+
+struct __go_string
+__go_string_slice (struct __go_string s, int start, int end)
+{
+ int len;
+ struct __go_string ret;
+
+ len = s.__length;
+ if (end == -1)
+ end = len;
+ if (start > len || end < start || end > len)
+ __go_panic_msg ("string index out of bounds");
+ ret.__data = s.__data + start;
+ ret.__length = end - start;
+ return ret;
+}
diff --git a/libgo/runtime/go-trampoline.c b/libgo/runtime/go-trampoline.c
new file mode 100644
index 000000000..43003e81c
--- /dev/null
+++ b/libgo/runtime/go-trampoline.c
@@ -0,0 +1,53 @@
+/* go-trampoline.c -- allocate a trampoline for a nested function.
+
+ 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. */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include "go-alloc.h"
+#include "go-assert.h"
+
+/* In order to build a trampoline we need space which is both writable
+ and executable. We currently just allocate a whole page. This
+ needs to be more system dependent. */
+
+void *
+__go_allocate_trampoline (size_t size, void *closure)
+{
+ unsigned int page_size;
+ void *ret;
+ size_t off;
+
+ page_size = getpagesize ();
+ __go_assert (page_size >= size);
+ ret = __go_alloc (2 * page_size - 1);
+ ret = (void *) (((uintptr_t) ret + page_size - 1)
+ & ~ ((uintptr_t) page_size - 1));
+
+ /* Because the garbage collector only looks at correct address
+ offsets, we need to ensure that it will see the closure
+ address. */
+ off = ((size + sizeof (void *) - 1) / sizeof (void *)) * sizeof (void *);
+ __go_assert (size + off + sizeof (void *) <= page_size);
+ __builtin_memcpy (ret + off, &closure, sizeof (void *));
+
+#ifdef HAVE_SYS_MMAN_H
+ {
+ int i;
+ i = mprotect (ret, size, PROT_READ | PROT_WRITE | PROT_EXEC);
+ __go_assert (i == 0);
+ }
+#endif
+
+ return ret;
+}
diff --git a/libgo/runtime/go-type-eface.c b/libgo/runtime/go-type-eface.c
new file mode 100644
index 000000000..84ca05ee1
--- /dev/null
+++ b/libgo/runtime/go-type-eface.c
@@ -0,0 +1,55 @@
+/* go-type-eface.c -- hash and equality empty interface functions.
+
+ 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 "interface.h"
+#include "go-type.h"
+
+/* A hash function for an empty interface. */
+
+size_t
+__go_type_hash_empty_interface (const void *vval,
+ size_t key_size __attribute__ ((unused)))
+{
+ const struct __go_empty_interface *val;
+ const struct __go_type_descriptor *descriptor;
+ size_t size;
+
+ val = (const struct __go_empty_interface *) vval;
+ descriptor = val->__type_descriptor;
+ if (descriptor == NULL)
+ return 0;
+ size = descriptor->__size;
+ if (__go_is_pointer_type (descriptor))
+ return descriptor->__hashfn (&val->__object, size);
+ else
+ return descriptor->__hashfn (val->__object, size);
+}
+
+/* An equality function for an empty interface. */
+
+_Bool
+__go_type_equal_empty_interface (const void *vv1, const void *vv2,
+ size_t key_size __attribute__ ((unused)))
+{
+ const struct __go_empty_interface *v1;
+ const struct __go_empty_interface *v2;
+ const struct __go_type_descriptor* v1_descriptor;
+ const struct __go_type_descriptor* v2_descriptor;
+
+ v1 = (const struct __go_empty_interface *) vv1;
+ v2 = (const struct __go_empty_interface *) vv2;
+ v1_descriptor = v1->__type_descriptor;
+ v2_descriptor = v2->__type_descriptor;
+ if (v1_descriptor == NULL || v2_descriptor == NULL)
+ return v1_descriptor == v2_descriptor;
+ if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor))
+ return 0;
+ if (__go_is_pointer_type (v1_descriptor))
+ return v1->__object == v2->__object;
+ else
+ return v1_descriptor->__equalfn (v1->__object, v2->__object,
+ v1_descriptor->__size);
+}
diff --git a/libgo/runtime/go-type-error.c b/libgo/runtime/go-type-error.c
new file mode 100644
index 000000000..865850c9c
--- /dev/null
+++ b/libgo/runtime/go-type-error.c
@@ -0,0 +1,28 @@
+/* go-type-error.c -- invalid hash and equality functions.
+
+ 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. */
+
+#include "go-type.h"
+#include "go-panic.h"
+
+/* A hash function used for a type which does not support hash
+ functions. */
+
+size_t
+__go_type_hash_error (const void *val __attribute__ ((unused)),
+ size_t key_size __attribute__ ((unused)))
+{
+ __go_panic_msg ("hash of unhashable type");
+}
+
+/* An equality function for an interface. */
+
+_Bool
+__go_type_equal_error (const void *v1 __attribute__ ((unused)),
+ const void *v2 __attribute__ ((unused)),
+ size_t key_size __attribute__ ((unused)))
+{
+ __go_panic_msg ("comparing uncomparable types");
+}
diff --git a/libgo/runtime/go-type-identity.c b/libgo/runtime/go-type-identity.c
new file mode 100644
index 000000000..f1de3c28a
--- /dev/null
+++ b/libgo/runtime/go-type-identity.c
@@ -0,0 +1,50 @@
+/* go-type-identity.c -- hash and equality identity functions.
+
+ 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. */
+
+#include <stddef.h>
+
+#include "go-type.h"
+
+/* Typedefs for accesses of different sizes. */
+
+typedef int QItype __attribute__ ((mode (QI)));
+typedef int HItype __attribute__ ((mode (HI)));
+typedef int SItype __attribute__ ((mode (SI)));
+typedef int DItype __attribute__ ((mode (DI)));
+
+/* An identity hash function for a type. This is used for types where
+ we can simply use the type value itself as a hash code. This is
+ true of, e.g., integers and pointers. */
+
+size_t
+__go_type_hash_identity (const void *key, size_t key_size)
+{
+ switch (key_size)
+ {
+ case 1:
+ return *(const QItype *) key;
+ case 2:
+ return *(const HItype *) key;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return *(const SItype *) key;
+ default:
+ return *(const DItype *) key;
+ }
+}
+
+/* An identity equality function for a type. This is used for types
+ where we can check for equality by checking that the values have
+ the same bits. */
+
+_Bool
+__go_type_equal_identity (const void *k1, const void *k2, size_t key_size)
+{
+ return __builtin_memcmp (k1, k2, key_size) == 0;
+}
diff --git a/libgo/runtime/go-type-interface.c b/libgo/runtime/go-type-interface.c
new file mode 100644
index 000000000..9750b843c
--- /dev/null
+++ b/libgo/runtime/go-type-interface.c
@@ -0,0 +1,55 @@
+/* go-type-interface.c -- hash and equality interface functions.
+
+ 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. */
+
+#include "interface.h"
+#include "go-type.h"
+
+/* A hash function for an interface. */
+
+size_t
+__go_type_hash_interface (const void *vval,
+ size_t key_size __attribute__ ((unused)))
+{
+ const struct __go_interface *val;
+ const struct __go_type_descriptor *descriptor;
+ size_t size;
+
+ val = (const struct __go_interface *) vval;
+ if (val->__methods == NULL)
+ return 0;
+ descriptor = (const struct __go_type_descriptor *) val->__methods[0];
+ size = descriptor->__size;
+ if (__go_is_pointer_type (descriptor))
+ return descriptor->__hashfn (&val->__object, size);
+ else
+ return descriptor->__hashfn (val->__object, size);
+}
+
+/* An equality function for an interface. */
+
+_Bool
+__go_type_equal_interface (const void *vv1, const void *vv2,
+ size_t key_size __attribute__ ((unused)))
+{
+ const struct __go_interface *v1;
+ const struct __go_interface *v2;
+ const struct __go_type_descriptor* v1_descriptor;
+ const struct __go_type_descriptor* v2_descriptor;
+
+ v1 = (const struct __go_interface *) vv1;
+ v2 = (const struct __go_interface *) vv2;
+ if (v1->__methods == NULL || v2->__methods == NULL)
+ return v1->__methods == v2->__methods;
+ v1_descriptor = (const struct __go_type_descriptor *) v1->__methods[0];
+ v2_descriptor = (const struct __go_type_descriptor *) v2->__methods[0];
+ if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor))
+ return 0;
+ if (__go_is_pointer_type (v1_descriptor))
+ return v1->__object == v2->__object;
+ else
+ return v1_descriptor->__equalfn (v1->__object, v2->__object,
+ v1_descriptor->__size);
+}
diff --git a/libgo/runtime/go-type-string.c b/libgo/runtime/go-type-string.c
new file mode 100644
index 000000000..998955d62
--- /dev/null
+++ b/libgo/runtime/go-type-string.c
@@ -0,0 +1,45 @@
+/* go-type-string.c -- hash and equality string functions.
+
+ 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. */
+
+#include <stddef.h>
+
+#include "go-string.h"
+#include "go-type.h"
+
+/* A string hash function for a map. */
+
+size_t
+__go_type_hash_string (const void *vkey,
+ size_t key_size __attribute__ ((unused)))
+{
+ size_t ret;
+ const struct __go_string *key;
+ size_t len;
+ size_t i;
+ const unsigned char *p;
+
+ ret = 5381;
+ key = (const struct __go_string *) vkey;
+ len = key->__length;
+ for (i = 0, p = key->__data; i < len; i++, p++)
+ ret = ret * 33 + *p;
+ return ret;
+}
+
+/* A string equality function for a map. */
+
+_Bool
+__go_type_equal_string (const void *vk1, const void *vk2,
+ size_t key_size __attribute__ ((unused)))
+{
+ const struct __go_string *k1;
+ const struct __go_string *k2;
+
+ k1 = (const struct __go_string *) vk1;
+ k2 = (const struct __go_string *) vk2;
+ return (k1->__length == k2->__length
+ && __builtin_memcmp (k1->__data, k2->__data, k1->__length) == 0);
+}
diff --git a/libgo/runtime/go-type.h b/libgo/runtime/go-type.h
new file mode 100644
index 000000000..b1f32850a
--- /dev/null
+++ b/libgo/runtime/go-type.h
@@ -0,0 +1,309 @@
+/* go-type.h -- basic information for a Go type.
+
+ 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. */
+
+#ifndef LIBGO_GO_TYPE_H
+#define LIBGO_GO_TYPE_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "go-string.h"
+#include "array.h"
+
+/* Many of the types in this file must match the data structures
+ generated by the compiler, and must also match the Go types which
+ appear in go/runtime/type.go and go/reflect/type.go. */
+
+/* Type kinds. These are used to get the type descriptor to use for
+ the type itself, when using unsafe.Typeof or unsafe.Reflect. The
+ values here must match the values generated by the compiler (the
+ RUNTIME_TYPE_KIND_xxx values in gcc/go/types.h). These are macros
+ rather than an enum to make it easy to change values in the future
+ and hard to get confused about it.
+
+ These correspond to the kind values used by the gc compiler. */
+
+#define GO_BOOL 1
+#define GO_INT 2
+#define GO_INT8 3
+#define GO_INT16 4
+#define GO_INT32 5
+#define GO_INT64 6
+#define GO_UINT 7
+#define GO_UINT8 8
+#define GO_UINT16 9
+#define GO_UINT32 10
+#define GO_UINT64 11
+#define GO_UINTPTR 12
+#define GO_FLOAT32 13
+#define GO_FLOAT64 14
+#define GO_COMPLEX64 15
+#define GO_COMPLEX128 16
+#define GO_ARRAY 17
+#define GO_CHAN 18
+#define GO_FUNC 19
+#define GO_INTERFACE 20
+#define GO_MAP 21
+#define GO_PTR 22
+#define GO_SLICE 23
+#define GO_STRING 24
+#define GO_STRUCT 25
+#define GO_UNSAFE_POINTER 26
+
+/* For each Go type the compiler constructs one of these structures.
+ This is used for type reflectin, interfaces, maps, and reference
+ counting. */
+
+struct __go_type_descriptor
+{
+ /* The type code for this type, a value in enum __go_type_codes.
+ This is used by unsafe.Reflect and unsafe.Typeof to determine the
+ type descriptor to return for this type itself. It is also used
+ by reflect.toType when mapping to a reflect Type structure. */
+ unsigned char __code;
+
+ /* The alignment in bytes of a variable with this type. */
+ unsigned char __align;
+
+ /* The alignment in bytes of a struct field with this type. */
+ unsigned char __field_align;
+
+ /* The size in bytes of a value of this type. Note that all types
+ in Go have a fixed size. */
+ uintptr_t __size;
+
+ /* The type's hash code. */
+ uint32_t __hash;
+
+ /* This function takes a pointer to a value of this type, and the
+ size of this type, and returns a hash code. We pass the size
+ explicitly becaues it means that we can share a single instance
+ of this function for various different types. */
+ size_t (*__hashfn) (const void *, size_t);
+
+ /* This function takes two pointers to values of this type, and the
+ size of this type, and returns whether the values are equal. */
+ _Bool (*__equalfn) (const void *, const void *, size_t);
+
+ /* A string describing this type. This is only used for
+ debugging. */
+ const struct __go_string *__reflection;
+
+ /* A pointer to fields which are only used for some types. */
+ const struct __go_uncommon_type *__uncommon;
+};
+
+/* The information we store for each method of a type. */
+
+struct __go_method
+{
+ /* The name of the method. */
+ const struct __go_string *__name;
+
+ /* This is NULL for an exported method, or the name of the package
+ where it lives. */
+ const struct __go_string *__pkg_path;
+
+ /* The type of the method, without the receiver. This will be a
+ function type. */
+ const struct __go_type_descriptor *__mtype;
+
+ /* The type of the method, with the receiver. This will be a
+ function type. */
+ const struct __go_type_descriptor *__type;
+
+ /* A pointer to the code which implements the method. This is
+ really a function pointer. */
+ const void *__function;
+};
+
+/* Additional information that we keep for named types and for types
+ with methods. */
+
+struct __go_uncommon_type
+{
+ /* The name of the type. */
+ const struct __go_string *__name;
+
+ /* The type's package. This is NULL for builtin types. */
+ const struct __go_string *__pkg_path;
+
+ /* The type's methods. This is an array of struct __go_method. */
+ struct __go_open_array __methods;
+};
+
+/* The type descriptor for a fixed array type. */
+
+struct __go_array_type
+{
+ /* Starts like all type descriptors. */
+ struct __go_type_descriptor __common;
+
+ /* The element type. */
+ struct __go_type_descriptor *__element_type;
+
+ /* The length of the array. */
+ uintptr_t __len;
+};
+
+/* The type descriptor for a slice. */
+
+struct __go_slice_type
+{
+ /* Starts like all other type descriptors. */
+ struct __go_type_descriptor __common;
+
+ /* The element type. */
+ struct __go_type_descriptor *__element_type;
+};
+
+/* The direction of a channel. */
+#define CHANNEL_RECV_DIR 1
+#define CHANNEL_SEND_DIR 2
+#define CHANNEL_BOTH_DIR (CHANNEL_RECV_DIR | CHANNEL_SEND_DIR)
+
+/* The type descriptor for a channel. */
+
+struct __go_channel_type
+{
+ /* Starts like all other type descriptors. */
+ struct __go_type_descriptor __common;
+
+ /* The element type. */
+ const struct __go_type_descriptor *__element_type;
+
+ /* The direction. */
+ uintptr_t __dir;
+};
+
+/* The type descriptor for a function. */
+
+struct __go_func_type
+{
+ /* Starts like all other type descriptors. */
+ struct __go_type_descriptor __common;
+
+ /* Whether this is a varargs function. If this is true, there will
+ be at least one parameter. For "..." the last parameter type is
+ "interface{}". For "... T" the last parameter type is "[]T". */
+ _Bool __dotdotdot;
+
+ /* The input parameter types. This is an array of pointers to
+ struct __go_type_descriptor. */
+ struct __go_open_array __in;
+
+ /* The output parameter types. This is an array of pointers to
+ struct __go_type_descriptor. */
+ struct __go_open_array __out;
+};
+
+/* A method on an interface type. */
+
+struct __go_interface_method
+{
+ /* The name of the method. */
+ const struct __go_string *__name;
+
+ /* This is NULL for an exported method, or the name of the package
+ where it lives. */
+ const struct __go_string *__pkg_path;
+
+ /* The real type of the method. */
+ struct __go_type_descriptor *__type;
+};
+
+/* An interface type. */
+
+struct __go_interface_type
+{
+ /* Starts like all other type descriptors. */
+ struct __go_type_descriptor __common;
+
+ /* Array of __go_interface_method . The methods are sorted in the
+ same order that they appear in the definition of the
+ interface. */
+ struct __go_open_array __methods;
+};
+
+/* A map type. */
+
+struct __go_map_type
+{
+ /* Starts like all other type descriptors. */
+ struct __go_type_descriptor __common;
+
+ /* The map key type. */
+ const struct __go_type_descriptor *__key_type;
+
+ /* The map value type. */
+ const struct __go_type_descriptor *__val_type;
+};
+
+/* A pointer type. */
+
+struct __go_ptr_type
+{
+ /* Starts like all other type descriptors. */
+ struct __go_type_descriptor __common;
+
+ /* The type to which this points. */
+ const struct __go_type_descriptor *__element_type;
+};
+
+/* A field in a structure. */
+
+struct __go_struct_field
+{
+ /* The name of the field--NULL for an anonymous field. */
+ const struct __go_string *__name;
+
+ /* This is NULL for an exported method, or the name of the package
+ where it lives. */
+ const struct __go_string *__pkg_path;
+
+ /* The type of the field. */
+ const struct __go_type_descriptor *__type;
+
+ /* The field tag, or NULL. */
+ const struct __go_string *__tag;
+
+ /* The offset of the field in the struct. */
+ uintptr_t __offset;
+};
+
+/* A struct type. */
+
+struct __go_struct_type
+{
+ /* Starts like all other type descriptors. */
+ struct __go_type_descriptor __common;
+
+ /* An array of struct __go_struct_field. */
+ struct __go_open_array __fields;
+};
+
+/* Whether a type descriptor is a pointer. */
+
+static inline _Bool
+__go_is_pointer_type (const struct __go_type_descriptor *td)
+{
+ return td->__code == GO_PTR || td->__code == GO_UNSAFE_POINTER;
+}
+
+extern _Bool
+__go_type_descriptors_equal(const struct __go_type_descriptor*,
+ const struct __go_type_descriptor*);
+
+extern size_t __go_type_hash_identity (const void *, size_t);
+extern _Bool __go_type_equal_identity (const void *, const void *, size_t);
+extern size_t __go_type_hash_string (const void *, size_t);
+extern _Bool __go_type_equal_string (const void *, const void *, size_t);
+extern size_t __go_type_hash_interface (const void *, size_t);
+extern _Bool __go_type_equal_interface (const void *, const void *, size_t);
+extern size_t __go_type_hash_error (const void *, size_t);
+extern _Bool __go_type_equal_error (const void *, const void *, size_t);
+
+#endif /* !defined(LIBGO_GO_TYPE_H) */
diff --git a/libgo/runtime/go-typedesc-equal.c b/libgo/runtime/go-typedesc-equal.c
new file mode 100644
index 000000000..932519aab
--- /dev/null
+++ b/libgo/runtime/go-typedesc-equal.c
@@ -0,0 +1,38 @@
+/* go-typedesc-equal.c -- return whether two type descriptors are equal.
+
+ 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. */
+
+#include "go-string.h"
+#include "go-type.h"
+
+/* Compare type descriptors for equality. This is necessary because
+ types may have different descriptors in different shared libraries.
+ Also, unnamed types may have multiple type descriptors even in a
+ single shared library. */
+
+_Bool
+__go_type_descriptors_equal (const struct __go_type_descriptor *td1,
+ const struct __go_type_descriptor *td2)
+{
+ if (td1 == td2)
+ return 1;
+ /* In a type switch we can get a NULL descriptor. */
+ if (td1 == NULL || td2 == NULL)
+ return 0;
+ if (td1->__code != td2->__code || td1->__hash != td2->__hash)
+ return 0;
+ if (td1->__uncommon != NULL && td1->__uncommon->__name != NULL)
+ {
+ if (td2->__uncommon == NULL || td2->__uncommon->__name == NULL)
+ return 0;
+ return (__go_ptr_strings_equal (td1->__uncommon->__name,
+ td2->__uncommon->__name)
+ && __go_ptr_strings_equal (td1->__uncommon->__pkg_path,
+ td2->__uncommon->__pkg_path));
+ }
+ if (td2->__uncommon != NULL && td2->__uncommon->__name != NULL)
+ return 0;
+ return __go_ptr_strings_equal (td1->__reflection, td2->__reflection);
+}
diff --git a/libgo/runtime/go-typestring.c b/libgo/runtime/go-typestring.c
new file mode 100644
index 000000000..dcbbc6575
--- /dev/null
+++ b/libgo/runtime/go-typestring.c
@@ -0,0 +1,18 @@
+/* go-typestring.c -- the runtime.typestring function.
+
+ 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 "interface.h"
+#include "go-type.h"
+#include "go-string.h"
+
+struct __go_string typestring(struct __go_empty_interface)
+ asm ("libgo_runtime.runtime.typestring");
+
+struct __go_string
+typestring (struct __go_empty_interface e)
+{
+ return *e.__type_descriptor->__reflection;
+}
diff --git a/libgo/runtime/go-unreflect.c b/libgo/runtime/go-unreflect.c
new file mode 100644
index 000000000..886048548
--- /dev/null
+++ b/libgo/runtime/go-unreflect.c
@@ -0,0 +1,30 @@
+/* go-unreflect.c -- implement unsafe.Unreflect for Go.
+
+ 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. */
+
+#include "go-alloc.h"
+#include "go-type.h"
+#include "interface.h"
+
+/* Implement unsafe.Unreflect. */
+
+struct __go_empty_interface Unreflect (struct __go_empty_interface type,
+ void *object)
+ asm ("libgo_unsafe.unsafe.Unreflect");
+
+struct __go_empty_interface
+Unreflect (struct __go_empty_interface type, void *object)
+{
+ struct __go_empty_interface ret;
+
+ /* FIXME: We should check __type_descriptor to verify that this is
+ really a type descriptor. */
+ ret.__type_descriptor = type.__object;
+ if (__go_is_pointer_type (ret.__type_descriptor))
+ ret.__object = *(void **) object;
+ else
+ ret.__object = object;
+ return ret;
+}
diff --git a/libgo/runtime/go-unsafe-new.c b/libgo/runtime/go-unsafe-new.c
new file mode 100644
index 000000000..e55d415be
--- /dev/null
+++ b/libgo/runtime/go-unsafe-new.c
@@ -0,0 +1,27 @@
+/* go-unsafe-new.c -- unsafe.New function for Go.
+
+ 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. */
+
+#include "go-alloc.h"
+#include "go-type.h"
+#include "interface.h"
+
+/* Implement unsafe.New. */
+
+void *New (struct __go_empty_interface type) asm ("libgo_unsafe.unsafe.New");
+
+/* The dynamic type of the argument will be a pointer to a type
+ descriptor. */
+
+void *
+New (struct __go_empty_interface type)
+{
+ const struct __go_type_descriptor *descriptor;
+
+ /* FIXME: We should check __type_descriptor to verify that this is
+ really a type descriptor. */
+ descriptor = (const struct __go_type_descriptor *) type.__object;
+ return __go_alloc (descriptor->__size);
+}
diff --git a/libgo/runtime/go-unsafe-newarray.c b/libgo/runtime/go-unsafe-newarray.c
new file mode 100644
index 000000000..3bea2829f
--- /dev/null
+++ b/libgo/runtime/go-unsafe-newarray.c
@@ -0,0 +1,28 @@
+/* go-unsafe-newarray.c -- unsafe.NewArray function for Go.
+
+ 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. */
+
+#include "go-alloc.h"
+#include "go-type.h"
+#include "interface.h"
+
+/* Implement unsafe.NewArray. */
+
+void *NewArray (struct __go_empty_interface type, int n)
+ asm ("libgo_unsafe.unsafe.NewArray");
+
+/* The dynamic type of the argument will be a pointer to a type
+ descriptor. */
+
+void *
+NewArray (struct __go_empty_interface type, int n)
+{
+ const struct __go_type_descriptor *descriptor;
+
+ /* FIXME: We should check __type_descriptor to verify that this is
+ really a type descriptor. */
+ descriptor = (const struct __go_type_descriptor *) type.__object;
+ return __go_alloc (descriptor->__size * n);
+}
diff --git a/libgo/runtime/go-unsafe-pointer.c b/libgo/runtime/go-unsafe-pointer.c
new file mode 100644
index 000000000..804360f8a
--- /dev/null
+++ b/libgo/runtime/go-unsafe-pointer.c
@@ -0,0 +1,97 @@
+/* go-unsafe-pointer.c -- unsafe.Pointer type descriptor for Go.
+
+ 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. */
+
+#include <stddef.h>
+
+#include "go-string.h"
+#include "go-type.h"
+
+/* This file provides the type descriptor for the unsafe.Pointer type.
+ The unsafe package is defined by the compiler itself, which means
+ that there is no package to compile to define the type
+ descriptor. */
+
+extern const struct __go_type_descriptor unsafe_Pointer
+ asm ("__go_tdn_libgo_unsafe.unsafe.Pointer");
+
+/* Used to determine the field alignment. */
+struct field_align
+{
+ char c;
+ void *p;
+};
+
+/* The reflection string. */
+#define REFLECTION "unsafe.Pointer"
+static const struct __go_string reflection_string =
+{
+ (const unsigned char *) REFLECTION,
+ sizeof REFLECTION - 1
+};
+
+const struct __go_type_descriptor unsafe_Pointer =
+{
+ /* __code */
+ GO_UNSAFE_POINTER,
+ /* __align */
+ __alignof (void *),
+ /* __field_align */
+ offsetof (struct field_align, p) - 1,
+ /* __size */
+ sizeof (void *),
+ /* __hash */
+ 78501163U,
+ /* __hashfn */
+ __go_type_hash_identity,
+ /* __equalfn */
+ __go_type_equal_identity,
+ /* __reflection */
+ &reflection_string,
+ /* __uncommon */
+ NULL
+};
+
+/* We also need the type descriptor for the pointer to unsafe.Pointer,
+ since any package which refers to that type descriptor will expect
+ it to be defined elsewhere. */
+
+extern const struct __go_ptr_type pointer_unsafe_Pointer
+ asm ("__go_td_pN27_libgo_unsafe.unsafe.Pointer");
+
+/* The reflection string. */
+#define PREFLECTION "*unsafe.Pointer"
+static const struct __go_string preflection_string =
+{
+ (const unsigned char *) PREFLECTION,
+ sizeof PREFLECTION - 1,
+};
+
+const struct __go_ptr_type pointer_unsafe_Pointer =
+{
+ /* __common */
+ {
+ /* __code */
+ GO_PTR,
+ /* __align */
+ __alignof (void *),
+ /* __field_align */
+ offsetof (struct field_align, p) - 1,
+ /* __size */
+ sizeof (void *),
+ /* __hash */
+ 1256018616U,
+ /* __hashfn */
+ __go_type_hash_identity,
+ /* __equalfn */
+ __go_type_equal_identity,
+ /* __reflection */
+ &preflection_string,
+ /* __uncommon */
+ NULL
+ },
+ /* __element_type */
+ &unsafe_Pointer
+};
diff --git a/libgo/runtime/go-unwind.c b/libgo/runtime/go-unwind.c
new file mode 100644
index 000000000..c0fc59cef
--- /dev/null
+++ b/libgo/runtime/go-unwind.c
@@ -0,0 +1,426 @@
+/* go-unwind.c -- unwind the stack for panic/recover.
+
+ 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 "config.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "unwind.h"
+#define NO_SIZE_OF_ENCODED_VALUE
+#include "unwind-pe.h"
+
+#include "go-alloc.h"
+#include "go-defer.h"
+#include "go-panic.h"
+
+/* The code for a Go exception. */
+
+#ifdef __ARM_EABI_UNWINDER__
+static const _Unwind_Exception_Class __go_exception_class =
+ { 'G', 'N', 'U', 'C', 'G', 'O', '\0', '\0' };
+#else
+static const _Unwind_Exception_Class __go_exception_class =
+ ((((((((_Unwind_Exception_Class) 'G'
+ << 8 | (_Unwind_Exception_Class) 'N')
+ << 8 | (_Unwind_Exception_Class) 'U')
+ << 8 | (_Unwind_Exception_Class) 'C')
+ << 8 | (_Unwind_Exception_Class) 'G')
+ << 8 | (_Unwind_Exception_Class) 'O')
+ << 8 | (_Unwind_Exception_Class) '\0')
+ << 8 | (_Unwind_Exception_Class) '\0');
+#endif
+
+
+/* This function is called by exception handlers used when unwinding
+ the stack after a recovered panic. The exception handler looks
+ like this:
+ __go_check_defer (frame);
+ return;
+ If we have not yet reached the frame we are looking for, we
+ continue unwinding. */
+
+void
+__go_check_defer (void *frame)
+{
+ struct _Unwind_Exception *hdr;
+
+ if (__go_panic_defer == NULL)
+ {
+ /* Some other language has thrown an exception. We know there
+ are no defer handlers, so there is nothing to do. */
+ }
+ else if (__go_panic_defer->__is_foreign)
+ {
+ struct __go_panic_stack *n;
+ _Bool was_recovered;
+
+ /* Some other language has thrown an exception. We need to run
+ the local defer handlers. If they call recover, we stop
+ unwinding the stack here. */
+
+ n = ((struct __go_panic_stack *)
+ __go_alloc (sizeof (struct __go_panic_stack)));
+
+ n->__arg.__type_descriptor = NULL;
+ n->__arg.__object = NULL;
+ n->__was_recovered = 0;
+ n->__is_foreign = 1;
+ n->__next = __go_panic_defer->__panic;
+ __go_panic_defer->__panic = n;
+
+ while (1)
+ {
+ struct __go_defer_stack *d;
+ void (*pfn) (void *);
+
+ d = __go_panic_defer->__defer;
+ if (d == NULL || d->__frame != frame || d->__pfn == NULL)
+ break;
+
+ pfn = d->__pfn;
+ __go_panic_defer->__defer = d->__next;
+
+ (*pfn) (d->__arg);
+
+ __go_free (d);
+
+ if (n->__was_recovered)
+ {
+ /* The recover function caught the panic thrown by some
+ other language. */
+ break;
+ }
+ }
+
+ was_recovered = n->__was_recovered;
+ __go_panic_defer->__panic = n->__next;
+ __go_free (n);
+
+ if (was_recovered)
+ {
+ /* Just return and continue executing Go code. */
+ return;
+ }
+ }
+ else if (__go_panic_defer->__defer != NULL
+ && __go_panic_defer->__defer->__pfn == NULL
+ && __go_panic_defer->__defer->__frame == frame)
+ {
+ struct __go_defer_stack *d;
+
+ /* This is the defer function which called recover. Simply
+ return to stop the stack unwind, and let the Go code continue
+ to execute. */
+ d = __go_panic_defer->__defer;
+ __go_panic_defer->__defer = d->__next;
+ __go_free (d);
+ return;
+ }
+
+ /* This is some other defer function. It was already run by the
+ call to panic, or just above. Rethrow the exception. */
+
+ hdr = (struct _Unwind_Exception *) __go_panic_defer->__exception;
+
+#ifdef LIBGO_SJLJ_EXCEPTIONS
+ _Unwind_SjLj_Resume_or_Rethrow (hdr);
+#else
+#if defined(_LIBUNWIND_STD_ABI)
+ _Unwind_RaiseException (hdr);
+#else
+ _Unwind_Resume_or_Rethrow (hdr);
+#endif
+#endif
+
+ /* Rethrowing the exception should not return. */
+ abort();
+}
+
+/* Unwind function calls until we reach the one which used a defer
+ function which called recover. Each function which uses a defer
+ statement will have an exception handler, as shown above. */
+
+void
+__go_unwind_stack ()
+{
+ struct _Unwind_Exception *hdr;
+
+ hdr = ((struct _Unwind_Exception *)
+ __go_alloc (sizeof (struct _Unwind_Exception)));
+ __builtin_memcpy (&hdr->exception_class, &__go_exception_class,
+ sizeof hdr->exception_class);
+ hdr->exception_cleanup = NULL;
+
+ __go_panic_defer->__exception = hdr;
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+ _Unwind_SjLj_RaiseException (hdr);
+#else
+ _Unwind_RaiseException (hdr);
+#endif
+
+ /* Raising an exception should not return. */
+ abort ();
+}
+
+/* The rest of this code is really similar to gcc/unwind-c.c and
+ libjava/exception.cc. */
+
+typedef struct
+{
+ _Unwind_Ptr Start;
+ _Unwind_Ptr LPStart;
+ _Unwind_Ptr ttype_base;
+ const unsigned char *TType;
+ const unsigned char *action_table;
+ unsigned char ttype_encoding;
+ unsigned char call_site_encoding;
+} lsda_header_info;
+
+static const unsigned char *
+parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
+ lsda_header_info *info)
+{
+ _uleb128_t tmp;
+ unsigned char lpstart_encoding;
+
+ info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
+
+ /* Find @LPStart, the base to which landing pad offsets are relative. */
+ lpstart_encoding = *p++;
+ if (lpstart_encoding != DW_EH_PE_omit)
+ p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
+ else
+ info->LPStart = info->Start;
+
+ /* Find @TType, the base of the handler and exception spec type data. */
+ info->ttype_encoding = *p++;
+ if (info->ttype_encoding != DW_EH_PE_omit)
+ {
+ p = read_uleb128 (p, &tmp);
+ info->TType = p + tmp;
+ }
+ else
+ info->TType = 0;
+
+ /* The encoding and length of the call-site table; the action table
+ immediately follows. */
+ info->call_site_encoding = *p++;
+ p = read_uleb128 (p, &tmp);
+ info->action_table = p + tmp;
+
+ return p;
+}
+
+/* The personality function is invoked when unwinding the stack due to
+ a panic. Its job is to find the cleanup and exception handlers to
+ run. We can't split the stack here, because we won't be able to
+ unwind from that split. */
+
+#ifdef __ARM_EABI_UNWINDER__
+/* ARM EABI personality routines must also unwind the stack. */
+#define CONTINUE_UNWINDING \
+ do \
+ { \
+ if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \
+ return _URC_FAILURE; \
+ return _URC_CONTINUE_UNWIND; \
+ } \
+ while (0)
+#else
+#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
+#endif
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+#define PERSONALITY_FUNCTION __gccgo_personality_sj0
+#define __builtin_eh_return_data_regno(x) x
+#else
+#define PERSONALITY_FUNCTION __gccgo_personality_v0
+#endif
+
+#ifdef __ARM_EABI_UNWINDER__
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
+ struct _Unwind_Context *)
+ __attribute__ ((no_split_stack, flatten));
+
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (_Unwind_State state,
+ struct _Unwind_Exception * ue_header,
+ struct _Unwind_Context * context)
+#else
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
+ struct _Unwind_Exception *, struct _Unwind_Context *)
+ __attribute__ ((no_split_stack, flatten));
+
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (int version,
+ _Unwind_Action actions,
+ _Unwind_Exception_Class exception_class,
+ struct _Unwind_Exception *ue_header,
+ struct _Unwind_Context *context)
+#endif
+{
+ lsda_header_info info;
+ const unsigned char *language_specific_data, *p, *action_record;
+ _Unwind_Ptr landing_pad, ip;
+ int ip_before_insn = 0;
+ _Bool is_foreign;
+
+#ifdef __ARM_EABI_UNWINDER__
+ _Unwind_Action actions;
+
+ switch (state & _US_ACTION_MASK)
+ {
+ case _US_VIRTUAL_UNWIND_FRAME:
+ actions = _UA_SEARCH_PHASE;
+ break;
+
+ case _US_UNWIND_FRAME_STARTING:
+ actions = _UA_CLEANUP_PHASE;
+ if (!(state & _US_FORCE_UNWIND)
+ && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
+ actions |= _UA_HANDLER_FRAME;
+ break;
+
+ case _US_UNWIND_FRAME_RESUME:
+ CONTINUE_UNWINDING;
+ break;
+
+ default:
+ std::abort();
+ }
+ actions |= state & _US_FORCE_UNWIND;
+
+ is_foreign = 0;
+
+ /* The dwarf unwinder assumes the context structure holds things like the
+ function and LSDA pointers. The ARM implementation caches these in
+ the exception header (UCB). To avoid rewriting everything we make the
+ virtual IP register point at the UCB. */
+ ip = (_Unwind_Ptr) ue_header;
+ _Unwind_SetGR (context, 12, ip);
+#else
+ if (version != 1)
+ return _URC_FATAL_PHASE1_ERROR;
+
+ is_foreign = exception_class != __go_exception_class;
+#endif
+
+ language_specific_data = (const unsigned char *)
+ _Unwind_GetLanguageSpecificData (context);
+
+ /* If no LSDA, then there are no handlers or cleanups. */
+ if (! language_specific_data)
+ CONTINUE_UNWINDING;
+
+ /* Parse the LSDA header. */
+ p = parse_lsda_header (context, language_specific_data, &info);
+#ifdef HAVE_GETIPINFO
+ ip = _Unwind_GetIPInfo (context, &ip_before_insn);
+#else
+ ip = _Unwind_GetIP (context);
+#endif
+ if (! ip_before_insn)
+ --ip;
+ landing_pad = 0;
+ action_record = NULL;
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+ /* The given "IP" is an index into the call-site table, with two
+ exceptions -- -1 means no-action, and 0 means terminate. But
+ since we're using uleb128 values, we've not got random access
+ to the array. */
+ if ((int) ip <= 0)
+ return _URC_CONTINUE_UNWIND;
+ else
+ {
+ _uleb128_t cs_lp, cs_action;
+ do
+ {
+ p = read_uleb128 (p, &cs_lp);
+ p = read_uleb128 (p, &cs_action);
+ }
+ while (--ip);
+
+ /* Can never have null landing pad for sjlj -- that would have
+ been indicated by a -1 call site index. */
+ landing_pad = (_Unwind_Ptr)cs_lp + 1;
+ if (cs_action)
+ action_record = info.action_table + cs_action - 1;
+ goto found_something;
+ }
+#else
+ /* Search the call-site table for the action associated with this IP. */
+ while (p < info.action_table)
+ {
+ _Unwind_Ptr cs_start, cs_len, cs_lp;
+ _uleb128_t cs_action;
+
+ /* Note that all call-site encodings are "absolute" displacements. */
+ p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
+ p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
+ p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
+ p = read_uleb128 (p, &cs_action);
+
+ /* The table is sorted, so if we've passed the ip, stop. */
+ if (ip < info.Start + cs_start)
+ p = info.action_table;
+ else if (ip < info.Start + cs_start + cs_len)
+ {
+ if (cs_lp)
+ landing_pad = info.LPStart + cs_lp;
+ if (cs_action)
+ action_record = info.action_table + cs_action - 1;
+ goto found_something;
+ }
+ }
+#endif
+
+ /* IP is not in table. No associated cleanups. */
+ CONTINUE_UNWINDING;
+
+ found_something:
+ if (landing_pad == 0)
+ {
+ /* IP is present, but has a null landing pad.
+ No handler to be run. */
+ CONTINUE_UNWINDING;
+ }
+
+ if (actions & _UA_SEARCH_PHASE)
+ {
+ if (action_record == 0)
+ {
+ /* This indicates a cleanup rather than an exception
+ handler. */
+ CONTINUE_UNWINDING;
+ }
+
+ return _URC_HANDLER_FOUND;
+ }
+
+ /* It's possible for __go_panic_defer to be NULL here for an
+ exception thrown by a language other than Go. */
+ if (__go_panic_defer == NULL)
+ {
+ if (!is_foreign)
+ abort ();
+ }
+ else
+ {
+ __go_panic_defer->__exception = ue_header;
+ __go_panic_defer->__is_foreign = is_foreign;
+ }
+
+ _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
+ (_Unwind_Ptr) ue_header);
+ _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
+ _Unwind_SetIP (context, landing_pad);
+ return _URC_INSTALL_CONTEXT;
+}
diff --git a/libgo/runtime/goc2c.c b/libgo/runtime/goc2c.c
new file mode 100644
index 000000000..bf7483309
--- /dev/null
+++ b/libgo/runtime/goc2c.c
@@ -0,0 +1,735 @@
+// 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.
+
+/* Translate a .goc file into a .c file. A .goc file is a combination
+ of a limited form of Go with C. */
+
+/*
+ package PACKAGENAME
+ {# line}
+ func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
+ C code with proper brace nesting
+ \}
+*/
+
+/* We generate C code which implements the function such that it can
+ be called from Go and executes the C code. */
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* Whether we're emitting for gcc */
+static int gcc;
+
+/* Package prefix to use; only meaningful for gcc */
+static const char *prefix;
+
+/* File and line number */
+static const char *file;
+static unsigned int lineno = 1;
+
+/* List of names and types. */
+struct params {
+ struct params *next;
+ char *name;
+ char *type;
+};
+
+/* index into type_table */
+enum {
+ Bool,
+ Float,
+ Int,
+ Uint,
+ Uintptr,
+ String,
+ Slice,
+ Eface,
+};
+
+static struct {
+ char *name;
+ int size;
+} type_table[] = {
+ /* variable sized first, for easy replacement */
+ /* order matches enum above */
+ /* default is 32-bit architecture sizes */
+ "bool", 1,
+ "float", 4,
+ "int", 4,
+ "uint", 4,
+ "uintptr", 4,
+ "String", 8,
+ "Slice", 12,
+ "Eface", 8,
+
+ /* fixed size */
+ "float32", 4,
+ "float64", 8,
+ "byte", 1,
+ "int8", 1,
+ "uint8", 1,
+ "int16", 2,
+ "uint16", 2,
+ "int32", 4,
+ "uint32", 4,
+ "int64", 8,
+ "uint64", 8,
+
+ NULL,
+};
+
+/* Fixed structure alignment (non-gcc only) */
+int structround = 4;
+
+/* Unexpected EOF. */
+static void
+bad_eof(void)
+{
+ fprintf(stderr, "%s:%u: unexpected EOF\n", file, lineno);
+ exit(1);
+}
+
+/* Out of memory. */
+static void
+bad_mem(void)
+{
+ fprintf(stderr, "%s:%u: out of memory\n", file, lineno);
+ exit(1);
+}
+
+/* Allocate memory without fail. */
+static void *
+xmalloc(unsigned int size)
+{
+ void *ret = malloc(size);
+ if (ret == NULL)
+ bad_mem();
+ return ret;
+}
+
+/* Reallocate memory without fail. */
+static void*
+xrealloc(void *buf, unsigned int size)
+{
+ void *ret = realloc(buf, size);
+ if (ret == NULL)
+ bad_mem();
+ return ret;
+}
+
+/* Free a list of parameters. */
+static void
+free_params(struct params *p)
+{
+ while (p != NULL) {
+ struct params *next;
+
+ next = p->next;
+ free(p->name);
+ free(p->type);
+ free(p);
+ p = next;
+ }
+}
+
+/* Read a character, tracking lineno. */
+static int
+getchar_update_lineno(void)
+{
+ int c;
+
+ c = getchar();
+ if (c == '\n')
+ ++lineno;
+ return c;
+}
+
+/* Read a character, giving an error on EOF, tracking lineno. */
+static int
+getchar_no_eof(void)
+{
+ int c;
+
+ c = getchar_update_lineno();
+ if (c == EOF)
+ bad_eof();
+ return c;
+}
+
+/* Read a character, skipping comments. */
+static int
+getchar_skipping_comments(void)
+{
+ int c;
+
+ while (1) {
+ c = getchar_update_lineno();
+ if (c != '/')
+ return c;
+
+ c = getchar();
+ if (c == '/') {
+ do {
+ c = getchar_update_lineno();
+ } while (c != EOF && c != '\n');
+ return c;
+ } else if (c == '*') {
+ while (1) {
+ c = getchar_update_lineno();
+ if (c == EOF)
+ return EOF;
+ if (c == '*') {
+ do {
+ c = getchar_update_lineno();
+ } while (c == '*');
+ if (c == '/')
+ break;
+ }
+ }
+ } else {
+ ungetc(c, stdin);
+ return '/';
+ }
+ }
+}
+
+/* Read and return a token. Tokens are delimited by whitespace or by
+ [(),{}]. The latter are all returned as single characters. */
+static char *
+read_token(void)
+{
+ int c;
+ char *buf;
+ unsigned int alc, off;
+ const char* delims = "(),{}";
+
+ while (1) {
+ c = getchar_skipping_comments();
+ if (c == EOF)
+ return NULL;
+ if (!isspace(c))
+ break;
+ }
+ alc = 16;
+ buf = xmalloc(alc + 1);
+ off = 0;
+ if (strchr(delims, c) != NULL) {
+ buf[off] = c;
+ ++off;
+ } else {
+ while (1) {
+ if (off >= alc) {
+ alc *= 2;
+ buf = xrealloc(buf, alc + 1);
+ }
+ buf[off] = c;
+ ++off;
+ c = getchar_skipping_comments();
+ if (c == EOF)
+ break;
+ if (isspace(c) || strchr(delims, c) != NULL) {
+ if (c == '\n')
+ lineno--;
+ ungetc(c, stdin);
+ break;
+ }
+ }
+ }
+ buf[off] = '\0';
+ return buf;
+}
+
+/* Read a token, giving an error on EOF. */
+static char *
+read_token_no_eof(void)
+{
+ char *token = read_token();
+ if (token == NULL)
+ bad_eof();
+ return token;
+}
+
+/* Read the package clause, and return the package name. */
+static char *
+read_package(void)
+{
+ char *token;
+
+ token = read_token_no_eof();
+ if (strcmp(token, "package") != 0) {
+ fprintf(stderr,
+ "%s:%u: expected \"package\", got \"%s\"\n",
+ file, lineno, token);
+ exit(1);
+ }
+ return read_token_no_eof();
+}
+
+/* Read and copy preprocessor lines. */
+static void
+read_preprocessor_lines(void)
+{
+ while (1) {
+ int c;
+
+ do {
+ c = getchar_skipping_comments();
+ } while (isspace(c));
+ if (c != '#') {
+ ungetc(c, stdin);
+ break;
+ }
+ putchar(c);
+ do {
+ c = getchar_update_lineno();
+ putchar(c);
+ } while (c != '\n');
+ }
+}
+
+/* Read a type in Go syntax and return a type in C syntax. We only
+ permit basic types and pointers. */
+static char *
+read_type(void)
+{
+ char *p, *op, *q;
+ int pointer_count;
+ unsigned int len;
+
+ p = read_token_no_eof();
+ if (*p != '*')
+ return p;
+ op = p;
+ pointer_count = 0;
+ while (*p == '*') {
+ ++pointer_count;
+ ++p;
+ }
+ len = strlen(p);
+ q = xmalloc(len + pointer_count + 1);
+ memcpy(q, p, len);
+ while (pointer_count > 0) {
+ q[len] = '*';
+ ++len;
+ --pointer_count;
+ }
+ q[len] = '\0';
+ free(op);
+ return q;
+}
+
+/* Return the size of the given type. */
+static int
+type_size(char *p)
+{
+ int i;
+
+ if(p[strlen(p)-1] == '*')
+ return type_table[Uintptr].size;
+
+ for(i=0; type_table[i].name; i++)
+ if(strcmp(type_table[i].name, p) == 0)
+ return type_table[i].size;
+ if(!gcc) {
+ fprintf(stderr, "%s:%u: unknown type %s\n", file, lineno, p);
+ exit(1);
+ }
+ return 1;
+}
+
+/* Read a list of parameters. Each parameter is a name and a type.
+ The list ends with a ')'. We have already read the '('. */
+static struct params *
+read_params(int *poffset)
+{
+ char *token;
+ struct params *ret, **pp, *p;
+ int offset, size, rnd;
+
+ ret = NULL;
+ pp = &ret;
+ token = read_token_no_eof();
+ offset = 0;
+ if (strcmp(token, ")") != 0) {
+ while (1) {
+ p = xmalloc(sizeof(struct params));
+ p->name = token;
+ p->type = read_type();
+ p->next = NULL;
+ *pp = p;
+ pp = &p->next;
+
+ size = type_size(p->type);
+ rnd = size;
+ if(rnd > structround)
+ rnd = structround;
+ if(offset%rnd)
+ offset += rnd - offset%rnd;
+ offset += size;
+
+ token = read_token_no_eof();
+ if (strcmp(token, ",") != 0)
+ break;
+ token = read_token_no_eof();
+ }
+ }
+ if (strcmp(token, ")") != 0) {
+ fprintf(stderr, "%s:%u: expected '('\n",
+ file, lineno);
+ exit(1);
+ }
+ if (poffset != NULL)
+ *poffset = offset;
+ return ret;
+}
+
+/* Read a function header. This reads up to and including the initial
+ '{' character. Returns 1 if it read a header, 0 at EOF. */
+static int
+read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
+{
+ int lastline;
+ char *token;
+
+ lastline = -1;
+ while (1) {
+ token = read_token();
+ if (token == NULL)
+ return 0;
+ if (strcmp(token, "func") == 0) {
+ if(lastline != -1)
+ printf("\n");
+ break;
+ }
+ if (lastline != lineno) {
+ if (lastline == lineno-1)
+ printf("\n");
+ else
+ printf("\n#line %d \"%s\"\n", lineno, file);
+ lastline = lineno;
+ }
+ printf("%s ", token);
+ }
+
+ *name = read_token_no_eof();
+
+ token = read_token();
+ if (token == NULL || strcmp(token, "(") != 0) {
+ fprintf(stderr, "%s:%u: expected \"(\"\n",
+ file, lineno);
+ exit(1);
+ }
+ *params = read_params(paramwid);
+
+ token = read_token();
+ if (token == NULL || strcmp(token, "(") != 0)
+ *rets = NULL;
+ else {
+ *rets = read_params(NULL);
+ token = read_token();
+ }
+ if (token == NULL || strcmp(token, "{") != 0) {
+ fprintf(stderr, "%s:%u: expected \"{\"\n",
+ file, lineno);
+ exit(1);
+ }
+ return 1;
+}
+
+/* Write out parameters. */
+static void
+write_params(struct params *params, int *first)
+{
+ struct params *p;
+
+ for (p = params; p != NULL; p = p->next) {
+ if (*first)
+ *first = 0;
+ else
+ printf(", ");
+ printf("%s %s", p->type, p->name);
+ }
+}
+
+/* Write a 6g function header. */
+static void
+write_6g_func_header(char *package, char *name, struct params *params,
+ int paramwid, struct params *rets)
+{
+ int first, n;
+
+ printf("void\n%s·%s(", package, name);
+ first = 1;
+ write_params(params, &first);
+
+ /* insert padding to align output struct */
+ if(rets != NULL && paramwid%structround != 0) {
+ n = structround - paramwid%structround;
+ if(n & 1)
+ printf(", uint8");
+ if(n & 2)
+ printf(", uint16");
+ if(n & 4)
+ printf(", uint32");
+ }
+
+ write_params(rets, &first);
+ printf(")\n{\n");
+}
+
+/* Write a 6g function trailer. */
+static void
+write_6g_func_trailer(struct params *rets)
+{
+ struct params *p;
+
+ for (p = rets; p != NULL; p = p->next)
+ printf("\tFLUSH(&%s);\n", p->name);
+ printf("}\n");
+}
+
+/* Define the gcc function return type if necessary. */
+static void
+define_gcc_return_type(char *package, char *name, struct params *rets)
+{
+ struct params *p;
+
+ if (rets == NULL || rets->next == NULL)
+ return;
+ printf("struct %s_%s_ret {\n", package, name);
+ for (p = rets; p != NULL; p = p->next)
+ printf(" %s %s;\n", p->type, p->name);
+ printf("};\n");
+}
+
+/* Write out the gcc function return type. */
+static void
+write_gcc_return_type(char *package, char *name, struct params *rets)
+{
+ if (rets == NULL)
+ printf("void");
+ else if (rets->next == NULL)
+ printf("%s", rets->type);
+ else
+ printf("struct %s_%s_ret", package, name);
+}
+
+/* Write out a gcc function header. */
+static void
+write_gcc_func_header(char *package, char *name, struct params *params,
+ struct params *rets)
+{
+ int first;
+ struct params *p;
+
+ define_gcc_return_type(package, name, rets);
+ write_gcc_return_type(package, name, rets);
+ printf(" %s_%s(", package, name);
+ first = 1;
+ write_params(params, &first);
+ printf(") asm (\"");
+ if (prefix != NULL)
+ printf("%s.", prefix);
+ printf("%s.%s\");\n", package, name);
+ write_gcc_return_type(package, name, rets);
+ printf(" %s_%s(", package, name);
+ first = 1;
+ write_params(params, &first);
+ printf(")\n{\n");
+ for (p = rets; p != NULL; p = p->next)
+ printf(" %s %s;\n", p->type, p->name);
+}
+
+/* Write out a gcc function trailer. */
+static void
+write_gcc_func_trailer(char *package, char *name, struct params *rets)
+{
+ if (rets == NULL)
+ ;
+ else if (rets->next == NULL)
+ printf("return %s;\n", rets->name);
+ else {
+ struct params *p;
+
+ printf(" {\n struct %s_%s_ret __ret;\n", package, name);
+ for (p = rets; p != NULL; p = p->next)
+ printf(" __ret.%s = %s;\n", p->name, p->name);
+ printf(" return __ret;\n }\n");
+ }
+ printf("}\n");
+}
+
+/* Write out a function header. */
+static void
+write_func_header(char *package, char *name,
+ struct params *params, int paramwid,
+ struct params *rets)
+{
+ if (gcc)
+ write_gcc_func_header(package, name, params, rets);
+ else
+ write_6g_func_header(package, name, params, paramwid, rets);
+ printf("#line %d \"%s\"\n", lineno, file);
+}
+
+/* Write out a function trailer. */
+static void
+write_func_trailer(char *package, char *name,
+ struct params *rets)
+{
+ if (gcc)
+ write_gcc_func_trailer(package, name, rets);
+ else
+ write_6g_func_trailer(rets);
+}
+
+/* Read and write the body of the function, ending in an unnested }
+ (which is read but not written). */
+static void
+copy_body(void)
+{
+ int nesting = 0;
+ while (1) {
+ int c;
+
+ c = getchar_no_eof();
+ if (c == '}' && nesting == 0)
+ return;
+ putchar(c);
+ switch (c) {
+ default:
+ break;
+ case '{':
+ ++nesting;
+ break;
+ case '}':
+ --nesting;
+ break;
+ case '/':
+ c = getchar_update_lineno();
+ putchar(c);
+ if (c == '/') {
+ do {
+ c = getchar_no_eof();
+ putchar(c);
+ } while (c != '\n');
+ } else if (c == '*') {
+ while (1) {
+ c = getchar_no_eof();
+ putchar(c);
+ if (c == '*') {
+ do {
+ c = getchar_no_eof();
+ putchar(c);
+ } while (c == '*');
+ if (c == '/')
+ break;
+ }
+ }
+ }
+ break;
+ case '"':
+ case '\'':
+ {
+ int delim = c;
+ do {
+ c = getchar_no_eof();
+ putchar(c);
+ if (c == '\\') {
+ c = getchar_no_eof();
+ putchar(c);
+ c = '\0';
+ }
+ } while (c != delim);
+ }
+ break;
+ }
+ }
+}
+
+/* Process the entire file. */
+static void
+process_file(void)
+{
+ char *package, *name;
+ struct params *params, *rets;
+ int paramwid;
+
+ package = read_package();
+ read_preprocessor_lines();
+ while (read_func_header(&name, &params, &paramwid, &rets)) {
+ write_func_header(package, name, params, paramwid, rets);
+ copy_body();
+ write_func_trailer(package, name, rets);
+ free(name);
+ free_params(params);
+ free_params(rets);
+ }
+ free(package);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: goc2c [--6g | --gc] [--go-prefix PREFIX] [file]\n");
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ char *goarch;
+
+ while(argc > 1 && argv[1][0] == '-') {
+ if(strcmp(argv[1], "-") == 0)
+ break;
+ if(strcmp(argv[1], "--6g") == 0)
+ gcc = 0;
+ else if(strcmp(argv[1], "--gcc") == 0)
+ gcc = 1;
+ else if (strcmp(argv[1], "--go-prefix") == 0 && argc > 2) {
+ prefix = argv[2];
+ argc--;
+ argv++;
+ } else
+ usage();
+ argc--;
+ argv++;
+ }
+
+ if(argc <= 1 || strcmp(argv[1], "-") == 0) {
+ file = "<stdin>";
+ process_file();
+ return 0;
+ }
+
+ if(argc > 2)
+ usage();
+
+ file = argv[1];
+ if(freopen(file, "r", stdin) == 0) {
+ fprintf(stderr, "open %s: %s\n", file, strerror(errno));
+ exit(1);
+ }
+
+ if(!gcc) {
+ // 6g etc; update size table
+ goarch = getenv("GOARCH");
+ if(goarch != NULL && strcmp(goarch, "amd64") == 0) {
+ type_table[Uintptr].size = 8;
+ type_table[String].size = 16;
+ type_table[Slice].size = 8+4+4;
+ type_table[Eface].size = 8+8;
+ structround = 8;
+ }
+ }
+
+ process_file();
+ return 0;
+}
diff --git a/libgo/runtime/iface.goc b/libgo/runtime/iface.goc
new file mode 100644
index 000000000..356b318cb
--- /dev/null
+++ b/libgo/runtime/iface.goc
@@ -0,0 +1,131 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+#include "go-type.h"
+#include "interface.h"
+#define nil NULL
+
+typedef _Bool bool;
+typedef struct __go_type_descriptor descriptor;
+typedef const struct __go_type_descriptor const_descriptor;
+typedef struct __go_interface interface;
+typedef struct __go_empty_interface empty_interface;
+
+// Compare two type descriptors.
+func ifacetypeeq(a *descriptor, b *descriptor) (eq bool) {
+ eq = __go_type_descriptors_equal(a, b);
+}
+
+// Return the descriptor for an empty interface type.n
+func efacetype(e empty_interface) (d *const_descriptor) {
+ return e.__type_descriptor;
+}
+
+// Return the descriptor for a non-empty interface type.
+func ifacetype(i interface) (d *const_descriptor) {
+ if (i.__methods == nil) {
+ return nil;
+ }
+ d = i.__methods[0];
+}
+
+// Convert an empty interface to an empty interface.
+func ifaceE2E2(e empty_interface) (ret empty_interface, ok bool) {
+ ret = e;
+ ok = ret.__type_descriptor != nil;
+}
+
+// Convert a non-empty interface to an empty interface.
+func ifaceI2E2(i interface) (ret empty_interface, ok bool) {
+ if (i.__methods == nil) {
+ ret.__type_descriptor = nil;
+ ret.__object = nil;
+ ok = 0;
+ } else {
+ ret.__type_descriptor = i.__methods[0];
+ ret.__object = i.__object;
+ ok = 1;
+ }
+}
+
+// Convert an empty interface to a non-empty interface.
+func ifaceE2I2(inter *descriptor, e empty_interface) (ret interface, ok bool) {
+ if (e.__type_descriptor == nil) {
+ ret.__methods = nil;
+ ret.__object = nil;
+ ok = 0;
+ } else {
+ ret.__methods = __go_convert_interface_2(inter,
+ e.__type_descriptor,
+ 1);
+ ret.__object = e.__object;
+ ok = ret.__methods != nil;
+ }
+}
+
+// Convert a non-empty interface to a non-empty interface.
+func ifaceI2I2(inter *descriptor, i interface) (ret interface, ok bool) {
+ if (i.__methods == nil) {
+ ret.__methods = nil;
+ ret.__object = nil;
+ ok = 0;
+ } else {
+ ret.__methods = __go_convert_interface_2(inter,
+ i.__methods[0], 1);
+ ret.__object = i.__object;
+ ok = ret.__methods != nil;
+ }
+}
+
+// Convert an empty interface to a pointer type.
+func ifaceE2T2P(inter *descriptor, e empty_interface) (ret *void, ok bool) {
+ if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) {
+ ret = nil;
+ ok = 0;
+ } else {
+ ret = e.__object;
+ ok = 1;
+ }
+}
+
+// Convert a non-empty interface to a pointer type.
+func ifaceI2T2P(inter *descriptor, i interface) (ret *void, ok bool) {
+ if (i.__methods == nil
+ || !__go_type_descriptors_equal(inter, i.__methods[0])) {
+ ret = nil;
+ ok = 0;
+ } else {
+ ret = i.__object;
+ ok = 1;
+ }
+}
+
+// Convert an empty interface to a non-pointer type.
+func ifaceE2T2(inter *descriptor, e empty_interface, ret *void) (ok bool) {
+ if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) {
+ __builtin_memset(ret, 0, inter->__size);
+ ok = 0;
+ } else {
+ __builtin_memcpy(ret, e.__object, inter->__size);
+ ok = 1;
+ }
+}
+
+// Convert a non-empty interface to a non-pointer type.
+func ifaceI2T2(inter *descriptor, i interface, ret *void) (ok bool) {
+ if (i.__methods == nil
+ || !__go_type_descriptors_equal(inter, i.__methods[0])) {
+ __builtin_memset(ret, 0, inter->__size);
+ ok = 0;
+ } else {
+ __builtin_memcpy(ret, i.__object, inter->__size);
+ ok = 1;
+ }
+}
+
+// Return whether we can convert an interface to a type.
+func ifaceI2Tp(to *descriptor, from *descriptor) (ok bool) {
+ ok = __go_can_convert_to_interface(to, from);
+}
diff --git a/libgo/runtime/interface.h b/libgo/runtime/interface.h
new file mode 100644
index 000000000..610f20890
--- /dev/null
+++ b/libgo/runtime/interface.h
@@ -0,0 +1,57 @@
+/* interface.h -- the interface type for Go.
+
+ 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. */
+
+#ifndef LIBGO_INTERFACE_H
+#define LIBGO_INTERFACE_H
+
+#include "go-type.h"
+
+/* A variable of interface type is an instance of this struct, if the
+ interface has any methods. */
+
+struct __go_interface
+{
+ /* A pointer to the interface method table. The first pointer is
+ the type descriptor of the object. Subsequent pointers are
+ pointers to functions. This is effectively the vtable for this
+ interface. The function pointers are in the same order as the
+ list in the internal representation of the interface, which sorts
+ them by name. */
+ const void **__methods;
+
+ /* The object. If the object is a pointer--if the type descriptor
+ code is GO_PTR or GO_UNSAFE_POINTER--then this field is the value
+ of the object itself. Otherwise this is a pointer to memory
+ which holds the value. */
+ void *__object;
+};
+
+/* A variable of an empty interface type is an instance of this
+ struct. */
+
+struct __go_empty_interface
+{
+ /* The type descriptor of the object. */
+ const struct __go_type_descriptor *__type_descriptor;
+
+ /* The object. This is the same as __go_interface above. */
+ void *__object;
+};
+
+extern void *
+__go_convert_interface (const struct __go_type_descriptor *,
+ const struct __go_type_descriptor *);
+
+extern void *
+__go_convert_interface_2 (const struct __go_type_descriptor *,
+ const struct __go_type_descriptor *,
+ _Bool may_fail);
+
+extern _Bool
+__go_can_convert_to_interface(const struct __go_type_descriptor *,
+ const struct __go_type_descriptor *);
+
+#endif /* !defined(LIBGO_INTERFACE_H) */
diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc
new file mode 100644
index 000000000..d826d479f
--- /dev/null
+++ b/libgo/runtime/malloc.goc
@@ -0,0 +1,357 @@
+// 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.
+
+// See malloc.h for overview.
+//
+// TODO(rsc): double-check stats.
+
+package runtime
+#include <stddef.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "go-alloc.h"
+#include "runtime.h"
+#include "malloc.h"
+#include "go-string.h"
+#include "interface.h"
+#include "go-type.h"
+typedef struct __go_empty_interface Eface;
+typedef struct __go_type_descriptor Type;
+typedef struct __go_func_type FuncType;
+
+MHeap runtime_mheap;
+extern MStats mstats; // defined in extern.go
+
+extern volatile int32 runtime_MemProfileRate
+ __asm__ ("libgo_runtime.runtime.MemProfileRate");
+
+// Same algorithm from chan.c, but a different
+// instance of the static uint32 x.
+// Not protected by a lock - let the threads use
+// the same random number if they like.
+static uint32
+fastrand1(void)
+{
+ static uint32 x = 0x49f6428aUL;
+
+ x += x;
+ if(x & 0x80000000L)
+ x ^= 0x88888eefUL;
+ return x;
+}
+
+// Allocate an object of at least size bytes.
+// Small objects are allocated from the per-thread cache's free lists.
+// Large objects (> 32 kB) are allocated straight from the heap.
+void*
+runtime_mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
+{
+ int32 sizeclass, rate;
+ MCache *c;
+ uintptr npages;
+ MSpan *s;
+ void *v;
+ uint32 *ref;
+
+ if(!__sync_bool_compare_and_swap(&m->mallocing, 0, 1))
+ runtime_throw("malloc/free - deadlock");
+ if(size == 0)
+ size = 1;
+
+ mstats.nmalloc++;
+ if(size <= MaxSmallSize) {
+ // Allocate from mcache free lists.
+ sizeclass = runtime_SizeToClass(size);
+ size = runtime_class_to_size[sizeclass];
+ c = m->mcache;
+ v = runtime_MCache_Alloc(c, sizeclass, size, zeroed);
+ if(v == nil)
+ runtime_throw("out of memory");
+ mstats.alloc += size;
+ mstats.total_alloc += size;
+ mstats.by_size[sizeclass].nmalloc++;
+
+ if(!runtime_mlookup(v, nil, nil, nil, &ref)) {
+ // runtime_printf("malloc %D; runtime_mlookup failed\n", (uint64)size);
+ runtime_throw("malloc runtime_mlookup");
+ }
+ *ref = RefNone | refflag;
+ } else {
+ // TODO(rsc): Report tracebacks for very large allocations.
+
+ // Allocate directly from heap.
+ npages = size >> PageShift;
+ if((size & PageMask) != 0)
+ npages++;
+ s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, 1);
+ if(s == nil)
+ runtime_throw("out of memory");
+ size = npages<<PageShift;
+ mstats.alloc += size;
+ mstats.total_alloc += size;
+ v = (void*)(s->start << PageShift);
+
+ // setup for mark sweep
+ s->gcref0 = RefNone | refflag;
+ ref = &s->gcref0;
+ }
+
+ __sync_bool_compare_and_swap(&m->mallocing, 1, 0);
+
+ if(__sync_bool_compare_and_swap(&m->gcing, 1, 0)) {
+ if(!(refflag & RefNoProfiling))
+ __go_run_goroutine_gc(0);
+ else {
+ // We are being called from the profiler. Tell it
+ // to invoke the garbage collector when it is
+ // done. No need to use a sync function here.
+ m->gcing_for_prof = 1;
+ }
+ }
+
+ if(!(refflag & RefNoProfiling) && (rate = runtime_MemProfileRate) > 0) {
+ if(size >= (uint32) rate)
+ goto profile;
+ if((uint32) m->mcache->next_sample > size)
+ m->mcache->next_sample -= size;
+ else {
+ // pick next profile time
+ if(rate > 0x3fffffff) // make 2*rate not overflow
+ rate = 0x3fffffff;
+ m->mcache->next_sample = fastrand1() % (2*rate);
+ profile:
+ *ref |= RefProfiled;
+ runtime_MProf_Malloc(v, size);
+ }
+ }
+
+ if(dogc && mstats.heap_alloc >= mstats.next_gc)
+ runtime_gc(0);
+ return v;
+}
+
+void*
+__go_alloc(uintptr size)
+{
+ return runtime_mallocgc(size, 0, 0, 1);
+}
+
+// Free the object whose base pointer is v.
+void
+__go_free(void *v)
+{
+ int32 sizeclass, size;
+ MSpan *s;
+ MCache *c;
+ uint32 prof, *ref;
+
+ if(v == nil)
+ return;
+
+ if(!__sync_bool_compare_and_swap(&m->mallocing, 0, 1))
+ runtime_throw("malloc/free - deadlock");
+
+ if(!runtime_mlookup(v, nil, nil, &s, &ref)) {
+ // runtime_printf("free %p: not an allocated block\n", v);
+ runtime_throw("free runtime_mlookup");
+ }
+ prof = *ref & RefProfiled;
+ *ref = RefFree;
+
+ // Find size class for v.
+ sizeclass = s->sizeclass;
+ if(sizeclass == 0) {
+ // Large object.
+ if(prof)
+ runtime_MProf_Free(v, s->npages<<PageShift);
+ mstats.alloc -= s->npages<<PageShift;
+ runtime_memclr(v, s->npages<<PageShift);
+ runtime_MHeap_Free(&runtime_mheap, s, 1);
+ } else {
+ // Small object.
+ c = m->mcache;
+ size = runtime_class_to_size[sizeclass];
+ if(size > (int32)sizeof(uintptr))
+ ((uintptr*)v)[1] = 1; // mark as "needs to be zeroed"
+ if(prof)
+ runtime_MProf_Free(v, size);
+ mstats.alloc -= size;
+ mstats.by_size[sizeclass].nfree++;
+ runtime_MCache_Free(c, v, sizeclass, size);
+ }
+ __sync_bool_compare_and_swap(&m->mallocing, 1, 0);
+
+ if(__sync_bool_compare_and_swap(&m->gcing, 1, 0))
+ __go_run_goroutine_gc(1);
+}
+
+int32
+runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
+{
+ uintptr n, nobj, i;
+ byte *p;
+ MSpan *s;
+
+ mstats.nlookup++;
+ s = runtime_MHeap_LookupMaybe(&runtime_mheap, (uintptr)v>>PageShift);
+ if(sp)
+ *sp = s;
+ if(s == nil) {
+ if(base)
+ *base = nil;
+ if(size)
+ *size = 0;
+ if(ref)
+ *ref = 0;
+ return 0;
+ }
+
+ p = (byte*)((uintptr)s->start<<PageShift);
+ if(s->sizeclass == 0) {
+ // Large object.
+ if(base)
+ *base = p;
+ if(size)
+ *size = s->npages<<PageShift;
+ if(ref)
+ *ref = &s->gcref0;
+ return 1;
+ }
+
+ if((byte*)v >= (byte*)s->gcref) {
+ // pointers into the gc ref counts
+ // do not count as pointers.
+ return 0;
+ }
+
+ n = runtime_class_to_size[s->sizeclass];
+ i = ((byte*)v - p)/n;
+ if(base)
+ *base = p + i*n;
+ if(size)
+ *size = n;
+
+ // good for error checking, but expensive
+ if(0) {
+ nobj = (s->npages << PageShift) / (n + RefcountOverhead);
+ if((byte*)s->gcref < p || (byte*)(s->gcref+nobj) > p+(s->npages<<PageShift)) {
+ // runtime_printf("odd span state=%d span=%p base=%p sizeclass=%d n=%D size=%D npages=%D\n",
+ // s->state, s, p, s->sizeclass, (uint64)nobj, (uint64)n, (uint64)s->npages);
+ // runtime_printf("s->base sizeclass %d v=%p base=%p gcref=%p blocksize=%D nobj=%D size=%D end=%p end=%p\n",
+ // s->sizeclass, v, p, s->gcref, (uint64)s->npages<<PageShift,
+ // (uint64)nobj, (uint64)n, s->gcref + nobj, p+(s->npages<<PageShift));
+ runtime_throw("bad gcref");
+ }
+ }
+ if(ref)
+ *ref = &s->gcref[i];
+
+ return 1;
+}
+
+MCache*
+runtime_allocmcache(void)
+{
+ MCache *c;
+
+ if(!__sync_bool_compare_and_swap(&m->mallocing, 0, 1))
+ runtime_throw("allocmcache - deadlock");
+
+ runtime_lock(&runtime_mheap);
+ c = runtime_FixAlloc_Alloc(&runtime_mheap.cachealloc);
+
+ // Clear the free list used by FixAlloc; assume the rest is zeroed.
+ c->list[0].list = nil;
+
+ mstats.mcache_inuse = runtime_mheap.cachealloc.inuse;
+ mstats.mcache_sys = runtime_mheap.cachealloc.sys;
+ runtime_unlock(&runtime_mheap);
+
+ __sync_bool_compare_and_swap(&m->mallocing, 1, 0);
+ if(__sync_bool_compare_and_swap(&m->gcing, 1, 0))
+ __go_run_goroutine_gc(2);
+
+ return c;
+}
+
+extern int32 runtime_sizeof_C_MStats
+ __asm__ ("libgo_runtime.runtime.Sizeof_C_MStats");
+
+void
+runtime_mallocinit(void)
+{
+ runtime_sizeof_C_MStats = sizeof(MStats);
+
+ runtime_initfintab();
+ runtime_Mprof_Init();
+
+ runtime_SysMemInit();
+ runtime_InitSizes();
+ runtime_MHeap_Init(&runtime_mheap, runtime_SysAlloc);
+ m->mcache = runtime_allocmcache();
+
+ // See if it works.
+ runtime_free(runtime_malloc(1));
+}
+
+// Runtime stubs.
+
+void*
+runtime_mal(uintptr n)
+{
+ return runtime_mallocgc(n, 0, 1, 1);
+}
+
+func Alloc(n uintptr) (p *byte) {
+ p = runtime_malloc(n);
+}
+
+func Free(p *byte) {
+ runtime_free(p);
+}
+
+func Lookup(p *byte) (base *byte, size uintptr) {
+ runtime_mlookup(p, &base, &size, nil, nil);
+}
+
+func GC() {
+ runtime_gc(1);
+}
+
+func SetFinalizer(obj Eface, finalizer Eface) {
+ byte *base;
+ uintptr size;
+ const FuncType *ft;
+
+ if(obj.__type_descriptor == nil) {
+ // runtime_printf("runtime.SetFinalizer: first argument is nil interface\n");
+ throw:
+ runtime_throw("runtime.SetFinalizer");
+ }
+ if(obj.__type_descriptor->__code != GO_PTR) {
+ // runtime_printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
+ goto throw;
+ }
+ if(!runtime_mlookup(obj.__object, &base, &size, nil, nil) || obj.__object != base) {
+ // runtime_printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
+ goto throw;
+ }
+ ft = nil;
+ if(finalizer.__type_descriptor != nil) {
+ if(finalizer.__type_descriptor->__code != GO_FUNC) {
+ badfunc:
+ // runtime_printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string);
+ goto throw;
+ }
+ ft = (const FuncType*)finalizer.__type_descriptor;
+ if(ft->__dotdotdot || ft->__in.__count != 1 || !__go_type_descriptors_equal(*(Type**)ft->__in.__values, obj.__type_descriptor))
+ goto badfunc;
+
+ if(runtime_getfinalizer(obj.__object, 0)) {
+ // runtime_printf("runtime.SetFinalizer: finalizer already set");
+ goto throw;
+ }
+ }
+ runtime_addfinalizer(obj.__object, finalizer.__type_descriptor != nil ? *(void**)finalizer.__object : nil, ft);
+}
diff --git a/libgo/runtime/malloc.h b/libgo/runtime/malloc.h
new file mode 100644
index 000000000..369f9b8e7
--- /dev/null
+++ b/libgo/runtime/malloc.h
@@ -0,0 +1,399 @@
+// 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.
+
+// Memory allocator, based on tcmalloc.
+// http://goog-perftools.sourceforge.net/doc/tcmalloc.html
+
+// The main allocator works in runs of pages.
+// Small allocation sizes (up to and including 32 kB) are
+// rounded to one of about 100 size classes, each of which
+// has its own free list of objects of exactly that size.
+// Any free page of memory can be split into a set of objects
+// of one size class, which are then managed using free list
+// allocators.
+//
+// The allocator's data structures are:
+//
+// FixAlloc: a free-list allocator for fixed-size objects,
+// used to manage storage used by the allocator.
+// MHeap: the malloc heap, managed at page (4096-byte) granularity.
+// MSpan: a run of pages managed by the MHeap.
+// MHeapMap: a mapping from page IDs to MSpans.
+// MCentral: a shared free list for a given size class.
+// MCache: a per-thread (in Go, per-M) cache for small objects.
+// MStats: allocation statistics.
+//
+// Allocating a small object proceeds up a hierarchy of caches:
+//
+// 1. Round the size up to one of the small size classes
+// and look in the corresponding MCache free list.
+// If the list is not empty, allocate an object from it.
+// This can all be done without acquiring a lock.
+//
+// 2. If the MCache free list is empty, replenish it by
+// taking a bunch of objects from the MCentral free list.
+// Moving a bunch amortizes the cost of acquiring the MCentral lock.
+//
+// 3. If the MCentral free list is empty, replenish it by
+// allocating a run of pages from the MHeap and then
+// chopping that memory into a objects of the given size.
+// Allocating many objects amortizes the cost of locking
+// the heap.
+//
+// 4. If the MHeap is empty or has no page runs large enough,
+// allocate a new group of pages (at least 1MB) from the
+// operating system. Allocating a large run of pages
+// amortizes the cost of talking to the operating system.
+//
+// Freeing a small object proceeds up the same hierarchy:
+//
+// 1. Look up the size class for the object and add it to
+// the MCache free list.
+//
+// 2. If the MCache free list is too long or the MCache has
+// too much memory, return some to the MCentral free lists.
+//
+// 3. If all the objects in a given span have returned to
+// the MCentral list, return that span to the page heap.
+//
+// 4. If the heap has too much memory, return some to the
+// operating system.
+//
+// TODO(rsc): Step 4 is not implemented.
+//
+// Allocating and freeing a large object uses the page heap
+// directly, bypassing the MCache and MCentral free lists.
+//
+// The small objects on the MCache and MCentral free lists
+// may or may not be zeroed. They are zeroed if and only if
+// the second word of the object is zero. The spans in the
+// page heap are always zeroed. When a span full of objects
+// is returned to the page heap, the objects that need to be
+// are zeroed first. There are two main benefits to delaying the
+// zeroing this way:
+//
+// 1. stack frames allocated from the small object lists
+// can avoid zeroing altogether.
+// 2. the cost of zeroing when reusing a small object is
+// charged to the mutator, not the garbage collector.
+//
+// This C code was written with an eye toward translating to Go
+// in the future. Methods have the form Type_Method(Type *t, ...).
+
+typedef struct FixAlloc FixAlloc;
+typedef struct MCentral MCentral;
+typedef struct MHeap MHeap;
+typedef struct MHeapMap MHeapMap;
+typedef struct MSpan MSpan;
+typedef struct MStats MStats;
+typedef struct MLink MLink;
+
+enum
+{
+ PageShift = 12,
+ PageSize = 1<<PageShift,
+ PageMask = PageSize - 1,
+};
+typedef uintptr PageID; // address >> PageShift
+
+enum
+{
+ // Tunable constants.
+ NumSizeClasses = 67, // Number of size classes (must match msize.c)
+ MaxSmallSize = 32<<10,
+
+ FixAllocChunk = 128<<10, // Chunk size for FixAlloc
+ MaxMCacheListLen = 256, // Maximum objects on MCacheList
+ MaxMCacheSize = 2<<20, // Maximum bytes in one MCache
+ MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap.
+ HeapAllocChunk = 1<<20, // Chunk size for heap growth
+};
+
+#if __SIZEOF_POINTER__ == 8
+#include "mheapmap64.h"
+#else
+#include "mheapmap32.h"
+#endif
+
+// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).)
+struct MLink
+{
+ MLink *next;
+};
+
+// SysAlloc obtains a large chunk of zeroed memory from the
+// operating system, typically on the order of a hundred kilobytes
+// or a megabyte.
+//
+// SysUnused notifies the operating system that the contents
+// of the memory region are no longer needed and can be reused
+// for other purposes. The program reserves the right to start
+// accessing those pages in the future.
+//
+// SysFree returns it unconditionally; this is only used if
+// an out-of-memory error has been detected midway through
+// an allocation. It is okay if SysFree is a no-op.
+
+void* runtime_SysAlloc(uintptr nbytes);
+void runtime_SysFree(void *v, uintptr nbytes);
+void runtime_SysUnused(void *v, uintptr nbytes);
+void runtime_SysMemInit(void);
+
+// FixAlloc is a simple free-list allocator for fixed size objects.
+// Malloc uses a FixAlloc wrapped around SysAlloc to manages its
+// MCache and MSpan objects.
+//
+// Memory returned by FixAlloc_Alloc is not zeroed.
+// The caller is responsible for locking around FixAlloc calls.
+// Callers can keep state in the object but the first word is
+// smashed by freeing and reallocating.
+struct FixAlloc
+{
+ uintptr size;
+ void *(*alloc)(uintptr);
+ void (*first)(void *arg, byte *p); // called first time p is returned
+ void *arg;
+ MLink *list;
+ byte *chunk;
+ uint32 nchunk;
+ uintptr inuse; // in-use bytes now
+ uintptr sys; // bytes obtained from system
+};
+
+void runtime_FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg);
+void* runtime_FixAlloc_Alloc(FixAlloc *f);
+void runtime_FixAlloc_Free(FixAlloc *f, void *p);
+
+
+// Statistics.
+// Shared with Go: if you edit this structure, also edit extern.go.
+struct MStats
+{
+ // General statistics. No locking; approximate.
+ uint64 alloc; // bytes allocated and still in use
+ uint64 total_alloc; // bytes allocated (even if freed)
+ uint64 sys; // bytes obtained from system (should be sum of xxx_sys below)
+ uint64 nlookup; // number of pointer lookups
+ uint64 nmalloc; // number of mallocs
+ uint64 nfree; // number of frees
+
+ // Statistics about malloc heap.
+ // protected by mheap.Lock
+ uint64 heap_alloc; // bytes allocated and still in use
+ uint64 heap_sys; // bytes obtained from system
+ uint64 heap_idle; // bytes in idle spans
+ uint64 heap_inuse; // bytes in non-idle spans
+ uint64 heap_objects; // total number of allocated objects
+
+ // Statistics about allocation of low-level fixed-size structures.
+ // Protected by FixAlloc locks.
+ uint64 stacks_inuse; // bootstrap stacks
+ uint64 stacks_sys;
+ uint64 mspan_inuse; // MSpan structures
+ uint64 mspan_sys;
+ uint64 mcache_inuse; // MCache structures
+ uint64 mcache_sys;
+ uint64 heapmap_sys; // heap map
+ uint64 buckhash_sys; // profiling bucket hash table
+
+ // Statistics about garbage collector.
+ // Protected by stopping the world during GC.
+ uint64 next_gc; // next GC (in heap_alloc time)
+ uint64 pause_total_ns;
+ uint64 pause_ns[256];
+ uint32 numgc;
+ bool enablegc;
+ bool debuggc;
+
+ // Statistics about allocation size classes.
+ // No locking; approximate.
+ struct {
+ uint32 size;
+ uint64 nmalloc;
+ uint64 nfree;
+ } by_size[NumSizeClasses];
+};
+
+extern MStats mstats
+ __asm__ ("libgo_runtime.runtime.MemStats");
+
+
+// Size classes. Computed and initialized by InitSizes.
+//
+// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
+// 1 <= sizeclass < NumSizeClasses, for n.
+// Size class 0 is reserved to mean "not small".
+//
+// class_to_size[i] = largest size in class i
+// class_to_allocnpages[i] = number of pages to allocate when
+// making new objects in class i
+// class_to_transfercount[i] = number of objects to move when
+// taking a bunch of objects out of the central lists
+// and putting them in the thread free list.
+
+int32 runtime_SizeToClass(int32);
+extern int32 runtime_class_to_size[NumSizeClasses];
+extern int32 runtime_class_to_allocnpages[NumSizeClasses];
+extern int32 runtime_class_to_transfercount[NumSizeClasses];
+extern void runtime_InitSizes(void);
+
+
+// Per-thread (in Go, per-M) cache for small objects.
+// No locking needed because it is per-thread (per-M).
+typedef struct MCacheList MCacheList;
+struct MCacheList
+{
+ MLink *list;
+ uint32 nlist;
+ uint32 nlistmin;
+};
+
+struct MCache
+{
+ MCacheList list[NumSizeClasses];
+ uint64 size;
+ int64 local_alloc; // bytes allocated (or freed) since last lock of heap
+ int64 local_objects; // objects allocated (or freed) since last lock of heap
+ int32 next_sample; // trigger heap sample after allocating this many bytes
+};
+
+void* runtime_MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed);
+void runtime_MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
+void runtime_MCache_ReleaseAll(MCache *c);
+
+// An MSpan is a run of pages.
+enum
+{
+ MSpanInUse = 0,
+ MSpanFree,
+ MSpanListHead,
+ MSpanDead,
+};
+struct MSpan
+{
+ MSpan *next; // in a span linked list
+ MSpan *prev; // in a span linked list
+ MSpan *allnext; // in the list of all spans
+ PageID start; // starting page number
+ uintptr npages; // number of pages in span
+ MLink *freelist; // list of free objects
+ uint32 ref; // number of allocated objects in this span
+ uint32 sizeclass; // size class
+ uint32 state; // MSpanInUse etc
+ union {
+ uint32 *gcref; // sizeclass > 0
+ uint32 gcref0; // sizeclass == 0
+ };
+};
+
+void runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages);
+
+// Every MSpan is in one doubly-linked list,
+// either one of the MHeap's free lists or one of the
+// MCentral's span lists. We use empty MSpan structures as list heads.
+void runtime_MSpanList_Init(MSpan *list);
+bool runtime_MSpanList_IsEmpty(MSpan *list);
+void runtime_MSpanList_Insert(MSpan *list, MSpan *span);
+void runtime_MSpanList_Remove(MSpan *span); // from whatever list it is in
+
+
+// Central list of free objects of a given size.
+struct MCentral
+{
+ Lock;
+ int32 sizeclass;
+ MSpan nonempty;
+ MSpan empty;
+ int32 nfree;
+};
+
+void runtime_MCentral_Init(MCentral *c, int32 sizeclass);
+int32 runtime_MCentral_AllocList(MCentral *c, int32 n, MLink **first);
+void runtime_MCentral_FreeList(MCentral *c, int32 n, MLink *first);
+
+// Main malloc heap.
+// The heap itself is the "free[]" and "large" arrays,
+// but all the other global data is here too.
+struct MHeap
+{
+ Lock;
+ MSpan free[MaxMHeapList]; // free lists of given length
+ MSpan large; // free lists length >= MaxMHeapList
+ MSpan *allspans;
+
+ // span lookup
+ MHeapMap map;
+
+ // range of addresses we might see in the heap
+ byte *min;
+ byte *max;
+
+ // central free lists for small size classes.
+ // the union makes sure that the MCentrals are
+ // spaced 64 bytes apart, so that each MCentral.Lock
+ // gets its own cache line.
+ union {
+ MCentral;
+ byte pad[64];
+ } central[NumSizeClasses];
+
+ FixAlloc spanalloc; // allocator for Span*
+ FixAlloc cachealloc; // allocator for MCache*
+};
+extern MHeap runtime_mheap;
+
+void runtime_MHeap_Init(MHeap *h, void *(*allocator)(uintptr));
+MSpan* runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct);
+void runtime_MHeap_Free(MHeap *h, MSpan *s, int32 acct);
+MSpan* runtime_MHeap_Lookup(MHeap *h, PageID p);
+MSpan* runtime_MHeap_LookupMaybe(MHeap *h, PageID p);
+void runtime_MGetSizeClassInfo(int32 sizeclass, int32 *size, int32 *npages, int32 *nobj);
+
+void* runtime_mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed);
+int32 runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **s, uint32 **ref);
+void runtime_gc(int32 force);
+
+void* runtime_SysAlloc(uintptr);
+void runtime_SysUnused(void*, uintptr);
+void runtime_SysFree(void*, uintptr);
+
+enum
+{
+ RefcountOverhead = 4, // one uint32 per object
+
+ RefFree = 0, // must be zero
+ RefStack, // stack segment - don't free and don't scan for pointers
+ RefNone, // no references
+ RefSome, // some references
+ RefNoPointers = 0x80000000U, // flag - no pointers here
+ RefHasFinalizer = 0x40000000U, // flag - has finalizer
+ RefProfiled = 0x20000000U, // flag - is in profiling table
+ RefNoProfiling = 0x10000000U, // flag - must not profile
+ RefFlags = 0xFFFF0000U,
+};
+
+void runtime_Mprof_Init(void);
+void runtime_MProf_Malloc(void*, uintptr);
+void runtime_MProf_Free(void*, uintptr);
+void runtime_MProf_Mark(void (*scan)(byte *, int64));
+
+// Malloc profiling settings.
+// Must match definition in extern.go.
+enum {
+ MProf_None = 0,
+ MProf_Sample = 1,
+ MProf_All = 2,
+};
+extern int32 runtime_malloc_profile;
+
+typedef struct Finalizer Finalizer;
+struct Finalizer
+{
+ Finalizer *next; // for use by caller of getfinalizer
+ void (*fn)(void*);
+ void *arg;
+ const struct __go_func_type *ft;
+};
+
+Finalizer* runtime_getfinalizer(void*, bool);
diff --git a/libgo/runtime/map.goc b/libgo/runtime/map.goc
new file mode 100644
index 000000000..d6308cbd3
--- /dev/null
+++ b/libgo/runtime/map.goc
@@ -0,0 +1,69 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+#include "map.h"
+#define nil NULL
+
+typedef unsigned char byte;
+typedef _Bool bool;
+
+typedef struct __go_map hmap;
+typedef struct __go_hash_iter hiter;
+
+/* Access a value in a map, returning a value and a presence indicator. */
+
+func mapaccess2(h *hmap, key *byte, val *byte) (present bool) {
+ byte *mapval;
+ size_t valsize;
+
+ mapval = __go_map_index(h, key, 0);
+ valsize = h->__descriptor->__map_descriptor->__val_type->__size;
+ if (mapval == nil) {
+ __builtin_memset(val, 0, valsize);
+ present = 0;
+ } else {
+ __builtin_memcpy(val, mapval, valsize);
+ present = 1;
+ }
+}
+
+/* Optionally assign a value to a map (m[k] = v, p). */
+
+func mapassign2(h *hmap, key *byte, val *byte, p bool) {
+ if (!p) {
+ __go_map_delete(h, key);
+ } else {
+ byte *mapval;
+ size_t valsize;
+
+ mapval = __go_map_index(h, key, 1);
+ valsize = h->__descriptor->__map_descriptor->__val_type->__size;
+ __builtin_memcpy(mapval, val, valsize);
+ }
+}
+
+/* Initialize a range over a map. */
+
+func mapiterinit(h *hmap, it *hiter) {
+ __go_mapiterinit(h, it);
+}
+
+/* Move to the next iteration, updating *HITER. */
+
+func mapiternext(it *hiter) {
+ __go_mapiternext(it);
+}
+
+/* Get the key of the current iteration. */
+
+func mapiter1(it *hiter, key *byte) {
+ __go_mapiter1(it, key);
+}
+
+/* Get the key and value of the current iteration. */
+
+func mapiter2(it *hiter, key *byte, val *byte) {
+ __go_mapiter2(it, key, val);
+}
diff --git a/libgo/runtime/map.h b/libgo/runtime/map.h
new file mode 100644
index 000000000..a0c834a54
--- /dev/null
+++ b/libgo/runtime/map.h
@@ -0,0 +1,86 @@
+/* map.h -- the map type for Go.
+
+ Copyright 2009, 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 <stddef.h>
+
+#include "go-type.h"
+
+/* A map descriptor is what we need to manipulate the map. This is
+ constant for a given map type. */
+
+struct __go_map_descriptor
+{
+ /* A pointer to the type descriptor for the type of the map itself. */
+ const struct __go_map_type *__map_descriptor;
+
+ /* A map entry is a struct with three fields:
+ map_entry_type *next_entry;
+ key_type key;
+ value_type value;
+ This is the size of that struct. */
+ size_t __entry_size;
+
+ /* The offset of the key field in a map entry struct. */
+ size_t __key_offset;
+
+ /* The offset of the value field in a map entry struct (the value
+ field immediately follows the key field, but there may be some
+ bytes inserted for alignment). */
+ size_t __val_offset;
+};
+
+struct __go_map
+{
+ /* The constant descriptor for this map. */
+ const struct __go_map_descriptor *__descriptor;
+
+ /* The number of elements in the hash table. */
+ size_t __element_count;
+
+ /* The number of entries in the __buckets array. */
+ size_t __bucket_count;
+
+ /* Each bucket is a pointer to a linked list of map entries. */
+ void **__buckets;
+};
+
+/* For a map iteration the compiled code will use a pointer to an
+ iteration structure. The iteration structure will be allocated on
+ the stack. The Go code must allocate at least enough space. */
+
+struct __go_hash_iter
+{
+ /* A pointer to the current entry. This will be set to NULL when
+ the range has completed. The Go will test this field, so it must
+ be the first one in the structure. */
+ const void *entry;
+ /* The map we are iterating over. */
+ const struct __go_map *map;
+ /* A pointer to the next entry in the current bucket. This permits
+ deleting the current entry. This will be NULL when we have seen
+ all the entries in the current bucket. */
+ const void *next_entry;
+ /* The bucket index of the current and next entry. */
+ size_t bucket;
+};
+
+extern struct __go_map *__go_new_map (const struct __go_map_descriptor *,
+ size_t);
+
+extern unsigned long __go_map_next_prime (unsigned long);
+
+extern void *__go_map_index (struct __go_map *, const void *, _Bool);
+
+extern void __go_map_delete (struct __go_map *, const void *);
+
+extern void __go_mapiterinit (const struct __go_map *, struct __go_hash_iter *);
+
+extern void __go_mapiternext (struct __go_hash_iter *);
+
+extern void __go_mapiter1 (struct __go_hash_iter *it, unsigned char *key);
+
+extern void __go_mapiter2 (struct __go_hash_iter *it, unsigned char *key,
+ unsigned char *val);
diff --git a/libgo/runtime/mcache.c b/libgo/runtime/mcache.c
new file mode 100644
index 000000000..ce6575758
--- /dev/null
+++ b/libgo/runtime/mcache.c
@@ -0,0 +1,131 @@
+// 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.
+
+// Per-thread (in Go, per-M) malloc cache for small objects.
+//
+// See malloc.h for an overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+void*
+runtime_MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
+{
+ MCacheList *l;
+ MLink *first, *v;
+ int32 n;
+
+ // Allocate from list.
+ l = &c->list[sizeclass];
+ if(l->list == nil) {
+ // Replenish using central lists.
+ n = runtime_MCentral_AllocList(&runtime_mheap.central[sizeclass],
+ runtime_class_to_transfercount[sizeclass], &first);
+ l->list = first;
+ l->nlist = n;
+ c->size += n*size;
+ }
+ v = l->list;
+ l->list = v->next;
+ l->nlist--;
+ if(l->nlist < l->nlistmin)
+ l->nlistmin = l->nlist;
+ c->size -= size;
+
+ // v is zeroed except for the link pointer
+ // that we used above; zero that.
+ v->next = nil;
+ if(zeroed) {
+ // block is zeroed iff second word is zero ...
+ if(size > sizeof(uintptr) && ((uintptr*)v)[1] != 0)
+ runtime_memclr((byte*)v, size);
+ else {
+ // ... except for the link pointer
+ // that we used above; zero that.
+ v->next = nil;
+ }
+ }
+ c->local_alloc += size;
+ c->local_objects++;
+ return v;
+}
+
+// Take n elements off l and return them to the central free list.
+static void
+ReleaseN(MCache *c, MCacheList *l, int32 n, int32 sizeclass)
+{
+ MLink *first, **lp;
+ int32 i;
+
+ // Cut off first n elements.
+ first = l->list;
+ lp = &l->list;
+ for(i=0; i<n; i++)
+ lp = &(*lp)->next;
+ l->list = *lp;
+ *lp = nil;
+ l->nlist -= n;
+ if(l->nlist < l->nlistmin)
+ l->nlistmin = l->nlist;
+ c->size -= n*runtime_class_to_size[sizeclass];
+
+ // Return them to central free list.
+ runtime_MCentral_FreeList(&runtime_mheap.central[sizeclass], n, first);
+}
+
+void
+runtime_MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
+{
+ int32 i, n;
+ MCacheList *l;
+ MLink *p;
+
+ // Put back on list.
+ l = &c->list[sizeclass];
+ p = v;
+ p->next = l->list;
+ l->list = p;
+ l->nlist++;
+ c->size += size;
+ c->local_alloc -= size;
+ c->local_objects--;
+
+ if(l->nlist >= MaxMCacheListLen) {
+ // Release a chunk back.
+ ReleaseN(c, l, runtime_class_to_transfercount[sizeclass], sizeclass);
+ }
+
+ if(c->size >= MaxMCacheSize) {
+ // Scavenge.
+ for(i=0; i<NumSizeClasses; i++) {
+ l = &c->list[i];
+ n = l->nlistmin;
+
+ // n is the minimum number of elements we've seen on
+ // the list since the last scavenge. If n > 0, it means that
+ // we could have gotten by with n fewer elements
+ // without needing to consult the central free list.
+ // Move toward that situation by releasing n/2 of them.
+ if(n > 0) {
+ if(n > 1)
+ n /= 2;
+ ReleaseN(c, l, n, i);
+ }
+ l->nlistmin = l->nlist;
+ }
+ }
+}
+
+void
+runtime_MCache_ReleaseAll(MCache *c)
+{
+ int32 i;
+ MCacheList *l;
+
+ for(i=0; i<NumSizeClasses; i++) {
+ l = &c->list[i];
+ ReleaseN(c, l, l->nlist, i);
+ l->nlistmin = 0;
+ }
+}
diff --git a/libgo/runtime/mcentral.c b/libgo/runtime/mcentral.c
new file mode 100644
index 000000000..81e54b07d
--- /dev/null
+++ b/libgo/runtime/mcentral.c
@@ -0,0 +1,209 @@
+// 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.
+
+// Central free lists.
+//
+// See malloc.h for an overview.
+//
+// The MCentral doesn't actually contain the list of free objects; the MSpan does.
+// Each MCentral is two lists of MSpans: those with free objects (c->nonempty)
+// and those that are completely allocated (c->empty).
+//
+// TODO(rsc): tcmalloc uses a "transfer cache" to split the list
+// into sections of class_to_transfercount[sizeclass] objects
+// so that it is faster to move those lists between MCaches and MCentrals.
+
+#include "runtime.h"
+#include "malloc.h"
+
+static bool MCentral_Grow(MCentral *c);
+static void* MCentral_Alloc(MCentral *c);
+static void MCentral_Free(MCentral *c, void *v);
+
+// Initialize a single central free list.
+void
+runtime_MCentral_Init(MCentral *c, int32 sizeclass)
+{
+ runtime_initlock(c);
+ c->sizeclass = sizeclass;
+ runtime_MSpanList_Init(&c->nonempty);
+ runtime_MSpanList_Init(&c->empty);
+}
+
+// Allocate up to n objects from the central free list.
+// Return the number of objects allocated.
+// The objects are linked together by their first words.
+// On return, *pstart points at the first object and *pend at the last.
+int32
+runtime_MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst)
+{
+ MLink *first, *last, *v;
+ int32 i;
+
+ runtime_lock(c);
+ // Replenish central list if empty.
+ if(runtime_MSpanList_IsEmpty(&c->nonempty)) {
+ if(!MCentral_Grow(c)) {
+ runtime_unlock(c);
+ *pfirst = nil;
+ return 0;
+ }
+ }
+
+ // Copy from list, up to n.
+ // First one is guaranteed to work, because we just grew the list.
+ first = MCentral_Alloc(c);
+ last = first;
+ for(i=1; i<n && (v = MCentral_Alloc(c)) != nil; i++) {
+ last->next = v;
+ last = v;
+ }
+ last->next = nil;
+ c->nfree -= i;
+
+ runtime_unlock(c);
+ *pfirst = first;
+ return i;
+}
+
+// Helper: allocate one object from the central free list.
+static void*
+MCentral_Alloc(MCentral *c)
+{
+ MSpan *s;
+ MLink *v;
+
+ if(runtime_MSpanList_IsEmpty(&c->nonempty))
+ return nil;
+ s = c->nonempty.next;
+ s->ref++;
+ v = s->freelist;
+ s->freelist = v->next;
+ if(s->freelist == nil) {
+ runtime_MSpanList_Remove(s);
+ runtime_MSpanList_Insert(&c->empty, s);
+ }
+ return v;
+}
+
+// Free n objects back into the central free list.
+// Return the number of objects allocated.
+// The objects are linked together by their first words.
+// On return, *pstart points at the first object and *pend at the last.
+void
+runtime_MCentral_FreeList(MCentral *c, int32 n, MLink *start)
+{
+ MLink *v, *next;
+
+ // Assume next == nil marks end of list.
+ // n and end would be useful if we implemented
+ // the transfer cache optimization in the TODO above.
+ USED(n);
+
+ runtime_lock(c);
+ for(v=start; v; v=next) {
+ next = v->next;
+ MCentral_Free(c, v);
+ }
+ runtime_unlock(c);
+}
+
+// Helper: free one object back into the central free list.
+static void
+MCentral_Free(MCentral *c, void *v)
+{
+ MSpan *s;
+ PageID page;
+ MLink *p, *next;
+ int32 size;
+
+ // Find span for v.
+ page = (uintptr)v >> PageShift;
+ s = runtime_MHeap_Lookup(&runtime_mheap, page);
+ if(s == nil || s->ref == 0)
+ runtime_throw("invalid free");
+
+ // Move to nonempty if necessary.
+ if(s->freelist == nil) {
+ runtime_MSpanList_Remove(s);
+ runtime_MSpanList_Insert(&c->nonempty, s);
+ }
+
+ // Add v back to s's free list.
+ p = v;
+ p->next = s->freelist;
+ s->freelist = p;
+ c->nfree++;
+
+ // If s is completely freed, return it to the heap.
+ if(--s->ref == 0) {
+ size = runtime_class_to_size[c->sizeclass];
+ runtime_MSpanList_Remove(s);
+ // The second word of each freed block indicates
+ // whether it needs to be zeroed. The first word
+ // is the link pointer and must always be cleared.
+ for(p=s->freelist; p; p=next) {
+ next = p->next;
+ if(size > (int32)sizeof(uintptr) && ((uintptr*)p)[1] != 0)
+ runtime_memclr((byte*)p, size);
+ else
+ p->next = nil;
+ }
+ s->freelist = nil;
+ c->nfree -= (s->npages << PageShift) / size;
+ runtime_unlock(c);
+ runtime_MHeap_Free(&runtime_mheap, s, 0);
+ runtime_lock(c);
+ }
+}
+
+void
+runtime_MGetSizeClassInfo(int32 sizeclass, int32 *sizep, int32 *npagesp, int32 *nobj)
+{
+ int32 size;
+ int32 npages;
+
+ npages = runtime_class_to_allocnpages[sizeclass];
+ size = runtime_class_to_size[sizeclass];
+ *npagesp = npages;
+ *sizep = size;
+ *nobj = (npages << PageShift) / (size + RefcountOverhead);
+}
+
+// Fetch a new span from the heap and
+// carve into objects for the free list.
+static bool
+MCentral_Grow(MCentral *c)
+{
+ int32 i, n, npages, size;
+ MLink **tailp, *v;
+ byte *p;
+ MSpan *s;
+
+ runtime_unlock(c);
+ runtime_MGetSizeClassInfo(c->sizeclass, &size, &npages, &n);
+ s = runtime_MHeap_Alloc(&runtime_mheap, npages, c->sizeclass, 0);
+ if(s == nil) {
+ // TODO(rsc): Log out of memory
+ runtime_lock(c);
+ return false;
+ }
+
+ // Carve span into sequence of blocks.
+ tailp = &s->freelist;
+ p = (byte*)(s->start << PageShift);
+ s->gcref = (uint32*)(p + size*n);
+ for(i=0; i<n; i++) {
+ v = (MLink*)p;
+ *tailp = v;
+ tailp = &v->next;
+ p += size;
+ }
+ *tailp = nil;
+
+ runtime_lock(c);
+ c->nfree += n;
+ runtime_MSpanList_Insert(&c->nonempty, s);
+ return true;
+}
diff --git a/libgo/runtime/mem.c b/libgo/runtime/mem.c
new file mode 100644
index 000000000..4d6c74209
--- /dev/null
+++ b/libgo/runtime/mem.c
@@ -0,0 +1,76 @@
+#include <errno.h>
+
+#include "runtime.h"
+#include "malloc.h"
+
+#ifndef MAP_ANON
+#ifdef MAP_ANONYMOUS
+#define MAP_ANON MAP_ANONYMOUS
+#else
+#define USE_DEV_ZERO
+#define MAP_ANON 0
+#endif
+#endif
+
+#ifdef USE_DEV_ZERO
+static int dev_zero = -1;
+#endif
+
+void*
+runtime_SysAlloc(uintptr n)
+{
+ void *p;
+ int fd = -1;
+
+ mstats.sys += n;
+
+#ifdef USE_DEV_ZERO
+ if (dev_zero == -1) {
+ dev_zero = open("/dev/zero", O_RDONLY);
+ if (dev_zero < 0) {
+ printf("open /dev/zero: errno=%d\n", errno);
+ exit(2);
+ }
+ }
+ fd = dev_zero;
+#endif
+
+ p = runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, fd, 0);
+ if (p == MAP_FAILED) {
+ if(errno == EACCES) {
+ printf("mmap: access denied\n");
+ printf("If you're running SELinux, enable execmem for this process.\n");
+ } else {
+ printf("mmap: errno=%d\n", errno);
+ }
+ exit(2);
+ }
+ return p;
+}
+
+void
+runtime_SysUnused(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+ // TODO(rsc): call madvise MADV_DONTNEED
+}
+
+void
+runtime_SysFree(void *v, uintptr n)
+{
+ mstats.sys -= n;
+ runtime_munmap(v, n);
+}
+
+void
+runtime_SysMemInit(void)
+{
+ // Code generators assume that references to addresses
+ // on the first page will fault. Map the page explicitly with
+ // no permissions, to head off possible bugs like the system
+ // allocating that page as the virtual address space fills.
+ // Ignore any error, since other systems might be smart
+ // enough to never allow anything there.
+ runtime_mmap(nil, 4096, PROT_NONE, MAP_FIXED|MAP_ANON|MAP_PRIVATE, -1, 0);
+}
diff --git a/libgo/runtime/mem_posix_memalign.c b/libgo/runtime/mem_posix_memalign.c
new file mode 100644
index 000000000..3855dfcf1
--- /dev/null
+++ b/libgo/runtime/mem_posix_memalign.c
@@ -0,0 +1,38 @@
+#include <errno.h>
+
+#include "runtime.h"
+#include "malloc.h"
+
+void*
+runtime_SysAlloc(uintptr n)
+{
+ void *p;
+
+ mstats.sys += n;
+ errno = posix_memalign(&p, PageSize, n);
+ if (errno > 0) {
+ perror("posix_memalign");
+ exit(2);
+ }
+ return p;
+}
+
+void
+runtime_SysUnused(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+ // TODO(rsc): call madvise MADV_DONTNEED
+}
+
+void
+runtime_SysFree(void *v, uintptr n)
+{
+ mstats.sys -= n;
+ free(v);
+}
+
+void
+runtime_SysMemInit(void)
+{
+}
diff --git a/libgo/runtime/mfinal.c b/libgo/runtime/mfinal.c
new file mode 100644
index 000000000..23c0d7a16
--- /dev/null
+++ b/libgo/runtime/mfinal.c
@@ -0,0 +1,217 @@
+// 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 "runtime.h"
+#include "malloc.h"
+
+static Lock finlock;
+
+void
+runtime_initfintab()
+{
+ runtime_initlock(&finlock);
+}
+
+// Finalizer hash table. Direct hash, linear scan, at most 3/4 full.
+// Table size is power of 3 so that hash can be key % max.
+// Key[i] == (void*)-1 denotes free but formerly occupied entry
+// (doesn't stop the linear scan).
+// Key and val are separate tables because the garbage collector
+// must be instructed to ignore the pointers in key but follow the
+// pointers in val.
+typedef struct Fintab Fintab;
+struct Fintab
+{
+ void **key;
+ Finalizer **val;
+ int32 nkey; // number of non-nil entries in key
+ int32 ndead; // number of dead (-1) entries in key
+ int32 max; // size of key, val allocations
+};
+
+static void
+addfintab(Fintab *t, void *k, Finalizer *v)
+{
+ int32 i, j;
+
+ i = (uintptr)k % (uintptr)t->max;
+ for(j=0; j<t->max; j++) {
+ if(t->key[i] == nil) {
+ t->nkey++;
+ goto ret;
+ }
+ if(t->key[i] == (void*)-1) {
+ t->ndead--;
+ goto ret;
+ }
+ if(++i == t->max)
+ i = 0;
+ }
+
+ // cannot happen - table is known to be non-full
+ runtime_throw("finalizer table inconsistent");
+
+ret:
+ t->key[i] = k;
+ t->val[i] = v;
+}
+
+static Finalizer*
+lookfintab(Fintab *t, void *k, bool del)
+{
+ int32 i, j;
+ Finalizer *v;
+
+ if(t->max == 0)
+ return nil;
+ i = (uintptr)k % (uintptr)t->max;
+ for(j=0; j<t->max; j++) {
+ if(t->key[i] == nil)
+ return nil;
+ if(t->key[i] == k) {
+ v = t->val[i];
+ if(del) {
+ t->key[i] = (void*)-1;
+ t->val[i] = nil;
+ t->ndead++;
+ }
+ return v;
+ }
+ if(++i == t->max)
+ i = 0;
+ }
+
+ // cannot happen - table is known to be non-full
+ runtime_throw("finalizer table inconsistent");
+ return nil;
+}
+
+static Fintab fintab;
+
+// add finalizer; caller is responsible for making sure not already in table
+void
+runtime_addfinalizer(void *p, void (*f)(void*), const struct __go_func_type *ft)
+{
+ Fintab newtab;
+ int32 i;
+ uint32 *ref;
+ byte *base;
+ Finalizer *e;
+
+ e = nil;
+ if(f != nil) {
+ e = runtime_mal(sizeof *e);
+ e->fn = f;
+ e->ft = ft;
+ }
+
+ if(!__sync_bool_compare_and_swap(&m->holds_finlock, 0, 1))
+ runtime_throw("finalizer deadlock");
+
+ runtime_lock(&finlock);
+ if(!runtime_mlookup(p, &base, nil, nil, &ref) || p != base) {
+ runtime_unlock(&finlock);
+ __sync_bool_compare_and_swap(&m->holds_finlock, 1, 0);
+ runtime_throw("addfinalizer on invalid pointer");
+ }
+ if(f == nil) {
+ if(*ref & RefHasFinalizer) {
+ lookfintab(&fintab, p, 1);
+ *ref &= ~RefHasFinalizer;
+ }
+ goto unlock;
+ }
+
+ if(*ref & RefHasFinalizer) {
+ runtime_unlock(&finlock);
+ __sync_bool_compare_and_swap(&m->holds_finlock, 1, 0);
+ runtime_throw("double finalizer");
+ }
+ *ref |= RefHasFinalizer;
+
+ if(fintab.nkey >= fintab.max/2+fintab.max/4) {
+ // keep table at most 3/4 full:
+ // allocate new table and rehash.
+
+ runtime_memclr((byte*)&newtab, sizeof newtab);
+ newtab.max = fintab.max;
+ if(newtab.max == 0)
+ newtab.max = 3*3*3;
+ else if(fintab.ndead < fintab.nkey/2) {
+ // grow table if not many dead values.
+ // otherwise just rehash into table of same size.
+ newtab.max *= 3;
+ }
+
+ newtab.key = runtime_mallocgc(newtab.max*sizeof newtab.key[0], RefNoPointers, 0, 1);
+ newtab.val = runtime_mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1);
+
+ for(i=0; i<fintab.max; i++) {
+ void *k;
+
+ k = fintab.key[i];
+ if(k != nil && k != (void*)-1)
+ addfintab(&newtab, k, fintab.val[i]);
+ }
+ runtime_free(fintab.key);
+ runtime_free(fintab.val);
+ fintab = newtab;
+ }
+
+ addfintab(&fintab, p, e);
+ unlock:
+ runtime_unlock(&finlock);
+
+ __sync_bool_compare_and_swap(&m->holds_finlock, 1, 0);
+
+ if(__sync_bool_compare_and_swap(&m->gcing_for_finlock, 1, 0)) {
+ __go_run_goroutine_gc(200);
+ }
+}
+
+// get finalizer; if del, delete finalizer.
+// caller is responsible for updating RefHasFinalizer bit.
+Finalizer*
+runtime_getfinalizer(void *p, bool del)
+{
+ Finalizer *f;
+
+ if(!__sync_bool_compare_and_swap(&m->holds_finlock, 0, 1))
+ runtime_throw("finalizer deadlock");
+
+ runtime_lock(&finlock);
+ f = lookfintab(&fintab, p, del);
+ runtime_unlock(&finlock);
+
+ __sync_bool_compare_and_swap(&m->holds_finlock, 1, 0);
+ if(__sync_bool_compare_and_swap(&m->gcing_for_finlock, 1, 0)) {
+ __go_run_goroutine_gc(201);
+ }
+
+ return f;
+}
+
+void
+runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64))
+{
+ void **key;
+ void **ekey;
+
+ if(!__sync_bool_compare_and_swap(&m->holds_finlock, 0, 1))
+ runtime_throw("finalizer deadlock");
+
+ scan((byte*)&fintab, sizeof fintab);
+ runtime_lock(&finlock);
+ key = fintab.key;
+ ekey = key + fintab.max;
+ for(; key < ekey; key++)
+ if(*key != nil && *key != ((void*)-1))
+ fn(*key);
+ runtime_unlock(&finlock);
+
+ __sync_bool_compare_and_swap(&m->holds_finlock, 1, 0);
+ if(__sync_bool_compare_and_swap(&m->gcing_for_finlock, 1, 0)) {
+ runtime_throw("walkfintab not called from gc");
+ }
+}
diff --git a/libgo/runtime/mfixalloc.c b/libgo/runtime/mfixalloc.c
new file mode 100644
index 000000000..c05583dc2
--- /dev/null
+++ b/libgo/runtime/mfixalloc.c
@@ -0,0 +1,62 @@
+// 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.
+
+// Fixed-size object allocator. Returned memory is not zeroed.
+//
+// See malloc.h for overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+// Initialize f to allocate objects of the given size,
+// using the allocator to obtain chunks of memory.
+void
+runtime_FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg)
+{
+ f->size = size;
+ f->alloc = alloc;
+ f->first = first;
+ f->arg = arg;
+ f->list = nil;
+ f->chunk = nil;
+ f->nchunk = 0;
+ f->inuse = 0;
+ f->sys = 0;
+}
+
+void*
+runtime_FixAlloc_Alloc(FixAlloc *f)
+{
+ void *v;
+
+ if(f->list) {
+ v = f->list;
+ f->list = *(void**)f->list;
+ f->inuse += f->size;
+ return v;
+ }
+ if(f->nchunk < f->size) {
+ f->sys += FixAllocChunk;
+ f->chunk = f->alloc(FixAllocChunk);
+ if(f->chunk == nil)
+ runtime_throw("out of memory (FixAlloc)");
+ f->nchunk = FixAllocChunk;
+ }
+ v = f->chunk;
+ if(f->first)
+ f->first(f->arg, v);
+ f->chunk += f->size;
+ f->nchunk -= f->size;
+ f->inuse += f->size;
+ return v;
+}
+
+void
+runtime_FixAlloc_Free(FixAlloc *f, void *p)
+{
+ f->inuse -= f->size;
+ *(void**)p = f->list;
+ f->list = p;
+}
+
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
new file mode 100644
index 000000000..f2703ab02
--- /dev/null
+++ b/libgo/runtime/mgc0.c
@@ -0,0 +1,392 @@
+// 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.
+
+// Garbage collector -- step 0.
+//
+// Stop the world, mark and sweep garbage collector.
+// NOT INTENDED FOR PRODUCTION USE.
+//
+// A mark and sweep collector provides a way to exercise
+// and test the memory allocator and the stack walking machinery
+// without also needing to get reference counting
+// exactly right.
+
+#include "runtime.h"
+#include "malloc.h"
+
+enum {
+ Debug = 0
+};
+
+typedef struct BlockList BlockList;
+struct BlockList
+{
+ byte *obj;
+ uintptr size;
+};
+
+static bool finstarted;
+static pthread_mutex_t finqlock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t finqcond = PTHREAD_COND_INITIALIZER;
+static Finalizer *finq;
+static int32 fingwait;
+static BlockList *bl, *ebl;
+
+static void runfinq(void*);
+
+enum {
+ PtrSize = sizeof(void*)
+};
+
+static void
+scanblock(byte *b, int64 n)
+{
+ int32 off;
+ void *obj;
+ uintptr size;
+ uint32 *refp, ref;
+ void **vp;
+ int64 i;
+ BlockList *w;
+
+ w = bl;
+ w->obj = b;
+ w->size = n;
+ w++;
+
+ while(w > bl) {
+ w--;
+ b = w->obj;
+ n = w->size;
+
+ if(Debug > 1)
+ runtime_printf("scanblock %p %lld\n", b, (long long) n);
+ off = (uint32)(uintptr)b & (PtrSize-1);
+ if(off) {
+ b += PtrSize - off;
+ n -= PtrSize - off;
+ }
+
+ vp = (void**)b;
+ n /= PtrSize;
+ for(i=0; i<n; i++) {
+ obj = vp[i];
+ if(obj == nil)
+ continue;
+ if(runtime_mheap.min <= (byte*)obj && (byte*)obj < runtime_mheap.max) {
+ if(runtime_mlookup(obj, (byte**)&obj, &size, nil, &refp)) {
+ ref = *refp;
+ switch(ref & ~RefFlags) {
+ case RefNone:
+ if(Debug > 1)
+ runtime_printf("found at %p: ", &vp[i]);
+ *refp = RefSome | (ref & RefFlags);
+ if(!(ref & RefNoPointers)) {
+ if(w >= ebl)
+ runtime_throw("scanblock: garbage collection stack overflow");
+ w->obj = obj;
+ w->size = size;
+ w++;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void
+markfin(void *v)
+{
+ uintptr size;
+ uint32 *refp;
+
+ size = 0;
+ refp = nil;
+ if(!runtime_mlookup(v, (byte**)&v, &size, nil, &refp) || !(*refp & RefHasFinalizer))
+ runtime_throw("mark - finalizer inconsistency");
+
+ // do not mark the finalizer block itself. just mark the things it points at.
+ scanblock(v, size);
+}
+
+struct root_list {
+ struct root_list *next;
+ struct root {
+ void *decl;
+ size_t size;
+ } roots[];
+};
+
+static struct root_list* roots;
+
+void
+__go_register_gc_roots (struct root_list* r)
+{
+ // FIXME: This needs locking if multiple goroutines can call
+ // dlopen simultaneously.
+ r->next = roots;
+ roots = r;
+}
+
+static void
+mark(void)
+{
+ uintptr blsize, nobj;
+ struct root_list *pl;
+
+ // Figure out how big an object stack we need.
+ // Get a new one if we need more than we have
+ // or we need significantly less than we have.
+ nobj = mstats.heap_objects;
+ if(nobj > (uintptr)(ebl - bl) || nobj < (uintptr)(ebl-bl)/4) {
+ if(bl != nil)
+ runtime_SysFree(bl, (byte*)ebl - (byte*)bl);
+
+ // While we're allocated a new object stack,
+ // add 20% headroom and also round up to
+ // the nearest page boundary, since mmap
+ // will anyway.
+ nobj = nobj * 12/10;
+ blsize = nobj * sizeof *bl;
+ blsize = (blsize + 4095) & ~4095;
+ nobj = blsize / sizeof *bl;
+ bl = runtime_SysAlloc(blsize);
+ ebl = bl + nobj;
+ }
+
+ for(pl = roots; pl != nil; pl = pl->next) {
+ struct root* pr = &pl->roots[0];
+ while(1) {
+ void *decl = pr->decl;
+ if(decl == nil)
+ break;
+ scanblock(decl, pr->size);
+ pr++;
+ }
+ }
+
+ scanblock((byte*)&m0, sizeof m0);
+ scanblock((byte*)&finq, sizeof finq);
+ runtime_MProf_Mark(scanblock);
+
+ // mark stacks
+ __go_scanstacks(scanblock);
+
+ // mark things pointed at by objects with finalizers
+ runtime_walkfintab(markfin, scanblock);
+}
+
+// free RefNone, free & queue finalizers for RefNone|RefHasFinalizer, reset RefSome
+static void
+sweepspan(MSpan *s)
+{
+ int32 n, npages, size;
+ byte *p;
+ uint32 ref, *gcrefp, *gcrefep;
+ MCache *c;
+ Finalizer *f;
+
+ p = (byte*)(s->start << PageShift);
+ if(s->sizeclass == 0) {
+ // Large block.
+ ref = s->gcref0;
+ switch(ref & ~(RefFlags^RefHasFinalizer)) {
+ case RefNone:
+ // Free large object.
+ mstats.alloc -= s->npages<<PageShift;
+ mstats.nfree++;
+ runtime_memclr(p, s->npages<<PageShift);
+ if(ref & RefProfiled)
+ runtime_MProf_Free(p, s->npages<<PageShift);
+ s->gcref0 = RefFree;
+ runtime_MHeap_Free(&runtime_mheap, s, 1);
+ break;
+ case RefNone|RefHasFinalizer:
+ f = runtime_getfinalizer(p, 1);
+ if(f == nil)
+ runtime_throw("finalizer inconsistency");
+ f->arg = p;
+ f->next = finq;
+ finq = f;
+ ref &= ~RefHasFinalizer;
+ // fall through
+ case RefSome:
+ case RefSome|RefHasFinalizer:
+ s->gcref0 = RefNone | (ref&RefFlags);
+ break;
+ }
+ return;
+ }
+
+ // Chunk full of small blocks.
+ runtime_MGetSizeClassInfo(s->sizeclass, &size, &npages, &n);
+ gcrefp = s->gcref;
+ gcrefep = s->gcref + n;
+ for(; gcrefp < gcrefep; gcrefp++, p += size) {
+ ref = *gcrefp;
+ if(ref < RefNone) // RefFree or RefStack
+ continue;
+ switch(ref & ~(RefFlags^RefHasFinalizer)) {
+ case RefNone:
+ // Free small object.
+ if(ref & RefProfiled)
+ runtime_MProf_Free(p, size);
+ *gcrefp = RefFree;
+ c = m->mcache;
+ if(size > (int32)sizeof(uintptr))
+ ((uintptr*)p)[1] = 1; // mark as "needs to be zeroed"
+ mstats.alloc -= size;
+ mstats.nfree++;
+ mstats.by_size[s->sizeclass].nfree++;
+ runtime_MCache_Free(c, p, s->sizeclass, size);
+ break;
+ case RefNone|RefHasFinalizer:
+ f = runtime_getfinalizer(p, 1);
+ if(f == nil)
+ runtime_throw("finalizer inconsistency");
+ f->arg = p;
+ f->next = finq;
+ finq = f;
+ ref &= ~RefHasFinalizer;
+ // fall through
+ case RefSome:
+ case RefSome|RefHasFinalizer:
+ *gcrefp = RefNone | (ref&RefFlags);
+ break;
+ }
+ }
+}
+
+static void
+sweep(void)
+{
+ MSpan *s;
+
+ for(s = runtime_mheap.allspans; s != nil; s = s->allnext)
+ if(s->state == MSpanInUse)
+ sweepspan(s);
+}
+
+static pthread_mutex_t gcsema = PTHREAD_MUTEX_INITIALIZER;
+
+// Initialized from $GOGC. GOGC=off means no gc.
+//
+// Next gc is after we've allocated an extra amount of
+// memory proportional to the amount already in use.
+// If gcpercent=100 and we're using 4M, we'll gc again
+// when we get to 8M. This keeps the gc cost in linear
+// proportion to the allocation cost. Adjusting gcpercent
+// just changes the linear constant (and also the amount of
+// extra memory used).
+static int32 gcpercent = -2;
+
+void
+runtime_gc(int32 force __attribute__ ((unused)))
+{
+ int64 t0, t1;
+ char *p;
+ Finalizer *fp;
+
+ // The gc is turned off (via enablegc) until
+ // the bootstrap has completed.
+ // Also, malloc gets called in the guts
+ // of a number of libraries that might be
+ // holding locks. To avoid priority inversion
+ // problems, don't bother trying to run gc
+ // while holding a lock. The next mallocgc
+ // without a lock will do the gc instead.
+ if(!mstats.enablegc || m->locks > 0 /* || runtime_panicking */)
+ return;
+
+ if(gcpercent == -2) { // first time through
+ p = runtime_getenv("GOGC");
+ if(p == nil || p[0] == '\0')
+ gcpercent = 100;
+ else if(runtime_strcmp(p, "off") == 0)
+ gcpercent = -1;
+ else
+ gcpercent = runtime_atoi(p);
+ }
+ if(gcpercent < 0)
+ return;
+
+ pthread_mutex_lock(&finqlock);
+ pthread_mutex_lock(&gcsema);
+ m->locks++; // disable gc during the mallocs in newproc
+ t0 = runtime_nanotime();
+ runtime_stoptheworld();
+ if(force || mstats.heap_alloc >= mstats.next_gc) {
+ __go_cachestats();
+ mark();
+ sweep();
+ __go_stealcache();
+ mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100;
+ }
+
+ t1 = runtime_nanotime();
+ mstats.numgc++;
+ mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t1 - t0;
+ mstats.pause_total_ns += t1 - t0;
+ if(mstats.debuggc)
+ runtime_printf("pause %llu\n", (unsigned long long)t1-t0);
+ pthread_mutex_unlock(&gcsema);
+ runtime_starttheworld();
+
+ // finqlock is still held.
+ fp = finq;
+ if(fp != nil) {
+ // kick off or wake up goroutine to run queued finalizers
+ if(!finstarted) {
+ __go_go(runfinq, nil);
+ finstarted = 1;
+ }
+ else if(fingwait) {
+ fingwait = 0;
+ pthread_cond_signal(&finqcond);
+ }
+ }
+ m->locks--;
+ pthread_mutex_unlock(&finqlock);
+}
+
+static void
+runfinq(void* dummy)
+{
+ Finalizer *f, *next;
+
+ USED(dummy);
+
+ for(;;) {
+ pthread_mutex_lock(&finqlock);
+ f = finq;
+ finq = nil;
+ if(f == nil) {
+ fingwait = 1;
+ pthread_cond_wait(&finqcond, &finqlock);
+ pthread_mutex_unlock(&finqlock);
+ continue;
+ }
+ pthread_mutex_unlock(&finqlock);
+ for(; f; f=next) {
+ void *params[1];
+
+ next = f->next;
+ params[0] = &f->arg;
+ reflect_call(f->ft, (void*)f->fn, 0, params, nil);
+ f->fn = nil;
+ f->arg = nil;
+ f->next = nil;
+ runtime_free(f);
+ }
+ runtime_gc(1); // trigger another gc to clean up the finalized objects, if possible
+ }
+}
+
+void
+__go_enable_gc()
+{
+ mstats.enablegc = 1;
+}
diff --git a/libgo/runtime/mheap.c b/libgo/runtime/mheap.c
new file mode 100644
index 000000000..52c6d8c1b
--- /dev/null
+++ b/libgo/runtime/mheap.c
@@ -0,0 +1,350 @@
+// 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.
+
+// Page heap.
+//
+// See malloc.h for overview.
+//
+// When a MSpan is in the heap free list, state == MSpanFree
+// and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
+//
+// When a MSpan is allocated, state == MSpanInUse
+// and heapmap(i) == span for all s->start <= i < s->start+s->npages.
+
+#include "runtime.h"
+#include "malloc.h"
+
+static MSpan *MHeap_AllocLocked(MHeap*, uintptr, int32);
+static bool MHeap_Grow(MHeap*, uintptr);
+static void MHeap_FreeLocked(MHeap*, MSpan*);
+static MSpan *MHeap_AllocLarge(MHeap*, uintptr);
+static MSpan *BestFit(MSpan*, uintptr, MSpan*);
+
+static void
+RecordSpan(void *vh, byte *p)
+{
+ MHeap *h;
+ MSpan *s;
+
+ h = vh;
+ s = (MSpan*)p;
+ s->allnext = h->allspans;
+ h->allspans = s;
+}
+
+// Initialize the heap; fetch memory using alloc.
+void
+runtime_MHeap_Init(MHeap *h, void *(*alloc)(uintptr))
+{
+ uint32 i;
+
+ runtime_initlock(h);
+ runtime_FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h);
+ runtime_FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil);
+ runtime_MHeapMap_Init(&h->map, alloc);
+ // h->mapcache needs no init
+ for(i=0; i<nelem(h->free); i++)
+ runtime_MSpanList_Init(&h->free[i]);
+ runtime_MSpanList_Init(&h->large);
+ for(i=0; i<nelem(h->central); i++)
+ runtime_MCentral_Init(&h->central[i], i);
+}
+
+// Allocate a new span of npage pages from the heap
+// and record its size class in the HeapMap and HeapMapCache.
+MSpan*
+runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct)
+{
+ MSpan *s;
+
+ runtime_lock(h);
+ mstats.heap_alloc += m->mcache->local_alloc;
+ m->mcache->local_alloc = 0;
+ mstats.heap_objects += m->mcache->local_objects;
+ m->mcache->local_objects = 0;
+ s = MHeap_AllocLocked(h, npage, sizeclass);
+ if(s != nil) {
+ mstats.heap_inuse += npage<<PageShift;
+ if(acct) {
+ mstats.heap_objects++;
+ mstats.heap_alloc += npage<<PageShift;
+ }
+ }
+ runtime_unlock(h);
+ return s;
+}
+
+static MSpan*
+MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
+{
+ uintptr n;
+ MSpan *s, *t;
+
+ // Try in fixed-size lists up to max.
+ for(n=npage; n < nelem(h->free); n++) {
+ if(!runtime_MSpanList_IsEmpty(&h->free[n])) {
+ s = h->free[n].next;
+ goto HaveSpan;
+ }
+ }
+
+ // Best fit in list of large spans.
+ if((s = MHeap_AllocLarge(h, npage)) == nil) {
+ if(!MHeap_Grow(h, npage))
+ return nil;
+ if((s = MHeap_AllocLarge(h, npage)) == nil)
+ return nil;
+ }
+
+HaveSpan:
+ // Mark span in use.
+ if(s->state != MSpanFree)
+ runtime_throw("MHeap_AllocLocked - MSpan not free");
+ if(s->npages < npage)
+ runtime_throw("MHeap_AllocLocked - bad npages");
+ runtime_MSpanList_Remove(s);
+ s->state = MSpanInUse;
+
+ if(s->npages > npage) {
+ // Trim extra and put it back in the heap.
+ t = runtime_FixAlloc_Alloc(&h->spanalloc);
+ mstats.mspan_inuse = h->spanalloc.inuse;
+ mstats.mspan_sys = h->spanalloc.sys;
+ runtime_MSpan_Init(t, s->start + npage, s->npages - npage);
+ s->npages = npage;
+ runtime_MHeapMap_Set(&h->map, t->start - 1, s);
+ runtime_MHeapMap_Set(&h->map, t->start, t);
+ runtime_MHeapMap_Set(&h->map, t->start + t->npages - 1, t);
+ t->state = MSpanInUse;
+ MHeap_FreeLocked(h, t);
+ }
+
+ // Record span info, because gc needs to be
+ // able to map interior pointer to containing span.
+ s->sizeclass = sizeclass;
+ for(n=0; n<npage; n++)
+ runtime_MHeapMap_Set(&h->map, s->start+n, s);
+ return s;
+}
+
+// Allocate a span of exactly npage pages from the list of large spans.
+static MSpan*
+MHeap_AllocLarge(MHeap *h, uintptr npage)
+{
+ return BestFit(&h->large, npage, nil);
+}
+
+// Search list for smallest span with >= npage pages.
+// If there are multiple smallest spans, take the one
+// with the earliest starting address.
+static MSpan*
+BestFit(MSpan *list, uintptr npage, MSpan *best)
+{
+ MSpan *s;
+
+ for(s=list->next; s != list; s=s->next) {
+ if(s->npages < npage)
+ continue;
+ if(best == nil
+ || s->npages < best->npages
+ || (s->npages == best->npages && s->start < best->start))
+ best = s;
+ }
+ return best;
+}
+
+// Try to add at least npage pages of memory to the heap,
+// returning whether it worked.
+static bool
+MHeap_Grow(MHeap *h, uintptr npage)
+{
+ uintptr ask;
+ void *v;
+ MSpan *s;
+
+ // Ask for a big chunk, to reduce the number of mappings
+ // the operating system needs to track; also amortizes
+ // the overhead of an operating system mapping.
+ // Allocate a multiple of 64kB (16 pages).
+ npage = (npage+15)&~15;
+ ask = npage<<PageShift;
+ if(ask < HeapAllocChunk)
+ ask = HeapAllocChunk;
+
+ v = runtime_SysAlloc(ask);
+ if(v == nil) {
+ if(ask > (npage<<PageShift)) {
+ ask = npage<<PageShift;
+ v = runtime_SysAlloc(ask);
+ }
+ if(v == nil)
+ return false;
+ }
+ mstats.heap_sys += ask;
+
+ if((byte*)v < h->min || h->min == nil)
+ h->min = v;
+ if((byte*)v+ask > h->max)
+ h->max = (byte*)v+ask;
+
+ // NOTE(rsc): In tcmalloc, if we've accumulated enough
+ // system allocations, the heap map gets entirely allocated
+ // in 32-bit mode. (In 64-bit mode that's not practical.)
+ if(!runtime_MHeapMap_Preallocate(&h->map, ((uintptr)v>>PageShift) - 1, (ask>>PageShift) + 2)) {
+ runtime_SysFree(v, ask);
+ return false;
+ }
+
+ // Create a fake "in use" span and free it, so that the
+ // right coalescing happens.
+ s = runtime_FixAlloc_Alloc(&h->spanalloc);
+ mstats.mspan_inuse = h->spanalloc.inuse;
+ mstats.mspan_sys = h->spanalloc.sys;
+ runtime_MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
+ runtime_MHeapMap_Set(&h->map, s->start, s);
+ runtime_MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
+ s->state = MSpanInUse;
+ MHeap_FreeLocked(h, s);
+ return true;
+}
+
+// Look up the span at the given page number.
+// Page number is guaranteed to be in map
+// and is guaranteed to be start or end of span.
+MSpan*
+runtime_MHeap_Lookup(MHeap *h, PageID p)
+{
+ return runtime_MHeapMap_Get(&h->map, p);
+}
+
+// Look up the span at the given page number.
+// Page number is *not* guaranteed to be in map
+// and may be anywhere in the span.
+// Map entries for the middle of a span are only
+// valid for allocated spans. Free spans may have
+// other garbage in their middles, so we have to
+// check for that.
+MSpan*
+runtime_MHeap_LookupMaybe(MHeap *h, PageID p)
+{
+ MSpan *s;
+
+ s = runtime_MHeapMap_GetMaybe(&h->map, p);
+ if(s == nil || p < s->start || p - s->start >= s->npages)
+ return nil;
+ if(s->state != MSpanInUse)
+ return nil;
+ return s;
+}
+
+// Free the span back into the heap.
+void
+runtime_MHeap_Free(MHeap *h, MSpan *s, int32 acct)
+{
+ runtime_lock(h);
+ mstats.heap_alloc += m->mcache->local_alloc;
+ m->mcache->local_alloc = 0;
+ mstats.heap_objects += m->mcache->local_objects;
+ m->mcache->local_objects = 0;
+ mstats.heap_inuse -= s->npages<<PageShift;
+ if(acct) {
+ mstats.heap_alloc -= s->npages<<PageShift;
+ mstats.heap_objects--;
+ }
+ MHeap_FreeLocked(h, s);
+ runtime_unlock(h);
+}
+
+static void
+MHeap_FreeLocked(MHeap *h, MSpan *s)
+{
+ MSpan *t;
+
+ if(s->state != MSpanInUse || s->ref != 0) {
+ // runtime_printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
+ runtime_throw("MHeap_FreeLocked - invalid free");
+ }
+ s->state = MSpanFree;
+ runtime_MSpanList_Remove(s);
+
+ // Coalesce with earlier, later spans.
+ if((t = runtime_MHeapMap_Get(&h->map, s->start - 1)) != nil && t->state != MSpanInUse) {
+ s->start = t->start;
+ s->npages += t->npages;
+ runtime_MHeapMap_Set(&h->map, s->start, s);
+ runtime_MSpanList_Remove(t);
+ t->state = MSpanDead;
+ runtime_FixAlloc_Free(&h->spanalloc, t);
+ mstats.mspan_inuse = h->spanalloc.inuse;
+ mstats.mspan_sys = h->spanalloc.sys;
+ }
+ if((t = runtime_MHeapMap_Get(&h->map, s->start + s->npages)) != nil && t->state != MSpanInUse) {
+ s->npages += t->npages;
+ runtime_MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
+ runtime_MSpanList_Remove(t);
+ t->state = MSpanDead;
+ runtime_FixAlloc_Free(&h->spanalloc, t);
+ mstats.mspan_inuse = h->spanalloc.inuse;
+ mstats.mspan_sys = h->spanalloc.sys;
+ }
+
+ // Insert s into appropriate list.
+ if(s->npages < nelem(h->free))
+ runtime_MSpanList_Insert(&h->free[s->npages], s);
+ else
+ runtime_MSpanList_Insert(&h->large, s);
+
+ // TODO(rsc): IncrementalScavenge() to return memory to OS.
+}
+
+// Initialize a new span with the given start and npages.
+void
+runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages)
+{
+ span->next = nil;
+ span->prev = nil;
+ span->start = start;
+ span->npages = npages;
+ span->freelist = nil;
+ span->ref = 0;
+ span->sizeclass = 0;
+ span->state = 0;
+}
+
+// Initialize an empty doubly-linked list.
+void
+runtime_MSpanList_Init(MSpan *list)
+{
+ list->state = MSpanListHead;
+ list->next = list;
+ list->prev = list;
+}
+
+void
+runtime_MSpanList_Remove(MSpan *span)
+{
+ if(span->prev == nil && span->next == nil)
+ return;
+ span->prev->next = span->next;
+ span->next->prev = span->prev;
+ span->prev = nil;
+ span->next = nil;
+}
+
+bool
+runtime_MSpanList_IsEmpty(MSpan *list)
+{
+ return list->next == list;
+}
+
+void
+runtime_MSpanList_Insert(MSpan *list, MSpan *span)
+{
+ if(span->next != nil || span->prev != nil)
+ runtime_throw("MSpanList_Insert");
+ span->next = list->next;
+ span->prev = list;
+ span->next->prev = span;
+ span->prev->next = span;
+}
diff --git a/libgo/runtime/mheapmap32.c b/libgo/runtime/mheapmap32.c
new file mode 100644
index 000000000..547c602fe
--- /dev/null
+++ b/libgo/runtime/mheapmap32.c
@@ -0,0 +1,99 @@
+// 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.
+
+// Heap map, 32-bit version
+// See malloc.h and mheap.c for overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+#if __SIZEOF_POINTER__ == 4
+
+// 3-level radix tree mapping page ids to Span*.
+void
+runtime_MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
+{
+ m->allocator = allocator;
+}
+
+MSpan*
+runtime_MHeapMap_Get(MHeapMap *m, PageID k)
+{
+ int32 i1, i2;
+
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ runtime_throw("MHeapMap_Get");
+
+ return m->p[i1]->s[i2];
+}
+
+MSpan*
+runtime_MHeapMap_GetMaybe(MHeapMap *m, PageID k)
+{
+ int32 i1, i2;
+ MHeapMapNode2 *p2;
+
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ runtime_throw("MHeapMap_Get");
+
+ p2 = m->p[i1];
+ if(p2 == nil)
+ return nil;
+ return p2->s[i2];
+}
+
+void
+runtime_MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
+{
+ int32 i1, i2;
+
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ runtime_throw("MHeapMap_Set");
+
+ m->p[i1]->s[i2] = s;
+}
+
+// Allocate the storage required for entries [k, k+1, ..., k+len-1]
+// so that Get and Set calls need not check for nil pointers.
+bool
+runtime_MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
+{
+ uintptr end;
+ int32 i1;
+ MHeapMapNode2 *p2;
+
+ end = k+len;
+ while(k < end) {
+ if((k >> MHeapMap_TotalBits) != 0)
+ return false;
+ i1 = (k >> MHeapMap_Level2Bits) & MHeapMap_Level1Mask;
+
+ // first-level pointer
+ if(m->p[i1] == nil) {
+ p2 = m->allocator(sizeof *p2);
+ if(p2 == nil)
+ return false;
+ mstats.heapmap_sys += sizeof *p2;
+ m->p[i1] = p2;
+ }
+
+ // advance key past this leaf node
+ k = ((k >> MHeapMap_Level2Bits) + 1) << MHeapMap_Level2Bits;
+ }
+ return true;
+}
+
+#endif /* __SIZEOF_POINTER__ == 4 */
diff --git a/libgo/runtime/mheapmap32.h b/libgo/runtime/mheapmap32.h
new file mode 100644
index 000000000..286162469
--- /dev/null
+++ b/libgo/runtime/mheapmap32.h
@@ -0,0 +1,41 @@
+// 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.
+
+// Free(v) must be able to determine the MSpan containing v.
+// The MHeapMap is a 2-level radix tree mapping page numbers to MSpans.
+
+typedef struct MHeapMapNode2 MHeapMapNode2;
+
+enum
+{
+ // 32 bit address - 12 bit page size = 20 bits to map
+ MHeapMap_Level1Bits = 10,
+ MHeapMap_Level2Bits = 10,
+
+ MHeapMap_TotalBits =
+ MHeapMap_Level1Bits +
+ MHeapMap_Level2Bits,
+
+ MHeapMap_Level1Mask = (1<<MHeapMap_Level1Bits) - 1,
+ MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1,
+};
+
+struct MHeapMap
+{
+ void *(*allocator)(uintptr);
+ MHeapMapNode2 *p[1<<MHeapMap_Level1Bits];
+};
+
+struct MHeapMapNode2
+{
+ MSpan *s[1<<MHeapMap_Level2Bits];
+};
+
+void runtime_MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool runtime_MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* runtime_MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* runtime_MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void runtime_MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
+
+
diff --git a/libgo/runtime/mheapmap64.c b/libgo/runtime/mheapmap64.c
new file mode 100644
index 000000000..d6305953a
--- /dev/null
+++ b/libgo/runtime/mheapmap64.c
@@ -0,0 +1,120 @@
+// 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.
+
+// Heap map, 64-bit version
+// See malloc.h and mheap.c for overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+#if __SIZEOF_POINTER__ == 8
+
+// 3-level radix tree mapping page ids to Span*.
+void
+runtime_MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
+{
+ m->allocator = allocator;
+}
+
+MSpan*
+runtime_MHeapMap_Get(MHeapMap *m, PageID k)
+{
+ int32 i1, i2, i3;
+
+ i3 = k & MHeapMap_Level3Mask;
+ k >>= MHeapMap_Level3Bits;
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ runtime_throw("MHeapMap_Get");
+
+ return m->p[i1]->p[i2]->s[i3];
+}
+
+MSpan*
+runtime_MHeapMap_GetMaybe(MHeapMap *m, PageID k)
+{
+ int32 i1, i2, i3;
+ MHeapMapNode2 *p2;
+ MHeapMapNode3 *p3;
+
+ i3 = k & MHeapMap_Level3Mask;
+ k >>= MHeapMap_Level3Bits;
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ runtime_throw("MHeapMap_Get");
+
+ p2 = m->p[i1];
+ if(p2 == nil)
+ return nil;
+ p3 = p2->p[i2];
+ if(p3 == nil)
+ return nil;
+ return p3->s[i3];
+}
+
+void
+runtime_MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
+{
+ int32 i1, i2, i3;
+
+ i3 = k & MHeapMap_Level3Mask;
+ k >>= MHeapMap_Level3Bits;
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ runtime_throw("MHeapMap_Set");
+
+ m->p[i1]->p[i2]->s[i3] = s;
+}
+
+// Allocate the storage required for entries [k, k+1, ..., k+len-1]
+// so that Get and Set calls need not check for nil pointers.
+bool
+runtime_MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
+{
+ uintptr end;
+ int32 i1, i2;
+ MHeapMapNode2 *p2;
+ MHeapMapNode3 *p3;
+
+ end = k+len;
+ while(k < end) {
+ if((k >> MHeapMap_TotalBits) != 0)
+ return false;
+ i2 = (k >> MHeapMap_Level3Bits) & MHeapMap_Level2Mask;
+ i1 = (k >> (MHeapMap_Level3Bits + MHeapMap_Level2Bits)) & MHeapMap_Level1Mask;
+
+ // first-level pointer
+ if((p2 = m->p[i1]) == nil) {
+ p2 = m->allocator(sizeof *p2);
+ if(p2 == nil)
+ return false;
+ mstats.heapmap_sys += sizeof *p2;
+ m->p[i1] = p2;
+ }
+
+ // second-level pointer
+ if(p2->p[i2] == nil) {
+ p3 = m->allocator(sizeof *p3);
+ if(p3 == nil)
+ return false;
+ mstats.heapmap_sys += sizeof *p3;
+ p2->p[i2] = p3;
+ }
+
+ // advance key past this leaf node
+ k = ((k >> MHeapMap_Level3Bits) + 1) << MHeapMap_Level3Bits;
+ }
+ return true;
+}
+
+#endif /* __SIZEOF_POINTER__ == 8 */
diff --git a/libgo/runtime/mheapmap64.h b/libgo/runtime/mheapmap64.h
new file mode 100644
index 000000000..be304cb2e
--- /dev/null
+++ b/libgo/runtime/mheapmap64.h
@@ -0,0 +1,60 @@
+// 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.
+
+// Free(v) must be able to determine the MSpan containing v.
+// The MHeapMap is a 3-level radix tree mapping page numbers to MSpans.
+//
+// NOTE(rsc): On a 32-bit platform (= 20-bit page numbers),
+// we can swap in a 2-level radix tree.
+//
+// NOTE(rsc): We use a 3-level tree because tcmalloc does, but
+// having only three levels requires approximately 1 MB per node
+// in the tree, making the minimum map footprint 3 MB.
+// Using a 4-level tree would cut the minimum footprint to 256 kB.
+// On the other hand, it's just virtual address space: most of
+// the memory is never going to be touched, thus never paged in.
+
+typedef struct MHeapMapNode2 MHeapMapNode2;
+typedef struct MHeapMapNode3 MHeapMapNode3;
+
+enum
+{
+ // 64 bit address - 12 bit page size = 52 bits to map
+ MHeapMap_Level1Bits = 18,
+ MHeapMap_Level2Bits = 18,
+ MHeapMap_Level3Bits = 16,
+
+ MHeapMap_TotalBits =
+ MHeapMap_Level1Bits +
+ MHeapMap_Level2Bits +
+ MHeapMap_Level3Bits,
+
+ MHeapMap_Level1Mask = (1<<MHeapMap_Level1Bits) - 1,
+ MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1,
+ MHeapMap_Level3Mask = (1<<MHeapMap_Level3Bits) - 1,
+};
+
+struct MHeapMap
+{
+ void *(*allocator)(uintptr);
+ MHeapMapNode2 *p[1<<MHeapMap_Level1Bits];
+};
+
+struct MHeapMapNode2
+{
+ MHeapMapNode3 *p[1<<MHeapMap_Level2Bits];
+};
+
+struct MHeapMapNode3
+{
+ MSpan *s[1<<MHeapMap_Level3Bits];
+};
+
+void runtime_MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool runtime_MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* runtime_MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* runtime_MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void runtime_MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
+
+
diff --git a/libgo/runtime/mprof.goc b/libgo/runtime/mprof.goc
new file mode 100644
index 000000000..6bd4ef727
--- /dev/null
+++ b/libgo/runtime/mprof.goc
@@ -0,0 +1,305 @@
+// 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.
+
+// Malloc profiling.
+// Patterned after tcmalloc's algorithms; shorter code.
+
+package runtime
+#include "runtime.h"
+#include "malloc.h"
+#include "defs.h"
+#include "go-type.h"
+
+typedef struct __go_open_array Slice;
+
+// NOTE(rsc): Everything here could use cas if contention became an issue.
+static Lock proflock;
+
+// Per-call-stack allocation information.
+// Lookup by hashing call stack into a linked-list hash table.
+typedef struct Bucket Bucket;
+struct Bucket
+{
+ Bucket *next; // next in hash list
+ Bucket *allnext; // next in list of all buckets
+ uintptr allocs;
+ uintptr frees;
+ uintptr alloc_bytes;
+ uintptr free_bytes;
+ uintptr hash;
+ uintptr nstk;
+ uintptr stk[1];
+};
+enum {
+ BuckHashSize = 179999,
+};
+static Bucket **buckhash;
+static Bucket *buckets;
+static uintptr bucketmem;
+
+// Return the bucket for stk[0:nstk], allocating new bucket if needed.
+static Bucket*
+stkbucket(uintptr *stk, int32 nstk)
+{
+ int32 i;
+ uintptr h;
+ Bucket *b;
+
+ if(buckhash == nil) {
+ buckhash = runtime_SysAlloc(BuckHashSize*sizeof buckhash[0]);
+ mstats.buckhash_sys += BuckHashSize*sizeof buckhash[0];
+ }
+
+ // Hash stack.
+ h = 0;
+ for(i=0; i<nstk; i++) {
+ h += stk[i];
+ h += h<<10;
+ h ^= h>>6;
+ }
+ h += h<<3;
+ h ^= h>>11;
+
+ i = h%BuckHashSize;
+ for(b = buckhash[i]; b; b=b->next)
+ if(b->hash == h && b->nstk == (uintptr)nstk &&
+ runtime_mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
+ return b;
+
+ b = runtime_mallocgc(sizeof *b + nstk*sizeof stk[0], RefNoProfiling, 0, 1);
+ bucketmem += sizeof *b + nstk*sizeof stk[0];
+ runtime_memmove(b->stk, stk, nstk*sizeof stk[0]);
+ b->hash = h;
+ b->nstk = nstk;
+ b->next = buckhash[i];
+ buckhash[i] = b;
+ b->allnext = buckets;
+ buckets = b;
+ return b;
+}
+
+// Map from pointer to Bucket* that allocated it.
+// Three levels:
+// Linked-list hash table for top N-20 bits.
+// Array index for next 13 bits.
+// Linked list for next 7 bits.
+// This is more efficient than using a general map,
+// because of the typical clustering of the pointer keys.
+
+typedef struct AddrHash AddrHash;
+typedef struct AddrEntry AddrEntry;
+
+struct AddrHash
+{
+ AddrHash *next; // next in top-level hash table linked list
+ uintptr addr; // addr>>20
+ AddrEntry *dense[1<<13];
+};
+
+struct AddrEntry
+{
+ AddrEntry *next; // next in bottom-level linked list
+ uint32 addr;
+ Bucket *b;
+};
+
+enum {
+ AddrHashBits = 12 // 1MB per entry, so good for 4GB of used address space
+};
+static AddrHash *addrhash[1<<AddrHashBits];
+static AddrEntry *addrfree;
+static uintptr addrmem;
+
+// Multiplicative hash function:
+// hashMultiplier is the bottom 32 bits of int((sqrt(5)-1)/2 * (1<<32)).
+// This is a good multiplier as suggested in CLR, Knuth. The hash
+// value is taken to be the top AddrHashBits bits of the bottom 32 bits
+// of the muliplied value.
+enum {
+ HashMultiplier = 2654435769U
+};
+
+// Set the bucket associated with addr to b.
+static void
+setaddrbucket(uintptr addr, Bucket *b)
+{
+ int32 i;
+ uint32 h;
+ AddrHash *ah;
+ AddrEntry *e;
+
+ h = (uint32)((addr>>20)*HashMultiplier) >> (32-AddrHashBits);
+ for(ah=addrhash[h]; ah; ah=ah->next)
+ if(ah->addr == (addr>>20))
+ goto found;
+
+ ah = runtime_mallocgc(sizeof *ah, RefNoProfiling, 0, 1);
+ addrmem += sizeof *ah;
+ ah->next = addrhash[h];
+ ah->addr = addr>>20;
+ addrhash[h] = ah;
+
+found:
+ if((e = addrfree) == nil) {
+ e = runtime_mallocgc(64*sizeof *e, RefNoProfiling, 0, 0);
+ addrmem += 64*sizeof *e;
+ for(i=0; i+1<64; i++)
+ e[i].next = &e[i+1];
+ e[63].next = nil;
+ }
+ addrfree = e->next;
+ e->addr = (uint32)~(addr & ((1<<20)-1));
+ e->b = b;
+ h = (addr>>7)&(nelem(ah->dense)-1); // entry in dense is top 13 bits of low 20.
+ e->next = ah->dense[h];
+ ah->dense[h] = e;
+}
+
+// Get the bucket associated with addr and clear the association.
+static Bucket*
+getaddrbucket(uintptr addr)
+{
+ uint32 h;
+ AddrHash *ah;
+ AddrEntry *e, **l;
+ Bucket *b;
+
+ h = (uint32)((addr>>20)*HashMultiplier) >> (32-AddrHashBits);
+ for(ah=addrhash[h]; ah; ah=ah->next)
+ if(ah->addr == (addr>>20))
+ goto found;
+ return nil;
+
+found:
+ h = (addr>>7)&(nelem(ah->dense)-1); // entry in dense is top 13 bits of low 20.
+ for(l=&ah->dense[h]; (e=*l) != nil; l=&e->next) {
+ if(e->addr == (uint32)~(addr & ((1<<20)-1))) {
+ *l = e->next;
+ b = e->b;
+ e->next = addrfree;
+ addrfree = e;
+ return b;
+ }
+ }
+ return nil;
+}
+
+void
+runtime_Mprof_Init()
+{
+ runtime_initlock(&proflock);
+}
+
+// Called by malloc to record a profiled block.
+void
+runtime_MProf_Malloc(void *p, uintptr size)
+{
+ int32 nstk;
+ uintptr stk[32];
+ Bucket *b;
+
+ if(!__sync_bool_compare_and_swap(&m->nomemprof, 0, 1))
+ return;
+#if 0
+ nstk = runtime_callers(1, stk, 32);
+#else
+ nstk = 0;
+#endif
+ runtime_lock(&proflock);
+ b = stkbucket(stk, nstk);
+ b->allocs++;
+ b->alloc_bytes += size;
+ setaddrbucket((uintptr)p, b);
+ runtime_unlock(&proflock);
+ __sync_bool_compare_and_swap(&m->nomemprof, 1, 0);
+
+ if(__sync_bool_compare_and_swap(&m->gcing_for_prof, 1, 0))
+ __go_run_goroutine_gc(100);
+}
+
+// Called when freeing a profiled block.
+void
+runtime_MProf_Free(void *p, uintptr size)
+{
+ Bucket *b;
+
+ if(!__sync_bool_compare_and_swap(&m->nomemprof, 0, 1))
+ return;
+
+ runtime_lock(&proflock);
+ b = getaddrbucket((uintptr)p);
+ if(b != nil) {
+ b->frees++;
+ b->free_bytes += size;
+ }
+ runtime_unlock(&proflock);
+ __sync_bool_compare_and_swap(&m->nomemprof, 1, 0);
+
+ if(__sync_bool_compare_and_swap(&m->gcing_for_prof, 1, 0))
+ __go_run_goroutine_gc(101);
+}
+
+
+// Go interface to profile data. (Declared in extern.go)
+// Assumes Go sizeof(int) == sizeof(int32)
+
+// Must match MemProfileRecord in extern.go.
+typedef struct Record Record;
+struct Record {
+ int64 alloc_bytes, free_bytes;
+ int64 alloc_objects, free_objects;
+ uintptr stk[32];
+};
+
+// Write b's data to r.
+static void
+record(Record *r, Bucket *b)
+{
+ uint32 i;
+
+ r->alloc_bytes = b->alloc_bytes;
+ r->free_bytes = b->free_bytes;
+ r->alloc_objects = b->allocs;
+ r->free_objects = b->frees;
+ for(i=0; i<b->nstk && i<nelem(r->stk); i++)
+ r->stk[i] = b->stk[i];
+ for(; i<nelem(r->stk); i++)
+ r->stk[i] = 0;
+}
+
+func MemProfile(p Slice, include_inuse_zero bool) (n int32, ok bool) {
+ Bucket *b;
+ Record *r;
+
+ __sync_bool_compare_and_swap(&m->nomemprof, 0, 1);
+
+ runtime_lock(&proflock);
+ n = 0;
+ for(b=buckets; b; b=b->allnext)
+ if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
+ n++;
+ ok = false;
+ if(n <= p.__count) {
+ ok = true;
+ r = (Record*)p.__values;
+ for(b=buckets; b; b=b->allnext)
+ if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
+ record(r++, b);
+ }
+ runtime_unlock(&proflock);
+
+ __sync_bool_compare_and_swap(&m->nomemprof, 1, 0);
+
+ if(__sync_bool_compare_and_swap(&m->gcing_for_prof, 1, 0))
+ __go_run_goroutine_gc(102);
+}
+
+void
+runtime_MProf_Mark(void (*scan)(byte *, int64))
+{
+ // buckhash is not allocated via mallocgc.
+ scan((byte*)&buckets, sizeof buckets);
+ scan((byte*)&addrhash, sizeof addrhash);
+ scan((byte*)&addrfree, sizeof addrfree);
+}
diff --git a/libgo/runtime/msize.c b/libgo/runtime/msize.c
new file mode 100644
index 000000000..8b021a2b6
--- /dev/null
+++ b/libgo/runtime/msize.c
@@ -0,0 +1,169 @@
+// 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.
+
+// Malloc small size classes.
+//
+// See malloc.h for overview.
+//
+// The size classes are chosen so that rounding an allocation
+// request up to the next size class wastes at most 12.5% (1.125x).
+//
+// Each size class has its own page count that gets allocated
+// and chopped up when new objects of the size class are needed.
+// That page count is chosen so that chopping up the run of
+// pages into objects of the given size wastes at most 12.5% (1.125x)
+// of the memory. It is not necessary that the cutoff here be
+// the same as above.
+//
+// The two sources of waste multiply, so the worst possible case
+// for the above constraints would be that allocations of some
+// size might have a 26.6% (1.266x) overhead.
+// In practice, only one of the wastes comes into play for a
+// given size (sizes < 512 waste mainly on the round-up,
+// sizes > 512 waste mainly on the page chopping).
+//
+// TODO(rsc): Compute max waste for any given size.
+
+#include "runtime.h"
+#include "malloc.h"
+
+int32 runtime_class_to_size[NumSizeClasses];
+int32 runtime_class_to_allocnpages[NumSizeClasses];
+int32 runtime_class_to_transfercount[NumSizeClasses];
+
+// The SizeToClass lookup is implemented using two arrays,
+// one mapping sizes <= 1024 to their class and one mapping
+// sizes >= 1024 and <= MaxSmallSize to their class.
+// All objects are 8-aligned, so the first array is indexed by
+// the size divided by 8 (rounded up). Objects >= 1024 bytes
+// are 128-aligned, so the second array is indexed by the
+// size divided by 128 (rounded up). The arrays are filled in
+// by InitSizes.
+
+static int32 size_to_class8[1024/8 + 1];
+static int32 size_to_class128[(MaxSmallSize-1024)/128 + 1];
+
+int32
+runtime_SizeToClass(int32 size)
+{
+ if(size > MaxSmallSize)
+ runtime_throw("SizeToClass - invalid size");
+ if(size > 1024-8)
+ return size_to_class128[(size-1024+127) >> 7];
+ return size_to_class8[(size+7)>>3];
+}
+
+void
+runtime_InitSizes(void)
+{
+ int32 align, sizeclass, size, osize, nextsize, n;
+ uint32 i;
+ uintptr allocsize, npages;
+
+ // Initialize the runtime_class_to_size table (and choose class sizes in the process).
+ runtime_class_to_size[0] = 0;
+ sizeclass = 1; // 0 means no class
+ align = 8;
+ for(size = align; size <= MaxSmallSize; size += align) {
+ if((size&(size-1)) == 0) { // bump alignment once in a while
+ if(size >= 2048)
+ align = 256;
+ else if(size >= 128)
+ align = size / 8;
+ else if(size >= 16)
+ align = 16; // required for x86 SSE instructions, if we want to use them
+ }
+ if((align&(align-1)) != 0)
+ runtime_throw("InitSizes - bug");
+
+ // Make the allocnpages big enough that
+ // the leftover is less than 1/8 of the total,
+ // so wasted space is at most 12.5%.
+ allocsize = PageSize;
+ osize = size + RefcountOverhead;
+ while(allocsize%osize > (allocsize/8))
+ allocsize += PageSize;
+ npages = allocsize >> PageShift;
+
+ // If the previous sizeclass chose the same
+ // allocation size and fit the same number of
+ // objects into the page, we might as well
+ // use just this size instead of having two
+ // different sizes.
+ if(sizeclass > 1
+ && (int32)npages == runtime_class_to_allocnpages[sizeclass-1]
+ && allocsize/osize == allocsize/(runtime_class_to_size[sizeclass-1]+RefcountOverhead)) {
+ runtime_class_to_size[sizeclass-1] = size;
+ continue;
+ }
+
+ runtime_class_to_allocnpages[sizeclass] = npages;
+ runtime_class_to_size[sizeclass] = size;
+ sizeclass++;
+ }
+ if(sizeclass != NumSizeClasses) {
+ // runtime_printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
+ runtime_throw("InitSizes - bad NumSizeClasses");
+ }
+
+ // Initialize the size_to_class tables.
+ nextsize = 0;
+ for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+ for(; nextsize < 1024 && nextsize <= runtime_class_to_size[sizeclass]; nextsize+=8)
+ size_to_class8[nextsize/8] = sizeclass;
+ if(nextsize >= 1024)
+ for(; nextsize <= runtime_class_to_size[sizeclass]; nextsize += 128)
+ size_to_class128[(nextsize-1024)/128] = sizeclass;
+ }
+
+ // Double-check SizeToClass.
+ if(0) {
+ for(n=0; n < MaxSmallSize; n++) {
+ sizeclass = runtime_SizeToClass(n);
+ if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime_class_to_size[sizeclass] < n) {
+ // runtime_printf("size=%d sizeclass=%d runtime_class_to_size=%d\n", n, sizeclass, runtime_class_to_size[sizeclass]);
+ // runtime_printf("incorrect SizeToClass");
+ goto dump;
+ }
+ if(sizeclass > 1 && runtime_class_to_size[sizeclass-1] >= n) {
+ // runtime_printf("size=%d sizeclass=%d runtime_class_to_size=%d\n", n, sizeclass, runtime_class_to_size[sizeclass]);
+ // runtime_printf("SizeToClass too big");
+ goto dump;
+ }
+ }
+ }
+
+ // Copy out for statistics table.
+ for(i=0; i<nelem(runtime_class_to_size); i++)
+ mstats.by_size[i].size = runtime_class_to_size[i];
+
+ // Initialize the runtime_class_to_transfercount table.
+ for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+ n = 64*1024 / runtime_class_to_size[sizeclass];
+ if(n < 2)
+ n = 2;
+ if(n > 32)
+ n = 32;
+ runtime_class_to_transfercount[sizeclass] = n;
+ }
+ return;
+
+dump:
+ if(1){
+ runtime_printf("NumSizeClasses=%d\n", NumSizeClasses);
+ runtime_printf("runtime_class_to_size:");
+ for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++)
+ runtime_printf(" %d", runtime_class_to_size[sizeclass]);
+ runtime_printf("\n\n");
+ runtime_printf("size_to_class8:");
+ for(i=0; i<nelem(size_to_class8); i++)
+ runtime_printf(" %d=>%d(%d)\n", i*8, size_to_class8[i], runtime_class_to_size[size_to_class8[i]]);
+ runtime_printf("\n");
+ runtime_printf("size_to_class128:");
+ for(i=0; i<nelem(size_to_class128); i++)
+ runtime_printf(" %d=>%d(%d)\n", i*128, size_to_class128[i], runtime_class_to_size[size_to_class128[i]]);
+ runtime_printf("\n");
+ }
+ runtime_throw("InitSizes failed");
+}
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
new file mode 100644
index 000000000..191fac613
--- /dev/null
+++ b/libgo/runtime/proc.c
@@ -0,0 +1,16 @@
+// 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.
+
+#include "runtime.h"
+#include "malloc.h" /* so that acid generated from proc.c includes malloc data structures */
+
+typedef struct Sched Sched;
+
+M m0;
+
+#ifdef __rtems__
+#define __thread
+#endif
+
+__thread M *m = &m0;
diff --git a/libgo/runtime/reflect.goc b/libgo/runtime/reflect.goc
new file mode 100644
index 000000000..01d218adb
--- /dev/null
+++ b/libgo/runtime/reflect.goc
@@ -0,0 +1,35 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect
+#include "go-type.h"
+#include "interface.h"
+#define nil NULL
+typedef unsigned char byte;
+
+typedef struct __go_interface Iface;
+typedef struct __go_empty_interface Eface;
+
+func setiface(typ *byte, x *byte, ret *byte) {
+ struct __go_interface_type *t;
+ const struct __go_type_descriptor* xt;
+
+ /* FIXME: We should check __type_descriptor to verify that
+ this is really a type descriptor. */
+ t = (struct __go_interface_type *)typ;
+ if(t->__methods.__count == 0) {
+ // already an empty interface
+ *(Eface*)ret = *(Eface*)x;
+ return;
+ }
+ xt = ((Eface*)x)->__type_descriptor;
+ if(xt == nil) {
+ // can assign nil to any interface
+ ((Iface*)ret)->__methods = nil;
+ ((Iface*)ret)->__object = nil;
+ return;
+ }
+ ((Iface*)ret)->__methods = __go_convert_interface(&t->__common, xt);
+ ((Iface*)ret)->__object = ((Eface*)x)->__object;
+}
diff --git a/libgo/runtime/rtems-task-variable-add.c b/libgo/runtime/rtems-task-variable-add.c
new file mode 100644
index 000000000..89dbb007a
--- /dev/null
+++ b/libgo/runtime/rtems-task-variable-add.c
@@ -0,0 +1,24 @@
+/* rtems-task-variable-add.c -- adding a task specific variable in RTEMS OS.
+
+ 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 <rtems/error.h>
+#include <rtems/system.h>
+#include <rtems/rtems/tasks.h>
+
+#include "go-assert.h"
+
+/* RTEMS does not support GNU TLS extension __thread. */
+void
+__wrap_rtems_task_variable_add (void **var)
+{
+ rtems_status_code sc = rtems_task_variable_add (RTEMS_SELF, var, NULL);
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ rtems_error (sc, "rtems_task_variable_add failed");
+ __go_assert (0);
+ }
+}
+
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
new file mode 100644
index 000000000..95216e4a5
--- /dev/null
+++ b/libgo/runtime/runtime.h
@@ -0,0 +1,196 @@
+/* runtime.h -- runtime support for Go.
+
+ 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. */
+
+#include "config.h"
+
+#define _GNU_SOURCE
+#include "go-assert.h"
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include "go-alloc.h"
+#include "go-panic.h"
+#include "go-string.h"
+
+typedef struct __go_string String;
+
+/* This file supports C files copied from the 6g runtime library.
+ This is a version of the 6g runtime.h rewritten for gccgo's version
+ of the code. */
+
+typedef signed int int8 __attribute__ ((mode (QI)));
+typedef unsigned int uint8 __attribute__ ((mode (QI)));
+typedef signed int int16 __attribute__ ((mode (HI)));
+typedef unsigned int uint16 __attribute__ ((mode (HI)));
+typedef signed int int32 __attribute__ ((mode (SI)));
+typedef unsigned int uint32 __attribute__ ((mode (SI)));
+typedef signed int int64 __attribute__ ((mode (DI)));
+typedef unsigned int uint64 __attribute__ ((mode (DI)));
+typedef float float32 __attribute__ ((mode (SF)));
+typedef double float64 __attribute__ ((mode (DF)));
+typedef unsigned int uintptr __attribute__ ((mode (pointer)));
+
+/* Defined types. */
+
+typedef uint8 bool;
+typedef uint8 byte;
+typedef struct M M;
+typedef struct MCache MCache;
+typedef struct Lock Lock;
+
+/* We use mutexes for locks. 6g uses futexes directly, and perhaps
+ someday we will do that too. */
+
+struct Lock
+{
+ uint32 key;
+ sem_t sem;
+};
+
+/* A Note. */
+
+typedef struct Note Note;
+
+struct Note {
+ int32 woken;
+};
+
+/* Per CPU declarations. */
+
+#ifdef __rtems__
+#define __thread
+#endif
+
+extern __thread M* m;
+
+extern M m0;
+
+#ifdef __rtems__
+#undef __thread
+#endif
+
+/* Constants. */
+
+enum
+{
+ true = 1,
+ false = 0,
+};
+
+/* Structures. */
+
+struct M
+{
+ int32 mallocing;
+ int32 gcing;
+ int32 locks;
+ int32 nomemprof;
+ int32 gcing_for_prof;
+ int32 holds_finlock;
+ int32 gcing_for_finlock;
+ MCache *mcache;
+
+ /* For the list of all threads. */
+ struct __go_thread_id *list_entry;
+
+ /* For the garbage collector. */
+ void *gc_sp;
+ size_t gc_len;
+ void *gc_next_segment;
+ void *gc_next_sp;
+ void *gc_initial_sp;
+ struct __go_panic_defer_struct *gc_panic_defer;
+};
+
+/* Macros. */
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+#define nil ((void*)0)
+#define USED(v) ((void) v)
+
+/* We map throw to assert. */
+#define runtime_throw(s) __go_assert(s == 0)
+
+void* runtime_mal(uintptr);
+void runtime_mallocinit(void);
+void runtime_initfintab(void);
+void siginit(void);
+bool __go_sigsend(int32 sig);
+int64 runtime_nanotime(void);
+
+void runtime_stoptheworld(void);
+void runtime_starttheworld(void);
+void __go_go(void (*pfn)(void*), void*);
+void __go_gc_goroutine_init(void*);
+void __go_enable_gc(void);
+int __go_run_goroutine_gc(int);
+void __go_scanstacks(void (*scan)(byte *, int64));
+void __go_stealcache(void);
+void __go_cachestats(void);
+
+/*
+ * mutual exclusion locks. in the uncontended case,
+ * as fast as spin locks (just a few user-level instructions),
+ * but on the contention path they sleep in the kernel.
+ */
+void runtime_initlock(Lock*);
+void runtime_lock(Lock*);
+void runtime_unlock(Lock*);
+void runtime_destroylock(Lock*);
+
+void semacquire (uint32 *) asm ("libgo_runtime.runtime.Semacquire");
+void semrelease (uint32 *) asm ("libgo_runtime.runtime.Semrelease");
+
+/*
+ * sleep and wakeup on one-time events.
+ * before any calls to notesleep or notewakeup,
+ * must call noteclear to initialize the Note.
+ * then, any number of threads can call notesleep
+ * and exactly one thread can call notewakeup (once).
+ * once notewakeup has been called, all the notesleeps
+ * will return. future notesleeps will return immediately.
+ */
+void noteclear(Note*);
+void notesleep(Note*);
+void notewakeup(Note*);
+
+/* Functions. */
+#define runtime_printf printf
+#define runtime_malloc(s) __go_alloc(s)
+#define runtime_free(p) __go_free(p)
+#define runtime_memclr(buf, size) __builtin_memset((buf), 0, (size))
+#define runtime_strcmp(s1, s2) __builtin_strcmp((s1), (s2))
+#define runtime_getenv(s) getenv(s)
+#define runtime_atoi(s) atoi(s)
+#define runtime_mcmp(a, b, s) __builtin_memcmp((a), (b), (s))
+#define runtime_memmove(a, b, s) __builtin_memmove((a), (b), (s))
+MCache* runtime_allocmcache(void);
+void free(void *v);
+struct __go_func_type;
+void runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type *);
+void runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64));
+#define runtime_mmap mmap
+#define runtime_munmap(p, s) munmap((p), (s))
+#define runtime_cas(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
+
+struct __go_func_type;
+void reflect_call(const struct __go_func_type *, const void *, _Bool, void **,
+ void **)
+ asm ("libgo_reflect.reflect.call");
+
+#ifdef __rtems__
+void __wrap_rtems_task_variable_add(void **);
+#endif
diff --git a/libgo/runtime/sigqueue.goc b/libgo/runtime/sigqueue.goc
new file mode 100644
index 000000000..b5f2954bc
--- /dev/null
+++ b/libgo/runtime/sigqueue.goc
@@ -0,0 +1,113 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements runtime support for signal handling.
+//
+// Most synchronization primitives are not available from
+// the signal handler (it cannot block and cannot use locks)
+// so the handler communicates with a processing goroutine
+// via struct sig, below.
+//
+// Ownership for sig.Note passes back and forth between
+// the signal handler and the signal goroutine in rounds.
+// The initial state is that sig.note is cleared (setup by siginit).
+// At the beginning of each round, mask == 0.
+// The round goes through three stages:
+//
+// (In parallel)
+// 1a) One or more signals arrive and are handled
+// by sigsend using cas to set bits in sig.mask.
+// The handler that changes sig.mask from zero to non-zero
+// calls notewakeup(&sig).
+// 1b) Sigrecv calls notesleep(&sig) to wait for the wakeup.
+//
+// 2) Having received the wakeup, sigrecv knows that sigsend
+// will not send another wakeup, so it can noteclear(&sig)
+// to prepare for the next round. (Sigsend may still be adding
+// signals to sig.mask at this point, which is fine.)
+//
+// 3) Sigrecv uses cas to grab the current sig.mask and zero it,
+// triggering the next round.
+//
+// The signal handler takes ownership of the note by atomically
+// changing mask from a zero to non-zero value. It gives up
+// ownership by calling notewakeup. The signal goroutine takes
+// ownership by returning from notesleep (caused by the notewakeup)
+// and gives up ownership by clearing mask.
+
+package runtime
+#include "config.h"
+#include "runtime.h"
+#include "malloc.h"
+#include "defs.h"
+
+static struct {
+ Note;
+ uint32 mask;
+ bool inuse;
+} sig;
+
+void
+siginit(void)
+{
+ noteclear(&sig);
+}
+
+// Called from sighandler to send a signal back out of the signal handling thread.
+bool
+__go_sigsend(int32 s)
+{
+ uint32 bit, mask;
+
+ if(!sig.inuse)
+ return false;
+ bit = 1 << s;
+ for(;;) {
+ mask = sig.mask;
+ if(mask & bit)
+ break; // signal already in queue
+ if(runtime_cas(&sig.mask, mask, mask|bit)) {
+ // Added to queue.
+ // Only send a wakeup for the first signal in each round.
+ if(mask == 0)
+ notewakeup(&sig);
+ break;
+ }
+ }
+ return true;
+}
+
+// Called to receive a bitmask of queued signals.
+func Sigrecv() (m uint32) {
+ // runtime·entersyscall();
+ notesleep(&sig);
+ // runtime·exitsyscall();
+ noteclear(&sig);
+ for(;;) {
+ m = sig.mask;
+ if(runtime_cas(&sig.mask, m, 0))
+ break;
+ }
+}
+
+func Signame(sig int32) (name String) {
+ const char* s = NULL;
+ char buf[100];
+#if defined(HAVE_STRSIGNAL)
+ s = strsignal(sig);
+#endif
+ if (s == NULL) {
+ snprintf(buf, sizeof buf, "signal %d", sig);
+ s = buf;
+ }
+ int32 len = __builtin_strlen(s);
+ unsigned char *data = runtime_mallocgc(len, RefNoPointers, 0, 0);
+ __builtin_memcpy(data, s, len);
+ name.__data = data;
+ name.__length = len;
+}
+
+func Siginit() {
+ sig.inuse = true; // enable reception of signals; cannot disable
+}
diff --git a/libgo/runtime/string.goc b/libgo/runtime/string.goc
new file mode 100644
index 000000000..332277c52
--- /dev/null
+++ b/libgo/runtime/string.goc
@@ -0,0 +1,57 @@
+// Copyright 2009, 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+#include "runtime.h"
+#define charntorune(pv, str, len) __go_get_rune(str, len, pv)
+
+enum
+{
+ Runeself = 0x80,
+};
+
+func stringiter(s String, k int32) (retk int32) {
+ int32 l, n;
+
+ if(k >= s.__length) {
+ // retk=0 is end of iteration
+ retk = 0;
+ goto out;
+ }
+
+ l = s.__data[k];
+ if(l < Runeself) {
+ retk = k+1;
+ goto out;
+ }
+
+ // multi-char rune
+ n = charntorune(&l, s.__data+k, s.__length-k);
+ retk = k + (n ? n : 1);
+
+out:
+}
+
+func stringiter2(s String, k int32) (retk int32, retv int32) {
+ int32 n;
+
+ if(k >= s.__length) {
+ // retk=0 is end of iteration
+ retk = 0;
+ retv = 0;
+ goto out;
+ }
+
+ retv = s.__data[k];
+ if(retv < Runeself) {
+ retk = k+1;
+ goto out;
+ }
+
+ // multi-char rune
+ n = charntorune(&retv, s.__data+k, s.__length-k);
+ retk = k + (n ? n : 1);
+
+out:
+}
diff --git a/libgo/runtime/thread.c b/libgo/runtime/thread.c
new file mode 100644
index 000000000..bac3f7dfd
--- /dev/null
+++ b/libgo/runtime/thread.c
@@ -0,0 +1,118 @@
+// 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 <errno.h>
+#include "runtime.h"
+#include "go-assert.h"
+
+void
+runtime_initlock(Lock *l)
+{
+ l->key = 0;
+ if(sem_init(&l->sem, 0, 0) != 0)
+ runtime_throw("sem_init failed");
+}
+
+static uint32
+runtime_xadd(uint32 volatile *val, int32 delta)
+{
+ uint32 oval, nval;
+
+ for(;;){
+ oval = *val;
+ nval = oval + delta;
+ if(runtime_cas(val, oval, nval))
+ return nval;
+ }
+}
+
+// noinline so that runtime_lock doesn't have to split the stack.
+static void runtime_lock_full(Lock *l) __attribute__ ((noinline));
+
+static void
+runtime_lock_full(Lock *l)
+{
+ for(;;){
+ if(sem_wait(&l->sem) == 0)
+ return;
+ if(errno != EINTR)
+ runtime_throw("sem_wait failed");
+ }
+}
+
+void
+runtime_lock(Lock *l)
+{
+ if(m != nil) {
+ if(m->locks < 0)
+ runtime_throw("lock count");
+ m->locks++;
+ }
+
+ if(runtime_xadd(&l->key, 1) > 1) // someone else has it; wait
+ runtime_lock_full(l);
+}
+
+static void runtime_unlock_full(Lock *l) __attribute__ ((noinline));
+
+static void
+runtime_unlock_full(Lock *l)
+{
+ if(sem_post(&l->sem) != 0)
+ runtime_throw("sem_post failed");
+}
+
+void
+runtime_unlock(Lock *l)
+{
+ if(m != nil) {
+ m->locks--;
+ if(m->locks < 0)
+ runtime_throw("lock count");
+ }
+
+ if(runtime_xadd(&l->key, -1) > 0) // someone else is waiting
+ runtime_unlock_full(l);
+}
+
+void
+runtime_destroylock(Lock *l)
+{
+ sem_destroy(&l->sem);
+}
+
+#ifndef HAVE_SYNC_BOOL_COMPARE_AND_SWAP_4
+
+// For targets which don't have the required sync support. Really
+// this should be provided by gcc itself. FIXME.
+
+static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER;
+
+_Bool
+__sync_bool_compare_and_swap_4(uint32*, uint32, uint32)
+ __attribute__((visibility("hidden")));
+
+_Bool
+__sync_bool_compare_and_swap_4(uint32* ptr, uint32 old, uint32 new)
+{
+ int i;
+ _Bool ret;
+
+ i = pthread_mutex_lock(&sync_lock);
+ __go_assert(i == 0);
+
+ if(*ptr != old) {
+ ret = 0;
+ } else {
+ *ptr = new;
+ ret = 1;
+ }
+
+ i = pthread_mutex_unlock(&sync_lock);
+ __go_assert(i == 0);
+
+ return ret;
+}
+
+#endif
diff --git a/libgo/syscalls/errno.c b/libgo/syscalls/errno.c
new file mode 100644
index 000000000..34771a0d8
--- /dev/null
+++ b/libgo/syscalls/errno.c
@@ -0,0 +1,25 @@
+/* errno.c -- functions for getting and setting errno
+
+ 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 <errno.h>
+
+/* errno is typically a macro. These functions set
+ and get errno specific to the libc being used. */
+
+int GetErrno() asm ("libgo_syscalls.syscall.GetErrno");
+void SetErrno(int) asm ("libgo_syscalls.syscall.SetErrno");
+
+int
+GetErrno()
+{
+ return errno;
+}
+
+void
+SetErrno(int value)
+{
+ errno = value;
+}
diff --git a/libgo/syscalls/errstr.go b/libgo/syscalls/errstr.go
new file mode 100644
index 000000000..a95abc686
--- /dev/null
+++ b/libgo/syscalls/errstr.go
@@ -0,0 +1,24 @@
+// errstr.go -- Error strings.
+
+// 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 syscall
+
+func Errstr(errno int) string {
+ for len := Size_t(128); ; len *= 2 {
+ b := make([]byte, len)
+ r := libc_strerror_r(errno, &b[0], len)
+ if r >= 0 {
+ i := 0
+ for b[i] != 0 {
+ i++
+ }
+ return string(b[:i])
+ }
+ if GetErrno() != ERANGE {
+ return "Errstr failure"
+ }
+ }
+}
diff --git a/libgo/syscalls/errstr_decl.go b/libgo/syscalls/errstr_decl.go
new file mode 100644
index 000000000..b6bff0fb0
--- /dev/null
+++ b/libgo/syscalls/errstr_decl.go
@@ -0,0 +1,9 @@
+// errstr.go -- Declare strerror_r.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func libc_strerror_r(int, *byte, Size_t) int __asm__ ("strerror_r")
diff --git a/libgo/syscalls/errstr_decl_linux.go b/libgo/syscalls/errstr_decl_linux.go
new file mode 100644
index 000000000..4c1cb82a0
--- /dev/null
+++ b/libgo/syscalls/errstr_decl_linux.go
@@ -0,0 +1,9 @@
+// errstr_decl_linux.go -- Declare strerror_r for GNU/Linux.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func libc_strerror_r(int, *byte, Size_t) int __asm__ ("__xpg_strerror_r")
diff --git a/libgo/syscalls/errstr_decl_rtems.go b/libgo/syscalls/errstr_decl_rtems.go
new file mode 100644
index 000000000..b83eedc8e
--- /dev/null
+++ b/libgo/syscalls/errstr_decl_rtems.go
@@ -0,0 +1,10 @@
+// errstr.go -- Declare strerror_r for RTEMS.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+// RTEMS uses strerror_r in newlib, which is a GNU extension returning a char *.
+func libc_strerror_r(int, *byte, Size_t) *byte __asm__ ("strerror_r")
diff --git a/libgo/syscalls/errstr_rtems.go b/libgo/syscalls/errstr_rtems.go
new file mode 100644
index 000000000..f6b453bdc
--- /dev/null
+++ b/libgo/syscalls/errstr_rtems.go
@@ -0,0 +1,26 @@
+// errstr_rtems.go -- RTEMS specific error strings.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func Errstr(errno int) string {
+ for len := Size_t(128); ; len *= 2 {
+ b := make([]byte, len+1)
+
+ // The newlib strerror_r always returns the string in buffer.
+ libc_strerror_r(errno, &b[0], len)
+ b[len] = 0
+
+ i := 0
+ for b[i] != 0 {
+ i++
+ }
+
+ if Size_t(i) < len {
+ return string(b[0:i])
+ }
+ }
+}
diff --git a/libgo/syscalls/exec.go b/libgo/syscalls/exec.go
new file mode 100644
index 000000000..d0f56d3b9
--- /dev/null
+++ b/libgo/syscalls/exec.go
@@ -0,0 +1,248 @@
+// exec.go -- fork/exec syscall support.
+
+// 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.
+
+// Fork, exec, wait, etc.
+
+package syscall
+
+import "unsafe"
+
+func libc_fcntl(fd int, cmd int, arg int) int __asm__ ("fcntl")
+func libc_fork() Pid_t __asm__ ("fork")
+func libc_chdir(name *byte) int __asm__ ("chdir");
+func libc_dup2(int, int) int __asm__ ("dup2")
+func libc_execve(*byte, **byte, **byte) int __asm__ ("execve")
+func libc_sysexit(int) __asm__ ("_exit")
+func libc_wait4(Pid_t, *int, int, *Rusage) Pid_t __asm__ ("wait4")
+
+// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
+// If a dup or exec fails, write the errno int to pipe.
+// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
+// In the child, this function must not acquire any locks, because
+// they might have been locked at the time of the fork. This means
+// no rescheduling, no malloc calls, and no new stack segments.
+func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, traceme bool, dir *byte, fd []int, 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;
+ var nextfd int;
+ var i int;
+
+ darwin := OS == "darwin";
+
+ // About to call fork.
+ // No more allocation or calls of non-assembly functions.
+ child := libc_fork();
+ if child == -1 {
+ return 0, GetErrno();
+ }
+
+ if child != 0 {
+ // parent; return PID
+ return int(child), 0
+ }
+
+ // Fork succeeded, now in child.
+
+ // Enable tracing if requested.
+ if traceme {
+ if libc_ptrace(_PTRACE_TRACEME, 0, 0, nil) < 0 {
+ goto childerror;
+ }
+ }
+
+ // Chdir
+ if dir != nil {
+ r := libc_chdir(dir);
+ if r < 0 {
+ goto childerror;
+ }
+ }
+
+ // Pass 1: look for fd[i] < i and move those up above len(fd)
+ // so that pass 2 won't stomp on an fd it needs later.
+ nextfd = int(len(fd));
+ if pipe < nextfd {
+ r := libc_dup2(pipe, nextfd);
+ if r == -1 {
+ goto childerror;
+ }
+ libc_fcntl(nextfd, F_SETFD, FD_CLOEXEC);
+ pipe = nextfd;
+ nextfd++;
+ }
+ for i = 0; i < len(fd); i++ {
+ if fd[i] >= 0 && fd[i] < int(i) {
+ r := libc_dup2(fd[i], nextfd);
+ if r == -1 {
+ goto childerror;
+ }
+ libc_fcntl(nextfd, F_SETFD, FD_CLOEXEC);
+ fd[i] = nextfd;
+ nextfd++;
+ if nextfd == pipe { // don't stomp on pipe
+ nextfd++;
+ }
+ }
+ }
+
+ // Pass 2: dup fd[i] down onto i.
+ for i = 0; i < len(fd); i++ {
+ if fd[i] == -1 {
+ libc_close(i);
+ continue;
+ }
+ if fd[i] == int(i) {
+ // dup2(i, i) won't clear close-on-exec flag on Linux,
+ // probably not elsewhere either.
+ r := libc_fcntl(fd[i], F_SETFD, 0);
+ if r != 0 {
+ goto childerror;
+ }
+ continue;
+ }
+ // The new fd is created NOT close-on-exec,
+ // which is exactly what we want.
+ r := libc_dup2(fd[i], i);
+ if r == -1 {
+ goto childerror;
+ }
+ }
+
+ // By convention, we don't close-on-exec the fds we are
+ // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
+ // Programs that know they inherit fds >= 3 will need
+ // to set them close-on-exec.
+ for i = len(fd); i < 3; i++ {
+ libc_close(i);
+ }
+
+ // Time to exec.
+ libc_execve(argv0, &argv[0], &envv[0]);
+
+childerror:
+ // send error code on pipe
+ var e uintptr = uintptr(GetErrno());
+ libc_write(pipe, (*byte)(unsafe.Pointer(&e)),
+ Size_t(unsafe.Sizeof(err1)));
+ for {
+ libc_sysexit(253)
+ }
+
+ // Calling panic is not actually safe,
+ // but the for loop above won't break
+ // and this shuts up the compiler.
+ panic("unreached");
+}
+
+func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir string, fd []int) (pid int, err int) {
+ var p [2]int;
+ var r1 int;
+ var err1 uintptr;
+ var wstatus WaitStatus;
+
+ p[0] = -1;
+ p[1] = -1;
+
+ // Convert args to C form.
+ argv0p := StringBytePtr(argv0);
+ argvp := StringArrayPtr(argv);
+ envvp := StringArrayPtr(envv);
+ var dirp *byte;
+ if len(dir) > 0 {
+ dirp = StringBytePtr(dir);
+ }
+
+ // Acquire the fork lock so that no other threads
+ // create new fds that are not yet close-on-exec
+ // before we fork.
+ ForkLock.Lock();
+
+ // Allocate child status pipe close on exec.
+ if err = Pipe(p[0:]); err != 0 {
+ goto error;
+ }
+ var val int;
+ if val, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != 0 {
+ goto error;
+ }
+ if val, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != 0 {
+ goto error;
+ }
+
+ // Kick off child.
+ pid, err = forkAndExecInChild(argv0p, argvp, envvp, traceme, dirp, fd, p[1]);
+ if err != 0 {
+ error:
+ if p[0] >= 0 {
+ Close(p[0]);
+ Close(p[1]);
+ }
+ ForkLock.Unlock();
+ return 0, err
+ }
+ ForkLock.Unlock();
+
+ // Read child error status from pipe.
+ Close(p[1]);
+ n := libc_read(p[0], (*byte)(unsafe.Pointer(&err1)),
+ Size_t(unsafe.Sizeof(err1)));
+ err = 0;
+ if n < 0 {
+ err = GetErrno();
+ }
+ Close(p[0]);
+ if err != 0 || n != 0 {
+ if int(n) == unsafe.Sizeof(err1) {
+ err = int(err1);
+ }
+ if err == 0 {
+ err = EPIPE;
+ }
+
+ // Child failed; wait for it to exit, to make sure
+ // the zombies don't accumulate.
+ pid1, err1 := Wait4(pid, &wstatus, 0, nil);
+ for err1 == EINTR {
+ pid1, err1 = Wait4(pid, &wstatus, 0, nil);
+ }
+ return 0, err
+ }
+
+ // Read got EOF, so pipe closed on exec, so exec succeeded.
+ return pid, 0
+}
+
+// Combination of fork and exec, careful to be thread safe.
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
+ return forkExec(argv0, argv, envv, false, dir, fd);
+}
+
+// PtraceForkExec is like ForkExec, but starts the child in a traced state.
+func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
+ return forkExec(argv0, argv, envv, true, dir, fd);
+}
+
+// Ordinary exec.
+func Exec(argv0 string, argv []string, envv []string) (err int) {
+ argv_arg := StringArrayPtr(argv);
+ envv_arg := StringArrayPtr(envv);
+ libc_execve(StringBytePtr(argv0), &argv_arg[0], &envv_arg[0]);
+ return GetErrno();
+}
+
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
+ var status int;
+ r := libc_wait4(Pid_t(pid), &status, options, rusage);
+ wpid = int(r);
+ if r < 0 {
+ errno = GetErrno();
+ }
+ if wstatus != nil {
+ *wstatus = WaitStatus(status);
+ }
+ return;
+}
diff --git a/libgo/syscalls/exec_helpers.go b/libgo/syscalls/exec_helpers.go
new file mode 100644
index 000000000..c8a68a058
--- /dev/null
+++ b/libgo/syscalls/exec_helpers.go
@@ -0,0 +1,154 @@
+// exec_helpers.go -- helper functions used with fork, exec, wait.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "sync"
+
+// Lock synchronizing creation of new file descriptors with fork.
+//
+// We want the child in a fork/exec sequence to inherit only the
+// file descriptors we intend. To do that, we mark all file
+// descriptors close-on-exec and then, in the child, explicitly
+// unmark the ones we want the exec'ed program to keep.
+// Unix doesn't make this easy: there is, in general, no way to
+// allocate a new file descriptor close-on-exec. Instead you
+// have to allocate the descriptor and then mark it close-on-exec.
+// If a fork happens between those two events, the child's exec
+// will inherit an unwanted file descriptor.
+//
+// This lock solves that race: the create new fd/mark close-on-exec
+// operation is done holding ForkLock for reading, and the fork itself
+// is done holding ForkLock for writing. At least, that's the idea.
+// There are some complications.
+//
+// Some system calls that create new file descriptors can block
+// for arbitrarily long times: open on a hung NFS server or named
+// pipe, accept on a socket, and so on. We can't reasonably grab
+// the lock across those operations.
+//
+// It is worse to inherit some file descriptors than others.
+// If a non-malicious child accidentally inherits an open ordinary file,
+// that's not a big deal. On the other hand, if a long-lived child
+// accidentally inherits the write end of a pipe, then the reader
+// of that pipe will not see EOF until that child exits, potentially
+// causing the parent program to hang. This is a common problem
+// in threaded C programs that use popen.
+//
+// Luckily, the file descriptors that are most important not to
+// inherit are not the ones that can take an arbitrarily long time
+// to create: pipe returns instantly, and the net package uses
+// non-blocking I/O to accept on a listening socket.
+// The rules for which file descriptor-creating operations use the
+// ForkLock are as follows:
+//
+// 1) Pipe. Does not block. Use the ForkLock.
+// 2) Socket. Does not block. Use the ForkLock.
+// 3) Accept. If using non-blocking mode, use the ForkLock.
+// Otherwise, live with the race.
+// 4) Open. Can block. Use O_CLOEXEC if available (Linux).
+// Otherwise, live with the race.
+// 5) Dup. Does not block. Use the ForkLock.
+// On Linux, could use fcntl F_DUPFD_CLOEXEC
+// instead of the ForkLock, but only for dup(fd, -1).
+
+type WaitStatus int
+
+var ForkLock sync.RWMutex
+
+// Convert array of string to array
+// of NUL-terminated byte pointer.
+func StringArrayPtr(ss []string) []*byte {
+ bb := make([]*byte, len(ss)+1);
+ for i := 0; i < len(ss); i++ {
+ bb[i] = StringBytePtr(ss[i]);
+ }
+ bb[len(ss)] = nil;
+ return bb;
+}
+
+func CloseOnExec(fd int) {
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
+func SetNonblock(fd int, nonblocking bool) (errno int) {
+ flag, err := fcntl(fd, F_GETFL, 0);
+ if err != 0 {
+ return err;
+ }
+ if nonblocking {
+ flag |= O_NONBLOCK;
+ } else {
+ flag &= ^O_NONBLOCK;
+ }
+ flag, err = fcntl(fd, F_SETFL, flag);
+ return err;
+}
+
+// Wait status is 7 bits at bottom, either 0 (exited),
+// 0x7F (stopped), or a signal number that caused an exit.
+// The 0x80 bit is whether there was a core dump.
+// An extra number (exit code, signal causing a stop)
+// is in the high bits. At least that's the idea.
+// There are various irregularities. For example, the
+// "continued" status is 0xFFFF, distinguishing itself
+// from stopped via the core dump bit.
+
+const (
+ mask = 0x7F;
+ core = 0x80;
+ exited = 0x00;
+ stopped = 0x7F;
+ shift = 8;
+)
+
+func (w WaitStatus) Exited() bool {
+ return w&mask == exited;
+}
+
+func (w WaitStatus) Signaled() bool {
+ return w&mask != stopped && w&mask != exited;
+}
+
+func (w WaitStatus) Stopped() bool {
+ return w&0xFF == stopped;
+}
+
+func (w WaitStatus) Continued() bool {
+ return w == 0xFFFF;
+}
+
+func (w WaitStatus) CoreDump() bool {
+ return w.Signaled() && w&core != 0;
+}
+
+func (w WaitStatus) ExitStatus() int {
+ if !w.Exited() {
+ return -1;
+ }
+ return int(w >> shift) & 0xFF;
+}
+
+func (w WaitStatus) Signal() int {
+ if !w.Signaled() {
+ return -1;
+ }
+ return int(w & mask);
+}
+
+func (w WaitStatus) StopSignal() int {
+ if !w.Stopped() {
+ return -1;
+ }
+ return int(w >> shift) & 0xFF;
+}
+
+func (w WaitStatus) TrapCause() int {
+ if w.StopSignal() != SIGTRAP {
+ return -1;
+ }
+ return int(w >> shift) >> 8;
+}
diff --git a/libgo/syscalls/exec_stubs.go b/libgo/syscalls/exec_stubs.go
new file mode 100644
index 000000000..7b4346cc4
--- /dev/null
+++ b/libgo/syscalls/exec_stubs.go
@@ -0,0 +1,25 @@
+// exec_stubs.go -- fork/exec stubs.
+
+// 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.
+
+// Stubs for fork, exec and wait.
+
+package syscall
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
+ return -1, ENOSYS;
+}
+
+func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
+ return -1, ENOSYS;
+}
+
+func Exec(argv0 string, argv []string, envv []string) (err int) {
+ return ENOSYS;
+}
+
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
+ return -1, ENOSYS;
+}
diff --git a/libgo/syscalls/sleep_rtems.go b/libgo/syscalls/sleep_rtems.go
new file mode 100644
index 000000000..8a9ae8a30
--- /dev/null
+++ b/libgo/syscalls/sleep_rtems.go
@@ -0,0 +1,19 @@
+// sleep_rtems.go -- Sleep on RTEMS.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func libc_nanosleep(req *Timespec, rem *Timespec) int __asm__ ("nanosleep")
+
+func Sleep(nsec int64) (errno int) {
+ errno = 0
+ ts := NsecToTimespec(nsec)
+ r := libc_nanosleep(&ts, nil)
+ if r < 0 {
+ errno = GetErrno()
+ }
+ return
+}
diff --git a/libgo/syscalls/sleep_select.go b/libgo/syscalls/sleep_select.go
new file mode 100644
index 000000000..6fc13a0ea
--- /dev/null
+++ b/libgo/syscalls/sleep_select.go
@@ -0,0 +1,13 @@
+// sleep_select.go -- Sleep using select.
+
+// 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 syscall
+
+func Sleep(nsec int64) (errno int) {
+ tv := NsecToTimeval(nsec);
+ n, err := Select(0, nil, nil, nil, &tv);
+ return err;
+}
diff --git a/libgo/syscalls/socket.go b/libgo/syscalls/socket.go
new file mode 100644
index 000000000..65c191671
--- /dev/null
+++ b/libgo/syscalls/socket.go
@@ -0,0 +1,383 @@
+// socket.go -- Socket handling.
+
+// 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.
+
+// Low-level socket interface.
+// Only for implementing net package.
+// DO NOT USE DIRECTLY.
+
+package syscall
+
+import "unsafe"
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr;
+ Pad [12]int8;
+}
+
+const SizeofSockaddrAny = 0x1c;
+
+// For testing: clients can set this flag to force
+// creation of IPv6 sockets to return EAFNOSUPPORT.
+var SocketDisableIPv6 bool
+
+type Sockaddr interface {
+ sockaddr() (ptr *RawSockaddrAny, len Socklen_t, errno int); // lowercase; only we can define Sockaddrs
+}
+
+type SockaddrInet4 struct {
+ Port int;
+ Addr [4]byte;
+ raw RawSockaddrInet4;
+}
+
+type SockaddrInet6 struct {
+ Port int;
+ Addr [16]byte;
+ raw RawSockaddrInet6;
+}
+
+type SockaddrUnix struct {
+ Name string;
+ raw RawSockaddrUnix;
+}
+
+type Linger struct {
+ Onoff int32;
+ Linger int32;
+}
+
+func (sa *SockaddrInet4) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, EINVAL;
+ }
+ sa.raw.Family = AF_INET;
+ n := sa.raw.setLen()
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port));
+ p[0] = byte(sa.Port>>8);
+ p[1] = byte(sa.Port);
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i];
+ }
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), n, 0;
+}
+
+func (sa *SockaddrInet6) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, EINVAL;
+ }
+ sa.raw.Family = AF_INET6;
+ n := sa.raw.setLen()
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port));
+ p[0] = byte(sa.Port>>8);
+ p[1] = byte(sa.Port);
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i];
+ }
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), n, 0;
+}
+
+func (sa *SockaddrUnix) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+ name := sa.Name;
+ n := len(name);
+ if n >= len(sa.raw.Path) || n == 0 {
+ return nil, 0, EINVAL;
+ }
+ sa.raw.Family = AF_UNIX;
+ sa.raw.setLen(n)
+ for i := 0; i < n; i++ {
+ sa.raw.Path[i] = int8(name[i]);
+ }
+ if sa.raw.Path[0] == '@' {
+ sa.raw.Path[0] = 0;
+ }
+
+ // length is family (uint16), name, NUL.
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), 2 + Socklen_t(n) + 1, 0;
+}
+
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
+ switch rsa.Addr.Family {
+ case AF_UNIX:
+ pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
+ sa := new(SockaddrUnix)
+ n, err := pp.getLen()
+ if err != 0 {
+ return nil, err
+ }
+ bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]));
+ sa.Name = string(bytes[0:n]);
+ return sa, 0;
+
+ case AF_INET:
+ pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa));
+ sa := new(SockaddrInet4);
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port));
+ sa.Port = int(p[0])<<8 + int(p[1]);
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i];
+ }
+ return sa, 0;
+
+ case AF_INET6:
+ pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa));
+ sa := new(SockaddrInet6);
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port));
+ sa.Port = int(p[0])<<8 + int(p[1]);
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i];
+ }
+ return sa, 0;
+ }
+ return nil, EAFNOSUPPORT;
+}
+
+func libc_accept(fd int, sa *RawSockaddrAny, len *Socklen_t) int __asm__ ("accept");
+func libc_bind(fd int, sa *RawSockaddrAny, len Socklen_t) int __asm__ ("bind");
+func libc_connect(fd int, sa *RawSockaddrAny, len Socklen_t) int __asm__ ("connect");
+func libc_socket(domain, typ, protocol int) int __asm__ ("socket");
+func libc_setsockopt(fd, level, optname int, optval *byte, optlen Socklen_t) int __asm__ ("setsockopt");
+func libc_listen(fd, backlog int) int __asm__ ("listen");
+func libc_getsockopt(fd, level, optname int, optval *byte, optlen *Socklen_t) int __asm__ ("getsockopt");
+func libc_getsockname(fd int, sa *RawSockaddrAny, len *Socklen_t) int __asm__ ("getsockname");
+func libc_getpeername(fd int, sa *RawSockaddrAny, len *Socklen_t) int __asm__ ("getpeername");
+func libc_recv(fd int, buf *byte, len Size_t, flags int) Ssize_t __asm__ ("recv");
+func libc_recvfrom(fd int, buf *byte, len Size_t, flags int,
+ from *RawSockaddrAny, fromlen *Socklen_t) Ssize_t __asm__("recvfrom");
+func libc_recvmsg(fd int, msg *Msghdr, flags int) Ssize_t __asm__("recvmsg")
+func libc_send(fd int, buf *byte, len Size_t, flags int) Ssize_t __asm__("send");
+func libc_sendto(fd int, buf *byte, len Size_t, flags int,
+ to *RawSockaddrAny, tolen Socklen_t) Ssize_t __asm__("sendto");
+func libc_sendmsg(fd int, msg *Msghdr, flags int) Ssize_t __asm__("sendmsg")
+func libc_shutdown(fd int, how int) int __asm__ ("shutdown");
+
+func Accept(fd int) (nfd int, sa Sockaddr, errno int) {
+ var rsa RawSockaddrAny;
+ var len Socklen_t = SizeofSockaddrAny;
+ nfd = libc_accept(fd, &rsa, &len);
+ if nfd < 0 {
+ errno = GetErrno();
+ return;
+ }
+ sa, errno = anyToSockaddr(&rsa);
+ if errno != 0 {
+ Close(nfd);
+ nfd = 0;
+ }
+ return;
+}
+
+func Bind(fd int, sa Sockaddr) (errno int) {
+ ptr, n, err := sa.sockaddr();
+ if err != 0 {
+ return err;
+ }
+ if libc_bind(fd, ptr, n) < 0 {
+ errno = GetErrno();
+ }
+ return;
+}
+
+func Connect(fd int, sa Sockaddr) (errno int) {
+ ptr, n, err := sa.sockaddr();
+ if err != 0 {
+ return err;
+ }
+ if libc_connect(fd, ptr, n) < 0 {
+ errno = GetErrno();
+ }
+ return;
+}
+
+func Socket(domain, typ, proto int) (fd, errno int) {
+ if domain == AF_INET6 && SocketDisableIPv6 {
+ return -1, EAFNOSUPPORT
+ }
+ fd = libc_socket(int(domain), int(typ), int(proto));
+ if fd < 0 {
+ errno = GetErrno();
+ }
+ return;
+}
+
+func Listen(fd int, n int) (errno int) {
+ r := libc_listen(int(fd), int(n));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func setsockopt(fd, level, opt int, valueptr uintptr, length Socklen_t) (errno int) {
+ r := libc_setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(valueptr)),
+ length);
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func SetsockoptInt(fd, level, opt int, value int) (errno int) {
+ var n = int32(value);
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), 4);
+}
+
+func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(tv)), Socklen_t(unsafe.Sizeof(*tv)));
+}
+
+func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), Socklen_t(unsafe.Sizeof(*l)));
+}
+
+func SetsockoptString(fd, level, opt int, s string) (errno int) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), Socklen_t(len(s)))
+}
+
+func Getsockname(fd int) (sa Sockaddr, errno int) {
+ var rsa RawSockaddrAny;
+ var len Socklen_t = SizeofSockaddrAny;
+ if libc_getsockname(fd, &rsa, &len) != 0 {
+ errno = GetErrno();
+ return;
+ }
+ return anyToSockaddr(&rsa);
+}
+
+func Getpeername(fd int) (sa Sockaddr, errno int) {
+ var rsa RawSockaddrAny;
+ var len Socklen_t = SizeofSockaddrAny;
+ if libc_getpeername(fd, &rsa, &len) != 0 {
+ errno = GetErrno();
+ return;
+ }
+ return anyToSockaddr(&rsa);
+}
+
+func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, errno int) {
+ var rsa RawSockaddrAny;
+ var slen Socklen_t = SizeofSockaddrAny;
+ var _p0 *byte;
+ if len(p) > 0 { _p0 = &p[0]; }
+ r := libc_recvfrom(fd, _p0, Size_t(len(p)), flags, &rsa, &slen);
+ n = int(r);
+ if r == -1 {
+ errno = GetErrno();
+ } else {
+ from, errno = anyToSockaddr(&rsa);
+ }
+ return;
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = Iovec_len_t(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = Msghdr_controllen_t(length)
+}
+
+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 != 0 {
+ from, errno = anyToSockaddr(&rsa)
+ }
+ return
+}
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+ r := libc_recvmsg(s, msg, flags)
+ if r < 0 {
+ errno = GetErrno()
+ } else {
+ n = int(r)
+ }
+ return
+}
+
+func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
+ ptr, n, err := to.sockaddr();
+ if err != 0 {
+ return err;
+ }
+ var _p0 *byte;
+ if len(p) > 0 { _p0 = &p[0]; }
+ r := libc_sendto(fd, _p0, Size_t(len(p)), flags, ptr, n);
+ if r == -1 { errno = GetErrno(); }
+ return;
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
+ var ptr *RawSockaddrAny
+ var nsock Socklen_t
+ if to != nil {
+ var err int
+ ptr, nsock, err = to.sockaddr()
+ if err != 0 {
+ return err
+ }
+ }
+ var msg Msghdr
+ msg.Name = (*byte)(unsafe.Pointer(ptr))
+ msg.Namelen = uint32(nsock)
+ 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
+}
+
+func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+ if libc_sendmsg(s, msg, flags) < 0 {
+ errno = GetErrno()
+ }
+ return
+}
+
+func Shutdown(fd int, how int) (errno int) {
+ r := libc_shutdown(fd, how);
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+// FIXME: No getsockopt.
diff --git a/libgo/syscalls/socket_bsd.go b/libgo/syscalls/socket_bsd.go
new file mode 100644
index 000000000..f4d06b4f5
--- /dev/null
+++ b/libgo/syscalls/socket_bsd.go
@@ -0,0 +1,74 @@
+// socket_bsd.go -- Socket handling specific to *BSD based systems.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+const SizeofSockaddrInet4 = 16
+const SizeofSockaddrInet6 = 28
+const SizeofSockaddrUnix = 110
+
+type RawSockaddrInet4 struct {
+ Len uint8;
+ Family uint8;
+ Port uint16;
+ Addr [4]byte /* in_addr */;
+ Zero [8]uint8;
+}
+
+func (sa *RawSockaddrInet4) setLen() Socklen_t {
+ sa.Len = SizeofSockaddrInet4
+ return SizeofSockaddrInet4
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8;
+ Family uint8;
+ Port uint16;
+ Flowinfo uint32;
+ Addr [16]byte /* in6_addr */;
+ Scope_id uint32;
+}
+
+func (sa *RawSockaddrInet6) setLen() Socklen_t {
+ sa.Len = SizeofSockaddrInet6
+ return SizeofSockaddrInet6
+}
+
+type RawSockaddrUnix struct {
+ Len uint8;
+ Family uint8;
+ Path [108]int8;
+}
+
+func (sa *RawSockaddrUnix) setLen(n int) {
+ sa.Len = uint8(3 + n) // 2 for Family, Len; 1 for NUL.
+}
+
+func (sa *RawSockaddrUnix) getLen() (int, int) {
+ if sa.Len < 3 || sa.Len > SizeofSockaddrUnix {
+ return 0, EINVAL
+ }
+ n := int(sa.Len) - 3 // subtract leading Family, Len, terminating NUL.
+ for i := 0; i < n; i++ {
+ if sa.Path[i] == 0 {
+ // found early NUL; assume Len is overestimating.
+ n = i
+ break
+ }
+ }
+ return n, 0
+}
+
+type RawSockaddr struct {
+ Len uint8;
+ Family uint8;
+ Data [14]int8;
+}
+
+// BindToDevice binds the socket associated with fd to device.
+func BindToDevice(fd int, device string) (errno int) {
+ return ENOSYS
+}
diff --git a/libgo/syscalls/socket_epoll.go b/libgo/syscalls/socket_epoll.go
new file mode 100644
index 000000000..0013f3349
--- /dev/null
+++ b/libgo/syscalls/socket_epoll.go
@@ -0,0 +1,50 @@
+// socket_epoll.go -- GNU/Linux epoll handling.
+
+// 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.
+
+// Support for GNU/Linux epoll.
+// Only for implementing net package.
+// DO NOT USE DIRECTLY.
+
+package syscall
+
+// We don't take this type directly from the header file because it
+// uses a union. FIXME.
+
+type EpollEvent struct {
+ Events uint32;
+ Fd int32;
+ Pad int32;
+};
+
+func libc_epoll_create(size int) int __asm__ ("epoll_create");
+func libc_epoll_ctl(epfd, op, fd int, event *EpollEvent) int __asm__ ("epoll_ctl");
+func libc_epoll_wait(epfd int, events *EpollEvent, maxevents int,
+ timeout int) int __asm__ ("epoll_wait");
+
+
+func EpollCreate(size int) (fd int, errno int) {
+ fd = libc_epoll_create(int(size));
+ if fd < 0 { errno = GetErrno() }
+ return;
+}
+
+func EpollCtl(epfd, op, fd int, ev *EpollEvent) (errno int) {
+ r := libc_epoll_ctl(epfd, op, fd, ev);
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func EpollWait(epfd int, ev []EpollEvent, msec int) (n int, errno int) {
+ var events *EpollEvent;
+ var maxevents int;
+ if len(ev) > 0 {
+ maxevents = len(ev);
+ events = &ev[0]
+ }
+ n = libc_epoll_wait(epfd, events, maxevents, msec);
+ if n < 0 { errno = GetErrno() }
+ return;
+}
diff --git a/libgo/syscalls/socket_linux.go b/libgo/syscalls/socket_linux.go
new file mode 100644
index 000000000..cdcdf4ff2
--- /dev/null
+++ b/libgo/syscalls/socket_linux.go
@@ -0,0 +1,75 @@
+// socket_linux.go -- Socket handling specific to Linux.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+const SizeofSockaddrInet4 = 16
+const SizeofSockaddrInet6 = 28
+const SizeofSockaddrUnix = 110
+
+type RawSockaddrInet4 struct {
+ Family uint16;
+ Port uint16;
+ Addr [4]byte /* in_addr */;
+ Zero [8]uint8;
+}
+
+func (sa *RawSockaddrInet4) setLen() Socklen_t {
+ return SizeofSockaddrInet4
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16;
+ Port uint16;
+ Flowinfo uint32;
+ Addr [16]byte /* in6_addr */;
+ Scope_id uint32;
+}
+
+func (sa *RawSockaddrInet6) setLen() Socklen_t {
+ return SizeofSockaddrInet6
+}
+
+type RawSockaddrUnix struct {
+ Family uint16;
+ Path [108]int8;
+}
+
+func (sa *RawSockaddrUnix) setLen(int) {
+}
+
+func (sa *RawSockaddrUnix) getLen() (int, int) {
+ if sa.Path[0] == 0 {
+ // "Abstract" Unix domain socket.
+ // Rewrite leading NUL as @ for textual display.
+ // (This is the standard convention.)
+ // Not friendly to overwrite in place,
+ // but the callers below don't care.
+ sa.Path[0] = '@';
+ }
+
+ // Assume path ends at NUL.
+ // This is not technically the Linux semantics for
+ // abstract Unix domain sockets--they are supposed
+ // to be uninterpreted fixed-size binary blobs--but
+ // everyone uses this convention.
+ n := 0;
+ for n < len(sa.Path) - 3 && sa.Path[n] != 0 {
+ n++;
+ }
+
+ return n, 0
+}
+
+type RawSockaddr struct {
+ Family uint16;
+ Data [14]int8;
+}
+
+// BindToDevice binds the socket associated with fd to device.
+func BindToDevice(fd int, device string) (errno int) {
+ return SetsockoptString(fd, SOL_SOCKET, SO_BINDTODEVICE, device)
+}
diff --git a/libgo/syscalls/socket_solaris.go b/libgo/syscalls/socket_solaris.go
new file mode 100644
index 000000000..13fe727c3
--- /dev/null
+++ b/libgo/syscalls/socket_solaris.go
@@ -0,0 +1,76 @@
+// socket_solaris.go -- Socket handling specific to Solaris.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+const SizeofSockaddrInet4 = 16
+const SizeofSockaddrInet6 = 32
+const SizeofSockaddrUnix = 110
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+func (sa *RawSockaddrInet4) setLen() Socklen_t {
+ return SizeofSockaddrInet4
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+ Src_id uint32
+}
+
+func (sa *RawSockaddrInet6) setLen() Socklen_t {
+ return SizeofSockaddrInet6
+}
+
+type RawSockaddrUnix struct {
+ Family uint16
+ Path [108]int8
+}
+
+func (sa *RawSockaddrUnix) setLen(int) {
+}
+
+func (sa *RawSockaddrUnix) getLen() (int, int) {
+ if sa.Path[0] == 0 {
+ // "Abstract" Unix domain socket.
+ // Rewrite leading NUL as @ for textual display.
+ // (This is the standard convention.)
+ // Not friendly to overwrite in place,
+ // but the callers below don't care.
+ sa.Path[0] = '@'
+ }
+
+ // Assume path ends at NUL.
+ // This is not technically the Linux semantics for
+ // abstract Unix domain sockets--they are supposed
+ // to be uninterpreted fixed-size binary blobs--but
+ // everyone uses this convention.
+ n := 0
+ for n < len(sa.Path) - 3 && sa.Path[n] != 0 {
+ n++
+ }
+
+ return n, 0
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]int8
+}
+
+// BindToDevice binds the socket associated with fd to device.
+func BindToDevice(fd int, device string) (errno int) {
+ return ENOSYS
+}
diff --git a/libgo/syscalls/stringbyte.go b/libgo/syscalls/stringbyte.go
new file mode 100644
index 000000000..b673c9b02
--- /dev/null
+++ b/libgo/syscalls/stringbyte.go
@@ -0,0 +1,24 @@
+// stringbyte.go -- string to bytes functions.
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+// StringByteSlice returns a NUL-terminated slice of bytes
+// containing the text of s.
+func StringByteSlice(s string) []byte {
+ a := make([]byte, len(s)+1);
+ for i := 0; i < len(s); i++ {
+ a[i] = s[i];
+ }
+ return a;
+}
+
+// StringBytePtr returns a pointer to a NUL-terminated array of bytes
+// containing the text of s.
+func StringBytePtr(s string) *byte {
+ p := StringByteSlice(s);
+ return &p[0];
+}
diff --git a/libgo/syscalls/syscall.go b/libgo/syscalls/syscall.go
new file mode 100644
index 000000000..fa7d9d068
--- /dev/null
+++ b/libgo/syscalls/syscall.go
@@ -0,0 +1,48 @@
+// syscall.go -- Basic syscall interface.
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package contains an interface to the low-level operating system
+// primitives. The details vary depending on the underlying system.
+// Its primary use is inside other packages that provide a more portable
+// interface to the system, such as "os", "time" and "net". Use those
+// packages rather than this one if you can.
+// For details of the functions and data types in this package consult
+// the manuals for the appropriate operating system.
+package syscall
+
+import "unsafe"
+
+func libc_syscall32(trap int32, a1, a2, a3, a4, a5, a6 int32) int32 __asm__ ("syscall");
+func libc_syscall64(trap int64, a1, a2, a3, a4, a5, a6 int64) int64 __asm__ ("syscall");
+
+// Do a system call. We look at the size of uintptr to see how to pass
+// the arguments, so that we don't pass a 64-bit value when the function
+// expects a 32-bit one.
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
+ var r uintptr;
+ if unsafe.Sizeof(r) == 4 {
+ r1 := libc_syscall32(int32(trap), int32(a1), int32(a2), int32(a3), 0, 0, 0);
+ r = uintptr(r1);
+ } else {
+ r1 := libc_syscall64(int64(trap), int64(a1), int64(a2), int64(a3), 0, 0, 0);
+ r = uintptr(r1);
+ }
+ return r, 0, uintptr(GetErrno());
+}
+
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
+ var r uintptr;
+ if unsafe.Sizeof(r) == 4 {
+ r1 := libc_syscall32(int32(trap), int32(a1), int32(a2), int32(a3),
+ int32(a4), int32(a5), int32(a6));
+ r = uintptr(r1);
+ } else {
+ r1 := libc_syscall64(int64(trap), int64(a1), int64(a2), int64(a3),
+ int64(a4), int64(a5), int64(a6));
+ r = uintptr(r1);
+ }
+ return r, 0, uintptr(GetErrno());
+}
diff --git a/libgo/syscalls/syscall_linux.go b/libgo/syscalls/syscall_linux.go
new file mode 100644
index 000000000..bdb92c5f4
--- /dev/null
+++ b/libgo/syscalls/syscall_linux.go
@@ -0,0 +1,188 @@
+// syscall_linux.go -- GNU/Linux specific syscall interface.
+
+// 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 syscall
+
+import "unsafe"
+
+func libc_ptrace(request int, pid Pid_t, addr uintptr, data *byte) _C_long __asm__ ("ptrace")
+
+var dummy *byte
+const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy))
+
+func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno int) {
+ // The peek requests are machine-size oriented, so we wrap it
+ // to retrieve arbitrary-length data.
+
+ var buf [sizeofPtr]byte;
+
+ // Leading edge. PEEKTEXT/PEEKDATA don't require aligned
+ // access (PEEKUSER warns that it might), but if we don't
+ // align our reads, we might straddle an unmapped page
+ // boundary and not get the bytes leading up to the page
+ // boundary.
+ n := 0;
+ if addr % sizeofPtr != 0 {
+ SetErrno(0);
+ val := libc_ptrace(req, Pid_t(pid), addr - addr%sizeofPtr, nil);
+ if errno := GetErrno(); errno != 0 {
+ return 0, errno;
+ }
+ *(*_C_long)(unsafe.Pointer(&buf[0])) = val;
+ n += copy(out, buf[addr%sizeofPtr:]);
+ out = out[n:];
+ }
+
+ // Remainder.
+ for len(out) > 0 {
+ // We use an internal buffer to gaurantee alignment.
+ // It's not documented if this is necessary, but we're paranoid.
+ SetErrno(0);
+ val := libc_ptrace(req, Pid_t(pid), addr+uintptr(n), nil);
+ if errno = GetErrno(); errno != 0 {
+ return n, errno;
+ }
+ *(*_C_long)(unsafe.Pointer(&buf[0])) = val;
+ copied := copy(out, buf[0:]);
+ n += copied;
+ out = out[copied:];
+ }
+
+ return n, 0;
+}
+
+func PtracePeekText(pid int, addr uintptr, out []byte) (count int, errno int) {
+ return ptracePeek(_PTRACE_PEEKTEXT, pid, addr, out);
+}
+
+func PtracePeekData(pid int, addr uintptr, out []byte) (count int, errno int) {
+ return ptracePeek(_PTRACE_PEEKDATA, pid, addr, out);
+}
+
+func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, errno int) {
+ // As for ptracePeek, we need to align our accesses to deal
+ // with the possibility of straddling an invalid page.
+
+ // Leading edge.
+ n := 0;
+ if addr % sizeofPtr != 0 {
+ var buf [sizeofPtr]byte;
+ if libc_ptrace(peekReq, Pid_t(pid), addr - addr%sizeofPtr, &buf[0]) < 0 {
+ return 0, GetErrno();
+ }
+ n += copy(buf[addr%sizeofPtr:], data);
+ word := (*byte)(unsafe.Pointer(*((*uintptr)(unsafe.Pointer(&buf[0])))));
+ if libc_ptrace(pokeReq, Pid_t(pid), addr - addr%sizeofPtr, word) < 0 {
+ return 0, GetErrno();
+ }
+ data = data[n:len(data)];
+ }
+
+ // Interior.
+ for uintptr(len(data)) > sizeofPtr {
+ word := (*byte)(unsafe.Pointer(*((*uintptr)(unsafe.Pointer(&data[0])))));
+ if libc_ptrace(pokeReq, Pid_t(pid), addr+uintptr(n), word) < 0 {
+ return n, GetErrno();
+ }
+ n += int(sizeofPtr);
+ data = data[sizeofPtr:len(data)];
+ }
+
+ // Trailing edge.
+ if len(data) > 0 {
+ var buf [sizeofPtr]byte;
+ if libc_ptrace(peekReq, Pid_t(pid), addr+uintptr(n), &buf[0]) < 0 {
+ return n, GetErrno();
+ }
+ copy(buf[0:], data);
+ word := (*byte)(unsafe.Pointer(*((*uintptr)(unsafe.Pointer(&buf[0])))));
+ if libc_ptrace(pokeReq, Pid_t(pid), addr+uintptr(n), word) < 0 {
+ return n, GetErrno();
+ }
+ n += len(data);
+ }
+
+ return n, 0;
+}
+
+func PtracePokeText(pid int, addr uintptr, data []byte) (count int, errno int) {
+ return ptracePoke(_PTRACE_POKETEXT, _PTRACE_PEEKTEXT, pid, addr, data);
+}
+
+func PtracePokeData(pid int, addr uintptr, data []byte) (count int, errno int) {
+ return ptracePoke(_PTRACE_POKEDATA, _PTRACE_PEEKDATA, pid, addr, data);
+}
+
+func PtraceGetRegs(pid int, regsout *PtraceRegs) (errno int) {
+ if libc_ptrace(_PTRACE_GETREGS, Pid_t(pid), 0, (*byte)(unsafe.Pointer(regsout))) < 0 {
+ return GetErrno();
+ } else {
+ return 0;
+ }
+}
+
+func PtraceSetRegs(pid int, regs *PtraceRegs) (errno int) {
+ if libc_ptrace(_PTRACE_SETREGS, Pid_t(pid), 0, (*byte)(unsafe.Pointer(regs))) < 0 {
+ return GetErrno();
+ } else {
+ return 0;
+ }
+}
+
+func PtraceSetOptions(pid int, options int) (errno int) {
+ if libc_ptrace(_PTRACE_SETOPTIONS, Pid_t(pid), 0, (*byte)(unsafe.Pointer(uintptr(options)))) < 0 {
+ return GetErrno();
+ } else {
+ return 0;
+ }
+}
+
+func PtraceGetEventMsg(pid int) (msg uint, errno int) {
+ var data _C_long;
+ if libc_ptrace(_PTRACE_GETEVENTMSG, Pid_t(pid), 0, (*byte)(unsafe.Pointer(&data))) < 0 {
+ errno = GetErrno();
+ }
+ msg = uint(data);
+ return;
+}
+
+func PtraceCont(pid int, signal int) (errno int) {
+ if libc_ptrace(_PTRACE_CONT, Pid_t(pid), 0, (*byte)(unsafe.Pointer(uintptr(signal)))) < 0 {
+ return GetErrno();
+ } else {
+ return 0;
+ }
+}
+
+func PtraceSingleStep(pid int) (errno int) {
+ if libc_ptrace(_PTRACE_SINGLESTEP, Pid_t(pid), 0, nil) < 0 {
+ return GetErrno();
+ } else {
+ return 0;
+ }
+}
+
+func PtraceAttach(pid int) (errno int) {
+ if libc_ptrace(_PTRACE_ATTACH, Pid_t(pid), 0, nil) < 0 {
+ return GetErrno();
+ } else {
+ return 0;
+ }
+}
+
+func PtraceDetach(pid int) (errno int) {
+ if libc_ptrace(_PTRACE_DETACH, Pid_t(pid), 0, nil) < 0 {
+ return GetErrno();
+ } else {
+ return 0;
+ }
+}
+
+func Tgkill(tgid int, tid int, sig int) (errno int) {
+ r1, r2, err := Syscall(SYS_TGKILL, uintptr(tgid), uintptr(tid),
+ uintptr(sig));
+ return int(err);
+}
diff --git a/libgo/syscalls/syscall_linux_386.go b/libgo/syscalls/syscall_linux_386.go
new file mode 100644
index 000000000..aca9c7bf5
--- /dev/null
+++ b/libgo/syscalls/syscall_linux_386.go
@@ -0,0 +1,15 @@
+// syscall_linux_386.go -- GNU/Linux 386 specific support
+
+// 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 syscall
+
+func (r *PtraceRegs) PC() uint64 {
+ return uint64(uint32(r.Eip));
+}
+
+func (r *PtraceRegs) SetPC(pc uint64) {
+ r.Eip = int32(pc);
+}
diff --git a/libgo/syscalls/syscall_linux_amd64.go b/libgo/syscalls/syscall_linux_amd64.go
new file mode 100644
index 000000000..9932579cc
--- /dev/null
+++ b/libgo/syscalls/syscall_linux_amd64.go
@@ -0,0 +1,15 @@
+// syscall_linux_amd64.go -- GNU/Linux 386 specific support
+
+// 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 syscall
+
+func (r *PtraceRegs) PC() uint64 {
+ return r.Rip;
+}
+
+func (r *PtraceRegs) SetPC(pc uint64) {
+ r.Rip = pc;
+}
diff --git a/libgo/syscalls/syscall_rtems.go b/libgo/syscalls/syscall_rtems.go
new file mode 100644
index 000000000..7f0c11954
--- /dev/null
+++ b/libgo/syscalls/syscall_rtems.go
@@ -0,0 +1,7 @@
+// syscall_rtems.go -- RTEMS specific syscall interface.
+
+// 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 syscall
diff --git a/libgo/syscalls/syscall_solaris.go b/libgo/syscalls/syscall_solaris.go
new file mode 100644
index 000000000..ec229339d
--- /dev/null
+++ b/libgo/syscalls/syscall_solaris.go
@@ -0,0 +1,7 @@
+// syscall_solaris.go -- Solaris 2 specific syscall interface.
+
+// 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 syscall
diff --git a/libgo/syscalls/syscall_solaris_386.go b/libgo/syscalls/syscall_solaris_386.go
new file mode 100644
index 000000000..7ff8f5b07
--- /dev/null
+++ b/libgo/syscalls/syscall_solaris_386.go
@@ -0,0 +1,20 @@
+// syscall_solaris_386.go -- Solaris/x86 specific support
+
+// 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 syscall
+
+import "unsafe"
+
+// FIXME: ptrace(3C) has this, but exec.go expects the next.
+//func libc_ptrace(request int, pid Pid_t, addr int, data int) int __asm__ ("ptrace")
+
+func libc_ptrace(request int, pid Pid_t, addr uintptr, data *byte) int __asm__ ("ptrace")
+
+var dummy *byte
+const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy))
+
+// 32-bit Solaris 2/x86 needs to use _nuname internally, cf. <sys/utsname.h>.
+func libc_uname(buf *Utsname) (errno int) __asm__("_nuname")
diff --git a/libgo/syscalls/syscall_solaris_amd64.go b/libgo/syscalls/syscall_solaris_amd64.go
new file mode 100644
index 000000000..15d225615
--- /dev/null
+++ b/libgo/syscalls/syscall_solaris_amd64.go
@@ -0,0 +1,21 @@
+// syscall_solaris_amd64.go -- Solaris/x64 specific support
+
+// 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 syscall
+
+import "unsafe"
+
+// FIXME: ptrace(3C) has this, but exec.go expects the next.
+//func libc_ptrace(request int, pid Pid_t, addr int, data int) int __asm__ ("ptrace")
+
+// 64-bit ptrace(3C) doesn't exist
+func libc_ptrace(request int, pid Pid_t, addr uintptr, data *byte) int {
+ SetErrno(ENOSYS)
+ return -1
+}
+
+var dummy *byte
+const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy))
diff --git a/libgo/syscalls/syscall_solaris_sparc.go b/libgo/syscalls/syscall_solaris_sparc.go
new file mode 100644
index 000000000..0be60b929
--- /dev/null
+++ b/libgo/syscalls/syscall_solaris_sparc.go
@@ -0,0 +1,17 @@
+// syscall_solaris_sparc.go -- Solaris/SPARC specific support
+
+// 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 syscall
+
+import "unsafe"
+
+// FIXME: ptrace(3C) has this, but exec.go expects the next.
+//func libc_ptrace(request int, pid Pid_t, addr int, data int) int __asm__ ("ptrace")
+
+func libc_ptrace(request int, pid Pid_t, addr uintptr, data *byte) int __asm__ ("ptrace")
+
+var dummy *byte
+const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy))
diff --git a/libgo/syscalls/syscall_solaris_sparc64.go b/libgo/syscalls/syscall_solaris_sparc64.go
new file mode 100644
index 000000000..81e2010cd
--- /dev/null
+++ b/libgo/syscalls/syscall_solaris_sparc64.go
@@ -0,0 +1,21 @@
+// syscall_solaris_sparc64.go -- Solaris/SPARCV9 specific support
+
+// 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 syscall
+
+import "unsafe"
+
+// FIXME: ptrace(3C) has this, but exec.go expects the next.
+//func libc_ptrace(request int, pid Pid_t, addr int, data int) int __asm__ ("ptrace")
+
+// 64-bit ptrace(3C) doesn't exist
+func libc_ptrace(request int, pid Pid_t, addr uintptr, data *byte) int {
+ SetErrno(ENOSYS)
+ return -1
+}
+
+var dummy *byte
+const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy))
diff --git a/libgo/syscalls/syscall_stubs.go b/libgo/syscalls/syscall_stubs.go
new file mode 100644
index 000000000..d864902ea
--- /dev/null
+++ b/libgo/syscalls/syscall_stubs.go
@@ -0,0 +1,33 @@
+// syscall_stubs.go -- Stubs of the basic syscall interface.
+
+// 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.
+
+// This package contains an interface to the low-level operating system
+// primitives. The details vary depending on the underlying system.
+// Its primary use is inside other packages that provide a more portable
+// interface to the system, such as "os", "time" and "net". Use those
+// packages rather than this one if you can.
+// For details of the functions and data types in this package consult
+// the manuals for the appropriate operating system.
+
+// These are stubs.
+
+package syscall
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
+ var r uintptr;
+ var i int;
+ i = -1;
+ r = uintptr(i);
+ return r, 0, uintptr(ENOSYS);
+}
+
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
+ var r uintptr;
+ var i int;
+ i = -1;
+ r = uintptr(i);
+ return r, 0, uintptr(ENOSYS);
+}
diff --git a/libgo/syscalls/syscall_uname.go b/libgo/syscalls/syscall_uname.go
new file mode 100644
index 000000000..955866c89
--- /dev/null
+++ b/libgo/syscalls/syscall_uname.go
@@ -0,0 +1,7 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func libc_uname(buf *Utsname) (errno int) __asm__("uname")
diff --git a/libgo/syscalls/syscall_unix.go b/libgo/syscalls/syscall_unix.go
new file mode 100644
index 000000000..a29b6b54b
--- /dev/null
+++ b/libgo/syscalls/syscall_unix.go
@@ -0,0 +1,24 @@
+// 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 syscall
+
+var (
+ Stdin = 0
+ Stdout = 1
+ Stderr = 2
+)
+
+const ENONE = 0
+
+func GetErrno() int
+func SetErrno(int)
+
+func Uname(buf *Utsname) (errno int) {
+ r := libc_uname(buf)
+ if r < 0 {
+ errno = GetErrno()
+ }
+ return
+}
diff --git a/libgo/syscalls/sysfile_largefile.go b/libgo/syscalls/sysfile_largefile.go
new file mode 100644
index 000000000..963a624bd
--- /dev/null
+++ b/libgo/syscalls/sysfile_largefile.go
@@ -0,0 +1,13 @@
+// sysfile_largefile.go -- For systems which use the large file interface.
+
+// 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 syscall
+
+func libc_pread(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm__ ("pread64")
+func libc_pwrite(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm__ ("pwrite64")
+func libc_lseek(int, Offset_t, int) Offset_t __asm__ ("lseek64")
+func libc_truncate(path *byte, length Offset_t) int __asm__ ("truncate64")
+func libc_ftruncate(fd int, length Offset_t) int __asm__ ("ftruncate64")
diff --git a/libgo/syscalls/sysfile_posix.go b/libgo/syscalls/sysfile_posix.go
new file mode 100644
index 000000000..8b724983c
--- /dev/null
+++ b/libgo/syscalls/sysfile_posix.go
@@ -0,0 +1,427 @@
+// sysfile_posix.go -- POSIX File handling.
+
+// 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.
+
+// Support for basic Unix file operations. This file simply
+// translates from Go data types to Unix data types, and handles
+// errno. FIXME: This could probably be done mechanically.
+
+package syscall
+
+import "unsafe"
+
+func libc_open(name *byte, mode int, perm Mode_t) int __asm__ ("open");
+func libc_close(fd int) int __asm__ ("close");
+func libc_read(fd int, buf *byte, count Size_t) Ssize_t __asm__ ("read");
+func libc_write(fd int, buf *byte, count Size_t) Ssize_t __asm__ ("write");
+func libc_fsync(fd int) int __asm__ ("fsync")
+func libc_pipe(filedes *int) int __asm__("pipe");
+func libc_unlink(name *byte) int __asm__ ("unlink");
+func libc_rmdir(name *byte) int __asm__ ("rmdir");
+func libc_fcntl(fd int, cmd int, arg int) int __asm__ ("fcntl");
+func libc_mkdir(name *byte, perm Mode_t) int __asm__ ("mkdir");
+func libc_dup(int) int __asm__ ("dup")
+func libc_gettimeofday(tv *Timeval, tz *byte) int __asm__ ("gettimeofday");
+func libc_select(int, *byte, *byte, *byte, *Timeval) int __asm__ ("select");
+func libc_chdir(name *byte) int __asm__ ("chdir");
+func libc_fchdir(int) int __asm__ ("fchdir");
+func libc_getcwd(*byte, Size_t) *byte __asm__ ("getcwd");
+func libc_link(oldpath *byte, newpath *byte) int __asm__ ("link");
+func libc_symlink(oldpath *byte, newpath *byte) int __asm__ ("symlink");
+func libc_readlink(*byte, *byte, Size_t) Ssize_t __asm__ ("readlink");
+func libc_rename(oldpath *byte, newpath *byte) int __asm__ ("rename");
+func libc_chmod(path *byte, mode Mode_t) int __asm__ ("chmod");
+func libc_fchmod(fd int, mode Mode_t) int __asm__ ("fchmod");
+func libc_chown(path *byte, owner Uid_t, group Gid_t) int __asm__ ("chown");
+func libc_fchown(fd int, owner Uid_t, group Gid_t) int __asm__ ("fchown");
+func libc_lchown(path *byte, owner Uid_t, group Gid_t) int __asm__ ("lchown");
+func libc_utimes(filename *byte, times *[2]Timeval) int __asm__ ("utimes");
+func libc_getuid() Uid_t __asm__ ("getuid");
+func libc_geteuid() Uid_t __asm__ ("geteuid");
+func libc_getgid() Gid_t __asm__ ("getgid");
+func libc_getegid() Gid_t __asm__ ("getegid");
+func libc_getgroups(size int, list *Gid_t) int __asm__ ("getgroups");
+func libc_getpagesize() int __asm__ ("getpagesize");
+func libc_exit(status int) __asm__ ("exit")
+func libc_getpid() Pid_t __asm__ ("getpid")
+func libc_getppid() Pid_t __asm__ ("getppid")
+func libc_kill(Pid_t, int) int __asm__ ("kill")
+
+func Open(name string, mode int, perm uint32) (fd int, errno int) {
+ fd = libc_open(StringBytePtr(name), mode, Mode_t(perm));
+ if fd < 0 { errno = GetErrno() }
+ return;
+}
+
+func Creat(name string, perm uint32) (fd int, errno int) {
+ fd = libc_open(StringBytePtr(name), O_CREAT | O_WRONLY | O_TRUNC, Mode_t(perm));
+ if fd < 0 { errno = GetErrno() }
+ return;
+}
+
+func Close(fd int) (errno int) {
+ r := libc_close(fd);
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Read(fd int, p []byte) (n int, errno int) {
+ var _p0 *byte;
+ if len(p) > 0 { _p0 = &p[0]; }
+ r := libc_read(fd, _p0, Size_t(len(p)));
+ if r == -1 { errno = GetErrno() }
+ n = int(r);
+ return;
+}
+
+func Write(fd int, p []byte) (n int, errno int) {
+ var _p0 *byte;
+ if len(p) > 0 { _p0 = &p[0]; }
+ r := libc_write(fd, _p0, Size_t(len(p)));
+ if r == -1 { errno = GetErrno() }
+ n = int(r);
+ return;
+}
+
+func Fsync(fd int) (errno int) {
+ if libc_fsync(fd) < 0 {
+ errno = GetErrno()
+ }
+ return
+}
+
+func Pread(fd int, p []byte, offset int64) (n int, errno int) {
+ var _p0 *byte;
+ if len(p) > 0 { _p0 = &p[0]; }
+ r := libc_pread(fd, _p0, Size_t(len(p)), Offset_t(offset));
+ if r == -1 { errno = GetErrno() }
+ n = int(r);
+ return;
+}
+
+func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
+ var _p0 *byte;
+ if len(p) > 0 { _p0 = &p[0]; }
+ r := libc_pwrite(fd, _p0, Size_t(len(p)), Offset_t(offset));
+ if r == -1 { errno = GetErrno() }
+ n = int(r);
+ return;
+}
+
+func Seek(fd int, offset int64, whence int) (off int64, errno int) {
+ r := libc_lseek(fd, Offset_t(offset), whence);
+ if r == -1 { errno = GetErrno() }
+ off = int64(r);
+ return;
+}
+
+func Pipe(p []int) (errno int) {
+ if len(p) != 2 {
+ return EINVAL;
+ }
+ var pp [2]int;
+ r := libc_pipe(&pp[0]);
+ if r < 0 {
+ errno = GetErrno();
+ }
+ p[0] = pp[0];
+ p[1] = pp[1];
+ return;
+}
+
+func Stat(name string, buf *Stat_t) (errno int) {
+ r := libc_stat(StringBytePtr(name), buf);
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Lstat(name string, buf *Stat_t) (errno int) {
+ r := libc_lstat(StringBytePtr(name), buf);
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Fstat(fd int, buf *Stat_t) (errno int) {
+ r := libc_fstat(fd, buf);
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Unlink(name string) (errno int) {
+ r := libc_unlink(StringBytePtr(name));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Rmdir(name string) (errno int) {
+ r := libc_rmdir(StringBytePtr(name));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Mkdir(path string, mode uint32) (errno int) {
+ r := libc_mkdir(StringBytePtr(path), Mode_t(mode));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Dup(oldfd int) (fd int, errno int) {
+ fd = libc_dup(oldfd)
+ if fd < 0 {
+ errno = GetErrno()
+ }
+ return
+}
+
+func Gettimeofday(tv *Timeval) (errno int) {
+ r := libc_gettimeofday(tv, nil);
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+type FdSet_t struct {
+ Fds_bits [(FD_SETSIZE + 63) / 64]int64;
+}
+
+func FDSet(fd int, set *FdSet_t) {
+ set.Fds_bits[fd / 64] |= (1 << (uint)(fd % 64))
+}
+
+func FDClr(fd int, set *FdSet_t) {
+ set.Fds_bits[fd / 64] &= ^(1 << (uint)(fd % 64))
+}
+
+func FDIsSet(fd int, set *FdSet_t) bool {
+ if set.Fds_bits[fd / 64] & (1 << (uint)(fd % 64)) != 0 {
+ return true
+ } else {
+ return false
+ }
+}
+
+func FDZero(set *FdSet_t) {
+ for i := 0; i < ((FD_SETSIZE + 63) / 64); i++ {
+ set.Fds_bits[i] = 0
+ }
+}
+
+func Select(nfds int, r *FdSet_t, w *FdSet_t, e *FdSet_t, timeout *Timeval) (n int, errno int) {
+ n = libc_select(nfds, (*byte)(unsafe.Pointer(r)),
+ (*byte)(unsafe.Pointer(e)),
+ (*byte)(unsafe.Pointer(e)), timeout);
+ if n < 0 { errno = GetErrno() }
+ return;
+}
+
+func Chdir(path string) (errno int) {
+ r := libc_chdir(StringBytePtr(path));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Fchdir(fd int) (errno int) {
+ r := libc_fchdir(int(fd));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+const ImplementsGetwd = true
+
+func Getwd() (ret string, errno int) {
+ for len := Size_t(4096); ; len *= 2 {
+ b := make([]byte, len);
+ p := libc_getcwd(&b[0], len);
+ if p != nil {
+ i := 0;
+ for b[i] != 0 {
+ i++;
+ }
+ return string(b[0:i]), 0;
+ }
+ e := GetErrno();
+ if e != ERANGE {
+ return "", e;
+ }
+ }
+}
+
+func Link(oldpath, newpath string) (errno int) {
+ r := libc_link(StringBytePtr(oldpath), StringBytePtr(newpath));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Symlink(oldpath, newpath string) (errno int) {
+ r := libc_symlink(StringBytePtr(oldpath), StringBytePtr(newpath));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Readlink(path string, buf []byte) (n int, errno int) {
+ var _p0 *byte;
+ if len(buf) > 0 { _p0 = &buf[0]; }
+ r := libc_readlink(StringBytePtr(path), _p0, Size_t(len(buf)));
+ if r < 0 { errno = GetErrno() }
+ n = int(r);
+ return;
+}
+
+func Rename(oldpath, newpath string) (errno int) {
+ r := libc_rename(StringBytePtr(oldpath), StringBytePtr(newpath));
+ if r < 0 { errno = GetErrno() }
+ return
+}
+
+func Chmod(path string, mode uint32) (errno int) {
+ r := libc_chmod(StringBytePtr(path), Mode_t(mode));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Fchmod(fd int, mode uint32) (errno int) {
+ r := libc_fchmod(fd, Mode_t(mode));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Chown(path string, uid int, gid int) (errno int) {
+ r := libc_chown(StringBytePtr(path), Uid_t(uid), Gid_t(gid));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Lchown(path string, uid int, gid int) (errno int) {
+ r := libc_lchown(StringBytePtr(path), Uid_t(uid), Gid_t(gid));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Fchown(fd int, uid int, gid int) (errno int) {
+ r := libc_fchown(fd, Uid_t(uid), Gid_t(gid));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Truncate(path string, length int64) (errno int) {
+ r := libc_truncate(StringBytePtr(path), Offset_t(length));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Ftruncate(fd int, length int64) (errno int) {
+ r := libc_ftruncate(fd, Offset_t(length));
+ if r < 0 { errno = GetErrno() }
+ return;
+}
+
+func Utimes(path string, tv []Timeval) (errno int) {
+ if len(tv) != 2 {
+ return EINVAL;
+ }
+ r := libc_utimes(StringBytePtr(path),
+ (*[2]Timeval)(unsafe.Pointer(&tv[0])));
+ if r < 0 {
+ errno = GetErrno();
+ }
+ return;
+}
+
+// Getuid returns the numeric user id of the caller.
+func Getuid() int {
+ return int(libc_getuid());
+}
+
+// Geteuid returns the numeric effective user id of the caller.
+func Geteuid() int {
+ return int(libc_geteuid());
+}
+
+// Getgid returns the numeric group id of the caller.
+func Getgid() int {
+ return int(libc_getgid());
+}
+
+// Getegid returns the numeric effective group id of the caller.
+func Getegid() int {
+ return int(libc_getegid());
+}
+
+// Getgroups returns a list of the numeric ids of groups that the caller belongs to.
+func Getgroups() (gids []int, errno int) {
+ n := libc_getgroups(0, nil);
+ if n < 0 {
+ return nil, GetErrno();
+ }
+ if n == 0 {
+ return nil, 0;
+ }
+
+ // Sanity check group count. Max is 1<<16 on Linux.
+ if n < 0 || n > 1<<20 {
+ return nil, EINVAL;
+ }
+
+ a := make([]Gid_t, n);
+ n = libc_getgroups(n, &a[0]);
+ if n < 0 {
+ return nil, GetErrno();
+ }
+ gids = make([]int, n);
+ for i, v := range a[0:n] {
+ gids[i] = int(v);
+ }
+ return;
+}
+
+func Getpagesize() int {
+ return libc_getpagesize();
+}
+
+func TimespecToNsec(ts Timespec) int64 {
+ return int64(ts.Sec)*1e9 + int64(ts.Nsec);
+}
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = Timespec_sec_t(nsec / 1e9);
+ ts.Nsec = Timespec_nsec_t(nsec % 1e9);
+ return;
+}
+
+func TimevalToNsec(tv Timeval) int64 {
+ return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3;
+}
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999; // round up to microsecond
+ tv.Sec = Timeval_sec_t(nsec/1e9);
+ tv.Usec = Timeval_usec_t(nsec%1e9 / 1e3);
+ return;
+}
+
+func Exit(code int) {
+ libc_exit(code);
+}
+
+func fcntl(fd, cmd, arg int) (val int, errno int) {
+ val = libc_fcntl(int(fd), int(cmd), int(arg));
+ if val == -1 { errno = GetErrno() }
+ return;
+}
+
+func Getpid() (pid int) {
+ return int(libc_getpid());
+}
+
+func Getppid() (ppid int) {
+ return int(libc_getppid());
+}
+
+func Kill(pid int, sig int) (errno int) {
+ r := libc_kill(Pid_t(pid), sig)
+ if r < 0 {
+ errno = GetErrno()
+ }
+ return
+}
diff --git a/libgo/syscalls/sysfile_regfile.go b/libgo/syscalls/sysfile_regfile.go
new file mode 100644
index 000000000..731c59c97
--- /dev/null
+++ b/libgo/syscalls/sysfile_regfile.go
@@ -0,0 +1,13 @@
+// sysfile_regfile.go -- For systems which do not use the large file interface.
+
+// 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 syscall
+
+func libc_pread(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm__ ("pread")
+func libc_pwrite(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t __asm__ ("pwrite")
+func libc_lseek(int, Offset_t, int) Offset_t __asm__ ("lseek")
+func libc_truncate(path *byte, length Offset_t) int __asm__ ("truncate")
+func libc_ftruncate(fd int, length Offset_t) int __asm__ ("ftruncate")
diff --git a/libgo/syscalls/sysfile_stat_largefile.go b/libgo/syscalls/sysfile_stat_largefile.go
new file mode 100644
index 000000000..1b785f70a
--- /dev/null
+++ b/libgo/syscalls/sysfile_stat_largefile.go
@@ -0,0 +1,12 @@
+// sysfile_stat_largefile.go -- For systems which use the large file interface
+// for *stat.
+
+// 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 syscall
+
+func libc_stat(name *byte, buf *Stat_t) int __asm__ ("stat64");
+func libc_fstat(fd int, buf *Stat_t) int __asm__ ("fstat64");
+func libc_lstat(name *byte, buf *Stat_t) int __asm__ ("lstat64");
diff --git a/libgo/syscalls/sysfile_stat_regfile.go b/libgo/syscalls/sysfile_stat_regfile.go
new file mode 100644
index 000000000..b3d486413
--- /dev/null
+++ b/libgo/syscalls/sysfile_stat_regfile.go
@@ -0,0 +1,12 @@
+// sysfile_stat_regfile.go -- For systems which do not use the large file
+// interface for *stat.
+
+// 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 syscall
+
+func libc_stat(name *byte, buf *Stat_t) int __asm__ ("stat");
+func libc_fstat(fd int, buf *Stat_t) int __asm__ ("fstat");
+func libc_lstat(name *byte, buf *Stat_t) int __asm__ ("lstat");
diff --git a/libgo/testsuite/Makefile.am b/libgo/testsuite/Makefile.am
new file mode 100644
index 000000000..8c6249d9d
--- /dev/null
+++ b/libgo/testsuite/Makefile.am
@@ -0,0 +1,21 @@
+## Process this file with automake to produce Makefile.in.
+
+AUTOMAKE_OPTIONS = foreign dejagnu
+
+# Setup the testing framework, if you have one
+EXPECT = `if [ -f $(top_builddir)/../expect/expect ] ; then \
+ echo $(top_builddir)/../expect/expect ; \
+ else echo expect ; fi`
+
+RUNTEST = `if [ -f $(top_srcdir)/../dejagnu/runtest ] ; then \
+ echo $(top_srcdir)/../dejagnu/runtest ; \
+ else echo runtest; fi`
+
+# When running the tests we set GCC_EXEC_PREFIX to the install tree so that
+# files that have already been installed there will be found. The -B option
+# overrides it, so use of GCC_EXEC_PREFIX will not result in using GCC files
+# from the install tree.
+
+AM_RUNTESTFLAGS = "TEST_GCC_EXEC_PREFIX=$(libdir)/gcc"
+
+CLEANFILES = *.log *.sum
diff --git a/libgo/testsuite/Makefile.in b/libgo/testsuite/Makefile.in
new file mode 100644
index 000000000..28cc9b9c0
--- /dev/null
+++ b/libgo/testsuite/Makefile.in
@@ -0,0 +1,413 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = testsuite
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
+ $(top_srcdir)/../config/lead-dot.m4 \
+ $(top_srcdir)/../config/multi.m4 \
+ $(top_srcdir)/../config/override.m4 \
+ $(top_srcdir)/../config/unwind_ipinfo.m4 \
+ $(top_srcdir)/config/go.m4 $(top_srcdir)/config/libtool.m4 \
+ $(top_srcdir)/config/ltoptions.m4 \
+ $(top_srcdir)/config/ltsugar.m4 \
+ $(top_srcdir)/config/ltversion.m4 \
+ $(top_srcdir)/config/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DEJATOOL = $(PACKAGE)
+RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GOARCH = @GOARCH@
+GOC = @GOC@
+GOCFLAGS = @GOCFLAGS@
+GOOS = @GOOS@
+GO_DEBUG_PROC_REGS_OS_ARCH_FILE = @GO_DEBUG_PROC_REGS_OS_ARCH_FILE@
+GO_SYSCALLS_SYSCALL_OS_ARCH_FILE = @GO_SYSCALLS_SYSCALL_OS_ARCH_FILE@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBFFI = @LIBFFI@
+LIBFFIINCS = @LIBFFIINCS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MATH_LIBS = @MATH_LIBS@
+MKDIR_P = @MKDIR_P@
+NET_LIBS = @NET_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJCOPY = @OBJCOPY@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPLIT_STACK = @SPLIT_STACK@
+STRINGOPS_FLAG = @STRINGOPS_FLAG@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WARN_FLAGS = @WARN_FLAGS@
+WERROR = @WERROR@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_shared = @enable_shared@
+enable_static = @enable_static@
+exec_prefix = @exec_prefix@
+glibgo_prefixdir = @glibgo_prefixdir@
+glibgo_toolexecdir = @glibgo_toolexecdir@
+glibgo_toolexeclibdir = @glibgo_toolexeclibdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libtool_VERSION = @libtool_VERSION@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+multi_basedir = @multi_basedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign dejagnu
+
+# Setup the testing framework, if you have one
+EXPECT = `if [ -f $(top_builddir)/../expect/expect ] ; then \
+ echo $(top_builddir)/../expect/expect ; \
+ else echo expect ; fi`
+
+RUNTEST = `if [ -f $(top_srcdir)/../dejagnu/runtest ] ; then \
+ echo $(top_srcdir)/../dejagnu/runtest ; \
+ else echo runtest; fi`
+
+
+# When running the tests we set GCC_EXEC_PREFIX to the install tree so that
+# files that have already been installed there will be found. The -B option
+# overrides it, so use of GCC_EXEC_PREFIX will not result in using GCC files
+# from the install tree.
+AM_RUNTESTFLAGS = "TEST_GCC_EXEC_PREFIX=$(libdir)/gcc"
+CLEANFILES = *.log *.sum
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign testsuite/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+check-DEJAGNU: site.exp
+ srcdir=`$(am__cd) $(srcdir) && pwd`; export srcdir; \
+ EXPECT=$(EXPECT); export EXPECT; \
+ runtest=$(RUNTEST); \
+ if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
+ exit_status=0; l='$(DEJATOOL)'; for tool in $$l; do \
+ if $$runtest $(AM_RUNTESTFLAGS) $(RUNTESTDEFAULTFLAGS) $(RUNTESTFLAGS); \
+ then :; else exit_status=1; fi; \
+ done; \
+ else echo "WARNING: could not find \`runtest'" 1>&2; :;\
+ fi; \
+ exit $$exit_status
+site.exp: Makefile
+ @echo 'Making a new site.exp file...'
+ @echo '## these variables are automatically generated by make ##' >site.tmp
+ @echo '# Do not edit here. If you wish to override these values' >>site.tmp
+ @echo '# edit the last section' >>site.tmp
+ @echo 'set srcdir $(srcdir)' >>site.tmp
+ @echo "set objdir `pwd`" >>site.tmp
+ @echo 'set build_alias "$(build_alias)"' >>site.tmp
+ @echo 'set build_triplet $(build_triplet)' >>site.tmp
+ @echo 'set host_alias "$(host_alias)"' >>site.tmp
+ @echo 'set host_triplet $(host_triplet)' >>site.tmp
+ @echo 'set target_alias "$(target_alias)"' >>site.tmp
+ @echo 'set target_triplet $(target_triplet)' >>site.tmp
+ @echo '## All variables above are generated by configure. Do Not Edit ##' >>site.tmp
+ @test ! -f site.exp || \
+ sed '1,/^## All variables above are.*##/ d' site.exp >> site.tmp
+ @-rm -f site.bak
+ @test ! -f site.exp || mv site.exp site.bak
+ @mv site.tmp site.exp
+
+distclean-DEJAGNU:
+ -rm -f site.exp site.bak
+ -l='$(DEJATOOL)'; for tool in $$l; do \
+ rm -f $$tool.sum $$tool.log; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-DEJAGNU distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: all all-am check check-DEJAGNU check-am clean clean-generic \
+ clean-libtool distclean distclean-DEJAGNU distclean-generic \
+ distclean-libtool dvi dvi-am html html-am info info-am install \
+ install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libgo/testsuite/config/default.exp b/libgo/testsuite/config/default.exp
new file mode 100644
index 000000000..c82d65870
--- /dev/null
+++ b/libgo/testsuite/config/default.exp
@@ -0,0 +1,17 @@
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib "standard.exp"
diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest
new file mode 100755
index 000000000..28aba6e2d
--- /dev/null
+++ b/libgo/testsuite/gotest
@@ -0,0 +1,343 @@
+#!/bin/sh
+# 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.
+
+# Using all the *_test.go files in the current directory, write out a file
+# _testmain.go that runs all its tests. Compile everything and run the
+# tests.
+# If files are named on the command line, use them instead of *_test.go.
+
+# Makes egrep,grep work better in general if we put them
+# in ordinary C mode instead of what the current language is.
+unset LANG
+export LC_ALL=C
+export LC_CTYPE=C
+
+GC=${GC:-gccgo}
+GL=${GL:-${GC-gccgo}}
+GOLIBS=
+export GC GL GOLIBS
+
+NM=${NM:-nm}
+
+# srcdir is where the source files are found. basedir is where the
+# source file paths are relative to.
+# gofiles are the test files. pkgfiles are the source files.
+srcdir=.
+basedir=.
+gofiles=""
+pkgfiles=""
+loop=true
+keep=false
+prefix=
+dejagnu=no
+while $loop; do
+ case "x$1" in
+ x--srcdir)
+ srcdir=$2
+ shift
+ shift
+ ;;
+ x--srcdir=*)
+ srcdir=`echo $1 | sed -e 's/^--srcdir=//'`
+ shift
+ ;;
+ x--basedir)
+ basedir=$2
+ shift
+ shift
+ ;;
+ x--basedir=*)
+ basedir=`echo $1 | sed -e 's/^--basedir=//'`
+ shift
+ ;;
+ x--prefix)
+ prefix=$2
+ shift
+ shift
+ ;;
+ x--prefix=*)
+ prefix=`echo $1 | sed -e 's/^--prefix=//'`
+ shift
+ ;;
+ x--keep)
+ keep=true
+ shift
+ ;;
+ x--pkgfiles)
+ pkgfiles=$2
+ shift
+ shift
+ ;;
+ x--pkgfiles=*)
+ pkgfiles=`echo $1 | sed -e 's/^--pkgfiles=//'`
+ shift
+ ;;
+ x--dejagnu)
+ dejagnu=$2
+ shift
+ shift
+ ;;
+ x--dejagnu=*)
+ dejagnu=`echo $1 | sed -e 's/^--dejagnu=//'`
+ shift
+ ;;
+ x-*)
+ loop=false
+ ;;
+ x)
+ loop=false
+ ;;
+ *)
+ gofiles="$gofiles $1"
+ shift
+ ;;
+ esac
+done
+
+DIR=gotest$$
+rm -rf $DIR
+mkdir $DIR
+
+cd $DIR
+
+if test $keep = false; then
+ trap "cd ..; rm -rf $DIR" 0 1 2 3 14 15
+else
+ trap "cd ..; echo Keeping $DIR" 0 1 2 3 14 15
+fi
+
+case "$srcdir" in
+ /*)
+ ;;
+ *)
+ srcdir="../$srcdir"
+ ;;
+esac
+
+SRCDIR=$srcdir
+export SRCDIR
+
+case "$basedir" in
+ /*)
+ ;;
+ *)
+ basedir="../$basedir"
+ ;;
+esac
+
+# Link all the files/directories in srcdir into our working directory,
+# so that the tests do not have to refer to srcdir to find test data.
+ln -s $srcdir/* .
+
+# Copy the .go files because io/utils_test.go expects a regular file.
+case "x$gofiles" in
+x)
+ case "x$pkgfiles" in
+ x)
+ for f in `cd $srcdir; ls *.go`; do
+ rm -f $f;
+ cp $srcdir/$f .
+ done
+ ;;
+ *)
+ for f in $pkgfiles; do
+ if test -f $basedir/$f; then
+ b=`basename $f`
+ rm -f $b
+ cp $basedir/$f $b
+ elif test -f ../$f; then
+ b=`basename $f`
+ rm -f $b
+ cp ../$f $b
+ else
+ echo "file $f not found" 1>&2
+ exit 1
+ fi
+ done
+ for f in `cd $srcdir; ls *_test.go`; do
+ rm -f $f
+ cp $srcdir/$f .
+ done
+ ;;
+ esac
+ ;;
+*)
+ for f in $gofiles; do
+ b=`basename $f`
+ rm -f $b
+ cp $basedir/$f $b
+ done
+ case "x$pkgfiles" in
+ x)
+ for f in `cd $srcdir; ls *.go | grep -v *_test.go`; do
+ rm -f $f
+ cp $srcdir/$f .
+ done
+ ;;
+ *)
+ for f in $pkgfiles; do
+ if test -f $basedir/$f; then
+ b=`basename $f`
+ rm -f $b
+ cp $basedir/$f $b
+ elif test -f ../$f; then
+ b=`basename $f`
+ rm -f $b
+ cp ../$f $b
+ else
+ echo "file $f not found" 1>&2
+ exit 1
+ fi
+ done
+ ;;
+ esac
+ ;;
+esac
+
+# Some tests expect the _obj directory created by the gc Makefiles.
+mkdir _obj
+
+# Some tests expect the _test directory created by the gc Makefiles.
+mkdir _test
+
+case "x$gofiles" in
+x)
+ gofiles=$(echo -n $(ls *_test.go 2>/dev/null))
+esac
+
+case "x$gofiles" in
+x)
+ echo 'no test files found' 1>&2
+ exit 1
+esac
+
+# Run any commands given in sources, like
+# // gotest: $GC foo.go
+# to build any test-only dependencies.
+holdGC="$GC"
+GC="$GC -g -c -I ."
+sed -n 's/^\/\/ gotest: //p' $gofiles | sh
+GC="$holdGC"
+
+case "x$pkgfiles" in
+x)
+ pkgbasefiles=$(echo -n $(ls *.go | grep -v _test.go 2>/dev/null))
+ ;;
+*)
+ for f in $pkgfiles; do
+ pkgbasefiles="$pkgbasefiles `basename $f`"
+ done
+ ;;
+esac
+
+case "x$pkgfiles" in
+x)
+ echo 'no source files found' 1>&2
+ exit 1
+ ;;
+esac
+
+# Split $gofiles into external gofiles (those in *_test packages)
+# and internal ones (those in the main package).
+xgofiles=$(echo $(grep '^package[ ]' $gofiles /dev/null | grep ':.*_test' | sed 's/:.*//'))
+gofiles=$(echo $(grep '^package[ ]' $gofiles /dev/null | grep -v ':.*_test' | sed 's/:.*//'))
+
+# External $O file
+xofile=""
+havex=false
+if [ "x$xgofiles" != "x" ]; then
+ xofile="_xtest_.o"
+ havex=true
+fi
+
+set -e
+
+package=`echo ${srcdir} | sed -e 's|^.*libgo/go/||'`
+
+prefixarg=
+if test -n "$prefix"; then
+ prefixarg="-fgo-prefix=$prefix"
+fi
+
+$GC -g $prefixarg -c -I . -o _gotest_.o $gofiles $pkgbasefiles
+if $havex; then
+ mkdir -p `dirname $package`
+ cp _gotest_.o `dirname $package`/lib`basename $package`.a
+ $GC -g -c -I . -o $xofile $xgofiles
+fi
+
+# They all compile; now generate the code to call them.
+{
+ # test functions are named TestFoo
+ # the grep -v eliminates methods and other special names
+ # that have multiple dots.
+ pattern='Test([^a-z].*)?'
+ # The -p option tells GNU nm not to sort.
+ # The -v option tells Solaris nm to sort by value.
+ tests=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
+ if [ "x$tests" = x ]; then
+ echo 'gotest: warning: no tests matching '$pattern in _gotest_.o $xofile 1>&2
+ exit 2
+ fi
+
+ # package spec
+ echo 'package main'
+ echo
+ # imports
+ if echo "$tests" | egrep -v '_test\.' >/dev/null; then
+ echo 'import "./_gotest_"'
+ fi
+ if $havex; then
+ echo 'import "./_xtest_"'
+ fi
+ if [ $package != "testing" ]; then
+ echo 'import "testing"'
+ echo 'import __regexp__ "regexp"' # rename in case tested package is called regexp
+ fi
+ # test array
+ echo
+ echo 'var tests = []testing.InternalTest {'
+ for i in $tests
+ do
+ echo ' { "'$i'", '$i' },'
+ done
+ echo '}'
+ # body
+ echo
+ echo 'func main() {'
+ echo ' testing.Main(__regexp__.MatchString, tests)'
+ echo '}'
+}>_testmain.go
+
+case "x$dejagnu" in
+xno)
+ ${GC} -g -c _testmain.go
+ ${GL} *.o ${GOLIBS}
+ ./a.out "$@"
+ ;;
+xyes)
+ rm -rf ../testsuite/*.o
+ files=`echo *`
+ for f in $files; do
+ if test "$f" = "_obj" || test "$f" = "_test"; then
+ continue
+ fi
+ rm -rf ../testsuite/$f
+ if test -f $f; then
+ cp $f ../testsuite/
+ else
+ ln -s ../$DIR/$f ../testsuite/
+ fi
+ done
+ cd ../testsuite
+ rm -rf _obj _test
+ mkdir _obj _test
+ $MAKE check RUNTESTFLAGS="$RUNTESTFLAGS GOTEST_TMPDIR=$DIR"
+ # Useful when using make check-target-libgo
+ cat libgo.log >> libgo-all.log
+ cat libgo.sum >> libgo-all.sum
+ rm -rf $files
+ ;;
+esac
diff --git a/libgo/testsuite/lib/libgo.exp b/libgo/testsuite/lib/libgo.exp
new file mode 100644
index 000000000..a6d44323d
--- /dev/null
+++ b/libgo/testsuite/lib/libgo.exp
@@ -0,0 +1,50 @@
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+set gccdir [lookfor_file $tool_root_dir gcc/libgcc.a]
+if {$gccdir != ""} {
+ set gccdir [file dirname $gccdir]
+}
+set GOC_UNDER_TEST "$gccdir/gccgo -B$gccdir/"
+set TESTING_IN_BUILD_TREE 1
+
+if [info exists GOTEST_TMPDIR] {
+ set tmpdir $GOTEST_TMPDIR
+}
+
+proc go_maybe_build_wrapper { args } {
+ libgo_maybe_build_wrapper $args
+}
+
+# DejaGnu does not have proper library search paths for load_lib.
+# We have to explicitly load everything that go.exp wants to load.
+
+proc load_gcc_lib { filename } {
+ global srcdir loaded_libs
+
+ load_file $srcdir/../../gcc/testsuite/lib/$filename
+ set loaded_libs($filename) ""
+}
+
+load_gcc_lib prune.exp
+load_gcc_lib target-libpath.exp
+load_gcc_lib wrapper.exp
+load_gcc_lib gcc-defs.exp
+load_gcc_lib go.exp
+
+proc libgo_init { args } {
+ go_init $args
+}
diff --git a/libgo/testsuite/libgo.testmain/testmain.exp b/libgo/testsuite/libgo.testmain/testmain.exp
new file mode 100644
index 000000000..efdd28d91
--- /dev/null
+++ b/libgo/testsuite/libgo.testmain/testmain.exp
@@ -0,0 +1,60 @@
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib libgo.exp
+
+lappend options "additional_flags=-I. -w -g"
+
+if [istarget "*-*-rtems*"] {
+ global options
+
+ verbose -log "Executing on host: tar cf FilesystemImage -h -C \
+ $tool_root_dir/$tool/${GOTEST_TMPDIR} ."
+ if [catch "exec tar cf FilesystemImage -h -C \
+ $tool_root_dir/$tool/${GOTEST_TMPDIR} ." error] {
+ perror "Error during tar of local filesystem: $error"
+ exit 1
+ }
+
+ verbose -log "Executing on host: ${RTEMS_BIN2C} FilesystemImage FilesystemImage"
+ if [catch "exec ${RTEMS_BIN2C} FilesystemImage FilesystemImage" error] {
+ perror "Error when creating FilesystemImage source file: $error"
+ exit 1
+ }
+ set comp_output [target_compile "${RTEMS_LIBGO_INIT}" \
+ "./rtems_libgo_init.o" "object" $options]
+ if ![ string match "" $comp_output ] {
+ verbose -log $comp_output
+ exit 1
+ }
+}
+
+set object_files [glob -nocomplain "*.o"]
+if [info exists gluefile] {
+ regsub $gluefile $object_files "" object_files
+}
+
+set comp_output [go_target_compile "$object_files _testmain.go" \
+ "./a.exe" "executable" $options]
+if ![ string match "" $comp_output ] {
+ verbose -log $comp_output
+ exit 1
+}
+
+set result [libgo_load "./a.exe" "" ""]
+
+set status [lindex $result 0]
+$status go